adding one shot playback and custom module cleanup

dev
mwinter 2 years ago
parent 21611e92b8
commit e3d1b7c0a3

@ -32,31 +32,14 @@ stringifyToDepth = function(data, maxDepth){
} }
} }
module.exports = { loadModel = function(model){
if(typeof model.ref_uid !== 'undefined') {receive("/ref_uid", model.ref_uid)}
init: function(){
// this will be executed once when the osc server starts
},
oscInFilter:function(data) {
var {host, port, address, args} = data
//console.log(data)
if (address === '/playing') {
var modelPath = resolve(args[0].value)
var model = loadJSON(modelPath)
//receive('/STATE/OPEN', guiStatePath)
receive("/ref_uid", model.ref_uid)
receive("/order_seed", model.order_seed)
receive("/dur_seed", model.dur_seed)
receive("/weights_seed", model.motifs_seed)
if(typeof model.order_seed !== 'undefined') {receive("/order_seed", model.order_seed)}
if(typeof model.dur_seed !== 'undefined') {receive("/dur_seed", model.dur_seed)}
if(typeof model.motifs_seed !== 'undefined') {receive("/weights_seed", model.motifs_seed)}
if(typeof model.entrances_probs_vals !== 'undefined') {
var envValsFlat = model.entrances_probs_vals.slice(5) var envValsFlat = model.entrances_probs_vals.slice(5)
var envSize = envValsFlat.length / 2 var envSize = envValsFlat.length / 2
var envVals = new Array(64).fill({type: 'f', value: 0}) var envVals = new Array(64).fill({type: 'f', value: 0})
@ -68,7 +51,9 @@ module.exports = {
receive("/entrances_probs_pad_val_rslider", model.entrances_probs_vals.slice(1, 3)) receive("/entrances_probs_pad_val_rslider", model.entrances_probs_vals.slice(1, 3))
receive("/entrances_probs_dur_env_rslider", ...model.entrances_probs_vals.slice(3, 5)) receive("/entrances_probs_dur_env_rslider", ...model.entrances_probs_vals.slice(3, 5))
receive("/entrances_probs_dur_env_canvas", ...envVals) receive("/entrances_probs_dur_env_canvas", ...envVals)
}
if(typeof model.passages_probs_vals !== 'undefined') {
var envValsFlat = model.passages_probs_vals.slice(5) var envValsFlat = model.passages_probs_vals.slice(5)
var envSize = envValsFlat.length / 2 var envSize = envValsFlat.length / 2
var envVals = new Array(64).fill({type: 'f', value: 0}) var envVals = new Array(64).fill({type: 'f', value: 0})
@ -80,7 +65,9 @@ module.exports = {
receive("/passages_probs_pad_val_rslider", model.passages_probs_vals.slice(1, 3)) receive("/passages_probs_pad_val_rslider", model.passages_probs_vals.slice(1, 3))
receive("/passages_probs_dur_env_rslider", ...model.passages_probs_vals.slice(3, 5)) receive("/passages_probs_dur_env_rslider", ...model.passages_probs_vals.slice(3, 5))
receive("/passages_probs_dur_env_canvas", ...envVals) receive("/passages_probs_dur_env_canvas", ...envVals)
}
if(typeof model.exits_probs_vals !== 'undefined') {
var envValsFlat = model.exits_probs_vals.slice(5) var envValsFlat = model.exits_probs_vals.slice(5)
var envSize = envValsFlat.length / 2 var envSize = envValsFlat.length / 2
var envVals = new Array(64).fill({type: 'f', value: 0}) var envVals = new Array(64).fill({type: 'f', value: 0})
@ -92,29 +79,54 @@ module.exports = {
receive("/exits_probs_pad_val_rslider", model.exits_probs_vals.slice(1, 3)) receive("/exits_probs_pad_val_rslider", model.exits_probs_vals.slice(1, 3))
receive("/exits_probs_dur_env_rslider", ...model.exits_probs_vals.slice(3, 5)) receive("/exits_probs_dur_env_rslider", ...model.exits_probs_vals.slice(3, 5))
receive("/exits_probs_dur_env_canvas", ...envVals) receive("/exits_probs_dur_env_canvas", ...envVals)
}
// no idea why I need to call the range sliders twice if(typeof model.ranges !== 'undefined') {
receive("/range_matrix/0_val_rslider", ...model.ranges[0]) receive("/range_matrix/0_val_rslider", ...model.ranges[0])
receive("/range_matrix/1_val_rslider", ...model.ranges[1]) receive("/range_matrix/1_val_rslider", ...model.ranges[1])
receive("/range_matrix/2_val_rslider", ...model.ranges[2]) receive("/range_matrix/2_val_rslider", ...model.ranges[2])
receive("/range_matrix/3_val_rslider", ...model.ranges[3]) receive("/range_matrix/3_val_rslider", ...model.ranges[3])
}
if(typeof model.passages_weights !== 'undefined') {
receive("/passages_weights/0_val_slider", model.passages_weights[0]) receive("/passages_weights/0_val_slider", model.passages_weights[0])
receive("/passages_weights/1_val_slider", model.passages_weights[1]) receive("/passages_weights/1_val_slider", model.passages_weights[1])
receive("/passages_weights/2_val_slider", model.passages_weights[2]) receive("/passages_weights/2_val_slider", model.passages_weights[2])
receive("/passages_weights/3_val_slider", model.passages_weights[3]) receive("/passages_weights/3_val_slider", model.passages_weights[3])
receive("/passages_weights/4_val_slider", model.passages_weights[4]) receive("/passages_weights/4_val_slider", model.passages_weights[4])
}
receive("/order", stringifyToDepth(model.order, 1)) if(typeof model.order !== 'undefined') {receive("/order", stringifyToDepth(model.order, 1))}
if(typeof model.sus_weights !== 'undefined') {
receive("/sus_weights/0_val_slider", model.sus_weights[0]) receive("/sus_weights/0_val_slider", model.sus_weights[0])
receive("/sus_weights/1_val_slider", model.sus_weights[1]) receive("/sus_weights/1_val_slider", model.sus_weights[1])
receive("/sus_weights/2_val_slider", model.sus_weights[2]) receive("/sus_weights/2_val_slider", model.sus_weights[2])
}
receive("/order_size_rslider", ...model.order_size) if(typeof model.order_size !== 'undefined') {receive("/order_size_rslider", ...model.order_size)}
receive("/passages_size_rslider", ...model.passages_size) if(typeof model.passages_size !== 'undefined') {receive("/passages_size_rslider", ...model.passages_size)}
receive("/mus_seq", stringifyToDepth(model.music_data, 3)) receive("/mus_seq", stringifyToDepth(model.music_data, 3))
}
module.exports = {
init: function(){
// this will be executed once when the osc server starts
},
oscInFilter:function(data) {
var {host, port, address, args} = data
//console.log(data)
if (address === '/playing') {
var modelPath = resolve(args[0].value)
var model = loadJSON(modelPath)
loadModel(model)
receive("/cur_play_index", args[1].value) receive("/cur_play_index", args[1].value)
} }
@ -268,10 +280,29 @@ module.exports = {
return {host, port, address, args} return {host, port, address, args}
} }
if ([/*'/commit', '/save_ledger', */'/transport'].includes(address)) { if (address === '/load_model_state') {
id = args[0].value
var modelPath = resolve(__dirname + "/../../resources/" + id + "/" + id + "_mus_model.json")
var model = loadJSON(modelPath)
loadModel(model)
return
}
if (address === '/transport') {
if(args[0].value == 2){
var model = {}
model.music_data = JSON.parse(args[1].value)
args[1].value = JSON.stringify(model)
}
return {host, port, address, args}
}
/*
if (['/commit', '/save_ledger', '/transport'].includes(address)) {
//console.log(data) //console.log(data)
return data return data
} }
*/
return return

@ -205,6 +205,52 @@
"mode": "push", "mode": "push",
"doubleTap": false, "doubleTap": false,
"decoupled": false "decoupled": false
},
{
"type": "button",
"top": 10,
"left": 210,
"lock": false,
"id": "one_shot",
"visible": true,
"interaction": true,
"comments": "",
"width": 90,
"height": 30,
"expand": "false",
"colorText": "auto",
"colorWidget": "auto",
"colorStroke": "auto",
"colorFill": "auto",
"alphaStroke": "auto",
"alphaFillOff": "auto",
"alphaFillOn": "auto",
"lineWidth": "auto",
"borderRadius": "auto",
"padding": "auto",
"html": "",
"css": "",
"value": "",
"default": 0,
"linkId": "",
"address": "auto",
"preArgs": "",
"typeTags": "",
"decimals": 2,
"target": "",
"ignoreDefaults": false,
"bypass": true,
"onCreate": "",
"onValue": "if(value === 1){\n send(false, \"/transport\", 2, get(\"mus_seq\"));\n} else {\n send(false, \"/transport\", 0);\n}\n ",
"colorTextOn": "auto",
"label": "#{@{this} == 0 ? \"play\" : \"stop\"}",
"vertical": false,
"wrap": false,
"on": 1,
"off": 0,
"mode": "toggle",
"doubleTap": false,
"decoupled": false
} }
], ],
"tabs": [], "tabs": [],
@ -331,7 +377,7 @@
"align": "center", "align": "center",
"hidePath": true, "hidePath": true,
"mode": "open", "mode": "open",
"directory": "Sketches/seeds_and_ledgers/resources", "directory": "Sketches/seeds_and_ledgers/source/resources",
"extension": "*", "extension": "*",
"allowDir": false "allowDir": false
}, },
@ -688,7 +734,7 @@
"ignoreDefaults": false, "ignoreDefaults": false,
"bypass": false, "bypass": false,
"onCreate": "", "onCreate": "",
"onValue": "if(value === get(\"start_play_index\")){\n set(\"start_play_index\", \"\")\n} else {\n set(\"start_play_index\", value)\n}\nset(\"this\", \"\")" "onValue": "if(value === get(\"start_play_index\")){\n set(\"start_play_index\", \"\")\n} else {\n set(\"start_play_index\", value)\n send(false, \"/load_model_state\", get(\"ledger_switch_vals\")[get(\"start_play_index\") + 1]);\n}\nset(\"this\", \"\")"
}, },
{ {
"type": "switch", "type": "switch",

@ -1,5 +1,5 @@
{ {
music_data: "music_data":
[ [
[ [
[ [
@ -62,7 +62,7 @@ music_data:
] ]
] ]
], ],
last_changes: "last_changes":
[ [
[ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, -1, 0, -1, 0 ] ], [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, -1, 0, -1, 0 ] ],
[ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], [ [ 1, -1, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, -1, 0, 0, 0, 0 ] ],
@ -70,5 +70,5 @@ last_changes:
[ [ 2, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ] ], [ [ 2, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -2, 0 ] ],
[ [ 2, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, -1, 0, 0, -1, 1 ] ] [ [ 2, -2, 0, 0, -1, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, 0, 0, 0, -1, 0 ], [ 0, -1, 0, 0, -1, 1 ] ]
], ],
ref_seed: "nil" "ref_uid": "nil"
} }

@ -0,0 +1,796 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr, oneShot = false;
var voices, durs, pbinds, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
pbinds = voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
});
if(oneShot.not, {
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
pbinds = pbinds ++
[
Pbind(
\type, \osc,
\addr, addr,
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
});
res = Ppar(pbinds);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {
seq = musicData;
dict["music_data"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
if(msg[1] == 1, {
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
}, {
"here".postln;
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -0,0 +1,55 @@
{
"music_data":
[
[
[
[ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 16.75 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.125 ],
[ [ [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.5 ],
[ [ [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0 ],
[ [ [ 0, 0, 0, 1, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.375 ],
[ [ [ 1, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ 2, 0, 0, -1, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ 2, 0, 0, 0, 0, -1 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ 2, -1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.375 ],
[ [ [ 1, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.125 ],
[ [ [ 2, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 3.25 ]
],
[
[ [ [ 2, 0, -1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ 2, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 9.375 ],
[ [ [ 2, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 3.125 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 3.25 ]
]
]
],
"last_changes":
[
[ [ 2, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 2, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 2, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 2, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ]
],
"cur_uid": "46f2010f",
"ref_uid": "nil",
"order_seed": 209033,
"dur_seed": 797162,
"motifs_seed": 128998,
"entrances_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ],
"passages_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"exits_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ],
"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ],
"order":
[
[ [ 2 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 3, 1 ] ],
[ [ 1 ], [ 0 ], [ 2, 3 ] ]
],
"sus_weights": [ 0.75, 0.69, 0.75 ],
"order_size": [ 2, 6 ],
"passages_size": [ 0, 10 ],
"motif_edited": "true",
"order_edited": "false"
}

@ -0,0 +1,794 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr, oneShot = false;
var voices, durs, pbinds, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
pbinds = voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
});
if(oneShot.not, {
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
pbinds = pbinds ++
[
Pbind(
\type, \osc,
\addr, addr,
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
});
res = Ppar(pbinds);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {
seq = musicData;
dict["music_data"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
if(msg[1] == 1, {
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -0,0 +1,794 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr, oneShot = false;
var voices, durs, pbinds, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
pbinds = voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
});
if(oneShot.not, {
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
pbinds = pbinds ++
[
Pbind(
\type, \osc,
\addr, addr,
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
});
res = Ppar(pbinds);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {
seq = musicData;
dict["music_data"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
if(msg[1] == 1, {
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -0,0 +1,796 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr, oneShot = false;
var voices, durs, pbinds, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
pbinds = voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
});
if(oneShot.not, {
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
pbinds = pbinds ++
[
Pbind(
\type, \osc,
\addr, addr,
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
});
res = Ppar(pbinds);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {
seq = musicData;
dict["music_data"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
if(msg[1] == 1, {
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
}, {
"here".postln;
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -0,0 +1,55 @@
{
"music_data":
[
[
[
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 7.125 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ] ], 0.375 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ] ], 0.125 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ] ], 7.25 ]
],
[
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ] ], 0.125 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 5 ],
[ [ [ "Rest" ], [ 0, 0, 0, -1, 0, 1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.25 ],
[ [ [ "Rest" ], [ -1, 0, 1, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.125 ],
[ [ [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.5 ],
[ [ [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 10.25 ],
[ [ [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 6.125 ]
]
]
],
"last_changes":
[
[ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ]
],
"cur_uid": "64085471",
"ref_uid": "nil",
"order_seed": 815237,
"dur_seed": 146432,
"motifs_seed": 680955,
"entrances_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ],
"passages_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"exits_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ],
"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ],
"order":
[
[ [ 1, 0 ], [ 2, 2, 2, 2 ], [ 3 ] ],
[ [ 2, 3 ], [ 1, 1, 1, 1, 1 ], [ 0 ] ]
],
"sus_weights": [ 0.75, 0.69, 0.75 ],
"order_size": [ 2, 6 ],
"passages_size": [ 0, 10 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,825 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr;
var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
res = Ppar(
voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
}) ++
[
Pbind(
\type, \osc,
\addr, addr,
//\indexPath, "/cur_play_index",
//\indexMsg, Pseq(indices, 1),
//\seqPath, "/mus_seq",
//\seqMsg, Pseq(seq, 1),
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
/*
writeResources = {arg path;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = [nameSpaces, modelItems].flop.collect({arg item;
var nameSpace, modelItem, depth = 0, insert = " ";
# nameSpace, modelItem = item;
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (modelItem == nil), {modelItem = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
*/
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
//model = File(path, "r").readAllString.parseJSON;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {
seq = musicData;
dict["music_data"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
//"here".postln;
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -0,0 +1,73 @@
{
"music_data":
[
[
[
[ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 10.25 ],
[ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 3 ],
[ [ [ "Rest" ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ],
[ [ [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ 1, 0, 0, 0, 0, -1 ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 1.625 ]
],
[
[ [ [ "Rest" ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.25 ],
[ [ [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ], [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.125 ],
[ [ [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 1, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.25 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 1 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 0 ] ], 8.125 ]
],
[
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ] ], 4.625 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, 0, 1, 0, -1, 0 ] ], 0.25 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ -1, 0, 1, 0, 1, 0 ] ], 0.25 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ -1, 1, 1, 0, 0, 0 ] ], 0.375 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 7.375 ]
],
[
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 0, -1, 1, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ 2, -1, 0, 0, 0, -1 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, -1, 1, 0, 0, 0 ] ], 3.375 ],
[ [ [ "Rest" ], [ 2, -1, 0, 0, 0, -1 ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ 2, -1, 0, 0, 0, -1 ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 3.625 ]
]
]
],
"last_changes":
[
[ [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 1, 0, -1, 0 ] ],
[ [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 1, 0, 0, 0, 0, -1 ], [ -1, 0, 1, 0, 1, 0 ] ],
[ [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 1, 0, 0, 0, 0, -1 ], [ -1, 1, 1, 0, 0, 0 ] ],
[ [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, -1, 1, 0, 0, 0 ] ],
[ [ 0, 0, 1, 0, 0, 0 ], [ 2, -1, 0, 0, 0, -1 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, -1, 1, 0, 0, 0 ] ]
],
"cur_uid": "6506161e",
"ref_uid": "nil",
"order_seed": 629173,
"dur_seed": 841732,
"motifs_seed": 647828,
"entrances_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ],
"passages_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"exits_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ],
"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ],
"order":
[
[ [ 2, 3 ], [ 1, 0, 1, 0, 1, 1 ], [ ] ],
[ [ 3 ], [ 1, 2, 2, 1, 1, 1 ], [ 0 ] ],
[ [ 0 ], [ 3, 3, 3, 3 ], [ 2, 1 ] ],
[ [ 2, 3 ], [ 1 ], [ 0 ] ]
],
"sus_weights": [ 0.75, 0.69, 0.75 ],
"order_size": [ 2, 6 ],
"passages_size": [ 0, 10 ],
"motif_edited": "true",
"order_edited": "false"
}

@ -0,0 +1,825 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr;
var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
res = Ppar(
voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
}) ++
[
Pbind(
\type, \osc,
\addr, addr,
//\indexPath, "/cur_play_index",
//\indexMsg, Pseq(indices, 1),
//\seqPath, "/mus_seq",
//\seqMsg, Pseq(seq, 1),
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
/*
writeResources = {arg path;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = [nameSpaces, modelItems].flop.collect({arg item;
var nameSpace, modelItem, depth = 0, insert = " ";
# nameSpace, modelItem = item;
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (modelItem == nil), {modelItem = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
*/
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
//model = File(path, "r").readAllString.parseJSON;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {
seq = musicData;
dict["music_data"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
//"here".postln;
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -0,0 +1,91 @@
{
"music_data":
[
[
[
[ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 7.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ] ], 0.25 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, 0 ] ], 0.25 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, -1, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 1, 0, 0, 0 ] ], 0.125 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 1, 0, 0, 0, 0 ] ], 9.125 ]
],
[
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, 1, 0, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 7.125 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ], [ "Rest" ], [ "Rest" ] ], 0.375 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0.125 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, -1, 0 ], [ "Rest" ], [ "Rest" ] ], 0.5 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ], [ "Rest" ] ], 0.375 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0.375 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, -1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0.125 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0.375 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 9 ]
],
[
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 4.75 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, 0, -1, 0 ] ], 0 ],
[ [ [ 0, 1, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, 0, 0, 0, -1, 0 ] ], 0.25 ],
[ [ [ 0, 1, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 1, 0 ] ], 0.375 ],
[ [ [ 0, 1, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, -1, 0, 0, 0, 0 ] ], 5 ]
],
[
[ [ [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, -1, 0, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.5 ],
[ [ [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ], [ 1, 0, -1, -1, 0, 0 ], [ "Rest" ] ], 0.375 ],
[ [ [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ], [ 0, 0, 0, -1, 0, 1 ], [ "Rest" ] ], 0.375 ],
[ [ [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ], [ 2, 0, 0, -2, 0, 0 ], [ "Rest" ] ], 0.375 ],
[ [ [ "Rest" ], [ 2, 0, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ] ], 7 ]
],
[
[ [ [ "Rest" ], [ 2, -1, 0, -1, 0, 1 ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ "Rest" ], [ 3, -1, -1, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ "Rest" ], [ 3, -1, 0, -1, -1, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ] ], 0.5 ],
[ [ [ "Rest" ], [ 3, -2, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ "Rest" ] ], 6.5 ],
[ [ [ "Rest" ], [ 3, -2, 0, -1, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0.25 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1.375 ]
]
]
],
"last_changes":
[
[ [ 0, 1, 0, -1, 0, 0 ], [ 2, 0, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 2, -1, 0, 0, 0, 0 ] ],
[ [ 0, 1, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 1 ], [ 2, -1, 0, -1, 0, 0 ], [ 2, -1, 0, 0, 0, 0 ] ],
[ [ 0, 1, 0, -1, 0, 0 ], [ 3, -1, -1, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 2, -1, 0, 0, 0, 0 ] ],
[ [ 0, 1, 0, -1, 0, 0 ], [ 3, -1, 0, -1, -1, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 2, -1, 0, 0, 0, 0 ] ],
[ [ 0, 1, 0, -1, 0, 0 ], [ 3, -2, 0, -1, 0, 0 ], [ 2, -1, 0, -1, 0, 0 ], [ 2, -1, 0, 0, 0, 0 ] ]
],
"cur_uid": "65c4abeb",
"ref_uid": "nil",
"order_seed": 792993,
"dur_seed": 209090,
"motifs_seed": 340840,
"entrances_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ],
"passages_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"exits_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ],
"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ],
"order":
[
[ [ 2, 1 ], [ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 ], [ 0 ] ],
[ [ 0 ], [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], [ 2, 3 ] ],
[ [ 1, 2 ], [ 3, 0, 3, 3 ], [ ] ],
[ [ 1 ], [ 2, 2, 2, 2, 2 ], [ 0, 3 ] ],
[ [ 2 ], [ 1, 1, 1, 1 ], [ 3, 0 ] ]
],
"sus_weights": [ 0.75, 0.69, 0.75 ],
"order_size": [ 2, 6 ],
"passages_size": [ 0, 10 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,796 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr, oneShot = false;
var voices, durs, pbinds, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
pbinds = voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
});
if(oneShot.not, {
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
pbinds = pbinds ++
[
Pbind(
\type, \osc,
\addr, addr,
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
});
res = Ppar(pbinds);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {
seq = musicData;
dict["music_data"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
if(msg[1] == 1, {
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
}, {
"here".postln;
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -0,0 +1,55 @@
{
"music_data":
[
[
[
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 7.125 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ] ], 0.375 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ] ], 0.125 ],
[ [ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ] ], 7.25 ]
],
[
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ] ], 0.125 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 5 ],
[ [ [ "Rest" ], [ 0, 0, 0, -1, 0, 1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.25 ],
[ [ [ "Rest" ], [ -1, 0, 1, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.125 ],
[ [ [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 0.5 ],
[ [ [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ], 10.25 ],
[ [ [ "Rest" ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 1 ], [ "Rest" ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 6.125 ]
]
]
],
"last_changes":
[
[ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, -1, 0, 1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ] ]
],
"cur_uid": "661a850b",
"ref_uid": "nil",
"order_seed": 815237,
"dur_seed": 146432,
"motifs_seed": 680955,
"entrances_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ],
"passages_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"exits_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ],
"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ],
"order":
[
[ [ 1, 0 ], [ 2, 2, 2, 2 ], [ 3 ] ],
[ [ 2, 3 ], [ 1, 1, 1, 1, 1 ], [ 0 ] ]
],
"sus_weights": [ 0.75, 0.69, 0.75 ],
"order_size": [ 2, 6 ],
"passages_size": [ 0, 10 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,825 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr;
var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
res = Ppar(
voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
}) ++
[
Pbind(
\type, \osc,
\addr, addr,
//\indexPath, "/cur_play_index",
//\indexMsg, Pseq(indices, 1),
//\seqPath, "/mus_seq",
//\seqMsg, Pseq(seq, 1),
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
/*
writeResources = {arg path;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = [nameSpaces, modelItems].flop.collect({arg item;
var nameSpace, modelItem, depth = 0, insert = " ";
# nameSpace, modelItem = item;
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (modelItem == nil), {modelItem = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
*/
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
//model = File(path, "r").readAllString.parseJSON;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {
seq = musicData;
dict["motif_edited"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
//"here".postln;
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -0,0 +1,57 @@
{
"music_data":
[
[
[
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 2 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ -1, 0, 0, 0, 0, 1 ] ], 0.125 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, -1, 0 ] ], 0.25 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 10.375 ]
],
[
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -2, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, -1, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.125 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, -1, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 1, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.125 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.125 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.125 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.25 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 2, -2, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, -1, 0, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 0, -1, 0, 0, 0, 0 ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 3.875 ]
]
]
],
"last_changes":
[
[ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 1, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 1, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, -1, 1, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 2, -2, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ],
[ [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, 0 ], [ 0, -1, 0, 0, 0, 0 ] ]
],
"cur_uid": "69a72421",
"ref_uid": "nil",
"order_seed": 921464,
"dur_seed": 715865,
"motifs_seed": 525056,
"entrances_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ],
"passages_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"exits_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ],
"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ],
"order":
[
[ [ 1, 2 ], [ 3, 3, 3 ], [ 0 ] ],
[ [ 3, 1 ], [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ], [ 0 ] ]
],
"sus_weights": [ 0.75, 0.69, 0.75 ],
"order_size": [ 2, 6 ],
"passages_size": [ 0, 10 ],
"motif_edited": "true",
"order_edited": "false"
}

@ -0,0 +1,822 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr;
var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
res = Ppar(
voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
}) ++
[
Pbind(
\type, \osc,
\addr, addr,
//\indexPath, "/cur_play_index",
//\indexMsg, Pseq(indices, 1),
//\seqPath, "/mus_seq",
//\seqMsg, Pseq(seq, 1),
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
/*
writeResources = {arg path;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = [nameSpaces, modelItems].flop.collect({arg item;
var nameSpace, modelItem, depth = 0, insert = " ";
# nameSpace, modelItem = item;
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (modelItem == nil), {modelItem = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
*/
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
//model = File(path, "r").readAllString.parseJSON;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
dict.postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {dict["motif_edited"] = "true"});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
//"here".postln;
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -0,0 +1,84 @@
{
"music_data":
[
[
[
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0.625 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 1, 0, 0, 0 ] ], 0.25 ],
[ [ [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 1, 0, 0, 0 ] ], 0 ],
[ [ [ -1, 0, 0, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ] ], 0.125 ],
[ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 1, -1, 0, 0, 0, 0 ] ], 0 ],
[ [ [ -1, 0, 0, 0, 0, 1 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 1, 0, 0, 0, 0 ] ], 0.25 ],
[ [ [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 1, 0, 0, 0, 0 ] ], 0.125 ],
[ [ [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 1, 0, 0, 0, 0 ] ], 0 ],
[ [ [ 1, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 1 ] ], 0.375 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 1 ] ], 3 ]
],
[
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 1 ] ], 0 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ "Rest" ], [ 0, 0, 1, 0, 1, 0 ] ], 0 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ -1, 1, 1, 0, 0, 0 ], [ 0, 0, 1, 0, 1, 0 ] ], 0.25 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ -1, 0, 1, 0, 1, 0 ], [ 0, 0, 1, 0, 1, 0 ] ], 0 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ -1, 0, 1, 0, 1, 0 ], [ 1, -1, 1, 0, 0, 0 ] ], 0.25 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ -1, 0, 1, 0, 1, 0 ], [ 0, 0, 2, 0, 0, 0 ] ], 5.125 ]
],
[
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ 0, 0, 2, 0, 0, 0 ] ], 0 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ 0, 0, 0, 0, 0, 1 ] ], 0.25 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 3.375 ]
],
[
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 1, 0, 0 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0 ],
[ [ [ -1, -1, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 0 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0.375 ],
[ [ [ -2, 1, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 0 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0 ],
[ [ [ -2, 1, 1, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0.25 ],
[ [ [ -1, 0, 0, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 1.5 ]
],
[
[ [ [ -2, 0, 1, 2, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0.375 ],
[ [ [ -1, -1, 2, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0.375 ],
[ [ [ -2, 0, 1, 1, 0, 2 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0.25 ],
[ [ [ -2, 0, 3, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0.25 ],
[ [ [ -1, -1, 1, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0.375 ],
[ [ [ -1, 0, 1, 1, 0, 0 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0.375 ],
[ [ [ -2, 1, 1, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 0.125 ],
[ [ [ -1, -1, 2, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ], 9.25 ],
[ [ [ -1, -1, 2, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ "Rest" ], [ -1, 0, 1, 1, 0, 1 ] ], 0 ],
[ [ [ -1, -1, 2, 1, 0, 1 ], [ "Rest" ], [ "Rest" ], [ -1, 0, 1, 1, 0, 1 ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ -1, 0, 1, 1, 0, 1 ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 9.625 ]
]
]
],
"last_changes":
[
[ [ -2, 0, 3, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ],
[ [ -1, -1, 1, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ],
[ [ -1, 0, 1, 1, 0, 0 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ],
[ [ -2, 1, 1, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ],
[ [ -1, -1, 2, 1, 0, 1 ], [ -2, 0, 2, 1, 0, 1 ], [ -2, 0, 1, 1, 0, 1 ], [ -1, 0, 1, 1, 0, 1 ] ]
],
"cur_uid": "7000ae3e",
"ref_uid": "nil",
"order_seed": 992409,
"dur_seed": 284618,
"motifs_seed": 483475,
"entrances_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ],
"passages_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"exits_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ],
"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ],
"order":
[
[ [ 1 ], [ 3, 0, 3, 0, 3, 0, 0, 3, 0 ], [ 2 ] ],
[ [ 0 ], [ 1, 3, 2, 2, 3, 3 ], [ ] ],
[ [ 0, 1 ], [ 2, 3, 3 ], [ ] ],
[ [ 2, 3 ], [ 1, 0, 0, 1, 0 ], [ ] ],
[ [ 3, 1, 2 ], [ 0, 0, 0, 0, 0, 0, 0, 0 ], [ ] ]
],
"sus_weights": [ 0.75, 0.69, 0.75 ],
"order_size": [ 2, 6 ],
"passages_size": [ 0, 10 ],
"motif_edited": "true",
"order_edited": "false"
}

@ -0,0 +1,794 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr, oneShot = false;
var voices, durs, pbinds, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
pbinds = voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
});
if(oneShot.not, {
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
pbinds = pbinds ++
[
Pbind(
\type, \osc,
\addr, addr,
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
});
res = Ppar(pbinds);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {
seq = musicData;
dict["music_data"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
if(msg[1] == 1, {
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -0,0 +1,794 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc;
// primary routines
var genMotif, genSecondarySeq;
// audition funcs
var genPatterns, genMidiPatterns;
// resource management funcs
var seedFunc, genUID, writeResources, stringifyToDepth, setSeeds, sanityCheck,
msgInterpret, loadLedgerFile, loadLedgerJSON, loadModelFile, loadModelJSON,
setGlobalVars, globalVarsToDict, saveLedger;
// model vars
//(model and global vars mostly set by OSC funcs
var seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark
if(Quarks.isInstalled("JSONlib").not, {
Quarks.install("https://github.com/musikinformatik/JSONlib.git");
thisProcess.recompile;
//HelpBrowser.openHelpFor("Classes/JSONlib");
});
//------helper funcs
hsArrayToCents = {
arg hsArray;
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
};
pDist = {
arg array1, array2, signed = false;
var pDistance;
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
if(signed, {pDistance}, {abs(pDistance)})
};
hdSum = {
arg hsArrays;
var size, distances, mean;
size = hsArrays.size;
distances = (size - 1).collect({arg i;
((i + 1)..(size - 1)).collect({arg j;
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsChordalDistance = {
arg hsArrays1, hsArrays2;
var size, distances, mean;
size = hsArrays1.size;
distances = hsArrays1.size.collect({arg i;
hsArrays2.size.collect({arg j;
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
});
}).flat;
mean = distances.sum / distances.size;
distances.sum
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
};
hsArrayToFreq = {
arg array;
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
};
//------score funcs
/*
isInRange = {
arg hsArray, min, max;
var cents;
cents = hsArrayToCents.value(hsArray);
(cents >= min) && (cents <= max)
};
*/
spacingScore = {
arg hsArrays, min;
var centsArray;
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
};
rangeScore = {
arg hsArray1, hsArray2, min, max, low, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
if((pDistance >= min) && (pDistance <= max), {1}, {low});
};
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = false;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
pDistance.gaussCurve(1, mean, sd)
};
inclusionScore = {
arg array, test, min = 0.01;
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
};
//------subroutines
genTuples = {
var tuples;
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
};
initVoices = {
var init, voicesInit;
voicesInit = popSize.collect({dims.collect({0})});
/*
voicesInit = [dims.collect({0})];
(popSize - 1).do({
arg rep, new;
rep = dims.rand;
new = voicesInit.last.deepCopy;
new[rep] = new[rep] + [-1, 1].choose();
voicesInit = voicesInit.add(new);
});
*/
voicesInit.deepCopy;
};
genDurFunc = {arg chordProb, minPad, maxPad, minDur, maxDur, envData, seed;
var env, pTable, durFunc;
env = Env.pairs([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
pTable = env.asRandomTable;
[chordProb, minPad, maxPad, minDur, maxDur, envData].postln;
durFunc = {arg allowChord, pad = false;
var res;
res = if(allowChord.not, {
pTable.tableRand * (maxDur - minDur) + minDur
}, {
if(1.0.rand < chordProb, {0}, {pTable.tableRand * (maxDur - minDur) + minDur});
}).round(0.125);
if(pad, {res = res + rrand(minPad.asFloat, maxPad.asFloat).round(0.125)});
if(res.asInteger == res, {res = res.asInteger});
res
};
seedFunc.value(durFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength - minMotifLength).rand + minMotifLength).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
noProgIns = (popSize - noSusIns).rand + 1;
noSilentIns = popSize - noSusIns - noProgIns;
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength - minProgLength).rand + minProgLength).collect({prog.choose}).scramble);
if(silent == nil, {silent = []});
[sus.scramble, prog, silent.scramble]
});
};
updateVoices = {arg ins, sus;
var voices, candidates, nWeights, nProbs, sel;
voices = lastXChanges.deepCopy.last;
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
candidates = difference(candidates.asSet, voices.asSet).asList;
nProbs = candidates.collect({arg candidate;
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
//maybe what you want here is a vector to another root and then favoring movement towards it.
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
});
nWeights = passagesWeights;
//this handles nWeights of 0; mainly for testing
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
nWeights = nWeights.select({arg weight; weight != 0});
nProbs = nProbs.flop.collect({arg scores, s;
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
sel = candidates.wchoose(nProbs);
voices[ins] = sel;
lastXChanges = lastXChanges.add(voices).keep(-5);
};
genSubMotif = {arg order, orderIndex, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
var sus, prog, silent, flatOrder, res, isInChord, allowChord, pad, lastXChangesHold, voices, adder;
# sus, prog, silent = order;
flatOrder = silent ++ sus ++ prog;
lastXChangesHold = lastXChanges.deepCopy;
voices = lastState.deepCopy;
isInChord = popSize.collect({false});
allowChord = false;
pad = false;
res = [];
"------generating motif".postln;
//need to figure out here if voices move between motifs
flatOrder.do({arg ins, i;
if(prog.includes(ins) && repeatLast.not, {updateVoices.value(ins, sus)});
adder = if(silent.includes(ins), {["Rest"]}, {lastXChanges.last.deepCopy[ins]});
if(voices[ins] != adder, {
var dur;
if((sus ++ silent).includes(ins), {
allowChord = (ins != sus.last);
pad = (ins == sus.last);
}, {
if(i < (flatOrder.size - 1), {
allowChord = (isInChord[flatOrder[i + 1]] || (ins == flatOrder[i + 1])).not;
pad = false;
}, {
allowChord = false;
pad = true
});
});
if((orderIndex == 0) && sus.includes(ins), {
dur = entrancesDurFunc.value(allowChord, pad);
}, {
dur = passagesDurFunc.value(allowChord, pad);
});
if(dur == 0, {isInChord[ins] = true}, {isInChord = popSize.collect({false})});
voices[ins] = adder;
res = res.add([voices.deepCopy.postln, dur]);
});
});
// pad ending
if(orderIndex == (orders.size - 1), {
(0..(popSize-1)).scramble.do({arg ins;
if(res.last.first[ins] != ["Rest"], {
var dur;
voices[ins] = ["Rest"];
allowChord = (voices != popSize.collect({["Rest"]}));
pad = allowChord.not;
dur = exitsDurFunc.value(allowChord, pad);
res = res.add([voices.deepCopy.postln, dur]);
});
});
});
//format and return
if(startFromLast, {lastXChanges = lastXChangesHold});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq;
repeats = 1;
fSeq = [];
repeats.do({arg index;
var motif;
motif = [];
orders.do({arg order, o;
var lastState, subMotif;
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
subMotif = genSubMotif.value(order, o, lastState, isLastOrder: o == (orders.size - 1));
motif = motif.add(subMotif);
});
sanityCheck.value(motif, index);
fSeq = fSeq.add(motif);
});
fSeq
};
genSecondarySeq = {arg seq;
var curdles, fSeq;
curdles = [];
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
fSeq = seq.clumps(curdles).collect({arg clump, m;
var repeats, paddedSeq;
//add rest
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
//implement repeats
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
repeats.collect({paddedSeq});
});
fSeq
};
//------audition funcs
/*
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~addr.sendMsg(~indexPath, ~indexMsg);
~addr.sendMsg(~seqPath, stringifyToDepth.value(~seqMsg, 3));
//~addr.sendMsg("/STATE/OPEN", (dir.replace("supercollider", "resources") +/+ ~idMsg +/+ ~idMsg ++ "_gui_state" ++ ".state").standardizePath.postln);
};
});
*/
Event.addEventType(\osc, {
if (~addr.postln.notNil) {
~msg.postln;
~addr.sendMsg(~path, *~msg);
};
});
genPatterns = {arg inSeq, addr, oneShot = false;
var voices, durs, pbinds, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
pbinds = voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\instrument, \test,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1)
)
});
if(oneShot.not, {
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
pbinds = pbinds ++
[
Pbind(
\type, \osc,
\addr, addr,
\path, "/playing",
\msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1)
);
]
});
res = Ppar(pbinds);
res
};
/*
genMidiPatterns = {arg seq;
var voices, durs, patterns, res, mOut, pbRange;
pbRange = 1; //semitones - change this as needed for your situation
mOut = MIDIOut.newByName("TiMidity", "TiMidity port 0").latency_(Server.default.latency);
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
res = Ppar(
voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs;
mOut.program(v, 70);
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
Pbind(
\type, \midi,
\chan, v,
\noteval, Pseq(freqs.cpsmidi - 24, 1),
\note, Pfunc({ | event | event[\noteval].floor }),
\dur, Pseq(fDurs, 1),
\midiout, mOut,
\amp, 1,
\bend, Pfunc({
| event |
if (event[\note].isRest.not) {
var pitchbendvalue = event[\noteval].frac.linlin(0, pbRange, 8192, 8192*2).asInteger;
m.bend(v, pitchbendvalue);
};
0; // return something other than nil to avoid stopping the pattern
}),
);
});
);
res
};
*/
//------resource management funcs
genUID = {Date.seed.asHexString.toLower};
seedFunc = {arg func, seed;
var funcArgs, next;
next = Routine({loop{func.valueArray(funcArgs).yield }});
next.randSeed_(seed);
{arg ...args; funcArgs = args; next.value}
};
stringifyToDepth = {arg data, maxDepth = 1;
var prettyString = "", rCount = 0, writeArray, indent;
if(maxDepth == 0, {
data.asCompileString
}, {
indent = {arg size; size.collect({" "}).join("")};
writeArray = {arg array;
prettyString = prettyString ++ indent.value(rCount) ++ "[\n";
rCount = rCount + 1;
if(rCount < maxDepth, {
array.do({arg subArray; writeArray.value(subArray)});
}, {
prettyString = prettyString ++ array.collect({arg subArray;
indent.value(rCount + 1) ++ subArray.asCompileString
}).join(",\n");
});
rCount = rCount - 1;
prettyString = prettyString ++ "\n" ++ indent.value(rCount) ++ "],\n";
};
writeArray.value(data);
prettyString.replace(",\n\n", "\n").drop(-2);
})
};
sanityCheck = {arg motif, index;
//print functions = very helpful
("----------" + index + "------------").postln;
motif.flatten.do({arg val, v;
if(v > 0, {
if(motif.flatten[v-1][0].hammingDistance(val[0]) > 1, {"problem 1".postln});
if(motif.flatten[v-1][0].hammingDistance(val[0]) == 0, {"problem 2".postln});
});
val.postln
});
"***********".postln;
};
msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
var res;
res = in;
if(res.isNil.not, {
if((res.isArray && res.isString.not), {
res = res.asCompileString;
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
if(escapeSingleQuotes, {res = res.replace("\'", "")});
if(escapeDoubleQuotes, {res = res.replace("\"", "")});
res = res.replace("Rest", "\"Rest\"");
res = res.interpret;
}, {
//res.postln;
if(res.every({arg char; char.isDecDigit}), {res = res.asInteger});
});
});
res
};
writeResources = {arg path, dict;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = nameSpaces.collect({arg nameSpace;
var depth = 0, insert = " ";
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (dict[nameSpace] == nil), {dict[nameSpace] = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(dict[nameSpace], depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.parseJSON)};
loadModelJSON = {arg jsonObject;
var dict;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict
};
setGlobalVars = {arg dict;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file;
file = File(path, "w");
file.write("{\n\"ledger\":\n" ++ stringifyToDepth.value(ledger, 1) ++ "\n}");
file.close;
};
//------global vars
primes = [[2, 1], [3, 2], [5, 4], [7, 4], [11, 8], [13, 8]];
//ranges = [[-2400, 0], [-1200, 1200], [0, 2400], [0, 2400]];
exPath = thisProcess.nowExecutingPath;
dir = exPath.dirname;
//popSize = 4;
dims = primes.size;
tuples = genTuples.value();
//refUID = nil;
group = Group.new;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
//passagesWeights = [1, 1, 1, 1, 1];
//susWeights = [1, 1, 1];
// order really matters!!!!
nameSpaces = [
"music_data", "last_changes", "cur_uid", "ref_uid", "order_seed", "dur_seed", "motifs_seed",
"entrances_probs_vals","passages_probs_vals", "exits_probs_vals",
"ranges", "passages_weights", "order", "sus_weights", "order_size", "passages_size",
"motif_edited", "order_edited"
];
//------OSC funcs
OSCdef(\load_ledger, {arg msg, time, addr, port;
loadLedgerFile.value(msg[1].asString);
}, \load_ledger);
OSCdef(\load_model, {arg msg, time, addr, port;
var dict;
dict = loadModelFile.value(msg[1].asString);
setGlobalVars.value(dict);
}, \load_model);
OSCdef(\save_ledger, {arg msg, time, addr, port;
msg.postln;
ledger = msgInterpret.value(msg[1].asString.parseJSON["ledger"], false).postln;
//loadLedgerJSON.value(msg[0])
saveLedger.value(ledger, msg[2].asString);
//loadLedgerFile.value(msg[1].asString);
}, \save_ledger);
OSCdef(\generate, {arg msg, time, addr, port;
var path, dict, durSeeds, musPath, modelString;
msg.postln;
path = msg[1].asString;
dict = loadModelFile.value(path);
setGlobalVars.value(dict);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
lastXChanges = if(refUID == nil, {
[initVoices.value().deepCopy];
}, {
var file;
file = File((dir +/+ ".." +/+ "resources" +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
durSeeds = seedFunc.value({3.collect({rrand(100000, 999999)})}, durSeed).value.postln;
entrancesDurFunc = genDurFunc.valueArray(entrancesProbVals[..4] ++ [entrancesProbVals[5..]] ++ [durSeeds[0]]);
passagesDurFunc = genDurFunc.valueArray(passagesProbVals[..4] ++ [passagesProbVals[5..]] ++ [durSeeds[1]]);
exitsDurFunc = genDurFunc.valueArray(exitsProbVals[..4] ++ [exitsProbVals[5..]] ++ [durSeeds[2]]);
if(orders == nil, {
orders = seedFunc.value(genOrders, orderSeed).valueArray(orderSize ++ passagesSize);
//addr.sendMsg("/order", stringifyToDepth.value(orders, 1));
});
seq = seedFunc.value(genMotif, motifSeed).value;
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
addr.sendMsg("/generated", path, modelString);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2;
//msg.postln;
/*
test1 = msg[1].asString.parseJSON;
test2 = (dir +/+ ".." +/+ "resources/tmp/tmp_music" ++ ".json").standardizePath.parseJSONFile;
msgInterpret.value(test1["music"])[0][0][0][1].class.postln;
msgInterpret.value(test2["music_data"])[0][0][0][1].class.postln;
(test1["music"] == test2["music_data"]).postln;
*/
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
musicChanged = (musicData != seq).postln;
curUID = genUID.value;
File.mkdir((dir +/+ ".." +/+ "resources" +/+ curUID).standardizePath);
File.copy(exPath, (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value;
if(musicChanged, {
seq = musicData;
dict["music_data"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict);
File.delete(ledgerPath ++ "_bak");
File.copy(ledgerPath, ledgerPath ++ "_bak");
File.delete(ledgerPath);
ledger = ledger.drop(-1).add(curUID);
saveLedger.value(ledger, ledgerPath);
addr.sendMsg("/committed", curUID, ledgerPath);
//refUID = curUID;
}, \commit);
OSCdef(\transport, {arg msg, time, addr, port;
msg.postln;
if(msg[1] == 0, {
player.stop;
group.set(\gate, 0);
}, {
// the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
if(msg[1] == 1, {
pSeq = [];
cuedSeek = (seq != nil);
indexStart = msg[2].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close;
});
});
if(cuedSeek, {
var path, file;
path = (dir +/+ ".." +/+ "resources/tmp/tmp_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close;
});
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
});
patterns = genPatterns.value(pSeq, addr);
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
});
player = player.play
});
}, \transport);
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms;
noHarms = 30;
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
//Out.ar([0, 1], sig1 * EnvGen.kr(Env.asr(dur, 0.3, 1), gate, doneAction: 2));
}).add;
)
(
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
noHarms = 30;
freq = WhiteNoise.ar * 3 + freq;
freqFinal = Duty.ar((1/freq), 0, freq);
trig = Changed.ar(freqFinal);
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
sig1 = HPF.ar(sig1, 300);
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
}).add;
)
"{\"a\": 1}".parseYAML["a"].asInteger;
"{\"a\": 1}".parseJSON["a"].isNumber;
1223423434123.asHexString.toLower
Date.getDate.rawSeconds
Date.seed.asHexString.toLower
n = NetAddr("localhost", 8080);
n.sendMsg("/GET/#", (NetAddr.localAddr.hostname ++ ":" ++ NetAddr.localAddr.port), "/passage_probs_vals");

@ -17,6 +17,12 @@
"4cf4476d", "4cf4476d",
"6abf27d4", "6abf27d4",
"46a0e6a8", "46a0e6a8",
"6be1486c" "6be1486c",
"7000ae3e",
"69a72421",
"6506161e",
"65c4abeb",
"661a850b",
"46f2010f"
] ]
} }

@ -1,6 +1,7 @@
{ {
"ledger": "ledger":
[ [
"314s49e1",
"4c01589b", "4c01589b",
"7e170ef8", "7e170ef8",
"46b6952a", "46b6952a",
@ -15,6 +16,12 @@
"55930f4d", "55930f4d",
"4cf4476d", "4cf4476d",
"6abf27d4", "6abf27d4",
"46a0e6a8" "46a0e6a8",
"6be1486c",
"7000ae3e",
"69a72421",
"6506161e",
"65c4abeb",
"661a850b"
] ]
} }

@ -3,63 +3,49 @@
[ [
[ [
[ [
[ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.25 ], [ [ [ "Rest" ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 6.75 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 2 ], [ [ [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.125 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, -1, 0, 0, 0 ] ], 0.375 ], [ [ [ 1, -1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.5 ],
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ -1, 1, 0, 0, 0, 0 ] ], 2.25 ] [ [ [ 0, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0 ],
[ [ [ 0, 0, 0, 1, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.375 ],
[ [ [ 1, 0, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ 2, 0, 0, -1, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ 2, 0, 0, 0, 0, -1 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.25 ],
[ [ [ 2, -1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.375 ],
[ [ [ 1, 1, 0, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.125 ],
[ [ [ 2, 0, -1, 0, 0, 0 ], [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 3.25 ]
], ],
[ [
[ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0.125 ], [ [ [ 2, 0, -1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ] ], 0 ], [ [ [ 2, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 9.375 ],
[ [ [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 0, 0, 0, -1 ], [ "Rest" ] ], 0.375 ], [ [ [ 2, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 3.125 ],
[ [ [ 1, 0, 0, -1, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ], [ "Rest" ] ], 0 ], [ [ [ "Rest" ], [ 0, 0, 0, 0, 0, 0 ], [ "Rest" ], [ "Rest" ] ], 0 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ], [ "Rest" ] ], 1.875 ] [ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 3.25 ]
],
[
[ [ [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 1, 0 ], [ 0, -1, 1, 0, 0, 0 ] ], 0 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 1, 0, 1, -1, 0, 0 ], [ 0, -1, 1, 0, 0, 0 ] ], 0.5 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ 0, 0, 1, 0, -1, 0 ], [ 1, 0, 1, -1, 0, 0 ], [ 0, -1, 1, 0, 0, 0 ] ], 0.5 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 1, 0 ], [ 1, 0, 1, -1, 0, 0 ], [ 0, -1, 1, 0, 0, 0 ] ], 2.625 ]
],
[
[ [ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 1, 0 ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0.375 ],
[ [ [ 1, -2, 1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0.375 ],
[ [ [ 0, -1, 2, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0 ],
[ [ [ 1, -1, 1, -1, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0.125 ],
[ [ [ 1, -1, 1, 0, 0, -1 ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0.125 ],
[ [ [ 0, -1, 1, 0, 1, 0 ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0.25 ],
[ [ [ 0, 0, 1, 0, 0, 0 ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0.375 ],
[ [ [ 1, -1, 1, 0, -1, 0 ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 2.125 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ 0, -1, 1, 0, 0, 0 ] ], 0.375 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 2.375 ]
] ]
] ]
], ],
"last_changes": "last_changes":
[ [
[ [ 1, -1, 1, -1, 0, 0 ], [ -1, 0, 1, 0, 1, 0 ], [ 1, 0, 1, -1, 0, 0 ], [ 0, -1, 1, 0, 0, 0 ] ], [ [ 2, 0, 0, 0, 0, -1 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 1, -1, 1, 0, 0, -1 ], [ -1, 0, 1, 0, 1, 0 ], [ 1, 0, 1, -1, 0, 0 ], [ 0, -1, 1, 0, 0, 0 ] ], [ [ 2, -1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 0, -1, 1, 0, 1, 0 ], [ -1, 0, 1, 0, 1, 0 ], [ 1, 0, 1, -1, 0, 0 ], [ 0, -1, 1, 0, 0, 0 ] ], [ [ 1, 1, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 0, 0, 1, 0, 0, 0 ], [ -1, 0, 1, 0, 1, 0 ], [ 1, 0, 1, -1, 0, 0 ], [ 0, -1, 1, 0, 0, 0 ] ], [ [ 2, 0, -1, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ],
[ [ 1, -1, 1, 0, -1, 0 ], [ -1, 0, 1, 0, 1, 0 ], [ 1, 0, 1, -1, 0, 0 ], [ 0, -1, 1, 0, 0, 0 ] ] [ [ 2, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0 ] ]
], ],
"cur_uid": "tmp", "cur_uid": "tmp",
"ref_uid": "nil", "ref_uid": "nil",
"order_seed": 470326, "order_seed": 209033,
"dur_seed": 597592, "dur_seed": 797162,
"motifs_seed": 662946, "motifs_seed": 128998,
"entrances_probs_vals": [ 0.75, 1.1507936507937, 2.6190476190476, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], "entrances_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.26424870466321, 0.75675675675676, 0.5, 0.5, 0.58549222797927, 0.72635135135135, 1, 0.5 ],
"passages_probs_vals": [ 0.75, 1.1507936507937, 2.6190476190476, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], "passages_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"exits_probs_vals": [ 0.75, 1.1507936507937, 2.6190476190476, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ], "exits_probs_vals": [ 0.75, 0, 10, 0, 0.5, 0.20725388601036, 0.68581081081081, 0.24093264248705, 0.34121621621622, 0.5, 0.5, 0.67616580310881, 0.81081081081081, 1, 0.5 ],
"ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ], "ranges": [ [ -384, 2400 ], [ -507, 2400 ], [ -282, 2237 ], [ -1200, 2053 ] ],
"passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ], "passages_weights": [ 0.75, 0.75, 0.75, 0.75, 0.75 ],
"order": "order":
[ [
[ [ 2, 1 ], [ 3, 3 ], [ 0 ] ], [ [ 2 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 3, 1 ] ],
[ [ 1 ], [ 0, 2, 2, 0 ], [ 3 ] ], [ [ 1 ], [ 0 ], [ 2, 3 ] ]
[ [ 0 ], [ 3, 2, 1, 1 ], [ ] ],
[ [ 3 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 2, 1 ] ]
], ],
"sus_weights": [ 0.75, 0.69, 0.75 ], "sus_weights": [ 0.75, 0.69, 0.75 ],
"order_size": [ 2, 6 ], "order_size": [ 2, 6 ],

@ -354,15 +354,11 @@ Event.addEventType(\osc, {
}; };
}); });
genPatterns = {arg inSeq, addr; genPatterns = {arg inSeq, addr, oneShot = false;
var voices, durs, patterns, res, indices, sectionDurs, msg, ids, seq; var voices, durs, pbinds, res, indices, sectionDurs, msg, ids, seq;
seq = inSeq.collect({arg mSeq; mSeq[0]}); seq = inSeq.collect({arg mSeq; mSeq[0]});
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop; # voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
msg = inSeq.collect({arg mSeq, m; mSeq[1..]}); pbinds = voices.flop.collect({arg voice;
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
res = Ppar(
voices.flop.collect({arg voice;
var clumps, hdScores, freqs, fDurs; var clumps, hdScores, freqs, fDurs;
clumps = voice.separate({arg a, b; a != b }); clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})}); freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
@ -375,21 +371,23 @@ genPatterns = {arg inSeq, addr;
\dur, Pseq(fDurs, 1), \dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1) \sustain, Pseq(fDurs, 1)
) )
}) ++ });
if(oneShot.not, {
msg = inSeq.collect({arg mSeq, m; mSeq[1..]});
//ids = inSeq.collect({arg mSeq, m; mSeq[2]});
sectionDurs = seq.collect({arg mSeq; mSeq.flatten2(mSeq.maxDepth - 5).flop[1].sum});
pbinds = pbinds ++
[ [
Pbind( Pbind(
\type, \osc, \type, \osc,
\addr, addr, \addr, addr,
//\indexPath, "/cur_play_index",
//\indexMsg, Pseq(indices, 1),
//\seqPath, "/mus_seq",
//\seqMsg, Pseq(seq, 1),
\path, "/playing", \path, "/playing",
\msg, Pseq(msg, 1), \msg, Pseq(msg, 1),
\dur, Pseq(sectionDurs, 1) \dur, Pseq(sectionDurs, 1)
); );
] ]
); });
res = Ppar(pbinds);
res res
}; };
@ -504,37 +502,6 @@ msgInterpret = {arg in, escapeDoubleQuotes = true, escapeSingleQuotes = true;
res res
}; };
/*
writeResources = {arg path;
var file, modelItems, resString;
file = File(path,"w");
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, passagesWeights, orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
resString = [nameSpaces, modelItems].flop.collect({arg item;
var nameSpace, modelItem, depth = 0, insert = " ";
# nameSpace, modelItem = item;
if(nameSpace == "music_data", {depth = 3; insert = "\n"});
if(nameSpace == "last_changes", {depth = 1; insert = "\n"});
if(nameSpace == "order", {depth = 1; insert = "\n"});
if((nameSpace == "ref_uid") && (modelItem == nil), {modelItem = "nil"});
"\"" ++ nameSpace ++ "\":" ++ insert ++ stringifyToDepth.value(modelItem, depth)
}).join(",\n");
resString = "{\n" ++ resString ++ "\n}";
file.write(resString);
file.close;
resString
};
*/
writeResources = {arg path, dict; writeResources = {arg path, dict;
var file, modelItems, resString; var file, modelItems, resString;
file = File(path,"w"); file = File(path,"w");
@ -567,7 +534,6 @@ loadModelFile = {arg path; loadModelJSON.value(File(path, "r").readAllString.par
loadModelJSON = {arg jsonObject; loadModelJSON = {arg jsonObject;
var dict; var dict;
//model = File(path, "r").readAllString.parseJSON;
dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])})); dict = Dictionary.with(*nameSpaces.collect({arg nS; nS->msgInterpret.value(jsonObject[nS])}));
dict dict
}; };
@ -708,7 +674,6 @@ OSCdef(\commit, {arg msg, time, addr, port;
*/ */
musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln; musicData = loadModelJSON.value(msg[1].asString.parseJSON)["music_data"].postln;
dict.postln;
musicChanged = (musicData != seq).postln; musicChanged = (musicData != seq).postln;
curUID = genUID.value; curUID = genUID.value;
@ -718,7 +683,11 @@ OSCdef(\commit, {arg msg, time, addr, port;
modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath; modelPath = (dir +/+ ".." +/+ "resources" +/+ curUID +/+ curUID ++ "_mus_model" ++ ".json").standardizePath;
dict = globalVarsToDict.value; dict = globalVarsToDict.value;
if(musicChanged, {dict["motif_edited"] = "true"}); if(musicChanged, {
seq = musicData;
dict["music_data"] = seq;
dict["motif_edited"] = "true"
});
dict["cur_uid"] = curUID; dict["cur_uid"] = curUID;
writeResources.value(modelPath, dict); writeResources.value(modelPath, dict);
@ -743,6 +712,7 @@ OSCdef(\transport, {arg msg, time, addr, port;
}, { }, {
// the cued sequence can now be read from file, so this can be cleaned up // the cued sequence can now be read from file, so this can be cleaned up
var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger; var cSize, patterns, pSeq, cuedSeek, indexStart, indexEnd, tmpLedger;
if(msg[1] == 1, {
pSeq = []; pSeq = [];
cuedSeek = (seq != nil); cuedSeek = (seq != nil);
indexStart = msg[2].asInteger; indexStart = msg[2].asInteger;
@ -753,7 +723,6 @@ OSCdef(\transport, {arg msg, time, addr, port;
var path, file; var path, file;
path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath; path = (dir +/+ ".." +/+ "resources" +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r"); file = File(path, "r");
//"here".postln;
pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]); pSeq = pSeq.add([msgInterpret.value(file.readAllString.postln.parseJSON["music_data"]), path, indexStart + index, uid]);
file.close; file.close;
}); });
@ -765,9 +734,14 @@ OSCdef(\transport, {arg msg, time, addr, port;
pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]); pSeq = pSeq.add([msgInterpret.value(file.readAllString.parseJSON["music_data"]), path, ledger.size - 1, "tmp"]);
file.close; file.close;
}); });
patterns = genPatterns.value(pSeq, addr); }, {
"here".postln;
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
});
patterns = genPatterns.value(pSeq, addr, true);
player = Pfset(pattern: patterns, cleanupFunc: { player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0); addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
}); });
player = player.play player = player.play
}); });

Loading…
Cancel
Save