more codagit add .git add .!

dev
mwinter 11 months ago
parent 93c60a0a4f
commit 115f499d07

@ -13,5 +13,15 @@
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/47bdba0e/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5f3f1c84/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4f53a446/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/731cf7ae/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4da80bfb/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/624f7439/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/61207e49/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/50c2b0ad/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/66b20499/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/65120e88/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/567a9375/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/736745da/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5f0075ab/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5ef20586/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4dd2a130/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/767e70f0/lilypond/part_I.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/536cac90/lilypond/part_I.ly"

@ -13,5 +13,15 @@
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/47bdba0e/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5f3f1c84/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4f53a446/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/731cf7ae/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4da80bfb/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/624f7439/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/61207e49/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/50c2b0ad/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/66b20499/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/65120e88/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/567a9375/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/736745da/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5f0075ab/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5ef20586/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4dd2a130/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/767e70f0/lilypond/part_II.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/536cac90/lilypond/part_II.ly"

@ -13,5 +13,15 @@
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/47bdba0e/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5f3f1c84/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4f53a446/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/731cf7ae/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4da80bfb/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/624f7439/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/61207e49/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/50c2b0ad/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/66b20499/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/65120e88/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/567a9375/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/736745da/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5f0075ab/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5ef20586/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4dd2a130/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/767e70f0/lilypond/part_III.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/536cac90/lilypond/part_III.ly"

@ -13,5 +13,15 @@
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/47bdba0e/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5f3f1c84/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4f53a446/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/731cf7ae/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4da80bfb/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/624f7439/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/61207e49/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/50c2b0ad/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/66b20499/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/65120e88/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/567a9375/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/736745da/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5f0075ab/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/5ef20586/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/4dd2a130/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/767e70f0/lilypond/part_IV.ly"
\include "/home/mwinter/Sketches/seeds_and_ledgers/source/resources/string_quartet_3_rise/536cac90/lilypond/part_IV.ly"

Binary file not shown.

@ -16,8 +16,17 @@
"47bdba0e",
"5f3f1c84",
"4f53a446",
"731cf7ae",
"4da80bfb",
"624f7439"
"624f7439",
"61207e49",
"50c2b0ad",
"66b20499",
"65120e88",
"567a9375",
"736745da",
"5f0075ab",
"5ef20586",
"4dd2a130",
"767e70f0",
"536cac90"
]
}

@ -16,7 +16,16 @@
"47bdba0e",
"5f3f1c84",
"4f53a446",
"731cf7ae",
"4da80bfb"
"624f7439",
"61207e49",
"50c2b0ad",
"66b20499",
"65120e88",
"567a9375",
"736745da",
"5f0075ab",
"5ef20586",
"4dd2a130",
"767e70f0"
]
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,65 @@
{
"music_data":
[
[
[
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 1, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 1, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 4, 1, 2, -1, 3 ], [ -5, 4, 1, 1, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 4, 1, 2, -1, 3 ], [ -5, 4, -1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 4, 1, 2, -1, 3 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 1, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -5, 4, 1, 2, -1, 3 ], [ -5, 4, 1, 1, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -5, 4, 1, 2, -1, 3 ], [ -5, 4, -1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -5, 4, 1, 2, -1, 3 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ]
],
"cur_uid": "4dd2a130",
"ref_uid": "5ef20586",
"order_seed": 837263,
"dur_seed": 562162,
"motifs_seed": 328077,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46296296296296, 0.39204545454545, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,4 @@
{
{ f'1^\markup { \pad-markup #0.2 "-38"}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ f''8^\markup { \pad-markup #0.2 "-38"}[ c'8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] cis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ ais'8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}] ~ ais'8[ c''8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}] f''4^\markup { \pad-markup #0.2 "-38"}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ ais2^\markup { \pad-markup #0.2 "-40"} c'4^\markup { \pad-markup #0.2 "-37"} cis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ f8^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}]}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ c''4^\markup { \pad-markup #0.2 "-37"} cis''2.^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↓" }}}
\bar "||"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,141 @@
{
"music_data":
[
[
[
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -4, 6, -2, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -2, 3, -1, 1, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -2, 4, -2, 1, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -2, 4, -1, 1, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -4, 4, 0, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -5, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -4, 4, 0, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -4, 3, -1, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -4, 3, -1, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -2, 4, -1, 1, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -4, 3, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -4, 3, -1, 2, -2, 2 ], [ -3, 3, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 4, 0, 2, -2, 2 ], [ -3, 3, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 4, -1, 2, -2, 2 ], [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -3, 3, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 5, 0, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, -1, 3, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 4, -1, 3, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -5, 4, -1, 2, 0, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -2, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -5, 4, -1, 2, 0, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 1, -1, 2 ], [ -5, 4, -1, 2, 0, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 1, -1, 2 ], [ -5, 5, -1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -2, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 5, -1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -6, 5, -1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 5, -1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -6, 5, -1, 2, -1, 2 ], [ -4, 3, -1, 2, -1, 2 ], [ -5, 5, -1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -5, 4, -2, 2, -1, 2 ], [ -4, 3, -1, 2, -1, 2 ], [ -5, 5, -1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -5, 4, -2, 2, -1, 2 ], [ -4, 3, -1, 2, -1, 2 ], [ -4, 4, -2, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -5, 4, -2, 2, -1, 2 ], [ -4, 3, -1, 2, -1, 2 ], [ -3, 2, -1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 2, -1, 2, -1, 2 ], [ -4, 3, -1, 2, -1, 2 ], [ -3, 2, -1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 3, -1, 2, -1, 2 ], [ -3, 2, -1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -3, 3, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 3, -1, 2, -1, 2 ], [ -3, 2, -1, 2, -1, 2 ] ], 0 ],
[ [ [ -3, 3, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, -1, 2, -2, 2 ], [ -3, 2, -1, 2, -1, 2 ] ], 0 ],
[ [ [ -3, 3, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -3, 3, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, -2, 2, -1, 2 ], [ -4, 4, -1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, -2, 2, -1, 2 ], [ -4, 4, -1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, -2, 2, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -3, 4, -1, 2, -1, 1 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, -2, 2, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ], 0.25 ],
[ [ [ -3, 4, -1, 2, -1, 1 ], [ -5, 4, -1, 2, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ], 0 ],
[ [ [ -2, 4, -1, 0, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ], 0.25 ],
[ [ [ -3, 3, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ], 0.25 ],
[ [ [ -5, 4, -1, 1, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ], 0.25 ],
[ [ [ -5, 4, -1, 2, -1, 1 ], [ -5, 4, -1, 2, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 4, -1, 2, -1, 1 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, -2, 2, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, -1, 2, 0, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, -2, 2, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -3, 3, -1, 2, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ],
[ [ -5, 4, -1, 1, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ],
[ [ -5, 4, -1, 2, -1, 1 ], [ -5, 4, -1, 2, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ],
[ [ -5, 4, -1, 2, -1, 1 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, -2, 2, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ],
[ [ -6, 4, -1, 2, 0, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, -2, 2, -1, 2 ], [ -3, 4, -1, 1, -1, 2 ] ]
],
"cur_uid": "50620822",
"ref_uid": "61207e49",
"order_seed": 837263,
"dur_seed": 454936,
"motifs_seed": 788402,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46913580246914, 0.67045454545455, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 0, 2, 3 ], [ 1, 1, 1, 1 ], [ ] ],
[ [ 1 ], [ 3, 0, 2, 2, 2, 2 ], [ ] ],
[ [ 1, 0 ], [ 3, 2 ], [ ] ],
[ [ 3 ], [ 2, 1, 0, 0, 1, 1, 1 ], [ ] ],
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ],
[ [ 0 ], [ 1, 3, 2, 2, 3, 2, 1 ], [ ] ],
[ [ 1, 0, 3 ], [ 2 ], [ ] ],
[ [ 0, 2 ], [ 1, 3, 3, 1, 1 ], [ ] ],
[ [ 1 ], [ 0, 2, 3, 2, 0, 3 ], [ ] ],
[ [ 1, 3 ], [ 0, 2, 0, 0, 0, 0 ], [ ] ],
[ [ 3, 1 ], [ 2, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,96 @@
{
"music_data":
[
[
[
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -4, 6, -2, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -2, 3, -1, 1, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -2, 4, -2, 1, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -3, 4, -2, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -2, 4, -1, 1, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -4, 4, 0, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -5, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -4, 4, 0, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -4, 3, -1, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -4, 3, -1, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -5, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -2, 4, -1, 1, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -4, 3, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -4, 3, -1, 2, -2, 2 ], [ -3, 3, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 4, 0, 2, -2, 2 ], [ -3, 3, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 4, -1, 2, -2, 2 ], [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -5, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -3, 3, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 5, 0, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, -1, 3, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 4, -1, 3, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -3, 3, -1, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ],
[ [ -4, 4, 0, 2, -2, 2 ], [ -3, 4, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ],
[ [ -4, 4, 0, 2, -2, 2 ], [ -4, 5, 0, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ],
[ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, -1, 3, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ],
[ [ -4, 4, -1, 2, -1, 2 ], [ -4, 4, -1, 3, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ]
],
"cur_uid": "50c2b0ad",
"ref_uid": "61207e49",
"order_seed": 837263,
"dur_seed": 454936,
"motifs_seed": 788402,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46913580246914, 0.67045454545455, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 0, 2, 3 ], [ 1, 1, 1, 1 ], [ ] ],
[ [ 1 ], [ 3, 0, 2, 2, 2, 2 ], [ ] ],
[ [ 1, 0 ], [ 3, 2 ], [ ] ],
[ [ 3 ], [ 2, 1, 0, 0, 1, 1, 1 ], [ ] ],
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,6 @@
{
{ cis''2^\markup { \pad-markup #0.2 "-29"} d'2^\markup { \pad-markup #0.2 "-18"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↓" }} }
\bar "|"
{ dis'1^\markup { \pad-markup #0.2 "+38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}}
\bar "||"
}

@ -0,0 +1,6 @@
{
{ a'2^\markup { \pad-markup #0.2 "-16"} b'8^\markup { \pad-markup #0.2 "-33"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}[ cis''8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }}] d''8^\markup { \pad-markup #0.2 "-18"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }}[ dis''8^\markup { \pad-markup #0.2 "+38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 7↑" }}] }
\bar "|"
{ fis''8^\markup { \pad-markup #0.2 "-31"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ ais'8^\markup { \pad-markup #0.2 "+40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}] ~ ais'2 dis''8^\markup { \pad-markup #0.2 "+38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ fis''8^\markup { \pad-markup #0.2 "-31"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↓" }}]}
\bar "||"
}

@ -0,0 +1,6 @@
{
{ d'8^\markup { \pad-markup #0.2 "-18"}[ dis'8^\markup { \pad-markup #0.2 "+38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}] e'8^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 3↑" }}[ fis'8^\markup { \pad-markup #0.2 "-31"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↓" }}] ~ fis'2 ~ }
\bar "|"
{ fis'8[ g'8^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }}] gis8^\markup { \pad-markup #0.2 "+36"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}[ ais8^\markup { \pad-markup #0.2 "+40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}] gis8^\markup { \pad-markup #0.2 "+36"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}[ ais8^\markup { \pad-markup #0.2 "+40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}] ~ ais4}
\bar "||"
}

@ -0,0 +1,6 @@
{
{ ais2^\markup { \pad-markup #0.2 "+40"} fis2^\markup { \pad-markup #0.2 "-31"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }} ~ }
\bar "|"
{ fis8[ g8^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}] dis2^\markup { \pad-markup #0.2 "+38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }} ais'4^\markup { \pad-markup #0.2 "+40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}}
\bar "||"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,96 @@
{
"music_data":
[
[
[
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -2, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -6, 3, 1, 3, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -6, 3, 1, 3, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ], [ -6, 3, 1, 3, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, 0, 2 ], [ -6, 3, 1, 3, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 2, 1, 2, -1, 2 ], [ -6, 3, 1, 3, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 3, 2, 2, -1, 2 ], [ -6, 3, 1, 3, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 3, 2, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 3, 1, 1, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 3, 1, 2, -1, 1 ], [ -4, 3, 1, 1, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 3, 1, 2, -1, 1 ], [ -5, 3, 2, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 3, 1, 2, -1, 1 ], [ -4, 2, 1, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 3, 1, 2, -1, 1 ], [ -4, 3, 1, 2, -1, 1 ], [ -4, 3, 0, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 3, 1, 2, -1, 1 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 3, 1, 2, -1, 1 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 2, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 2, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 2, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 3, 2, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -5, 3, 2, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -5, 3, 1, 2, 0, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 2, 1, 2, -1, 2 ], [ -5, 3, 2, 2, -1, 2 ], [ -5, 3, 1, 2, 0, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 2, 1, 2, -1, 2 ], [ -5, 3, 2, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 2, 1, 2, -1, 2 ], [ -4, 2, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 2, 1, 2, -1, 2 ], [ -4, 2, 1, 2, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 2, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 3, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, 0, 2 ], [ -5, 3, 1, 2, 0, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, 0, 2 ], [ -4, 3, 1, 2, -2, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 3, 1, 2, -2, 2 ], [ -4, 3, 1, 2, -2, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ],
[ [ -6, 3, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ],
[ [ -6, 3, 1, 2, 0, 2 ], [ -5, 3, 1, 2, 0, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ],
[ [ -6, 3, 1, 2, 0, 2 ], [ -4, 3, 1, 2, -2, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ],
[ [ -5, 3, 1, 2, -2, 2 ], [ -4, 3, 1, 2, -2, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ]
],
"cur_uid": "536cac90",
"ref_uid": "767e70f0",
"order_seed": 837263,
"dur_seed": 210094,
"motifs_seed": 299013,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46913580246914, 0.67045454545455, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 0, 2, 3 ], [ 1, 1, 1, 1 ], [ ] ],
[ [ 1 ], [ 3, 0, 2, 2, 2, 2 ], [ ] ],
[ [ 1, 0 ], [ 3, 2 ], [ ] ],
[ [ 3 ], [ 2, 1, 0, 0, 1, 1, 1 ], [ ] ],
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,8 @@
{
{ f'2^\markup { \pad-markup #0.2 "-38"} g2^\markup { \pad-markup #0.2 "+28"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 7↑" }} ~ }
\bar "|"
{ g8[ ais'8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] ~ ais'2. ~ }
\bar "|"
{ ais'1}
\bar "||"
}

@ -0,0 +1,8 @@
{
{ d'2^\markup { \pad-markup #0.2 "+30"} ~ d'8[ f'8^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }}] dis'8^\markup { \pad-markup #0.2 "+11"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 11↑" }}[ dis'8^\markup { \pad-markup #0.2 "-42"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}] }
\bar "|"
{ cis'4^\markup { \pad-markup #0.2 "+46"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↑" }} c'8^\markup { \pad-markup #0.2 "-9"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 7↓" }}[ fis'8^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↓" }}] ~ fis'2 }
\bar "|"
{ f'8^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 3↑" }}[ dis'8^\markup { \pad-markup #0.2 "-42"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] cis'8^\markup { \pad-markup #0.2 "+46"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↑" }}[ dis'8^\markup { \pad-markup #0.2 "+11"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↑" }}] f'4^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }} dis''4^\markup { \pad-markup #0.2 "-42"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}}
\bar "||"
}

@ -0,0 +1,8 @@
{
{ ais8^\markup { \pad-markup #0.2 "+13"}[ c'8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }}] b8^\markup { \pad-markup #0.2 "+10"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 11↓" }}[ ais8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}] ~ ais2 ~ }
\bar "|"
{ ais4 ~ ais8[ c'8^\markup { \pad-markup #0.2 "-9"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 7↓" }}] cis'8^\markup { \pad-markup #0.2 "+46"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }}[ dis'8^\markup { \pad-markup #0.2 "-42"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↓" }}] cis'8^\markup { \pad-markup #0.2 "+19"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ ais8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }}] ~ }
\bar "|"
{ ais4 c'4^\markup { \pad-markup #0.2 "-9"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↓" }} cis'8^\markup { \pad-markup #0.2 "+46"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }}[ dis'8^\markup { \pad-markup #0.2 "-42"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] ~ dis'8[ f'8^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}]}
\bar "||"
}

@ -0,0 +1,8 @@
{
{ f2^\markup { \pad-markup #0.2 "-38"} ~ f8[ ais,8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}] ~ ais,4 ~ }
\bar "|"
{ ais,4 ~ ais,8[ c8^\markup { \pad-markup #0.2 "-9"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}] cis2^\markup { \pad-markup #0.2 "+19"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 13↓" }} }
\bar "|"
{ dis1^\markup { \pad-markup #0.2 "-42"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 3↓" }}}
\bar "||"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,65 @@
{
"music_data":
[
[
[
[ [ [ -7, 4, 0, 3, -1, 2 ], [ -7, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 4, 0, 3, -1, 2 ], [ -7, 4, 1, 3, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -7, 4, 1, 3, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -7, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -2, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -7, 4, 1, 3, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -2, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -2, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 2, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 2, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 4, 0, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 0, 2, -1, 2 ], [ -7, 6, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 1 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 5, 1, 1, -1, 2 ], [ -5, 4, 1, 2, -1, 1 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -7, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 4, 0, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 4, 0, 2, -1, 2 ], [ -7, 6, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 1 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 5, 1, 1, -1, 2 ], [ -5, 4, 1, 2, -1, 1 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ]
],
"cur_uid": "567a9375",
"ref_uid": "65120e88",
"order_seed": 837263,
"dur_seed": 805746,
"motifs_seed": 806271,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46913580246914, 0.67045454545455, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,4 @@
{
{ f'1^\markup { \pad-markup #0.2 "-38"}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ cis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 7↓" }}[ b8^\markup { \pad-markup #0.2 "+10"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↓" }}] ais8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ gis8^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↑" }}] ais4^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }} c'4^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ d4^\markup { \pad-markup #0.2 "+30"} f4^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }} e8^\markup { \pad-markup #0.2 "+8"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 11↓" }}[ dis8^\markup { \pad-markup #0.2 "-42"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}] f4^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ ais,2.^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↓" }} c8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}[ cis8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↓" }}]}
\bar "||"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,65 @@
{
"music_data":
[
[
[
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -3, 4, 1, 1, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -3, 4, 1, 1, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 2, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 2, 2, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 4, 2, 2, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 4, 1, 2, 0, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 4, 1, 2, 0, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 4, 1, 2, 0, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -5, 4, 2, 2, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -5, 4, 1, 2, 0, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -5, 4, 1, 2, 0, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -5, 4, 1, 2, 0, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ]
],
"cur_uid": "5ef20586",
"ref_uid": "5f0075ab",
"order_seed": 837263,
"dur_seed": 148789,
"motifs_seed": 771884,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.45884773662551, 0.5, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,4 @@
{
{ f'1^\markup { \pad-markup #0.2 "-38"}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ d''8^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 7↑" }}[ f''8^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }}] g''8^\markup { \pad-markup #0.2 "-7"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↓" }}[ ais8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] gis4^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 3↑" }} f''4^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ cis'4^\markup { \pad-markup #0.2 "-25"} d'4^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↑" }} cis'8^\markup { \pad-markup #0.2 "+46"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↑" }}[ ais8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] ~ ais8[ gis8^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 5↑" }}]}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ ais'2.^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↓" }} ~ ais'8[ gis'8^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}]}
\bar "||"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,65 @@
{
"music_data":
[
[
[
[ [ [ -7, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 1, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 1, -1, 2 ], [ -5, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 1, -1, 2 ], [ -5, 4, 1, 1, -1, 2 ], [ -5, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 1, -1, 2 ], [ -5, 4, 1, 1, -1, 2 ], [ -4, 4, 1, 1, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 1, -1, 2 ], [ -5, 4, 1, 1, -1, 2 ], [ -5, 4, 2, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 1, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -5, 4, 2, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 1, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 4, 1, 1, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 1, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 1, -1, 2 ], [ -5, 4, 2, 1, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 4, 1, 1, -1, 2 ], [ -5, 4, 2, 1, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 1, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 4, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 3, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 3, 0, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 3, 0, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -7, 4, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -5, 3, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -5, 3, 0, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -5, 3, 0, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 4, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ]
],
"cur_uid": "5f0075ab",
"ref_uid": "736745da",
"order_seed": 837263,
"dur_seed": 820526,
"motifs_seed": 826853,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.45884773662551, 0.5, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,4 @@
{
{ f'1^\markup { \pad-markup #0.2 "-38"}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ c''8^\markup { \pad-markup #0.2 "-37"}[ ais'8^\markup { \pad-markup #0.2 "+13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 11↑" }}] g'8^\markup { \pad-markup #0.2 "-7"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ gis'8^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }}] ais'4^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↓" }} c''8^\markup { \pad-markup #0.2 "-37"}[ cis''8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↓" }}]}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ g4^\markup { \pad-markup #0.2 "-7"} ~ g8[ gis8^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}] ~ gis8[ ais8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}] b8^\markup { \pad-markup #0.2 "-21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↑" }}[ cis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}]}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ f,4^\markup { \pad-markup #0.2 "-38"} g,2^\markup { \pad-markup #0.2 "-7"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }} ~ g,8[ f,8^\markup { \pad-markup #0.2 "-38"}]}
\bar "||"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,141 @@
{
"music_data":
[
[
[
[ [ [ -6, 6, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -6, 6, -1, 1, -2, 2 ], [ -4, 6, -2, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -6, 6, -1, 1, -2, 2 ], [ -5, 6, -1, 2, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -6, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 6, -2, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -5, 6, -1, 2, -2, 2 ], [ -3, 6, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 3 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -5, 8, -1, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -5, 8, -1, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 7, -2, 1, -2, 2 ], [ -5, 8, -1, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -5, 7, -2, 1, -2, 2 ], [ -4, 7, -2, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 7, -2, 1, -2, 2 ], [ -5, 7, -1, 2, -2, 2 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 7, -2, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 3 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 7, -2, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 7, -2, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -3, 7, -1, 0, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -3, 7, -1, 0, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 7, 0, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -5, 8, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -5, 7, 0, 1, -2, 2 ], [ -5, 8, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -5, 7, 0, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 3 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -6, 8, -1, 1, -2, 3 ], [ -5, 7, -1, 1, -2, 3 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -6, 8, -1, 1, -2, 3 ], [ -5, 8, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -6, 9, -1, 1, -2, 2 ], [ -5, 8, -1, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -6, 9, -1, 1, -2, 2 ], [ -4, 7, -2, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -6, 8, -1, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 1 ], [ -4, 7, -2, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -5, 7, -2, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 1 ], [ -4, 7, -2, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 7, -1, 1, -1, 2 ], [ -4, 7, -1, 1, -2, 1 ], [ -4, 7, -2, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -6, 7, -1, 1, -1, 2 ], [ -5, 7, -1, 1, -1, 2 ], [ -4, 7, -2, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -6, 7, -1, 1, -1, 2 ], [ -5, 8, -1, 1, -2, 2 ], [ -4, 7, -2, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -5, 8, -1, 1, -2, 2 ], [ -4, 7, -2, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 1 ], [ -4, 7, -2, 1, -2, 2 ], [ -5, 7, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 1 ], [ -4, 7, -2, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 3 ] ], 0 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 1 ], [ -3, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 3 ] ], 0.25 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 1 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 3 ] ], 0 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 1 ], [ -4, 7, -1, 1, -2, 2 ], [ -5, 6, 0, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -2, 1 ], [ -3, 6, -2, 1, -2, 2 ], [ -5, 6, 0, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -3, 6, -2, 1, -2, 2 ], [ -5, 6, 0, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -3, 2 ], [ -5, 6, 0, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -2, 2 ], [ -3, 6, -1, 1, -3, 2 ], [ -5, 6, 0, 1, -2, 2 ] ], 0 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -2, 2 ], [ -3, 6, -1, 1, -3, 2 ], [ -4, 6, -2, 1, -3, 2 ] ], 0.25 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -2, 2 ], [ -3, 6, -1, 1, -3, 2 ], [ -5, 7, -1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 7, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -3, 2 ], [ -5, 7, -1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -3, 2 ], [ -5, 7, -1, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 5, -1, 1, -3, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 6, -1, 1, -3, 2 ], [ -5, 7, -1, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 1, -3, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -3, 2 ], [ -5, 7, -1, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 1, -3, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -3, 2 ], [ -5, 6, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -1, 1, -3, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -4, 4, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 5, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 5, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 0, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 5, 0, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 6, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -2, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 5, -2, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -5, 5, -1, 2, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -5, 5, 0, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ],
[ [ -5, 6, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ],
[ [ -4, 5, -2, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ],
[ [ -4, 5, -2, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ],
[ [ -5, 5, -1, 2, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -2, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ] ]
],
"cur_uid": "61207e49",
"ref_uid": "624f7439",
"order_seed": 716491,
"dur_seed": 454936,
"motifs_seed": 126393,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46913580246914, 0.67045454545455, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 0, 2, 3 ], [ 1, 1, 1, 1 ], [ ] ],
[ [ 1 ], [ 3, 0, 2, 2, 2, 2 ], [ ] ],
[ [ 1, 0 ], [ 3, 2 ], [ ] ],
[ [ 3 ], [ 2, 1, 0, 0, 1, 1, 1 ], [ ] ],
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ],
[ [ 0 ], [ 1, 3, 2, 2, 3, 2, 1 ], [ ] ],
[ [ 1, 0, 3 ], [ 2 ], [ ] ],
[ [ 0, 2 ], [ 1, 3, 3, 1, 1 ], [ ] ],
[ [ 1 ], [ 0, 2, 3, 2, 0, 3 ], [ ] ],
[ [ 1, 3 ], [ 0, 2, 0, 0, 0, 0 ], [ ] ],
[ [ 3, 1 ], [ 2, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,12 @@
{
{ gis2^\markup { \pad-markup #0.2 "-27"} gis''2^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }} }
\bar "|"
{ dis'1^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }} ~ }
\bar "|"
{ dis'2. ~ dis'8[ e'8^\markup { \pad-markup #0.2 "+13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 13↑" }}] }
\bar "|"
{ c'2^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↑" }} ais8^\markup { \pad-markup #0.2 "+35"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 5↓" }}[ a8^\markup { \pad-markup #0.2 "+23"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 3↑" }}] ~ a4 }
\bar "|"
{ gis8^\markup { \pad-markup #0.2 "-27"}[ cis''8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}] ~ cis''2.}
\bar "||"
}

@ -0,0 +1,12 @@
{
{ cis'2^\markup { \pad-markup #0.2 "-29"} dis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }}[ e'8^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↓" }}] f'8^\markup { \pad-markup #0.2 "+41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 7↑" }}[ dis''8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }}] }
\bar "|"
{ e''8^\markup { \pad-markup #0.2 "+13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 13↑" }}[ dis''8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }}] ~ dis''2 f''8^\markup { \pad-markup #0.2 "+6"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↓" }}[ g''8^\markup { \pad-markup #0.2 "-39"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }}] }
\bar "|"
{ ais'8^\markup { \pad-markup #0.2 "-23"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ b'8^\markup { \pad-markup #0.2 "+15"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 13↑" }}] ais'4^\markup { \pad-markup #0.2 "-23"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }} b'4^\markup { \pad-markup #0.2 "-12"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↓" }} ~ b'8[ cis''8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}] }
\bar "|"
{ dis''8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }}[ e''8^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↓" }}] ~ e''8[ d''8^\markup { \pad-markup #0.2 "+21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 11↓" }}] ~ d''2 }
\bar "|"
{ g'8^\markup { \pad-markup #0.2 "+19"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ fis'8^\markup { \pad-markup #0.2 "-31"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 3↓" }}] ~ fis'8[ gis'8^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }}] ~ gis'4 ~ gis'8[ a'8^\markup { \pad-markup #0.2 "-16"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}]}
\bar "||"
}

@ -0,0 +1,12 @@
{
{ dis'8^\markup { \pad-markup #0.2 "-25"}[ e'8^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↓" }}] f'8^\markup { \pad-markup #0.2 "+41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 7↑" }}[ gis'8^\markup { \pad-markup #0.2 "-27"}] ~ gis'2 ~ }
\bar "|"
{ gis'8[ ais'8^\markup { \pad-markup #0.2 "-23"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 3↑" }}] b'8^\markup { \pad-markup #0.2 "-12"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ c''8^\markup { \pad-markup #0.2 "+43"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 7↑" }}] b'8^\markup { \pad-markup #0.2 "+15"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 13↑" }}[ gis'8^\markup { \pad-markup #0.2 "-27"}] ~ gis'4 }
\bar "|"
{ g'4^\markup { \pad-markup #0.2 "-39"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }} fis'8^\markup { \pad-markup #0.2 "+17"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 13↑" }}[ f'8^\markup { \pad-markup #0.2 "-21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }}] fis'8^\markup { \pad-markup #0.2 "+34"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 13↓" }}[ gis'8^\markup { \pad-markup #0.2 "+26"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] ais'8^\markup { \pad-markup #0.2 "-23"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}[ b'8^\markup { \pad-markup #0.2 "+32"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 13↓" }}] ~ }
\bar "|"
{ b'4 cis''4^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }} c''4^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }} dis''8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }}[ cis'8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}] ~ }
\bar "|"
{ cis'1}
\bar "||"
}

@ -0,0 +1,12 @@
{
{ gis,2^\markup { \pad-markup #0.2 "-27"} gis2^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }} ~ }
\bar "|"
{ gis8[ ais8^\markup { \pad-markup #0.2 "-23"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}] b2^\markup { \pad-markup #0.2 "-12"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 5↓" }} ais4^\markup { \pad-markup #0.2 "-23"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }} ~ }
\bar "|"
{ ais2 b8^\markup { \pad-markup #0.2 "-12"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}[ gis8^\markup { \pad-markup #0.2 "+26"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↑" }}] gis4^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↓" }} ~ }
\bar "|"
{ gis1 }
\bar "|"
{ g8^\markup { \pad-markup #0.2 "+19"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 11↓" }}[ fis8^\markup { \pad-markup #0.2 "-31"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}] cis8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}[ dis8^\markup { \pad-markup #0.2 "+2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 7↓" }}] f8^\markup { \pad-markup #0.2 "-43"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↑" }}[ gis8^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}] a4^\markup { \pad-markup #0.2 "-16"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↓" }}}
\bar "||"
}

@ -97,11 +97,11 @@
],
"last_changes":
[
[ [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ] ],
[ [ -5, 6, 0, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ] ],
[ [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ] ],
[ [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 5, 0, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ] ],
[ [ -4, 6, -1, 1, -3, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 5, 0, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ] ]
[ [ -3, 5, -2, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ] ],
[ [ -3, 5, -2, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -4, 5, -2, 1, -2, 2 ] ],
[ [ -3, 5, -2, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ],
[ [ -3, 5, -2, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ],
[ [ -6, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ]
],
"cur_uid": "624f7439",
"ref_uid": "4f53a446",

@ -0,0 +1,12 @@
{
{ gis2^\markup { \pad-markup #0.2 "-27"} gis''2^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }} }
\bar "|"
{ gis1^\markup { \pad-markup #0.2 "-27"} ~ }
\bar "|"
{ gis2. ~ gis8[ a8^\markup { \pad-markup #0.2 "-16"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}] }
\bar "|"
{ gis'2^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }} a'8^\markup { \pad-markup #0.2 "-16"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↓" }}[ g'8^\markup { \pad-markup #0.2 "+19"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 11↓" }}] ~ g'4 }
\bar "|"
{ a'8^\markup { \pad-markup #0.2 "-16"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ gis'8^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] ~ gis'2.}
\bar "||"
}

@ -0,0 +1,12 @@
{
{ cis'2^\markup { \pad-markup #0.2 "-29"} gis8^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}[ ais8^\markup { \pad-markup #0.2 "+4"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 7↓" }}] c'8^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↑" }}[ cis'8^\markup { \pad-markup #0.2 "-29"}] }
\bar "|"
{ dis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 3↑" }}[ e'8^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↓" }}] ~ e'2 dis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}[ c''8^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] }
\bar "|"
{ cis''8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↓" }}[ dis''8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}] gis'4^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }} c'4^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }} ~ c'8[ cis'8^\markup { \pad-markup #0.2 "-29"}] }
\bar "|"
{ f'8^\markup { \pad-markup #0.2 "-43"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↑" }}[ fis'8^\markup { \pad-markup #0.2 "-31"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}] ~ fis'8[ e'8^\markup { \pad-markup #0.2 "-14"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↓" }}] ~ e'2 }
\bar "|"
{ dis'8^\markup { \pad-markup #0.2 "+2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 7↓" }}[ f'8^\markup { \pad-markup #0.2 "-43"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↑" }}] ~ f'8[ fis'8^\markup { \pad-markup #0.2 "-31"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 3↓" }}] ~ fis'4 ~ fis'8[ f'8^\markup { \pad-markup #0.2 "-43"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↑" }}]}
\bar "||"
}

@ -0,0 +1,12 @@
{
{ a'8^\markup { \pad-markup #0.2 "-16"}[ gis'8^\markup { \pad-markup #0.2 "-27"}] a'8^\markup { \pad-markup #0.2 "+11"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 13↑" }}[ gis'8^\markup { \pad-markup #0.2 "-27"}] ~ gis'2 ~ }
\bar "|"
{ gis'8[ cis'8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] d'8^\markup { \pad-markup #0.2 "+21"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↓" }}[ dis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}] cis'8^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↑" }}[ c'8^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }}] ~ c'4 }
\bar "|"
{ cis'4^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }} dis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}[ f'8^\markup { \pad-markup #0.2 "-43"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}] f'8^\markup { \pad-markup #0.2 "+41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↑" }}[ g'8^\markup { \pad-markup #0.2 "-39"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↑" }}] gis'8^\markup { \pad-markup #0.2 "-27"}[ a'8^\markup { \pad-markup #0.2 "-16"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↓" }}] ~ }
\bar "|"
{ a'4 ais'4^\markup { \pad-markup #0.2 "+40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 7↑" }} cis''4^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }} d''8^\markup { \pad-markup #0.2 "-45"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 7↑" }}[ cis''8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] ~ }
\bar "|"
{ cis''1}
\bar "||"
}

@ -0,0 +1,12 @@
{
{ gis,2^\markup { \pad-markup #0.2 "-27"} cis''2^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }} ~ }
\bar "|"
{ cis''8[ gis'8^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }}] ais,2^\markup { \pad-markup #0.2 "+4"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↓" }} c4^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }} ~ }
\bar "|"
{ c2 cis8^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↑" }}[ dis8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}] cis4^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 3↓" }} ~ }
\bar "|"
{ cis1 }
\bar "|"
{ a8^\markup { \pad-markup #0.2 "-16"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↓" }}[ gis8^\markup { \pad-markup #0.2 "-27"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 3↑" }}] g8^\markup { \pad-markup #0.2 "+19"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 11↓" }}[ fis8^\markup { \pad-markup #0.2 "-31"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}] cis'8^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}[ c'8^\markup { \pad-markup #0.2 "-41"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }}] cis'4^\markup { \pad-markup #0.2 "-29"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}}
\bar "||"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,65 @@
{
"music_data":
[
[
[
[ [ [ -6, 4, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 3 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 3 ], [ -6, 4, 1, 2, -1, 3 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 2, -1, 3 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 0, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -7, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 1 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 4, 1, 3, -1, 2 ], [ -6, 3, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 4, 0, 3, -1, 2 ], [ -6, 3, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -6, 4, 0, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -7, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -7, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 1 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -7, 4, 1, 3, -1, 2 ], [ -6, 3, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -7, 4, 0, 3, -1, 2 ], [ -6, 3, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ]
],
"cur_uid": "65120e88",
"ref_uid": "66b20499",
"order_seed": 837263,
"dur_seed": 378109,
"motifs_seed": 521249,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46913580246914, 0.67045454545455, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,4 @@
{
{ f'1^\markup { \pad-markup #0.2 "-38"}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ cis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ c'8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] ais8^\markup { \pad-markup #0.2 "+13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↑" }}[ c'8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] cis'4^\markup { \pad-markup #0.2 "+2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }} d'4^\markup { \pad-markup #0.2 "+30"}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ cis''4^\markup { \pad-markup #0.2 "-25"} c''4^\markup { \pad-markup #0.2 "-37"} cis''8^\markup { \pad-markup #0.2 "+2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 13↑" }}[ d''8^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↑" }}] f8^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }}[ fis8^\markup { \pad-markup #0.2 "-10"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 13↓" }}]}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ cis8^\markup { \pad-markup #0.2 "-25"}[ c8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}] ~ c2 cis8^\markup { \pad-markup #0.2 "-25"}[ d8^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}]}
\bar "||"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,96 @@
{
"music_data":
[
[
[
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 4, -1, 2, -2, 3 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -3, 4, -2, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 4, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, -1, 2, -1, 2 ], [ -4, 4, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -6, 5, 0, 2, -1, 2 ], [ -4, 4, 0, 1, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -6, 5, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -4, 4, 0, 1, -2, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 4, 0, 2, -2, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 4, 2, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 3 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 2, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 2, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 4, 2, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 4, 2, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 4, 2, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 2, -2, 2 ], [ -5, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -7, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 3 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 4, 1, 3, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 0, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -6, 4, 1, 2, -2, 2 ], [ -5, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -7, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 3, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -7, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 3 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -7, 4, 1, 3, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 4, 0, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ]
],
"cur_uid": "66b20499",
"ref_uid": "50c2b0ad",
"order_seed": 837263,
"dur_seed": 582673,
"motifs_seed": 530509,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46913580246914, 0.67045454545455, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 0, 2, 3 ], [ 1, 1, 1, 1 ], [ ] ],
[ [ 1 ], [ 3, 0, 2, 2, 2, 2 ], [ ] ],
[ [ 1, 0 ], [ 3, 2 ], [ ] ],
[ [ 3 ], [ 2, 1, 0, 0, 1, 1, 1 ], [ ] ],
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,8 @@
{
{ dis'2^\markup { \pad-markup #0.2 "+38"} dis'2^\markup { \pad-markup #0.2 "+6"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 7↓" }} ~ }
\bar "|"
{ dis'8[ f'8^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↑" }}] ~ f'2. ~ }
\bar "|"
{ f'1}
\bar "||"
}

@ -0,0 +1,8 @@
{
{ ais2^\markup { \pad-markup #0.2 "+40"} ~ ais8[ cis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}] a8^\markup { \pad-markup #0.2 "-11"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 5↓" }}[ g8^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] }
\bar "|"
{ gis8^\markup { \pad-markup #0.2 "-23"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 3↑" }}[ ais8^\markup { \pad-markup #0.2 "-45"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 7↓" }}] c'2^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }} cis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↓" }}[ d'8^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↑" }}] }
\bar "|"
{ ais8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ c'8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}] cis'4^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↓" }} d'2^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↑" }}}
\bar "||"
}

@ -0,0 +1,8 @@
{
{ c''8^\markup { \pad-markup #0.2 "-22"}[ ais'8^\markup { \pad-markup #0.2 "+40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}] c''8^\markup { \pad-markup #0.2 "-49"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↓" }}[ cis''8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↑" }}] ~ cis''2 ~ }
\bar "|"
{ cis''4 c''8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}[ cis''8^\markup { \pad-markup #0.2 "+2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 13↑" }}] c''8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}[ ais'8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↓" }}] gis'4^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 5↑" }} }
\bar "|"
{ ais'4^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }} c''8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}[ cis''8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}] d''4^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }} cis''8^\markup { \pad-markup #0.2 "+2"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 13↑" }}[ c''8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}]}
\bar "||"
}

@ -0,0 +1,8 @@
{
{ a'2^\markup { \pad-markup #0.2 "-11"} g'2^\markup { \pad-markup #0.2 "+24"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 11↓" }} ~ }
\bar "|"
{ g'4 gis'8^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }}[ f8^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }}] ~ f4 ais,4^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↓" }} ~ }
\bar "|"
{ ais,2 b,8^\markup { \pad-markup #0.2 "+10"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↓" }}[ d8^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}] ~ d4}
\bar "||"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,96 @@
{
"music_data":
[
[
[
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 4, -1, 2, -2, 3 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 5, -1, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -3, 4, -2, 2, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ],
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -4, 4, -1, 2, -2, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 4, -1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 5, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 5, -1, 2, -2, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 5, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 5, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 5, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -4, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 5, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -3, 3, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 5, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -3, 3, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 5, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 5, 0, 3, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 5, 0, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 5, 0, 2, -1, 2 ], [ -5, 3, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -3, 3, 0, 2, -1, 1 ], [ -5, 3, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 3, 0, 2, 0, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 0, 2, 0, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 3, 0, 2, 0, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 0, 2, 0, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 0, 2, 0, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 1 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 0, 2, 0, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 1 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 0, 2, 0, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 3, 0, 2, 0, 2 ], [ -5, 2, 0, 2, 0, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 0, 2, 0, 2 ], [ -5, 2, 0, 2, 0, 2 ], [ -6, 3, 0, 3, 0, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 0, 2, 0, 2 ], [ -5, 3, 0, 2, -1, 2 ], [ -6, 3, 0, 3, 0, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 3, 0, 2, 0, 2 ], [ -5, 3, 0, 2, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 0, 2, 0, 2 ], [ -3, 2, 0, 2, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -3, 2, 0, 2, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -3, 3, -1, 2, -1, 2 ], [ -3, 2, 0, 2, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -3, 3, -1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ],
[ [ [ -3, 3, -1, 2, -1, 2 ], [ -3, 3, 0, 2, -2, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0 ],
[ [ [ -3, 2, -1, 2, -1, 2 ], [ -3, 3, 0, 2, -2, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -4, 4, 0, 2, -1, 2 ], [ -3, 2, 0, 2, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ],
[ [ -3, 3, -1, 2, -1, 2 ], [ -3, 2, 0, 2, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ],
[ [ -3, 3, -1, 2, -1, 2 ], [ -4, 4, 0, 2, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ],
[ [ -3, 3, -1, 2, -1, 2 ], [ -3, 3, 0, 2, -2, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ],
[ [ -3, 2, -1, 2, -1, 2 ], [ -3, 3, 0, 2, -2, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -4, 3, 0, 2, -1, 2 ] ]
],
"cur_uid": "6c46f950",
"ref_uid": "50c2b0ad",
"order_seed": 837263,
"dur_seed": 454936,
"motifs_seed": 918136,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46913580246914, 0.67045454545455, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 0, 2, 3 ], [ 1, 1, 1, 1 ], [ ] ],
[ [ 1 ], [ 3, 0, 2, 2, 2, 2 ], [ ] ],
[ [ 1, 0 ], [ 3, 2 ], [ ] ],
[ [ 3 ], [ 2, 1, 0, 0, 1, 1, 1 ], [ ] ],
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,65 @@
{
"music_data":
[
[
[
[ [ [ -6, 5, 1, 1, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 5, 1, 1, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 4, 1, 2, 0, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 4, 1, 2, 0, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -2, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 4, 1, 2, 0, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 4, 1, 2, 0, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 4, 1, 2, 0, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -7, 4, 1, 2, 0, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 4, 1, 2, 0, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 4, 1, 2, 0, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -7, 4, 1, 2, 0, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 4, 1, 2, 0, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -7, 5, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -7, 4, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -7, 5, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 3, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 3, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -7, 4, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ]
],
"cur_uid": "736745da",
"ref_uid": "567a9375",
"order_seed": 837263,
"dur_seed": 409865,
"motifs_seed": 622222,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.45884773662551, 0.5, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,4 @@
{
{ f'1^\markup { \pad-markup #0.2 "-38"}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ cis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↓" }}[ b8^\markup { \pad-markup #0.2 "+10"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↓" }}] ais8^\markup { \pad-markup #0.2 "+13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ c'8^\markup { \pad-markup #0.2 "-37"}] ais'4^\markup { \pad-markup #0.2 "+13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }} c''4^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ ais4^\markup { \pad-markup #0.2 "-40"} gis4^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }} ais8^\markup { \pad-markup #0.2 "+13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ c'8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↑" }}] cis'8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↓" }}[ c'8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}]}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ ais,2.^\markup { \pad-markup #0.2 "+13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↑" }} c8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "II"\normal-size-super " 1↑" }}[ ais,8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 3↓" }}]}
\bar "||"
}

@ -0,0 +1,992 @@
(
// helper funcs
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
// score funcs
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
// subroutines
var genTuples, initVoices, genOrders, genSubMotif, updateVoices, genDurFunc, genStepFunc;
// 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, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited;
// model aux vars
var entrancesDurFunc, passagesDurFunc, exitsDurFunc, stepFunc;
// other global vars
var popSize, exPath, dir, primes, dims, tuples,
group, player, resourceDir, ledgerPath, ledger, currentlyPlayingUID,
nameSpaces;
// install JSON quark (not used)
/*
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(array2) - hsArrayToCents.value(array1);
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)
stepFunc.value(pDistance)
};
*/
intervalScore = {
arg hsArray1, hsArray2, mean, sd, signed = true;
var pDistance;
pDistance = pDist.value(hsArray1, hsArray2, signed);
//pDistance.gaussCurve(1, mean, sd)
//if(pDistance >= 0, {stepFunc.value(abs(pDistance))}, {0.01});
stepFunc.value(pDistance)
};
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 = dims.collect({[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);
};
genStepFunc = {arg minStep, maxStep, envData, seed;
var envDataNorm, env, pTable, stepFunc;
//[minStep, maxStep, envData].postln;
envDataNorm = ([[0, 0]] ++ envData.clump(2) ++ [[1, 0]]).flop;
envDataNorm = [envDataNorm[0].normalize(minStep, maxStep), envDataNorm[1]].flop;
env = Env.pairs(envDataNorm);
stepFunc = {arg pDist;
env.at(pDist).clip(0.001, 1);
};
seedFunc.value(stepFunc, seed);
};
genOrders = {arg minMotifLength = 1, maxMotifLength = 5, minProgLength = 0, maxProgLength = 5;
((maxMotifLength.asInteger - minMotifLength.asInteger).rand + minMotifLength.asInteger).collect({
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
noSusIns = [1, 2, 3].wchoose(susWeights.normalizeSum);
//noProgIns = (popSize - noSusIns).rand + 1;
noProgIns = (popSize - noSusIns);
noSilentIns = popSize - noSusIns - noProgIns;
/*
noSilentIns = (popSize - noSusIns).rand.clip(0, 1);
noProgIns = popSize - noSusIns - noSilentIns;
*/
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
prog = (prog.scramble ++ ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose}).scramble);
//prog = ((maxProgLength.asInteger - minProgLength.asInteger).rand + minProgLength.asInteger).collect({prog.choose});
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;
//candidates.select({arg item; (item ++ voices).asSet.size >= 4});
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.01);
//recentlySoundedScore = inclusionScore.value(lastXChanges.flatten.collect({arg item; item.drop(1)}), candidate.drop(1), 0.01);
/*
if(rangeScore.value(candidate.collect({0}), voices[ins], ranges[ins][1] - 500, ranges[ins][1], 0, true) == 1, {
isInRangeScore = 1 - rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0] + 500, ranges[ins][1] - 500, 0, true);
isInRangeScore = isInRangeScore * rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true)
}, {
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
});
*/
isInRangeScore = rangeScore.value(candidate.collect({0}), candidate, ranges[ins][0], ranges[ins][1], 0, true);
//old way - worked but actually by accident (I think)
//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 = pow(hdSum.value(voices.deepCopy.put(ins, candidate)), hdExp);
if(hdInvert == 0, {hdScore = 1/hdScore});
//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]}).postln;
});
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
nProbs.round(0.001).postln;
[candidates, nProbs.round(0.001)].flop.postln;
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.deepCopy});
res;
};
//------primary routines
genMotif = {
var repeats, fSeq, fDur, durAdd;
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});
lastState = if(o == 0, {lastXChanges.last.deepCopy}, {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);
});
//round last duration to measure
/*
fDur = fSeq.flatten.flatten.slice(nil, 1).sum;
durAdd = fDur.round(4) - fDur;
if(durAdd < 0, {durAdd = 4 - durAdd});
fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] = fSeq[0][orders.size - 1][fSeq[0][orders.size - 1].size - 1][1] + durAdd;
*/
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.notNil) {
~msg;
~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;
# voices, durs = seq.flatten2(if(oneShot, {2}, {3})).flop;
pbinds = voices.flop.collect({arg voice, v;
var clumps, hdScores, freqs, fDurs, attacks, rels, amps;
clumps = voice.separate({arg a, b; a != b });
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(62.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
//attacks = 2.collect({rrand(1, 3)}) ++ freqs.drop(2).collect({rrand(0.3, 0.5)});
attacks = fDurs.collect({arg dur; dur * rrand(0.2, 0.4)});
//rels = freqs.drop(2).collect({rrand(0.3, 0.5)}) ++ 2.collect({rrand(1, 3)});
rels = (clumps.size - 1).collect({arg c;
if(clumps[c + 1][0] == ["Rest"], {rrand(1.0, 3.0)}, {rrand(0.3, 0.5)});
});
rels = rels.add(rrand(1.0, 3.0));
amps = freqs.collect({rrand(0.6, 0.99)});
[
Pbind(
\instrument, \string_model,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\attack, Pseq(attacks, 1),
\sustain, Pseq(fDurs, 1),
\release, Pseq(rels, 1),
//\amp, Pseq(amps, 1),
\amp, Pbrown(0.5, 1, 0.5),
\busIndex, v
),
Pbind(
\instrument, \sine,
\group, group,
\freq, Pseq(freqs, 1),
\dur, Pseq(fDurs, 1),
\sustain, Pseq(fDurs, 1),
\busIndex, v
)
]
}).flatten;
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(2).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;
}, {
var tmpRes;
if(res.every({arg char; char.isDecDigit}), {tmpRes = res.asInteger});
if(res.contains("."), {tmpRes = res.asFloat});
if(tmpRes != nil, {res = tmpRes});
});
});
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, stepProbsVals, passagesWeights, hdExp, hdInvert,
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, skipLastXChanges = false;
var tmpLastXChanges;
tmpLastXChanges = lastXChanges.deepCopy;
// order really matters!!!!
# seq, lastXChanges, curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited = nameSpaces.collect({arg nS; dict[nS]});
if(skipLastXChanges, {lastXChanges = tmpLastXChanges});
dict
};
globalVarsToDict = {
var modelItems, dict;
// order really matters!!!!
modelItems = [
seq, lastXChanges,
curUID, refUID, orderSeed, durSeed, motifSeed,
entrancesProbVals, passagesProbVals, exitsProbVals,
ranges, stepProbsVals, passagesWeights, hdExp, hdInvert,
orders, susWeights, orderSize, passagesSize,
motifEdited, orderEdited
];
dict = Dictionary.with(*nameSpaces.collect({arg nS, n; nS->modelItems[n]}));
};
loadLedgerFile = {arg path;
ledgerPath = path;
resourceDir = path.splitext(".").drop(-1).join;
loadLedgerJSON.value(File(ledgerPath, "r").readAllString.parseJSON)
};
loadLedgerJSON = {arg jsonObject; ledger = jsonObject["ledger"]};
saveLedger = {arg ledger, path;
var file, curResourceDir;
file = File(path, "w");
curResourceDir = resourceDir;
resourceDir = path.splitext(".").drop(-1).join;
if(curResourceDir != resourceDir, {
File.mkdir(resourceDir);
ledger.do({arg id;
File.copy(curResourceDir +/+ id, resourceDir +/+ id);
});
});
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;
~group = group;
loadLedgerFile.value(dir +/+ ".." +/+ "resources" +/+ "piece_ledger.json");
resourceDir = (dir +/+ ".." +/+ "resources" +/+ "piece_ledger");
//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", "step_probs_vals", "passages_weights", "hd_exp", "hd_invert",
"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, true);
popSize = ranges.size;
//refUID.postln;
loadLedgerFile.value(ledgerPath);
if(ledger == nil, {ledger = ["tmp"]});
if(ledger.last != "tmp", {ledger = ledger.add("tmp")});
if(refUID == nil, {lastXChanges = [initVoices.value().deepCopy]});
if((refUID != nil) && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
lastXChanges = msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
});
refUID.postln;
lastXChanges.collect({arg item; item.postln});
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));
});
stepFunc = genStepFunc.valueArray(stepProbsVals[..1] ++ [stepProbsVals[2..]] ++ [motifSeed]);
seq = seedFunc.value(genMotif, motifSeed).value;
lastXChanges.collect({arg item; item.postln});
dict = globalVarsToDict.value;
modelString = writeResources.value(path, dict);
//addr.sendMsg("/generated", musPath, stringifyToDepth.value(seq, 3));
//~seq = seq;
addr.sendMsg("/generated", path, modelString, ledgerPath);
}, \generate);
OSCdef(\commit, {arg msg, time, addr, port;
var musicData, musicChanged, dict, newLedger, modelPath, musString, musFile, test1, test2, lastCurUID, commitType, commitPos, equalityLedger;
//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;
commitType = msg[2].asString;
commitPos = msg[3].postln.asInteger;
lastCurUID = curUID.deepCopy;
curUID = genUID.value;
File.mkdir((resourceDir +/+ curUID).standardizePath);
File.copy(exPath, (resourceDir +/+ curUID +/+ curUID ++ "_code" ++ ".scd").standardizePath);
modelPath = (resourceDir +/+ 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);
/*
if(commitType == "add", {
if(lastCurUID == "tmp", {
ledger = ledger.drop(-1).add(curUID);
}, {
ledger = ledger.add(curUID);
})
});
*/
ledger.postln;
if(commitType == "add", {ledger = ledger.add(curUID)});
if(commitType == "insert", {ledger = ledger.insert(commitPos + 1, curUID)});
if(commitType == "replace", {ledger = ledger.put(commitPos, curUID)});
equalityLedger = ledger.collect({arg item; item.asSymbol});
if(equalityLedger.includes(\tmp).postln, {ledger.removeAt(equalityLedger.indexOf(\tmp).postln)});
ledger.postln;
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, {
group.set(\release, 2);
group.set(\gate, 0);
player.stop;
}, {
// 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 = (resourceDir +/+ 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 = (resourceDir +/+ "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);
}, {
pSeq = [loadModelJSON.value(msg[2].asString.parseJSON)["music_data"].postln];
patterns = genPatterns.value(pSeq, addr, true);
});
player = Pfset(pattern: patterns, cleanupFunc: {
addr.sendMsg("/transport", 0);
addr.sendMsg("/one_shot", 0);
});
player = player.play
});
}, \transport);
OSCdef(\transcribe_motif, {arg msg, time, addr, port;
var tSeq, refChord, refUID;
msg.postln;
tSeq = [loadModelJSON.value(msg[1].asString.parseJSON)["music_data"]];
refUID = msg[2].asString.postln;
if((refUID != "nil") && (refUID != "tmp"), {
var file;
file = File((resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
}, {
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
});
~transcribe.value(tSeq, refChord, (dir +/+ ".." +/+ "lilypond" +/+ "includes").standardizePath, addr, "/transcribe_motif");
}, \transcribe_motif);
OSCdef(\transcribe_all, {arg msg, time, addr, port;
var cSize, patterns, cuedSeek, indexStart, indexEnd, tmpLedger;
if(true, {
cuedSeek = (seq != nil);
indexStart = msg[1].asInteger;
indexEnd = ledger.size - if(cuedSeek, {2}, {1});
//tmp for testing transcription
//indexEnd = (indexStart+5);
//ledger.postln;
if(((indexStart == (ledger.size - 1)) && cuedSeek).not, {
var lilyPartLedgerFiles;
lilyPartLedgerFiles = 4.collect({arg p;
File((dir +/+ ".." +/+ "lilypond" +/+ "includes" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly").standardizePath, "w");
});
ledger[indexStart..indexEnd].do({arg uid, index;
var path, file, fileString, tSeq, refUID, refChord;
path = (resourceDir +/+ uid +/+ uid ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
fileString = file.readAllString;
tSeq = msgInterpret.value(fileString.parseJSON["music_data"]);
refUID = msgInterpret.value(fileString.parseJSON["ref_uid"]);
file.close;
//uid.postln;
//(refUID == "nil").postln;
refChord = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]];
if(refUID != "nil", {
path = (resourceDir +/+ refUID +/+ refUID ++ "_mus_model" ++ ".json").standardizePath;
file = File(path, "r");
refChord = msgInterpret.value(file.readAllString.parseJSON["last_changes"]).last;
file.close;
});
if(index != indexEnd, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath);
}, {
~transcribe.value(tSeq, refChord, (resourceDir +/+ uid +/+ "lilypond").standardizePath, addr, "/transcribe_all");
});
lilyPartLedgerFiles.do({arg f, p;
f.write("\\include \"" ++ resourceDir +/+ uid +/+ "lilypond" +/+ "part_" ++ ["IV", "III", "II", "I"][p] ++ ".ly\"\n");
});
});
lilyPartLedgerFiles.do({arg f;
f.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;
});
*/
}, {
});
}, \transcribe_all);
)

@ -0,0 +1,65 @@
{
"music_data":
[
[
[
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -6, 4, 1, 2, 0, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -6, 5, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -7, 6, 1, 2, -1, 2 ], [ -5, 4, 0, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -7, 6, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -5, 5, 1, 2, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -4, 4, 0, 2, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 4, 1, 4, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 4, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -6, 4, 1, 4, -1, 2 ], [ -5, 4, 1, 2, -1, 1 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0 ],
[ [ [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 1 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -4, 4, 0, 2, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 4, 1, 4, -1, 2 ], [ -6, 4, 2, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 4, 1, 4, -1, 2 ], [ -5, 3, 1, 2, -1, 2 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 4, 1, 4, -1, 2 ], [ -5, 4, 1, 2, -1, 1 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ],
[ [ -6, 4, 1, 2, -1, 2 ], [ -5, 4, 1, 2, -1, 1 ], [ -6, 4, 1, 3, -1, 2 ], [ -5, 4, 1, 2, -1, 2 ] ]
],
"cur_uid": "767e70f0",
"ref_uid": "4dd2a130",
"order_seed": 837263,
"dur_seed": 452719,
"motifs_seed": 173645,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46296296296296, 0.39204545454545, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"
}

@ -0,0 +1,4 @@
{
{ f'1^\markup { \pad-markup #0.2 "-38"}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ ais8^\markup { \pad-markup #0.2 "-40"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}[ gis8^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }}] ais8^\markup { \pad-markup #0.2 "+13"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 11↑" }}[ c'8^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 1↑" }}] cis'4^\markup { \pad-markup #0.2 "-25"} d'4^\markup { \pad-markup #0.2 "+30"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 7↑" }}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ c'4^\markup { \pad-markup #0.2 "-37"} cis'4^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↓" }} f8^\markup { \pad-markup #0.2 "-38"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 1↑" }}[ g8^\markup { \pad-markup #0.2 "-35"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "IV"\normal-size-super " 3↑" }}] gis4^\markup { \pad-markup #0.2 "+48"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↑" }}}
\bar "||"
}

@ -0,0 +1,4 @@
{
{ c''2.^\markup { \pad-markup #0.2 "-37"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "III"\normal-size-super " 1↑" }} ~ c''8[ cis''8^\markup { \pad-markup #0.2 "-25"}_\markup { \lower #3 \pad-markup #0.2 \concat{ "I"\normal-size-super " 5↓" }}]}
\bar "||"
}

@ -3,223 +3,93 @@
[
[
[
[ [ [ -4, 6, -1, 1, -3, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -4, 6, -1, 1, -3, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 7, -1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -4, 6, -1, 1, -3, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 5, -1, 1, -3, 2 ] ], 0.25 ]
[ [ [ -5, 3, 1, 2, -2, 2 ], [ -4, 2, 1, 2, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 3, 1, 2, -2, 2 ], [ -5, 3, 2, 2, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 3, 1, 2, -2, 2 ], [ -5, 2, 1, 3, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ],
[ [ [ -5, 3, 1, 2, -2, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -4, 3, 1, 2, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 6, 0, 1, -4, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 5, -1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -4, 6, 0, 1, -4, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 5, -2, 1, -2, 2 ] ], 0 ],
[ [ [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 5, -2, 1, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, -1, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, -1, 1, -2, 2 ] ], 0 ],
[ [ [ -5, 6, 0, 1, -2, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, -1, 1, -2, 2 ] ], 0.25 ],
[ [ [ -4, 5, 0, 1, -3, 2 ], [ -3, 5, -1, 1, -2, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, -1, 1, -2, 2 ] ], 0.25 ]
[ [ [ -5, 3, 1, 2, -2, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -3, 3, 1, 1, -1, 2 ] ], 0 ],
[ [ [ -4, 2, 1, 1, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -3, 2, 1, 2, -1, 2 ], [ -3, 3, 1, 1, -1, 2 ] ], 0 ],
[ [ [ -4, 2, 1, 1, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -2, 2, 1, 1, -1, 2 ], [ -3, 3, 1, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 2, 1, 1, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -3, 4, 1, 1, -1, 2 ], [ -3, 3, 1, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 2, 1, 1, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -3, 2, 1, 1, -1, 2 ], [ -3, 3, 1, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 2, 1, 1, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -4, 4, 1, 1, -1, 2 ], [ -3, 3, 1, 1, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 5, 0, 1, -3, 2 ], [ -3, 5, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, -1, 1, -2, 2 ] ], 0.25 ]
[ [ [ -4, 2, 1, 1, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -4, 4, 1, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 2, 1, 1, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -3, 2, 2, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 5, 0, 1, -3, 2 ], [ -3, 5, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, 1, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 5, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, 1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -4, 5, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 5, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -4, 5, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, 0, 1, -4, 2 ] ], 0.25 ]
[ [ [ -4, 2, 1, 1, -1, 2 ], [ -4, 3, 1, 1, -1, 2 ], [ -3, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -4, 2, 1, 1, -1, 2 ], [ -3, 2, 0, 1, -1, 2 ], [ -3, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -3, 1, 0, 1, -1, 2 ], [ -3, 2, 0, 1, -1, 2 ], [ -3, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 0, 1, -1, 2 ], [ -3, 2, 0, 1, -1, 2 ], [ -3, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 0, -1, 2 ], [ -3, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 1 ], [ -3, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 3, 0, 1, -1, 2 ], [ -2, 1, 0, 1, -1, 2 ], [ -3, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 5, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, -1, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 5, 0, 1, -3, 2 ], [ -3, 6, 0, 1, -4, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, -1, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 6, 0, 1, -4, 2 ], [ -3, 6, 0, 1, -4, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, -1, 1, -3, 2 ] ], 0.25 ]
[ [ [ -4, 3, 0, 1, -1, 2 ], [ -3, 2, 1, 1, -1, 2 ], [ -3, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -4, 3, 0, 1, -1, 2 ], [ -3, 2, 1, 1, -1, 2 ], [ -3, 2, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -3, 2, 0, 1, -2, 2 ], [ -3, 2, 1, 1, -1, 2 ], [ -3, 2, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -3, 2, 0, 1, -2, 2 ], [ -3, 2, 1, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -3, 2, 0, 1, -2, 2 ], [ -3, 2, 1, 1, -1, 2 ], [ -3, 2, -1, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -3, 2, 0, 1, -2, 2 ], [ -2, 1, 0, 1, -1, 2 ], [ -3, 2, -1, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -3, 2, 0, 1, -2, 2 ], [ -2, 1, 0, 1, -1, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 6, 0, 1, -4, 2 ], [ -3, 6, 0, 1, -4, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -4, 6, 0, 1, -4, 2 ], [ -3, 5, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -4, 5, 0, 1, -3, 2 ], [ -3, 5, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 5, 0, 1, -3, 2 ], [ -4, 6, 1, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -5, 7, 0, 1, -3, 2 ], [ -4, 6, 1, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -5, 7, 0, 1, -3, 2 ], [ -4, 6, 1, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, -1, 1, -3, 2 ] ], 0 ],
[ [ [ -5, 7, 0, 1, -3, 2 ], [ -3, 6, 0, 0, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, -1, 1, -3, 2 ] ], 0.25 ]
[ [ [ -3, 2, 0, 1, -2, 2 ], [ -2, 2, 0, 1, -2, 2 ], [ -4, 2, 0, 2, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -3, 2, 0, 1, -2, 2 ], [ -2, 2, 0, 1, -2, 2 ], [ -2, 2, 0, 0, -2, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -3, 2, 0, 1, -2, 2 ], [ -2, 2, 0, 1, -3, 2 ], [ -2, 2, 0, 0, -2, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 7, 0, 1, -3, 2 ], [ -5, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, -1, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 6, -1, 1, -3, 2 ], [ -5, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, -1, 1, -3, 2 ] ], 0.25 ]
[ [ [ -3, 2, 0, 1, -2, 2 ], [ -2, 2, 0, 1, -3, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -3, 2, 0, 1, -2, 2 ], [ -3, 2, 0, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -3, 1, 0, 1, -1, 2 ], [ -3, 2, 0, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 6, -1, 1, -3, 2 ], [ -5, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 2, -3, 2 ] ], 0 ],
[ [ [ -5, 6, 0, 2, -3, 2 ], [ -5, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 2, -3, 2 ] ], 0.25 ],
[ [ [ -7, 6, 0, 2, -3, 2 ], [ -5, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 2, -3, 2 ] ], 0.25 ],
[ [ [ -6, 6, 0, 1, -3, 2 ], [ -5, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 2, -3, 2 ] ], 0.25 ],
[ [ [ -6, 6, 0, 1, -3, 2 ], [ -5, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, 0, 1, -3, 2 ] ], 0 ],
[ [ [ -5, 6, 0, 0, -3, 2 ], [ -5, 6, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, 0, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 6, 0, 0, -3, 2 ], [ -4, 6, 0, 0, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, 0, 1, -3, 2 ] ], 0 ],
[ [ [ -3, 5, 0, 1, -3, 2 ], [ -4, 6, 0, 0, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -3, 5, 0, 1, -3, 2 ], [ -4, 5, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, 0, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 7, 0, 1, -3, 2 ], [ -4, 5, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, 0, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -4, 5, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -3, 6, 0, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -4, 5, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -2, 5, 0, 0, -3, 2 ] ], 0 ],
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -5, 8, 0, 1, -3, 2 ], [ -2, 5, 0, 0, -3, 2 ] ], 0.25 ],
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -3, 6, 0, 0, -3, 2 ], [ -2, 5, 0, 0, -3, 2 ] ], 0.25 ],
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -4, 2 ], [ -2, 5, 0, 0, -3, 2 ] ], 0 ],
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -4, 2 ], [ -2, 6, 0, 0, -4, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -4, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -4, 6, 0, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -4, 6, 0, 0, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -5, 7, 1, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 6, 1, 1, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -5, 7, 1, 1, -3, 2 ], [ -4, 7, 0, 1, -3, 2 ] ], 0 ],
[ [ [ -5, 6, 1, 1, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -5, 7, 1, 1, -3, 2 ], [ -5, 8, 1, 1, -3, 2 ] ], 0 ],
[ [ [ -5, 6, 1, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -5, 7, 1, 1, -3, 2 ], [ -5, 8, 1, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 6, 1, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -6, 9, 1, 1, -3, 2 ], [ -5, 8, 1, 1, -3, 2 ] ], 0 ],
[ [ [ -5, 6, 1, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -6, 9, 1, 1, -3, 2 ], [ -4, 8, 1, 0, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 6, 1, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -5, 8, 0, 1, -3, 2 ], [ -4, 8, 1, 0, -3, 2 ] ], 0.25 ],
[ [ [ -5, 6, 1, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -4, 6, 1, 1, -3, 2 ], [ -4, 8, 1, 0, -3, 2 ] ], 0.25 ],
[ [ [ -5, 6, 1, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -5, 8, 1, 1, -3, 2 ], [ -4, 8, 1, 0, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -7, 8, 1, 2, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -5, 8, 1, 1, -3, 2 ], [ -4, 8, 1, 0, -3, 2 ] ], 0 ],
[ [ [ -7, 8, 1, 2, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -5, 8, 1, 1, -3, 2 ], [ -5, 8, 2, 1, -3, 2 ] ], 0.25 ],
[ [ [ -7, 8, 1, 2, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -6, 9, 1, 1, -3, 2 ], [ -5, 8, 2, 1, -3, 2 ] ], 0 ],
[ [ [ -7, 8, 1, 2, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -6, 9, 1, 1, -3, 2 ], [ -4, 7, 1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -7, 8, 1, 2, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -6, 9, 1, 1, -3, 2 ], [ -5, 9, 1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -7, 8, 1, 2, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ], [ -6, 9, 1, 1, -3, 2 ], [ -4, 8, 0, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -7, 8, 1, 2, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -6, 9, 1, 1, -3, 2 ], [ -4, 8, 0, 1, -3, 2 ] ], 0 ],
[ [ [ -7, 8, 1, 2, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -5, 8, 0, 1, -3, 2 ], [ -4, 8, 0, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 7, 0, 1, -3, 2 ], [ -5, 7, 0, 1, -3, 2 ], [ -5, 8, 0, 1, -3, 2 ], [ -4, 8, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -4, 7, 0, 1, -3, 2 ], [ -6, 8, 0, 1, -3, 2 ], [ -5, 8, 0, 1, -3, 2 ], [ -4, 8, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -4, 7, 0, 1, -3, 2 ], [ -5, 8, 0, 0, -3, 2 ], [ -5, 8, 0, 1, -3, 2 ], [ -4, 8, 0, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -5, 8, 1, 1, -3, 2 ], [ -5, 8, 0, 0, -3, 2 ], [ -5, 8, 0, 1, -3, 2 ], [ -4, 8, 0, 1, -3, 2 ] ], 0.25 ],
[ [ [ -5, 8, 1, 1, -3, 2 ], [ -5, 8, 0, 0, -3, 2 ], [ -5, 8, 0, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 8, 0, 0, -3, 2 ], [ -5, 8, 0, 0, -3, 2 ], [ -5, 8, 0, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -4, 8, 0, 0, -3, 2 ], [ -5, 8, 0, 0, -3, 2 ], [ -6, 9, 1, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ] ], 0 ],
[ [ [ -4, 8, 0, 0, -3, 2 ], [ -7, 8, 1, 2, -3, 2 ], [ -6, 9, 1, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ] ], 0 ],
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 1, 2, -3, 2 ], [ -6, 9, 1, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 1, 2, -3, 2 ], [ -6, 8, 0, 2, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 1, 2, -3, 2 ], [ -7, 9, 1, 2, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 1, 2, -3, 2 ], [ -7, 8, 1, 2, -3, 3 ], [ -6, 8, 1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 1, 2, -3, 2 ], [ -5, 7, 1, 1, -3, 2 ], [ -6, 8, 1, 1, -3, 2 ] ], 0.25 ],
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 1, 2, -3, 2 ], [ -6, 8, 1, 2, -4, 2 ], [ -6, 8, 1, 1, -3, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 1, 2, -3, 2 ], [ -6, 8, 1, 2, -4, 2 ], [ -7, 8, 2, 2, -3, 2 ] ], 0 ],
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 2, 2, -4, 2 ], [ -6, 8, 1, 2, -4, 2 ], [ -7, 8, 2, 2, -3, 2 ] ], 0.25 ],
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 2, 2, -4, 2 ], [ -6, 8, 1, 2, -4, 2 ], [ -6, 8, 0, 2, -4, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 2, 2, -4, 2 ], [ -7, 8, 2, 2, -4, 3 ], [ -6, 8, 0, 2, -4, 2 ] ], 0.25 ],
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 2, 2, -4, 2 ], [ -5, 8, 0, 2, -4, 1 ], [ -6, 8, 0, 2, -4, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 8, 1, 2, -3, 2 ], [ -7, 8, 2, 2, -4, 2 ], [ -5, 7, 0, 2, -4, 2 ], [ -6, 8, 0, 2, -4, 2 ] ], 0 ],
[ [ [ -6, 8, 2, 2, -4, 2 ], [ -7, 8, 2, 2, -4, 2 ], [ -5, 7, 0, 2, -4, 2 ], [ -6, 8, 0, 2, -4, 2 ] ], 0.25 ],
[ [ [ -6, 8, 2, 2, -4, 2 ], [ -7, 8, 2, 2, -4, 2 ], [ -6, 8, 1, 2, -4, 2 ], [ -6, 8, 0, 2, -4, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 8, 2, 2, -4, 2 ], [ -7, 8, 2, 2, -4, 2 ], [ -6, 8, 1, 2, -4, 2 ], [ -6, 7, 2, 2, -4, 2 ] ], 0 ],
[ [ [ -6, 8, 2, 2, -4, 2 ], [ -7, 8, 2, 2, -4, 2 ], [ -7, 9, 2, 2, -4, 2 ], [ -6, 7, 2, 2, -4, 2 ] ], 0 ],
[ [ [ -6, 8, 2, 2, -4, 2 ], [ -6, 9, 2, 2, -4, 2 ], [ -7, 9, 2, 2, -4, 2 ], [ -6, 7, 2, 2, -4, 2 ] ], 0.25 ],
[ [ [ -6, 8, 2, 2, -4, 2 ], [ -6, 9, 2, 2, -4, 2 ], [ -7, 9, 2, 2, -4, 2 ], [ -7, 8, 2, 2, -4, 2 ] ], 0 ],
[ [ [ -6, 8, 2, 2, -4, 2 ], [ -5, 8, 1, 2, -4, 2 ], [ -7, 9, 2, 2, -4, 2 ], [ -7, 8, 2, 2, -4, 2 ] ], 0.25 ],
[ [ [ -6, 8, 2, 2, -4, 2 ], [ -6, 9, 2, 2, -4, 2 ], [ -7, 9, 2, 2, -4, 2 ], [ -7, 8, 2, 2, -4, 2 ] ], 0.25 ],
[ [ [ -6, 8, 2, 2, -4, 2 ], [ -6, 8, 2, 2, -4, 3 ], [ -7, 9, 2, 2, -4, 2 ], [ -7, 8, 2, 2, -4, 2 ] ], 0.25 ]
],
[
[ [ [ -6, 8, 2, 2, -4, 2 ], [ -6, 8, 2, 2, -4, 3 ], [ -7, 9, 2, 2, -4, 2 ], [ -7, 7, 2, 2, -4, 3 ] ], 0 ],
[ [ [ -6, 7, 2, 2, -4, 3 ], [ -6, 8, 2, 2, -4, 3 ], [ -7, 9, 2, 2, -4, 2 ], [ -7, 7, 2, 2, -4, 3 ] ], 0.25 ],
[ [ [ -6, 7, 2, 2, -4, 3 ], [ -6, 8, 2, 2, -4, 3 ], [ -7, 9, 2, 2, -4, 2 ], [ -8, 9, 2, 2, -4, 3 ] ], 0.25 ]
],
[
[ [ [ -7, 9, 2, 2, -4, 3 ], [ -6, 8, 2, 2, -4, 3 ], [ -7, 9, 2, 2, -4, 2 ], [ -8, 9, 2, 2, -4, 3 ] ], 0 ],
[ [ [ -7, 9, 2, 2, -4, 3 ], [ -6, 8, 2, 2, -4, 3 ], [ -7, 8, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ], 0.25 ],
[ [ [ -7, 9, 2, 2, -4, 3 ], [ -6, 8, 2, 2, -4, 3 ], [ -8, 9, 3, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ], 0.25 ]
],
[
[ [ [ -7, 9, 2, 2, -4, 3 ], [ -6, 8, 2, 2, -4, 3 ], [ -7, 8, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ], 0 ],
[ [ [ -7, 9, 2, 2, -4, 3 ], [ -7, 9, 3, 2, -4, 3 ], [ -7, 8, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ], 0.25 ],
[ [ [ -7, 9, 2, 2, -4, 3 ], [ -6, 8, 2, 2, -4, 3 ], [ -7, 8, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ], 0 ],
[ [ [ -7, 9, 2, 2, -4, 3 ], [ -6, 8, 2, 2, -4, 3 ], [ -8, 10, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ], 0.25 ],
[ [ [ -7, 9, 2, 2, -4, 3 ], [ -6, 9, 2, 2, -4, 2 ], [ -8, 10, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ], 0.25 ]
],
[
[ [ [ -7, 9, 2, 2, -4, 3 ], [ -8, 11, 2, 2, -4, 3 ], [ -8, 10, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ], 0.25 ],
[ [ [ -8, 10, 3, 2, -4, 3 ], [ -8, 11, 2, 2, -4, 3 ], [ -8, 10, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ], 0 ],
[ [ [ -8, 10, 3, 2, -4, 3 ], [ -8, 8, 2, 2, -4, 3 ], [ -8, 10, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ], 0.25 ]
[ [ [ -4, 2, 0, 1, -1, 2 ], [ -3, 2, 0, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -4, 2, 0, 1, -1, 2 ], [ -4, 4, 0, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ],
[ [ [ -4, 2, 0, 1, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0 ],
[ [ [ -5, 4, 0, 1, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ], 0.25 ]
]
]
],
"last_changes":
[
[ [ -7, 9, 2, 2, -4, 3 ], [ -6, 8, 2, 2, -4, 3 ], [ -8, 10, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ],
[ [ -7, 9, 2, 2, -4, 3 ], [ -6, 9, 2, 2, -4, 2 ], [ -8, 10, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ],
[ [ -7, 9, 2, 2, -4, 3 ], [ -8, 11, 2, 2, -4, 3 ], [ -8, 10, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ],
[ [ -8, 10, 3, 2, -4, 3 ], [ -8, 11, 2, 2, -4, 3 ], [ -8, 10, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ],
[ [ -8, 10, 3, 2, -4, 3 ], [ -8, 8, 2, 2, -4, 3 ], [ -8, 10, 2, 2, -4, 3 ], [ -8, 9, 2, 2, -4, 3 ] ]
[ [ -3, 1, 0, 1, -1, 2 ], [ -3, 2, 0, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ],
[ [ -4, 2, 0, 1, -1, 2 ], [ -3, 2, 0, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ],
[ [ -4, 2, 0, 1, -1, 2 ], [ -4, 4, 0, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ],
[ [ -4, 2, 0, 1, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ],
[ [ -5, 4, 0, 1, -1, 2 ], [ -3, 3, -1, 1, -1, 2 ], [ -4, 3, 0, 1, -1, 2 ], [ -2, 2, 0, 1, -1, 2 ] ]
],
"cur_uid": "tmp",
"ref_uid": "624f7439",
"order_seed": 297821,
"dur_seed": 692519,
"motifs_seed": 730459,
"ref_uid": "536cac90",
"order_seed": 837263,
"dur_seed": 899115,
"motifs_seed": 454954,
"entrances_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"passages_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"exits_probs_vals": [ 0.78, 0, 0, 0, 1.02, 0.0098039215686275, 0, 0.20915032679739, 0, 0.24183006535948, 0.82432432432432, 0.28758169934641, 0, 1, 0 ],
"ranges": [ [ -2400, 1200 ], [ -1200, 1453 ], [ -702, 1694 ], [ -702, 1973 ] ],
"step_probs_vals": [ -1200, 1200, 0, 0, 0.41358024691358, 0.0056818181818177, 0.46913580246914, 0.67045454545455, 0.52057613168724, 0, 0.56378600823045, 0.85795454545455, 0.60082304526749, 0, 1, 0 ],
"passages_weights": [ 0.38, 0.15, 0.43, 1, 1 ],
"passages_weights": [ 1, 0.15, 0.43, 1, 1 ],
"hd_exp": 10,
"hd_invert": 0,
"order":
[
[ [ 0, 1 ], [ 2, 3, 3 ], [ ] ],
[ [ 1, 2 ], [ 0, 3, 0, 3, 0, 0 ], [ ] ],
[ [ 3, 0, 2 ], [ 1 ], [ ] ],
[ [ 0, 2 ], [ 3, 1, 3, 3 ], [ ] ],
[ [ 2 ], [ 3, 1, 0 ], [ ] ],
[ [ 2 ], [ 3, 1, 0, 1, 0, 3, 1 ], [ ] ],
[ [ 3, 2 ], [ 1, 0 ], [ ] ],
[ [ 2, 1 ], [ 3, 0, 0, 0, 3, 0 ], [ ] ],
[ [ 3, 2 ], [ 1, 0, 1, 0 ], [ ] ],
[ [ 2 ], [ 0, 3, 1 ], [ ] ],
[ [ 0, 1 ], [ 3, 2, 2, 2, 3 ], [ ] ],
[ [ 1, 0 ], [ 3, 2, 2 ], [ ] ],
[ [ 2 ], [ 0, 3, 1 ], [ ] ],
[ [ 1, 0 ], [ 2, 3 ], [ ] ],
[ [ 1, 0, 3 ], [ 2, 2, 2 ], [ ] ],
[ [ 1 ], [ 0, 3, 2, 3, 3, 3 ], [ ] ],
[ [ 3 ], [ 1, 2, 0, 1, 1 ], [ ] ],
[ [ 2, 1 ], [ 0, 3, 0 ], [ ] ],
[ [ 0, 2, 3 ], [ 1, 1, 1, 1 ], [ ] ],
[ [ 1 ], [ 3, 0, 2, 2, 2, 2 ], [ ] ],
[ [ 1, 0 ], [ 3, 2 ], [ ] ],
[ [ 3 ], [ 2, 1, 0, 0, 1, 1, 1 ], [ ] ],
[ [ 3 ], [ 1, 2, 0, 2, 2, 1, 2 ], [ ] ],
[ [ 0, 3 ], [ 1, 2, 1 ], [ ] ],
[ [ 3 ], [ 2, 1, 0 ], [ ] ],
[ [ 0, 3, 1 ], [ 2, 2, 2, 2, 2 ], [ ] ],
[ [ 2, 0 ], [ 3, 1, 3 ], [ ] ],
[ [ 0, 3, 1 ], [ 2, 2 ], [ ] ],
[ [ 3, 1 ], [ 2, 0, 2 ], [ ] ],
[ [ 0 ], [ 3, 2, 1, 3, 1, 1, 1 ], [ ] ],
[ [ 2, 1 ], [ 3, 0, 3 ], [ ] ],
[ [ 3, 1 ], [ 0, 2, 2 ], [ ] ],
[ [ 3, 0 ], [ 2, 1, 1, 2, 1 ], [ ] ],
[ [ 2, 3 ], [ 1, 0, 1 ], [ ] ]
[ [ 3, 2 ], [ 0, 1, 1, 0 ], [ ] ]
],
"sus_weights": [ 0.37, 0.61, 0.22535211267606 ],
"order_size": [ 28.275510204082, 28.275510204082 ],
"sus_weights": [ 0.7, 0.48, 0.49 ],
"order_size": [ 14.132653061224, 14.132653061224 ],
"passages_size": [ 0, 5 ],
"motif_edited": "false",
"order_edited": "false"

@ -57,35 +57,12 @@ swap = {arg data, swaplist;
c = [
[
[
[ [ [ -2, 3, -2, -1, 1, 0 ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 1 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ "Rest" ], [ "Rest" ], [ -2, 4, -2, -1, 1, 0 ] ], 0 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ "Rest" ], [ -1, 3, -2, -1, 2, 0 ], [ -2, 4, -2, -1, 1, 0 ] ], 0 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -2, 3, -1, -1, 1, 0 ], [ -1, 3, -2, -1, 2, 0 ], [ -2, 4, -2, -1, 1, 0 ] ], 7 ]
],
[
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -2, 3, -1, -1, 1, 0 ], [ -1, 3, -1, -1, 1, 0 ], [ -2, 4, -2, -1, 1, 0 ] ], 0 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -1, 3, -2, -1, 1, -1 ], [ -1, 3, -1, -1, 1, 0 ], [ -2, 4, -2, -1, 1, 0 ] ], 0 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -1, 3, -2, -1, 1, -1 ], [ -1, 3, -1, -1, 1, 0 ], [ -1, 3, -2, -1, 0, 0 ] ], 5.5 ]
],
[
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -1, 3, -2, -1, 1, -1 ], [ 0, 2, -2, -1, 1, 0 ], [ -1, 3, -2, -1, 0, 0 ] ], 0 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -1, 3, -2, -1, 1, -1 ], [ 0, 2, -2, -1, 1, 0 ], [ -1, 2, -2, -1, 1, 0 ] ], 0 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -1, 3, -3, -1, 1, 0 ], [ 0, 2, -2, -1, 1, 0 ], [ -1, 2, -2, -1, 1, 0 ] ], 4 ]
],
[
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -1, 3, -3, -1, 1, 0 ], [ 0, 3, -2, -2, 1, 0 ], [ -1, 2, -2, -1, 1, 0 ] ], 0 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -1, 3, -3, -1, 1, 0 ], [ 0, 3, -2, -2, 1, 0 ], [ -2, 3, -1, -1, 1, 0 ] ], 0 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -2, 3, -2, -1, 1, 1 ], [ 0, 3, -2, -2, 1, 0 ], [ -2, 3, -1, -1, 1, 0 ] ], 5.625 ]
],
[
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -2, 3, -2, -1, 1, 1 ], [ -1, 3, -2, -1, 1, 0 ], [ -2, 3, -1, -1, 1, 0 ] ], 0 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -2, 3, -2, -1, 1, 1 ], [ -1, 3, -2, -1, 1, 0 ], [ -1, 3, -2, -1, 1, -1 ] ], 0 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -2, 3, -2, 0, 1, 0 ], [ -1, 3, -2, -1, 1, 0 ], [ -1, 3, -2, -1, 1, -1 ] ], 6.5 ],
[ [ [ -2, 3, -2, -1, 1, 0 ], [ -2, 3, -2, 0, 1, 0 ], [ "Rest" ], [ -1, 3, -2, -1, 1, -1 ] ], 0 ],
[ [ [ "Rest" ], [ -2, 3, -2, 0, 1, 0 ], [ "Rest" ], [ -1, 3, -2, -1, 1, -1 ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ -1, 3, -2, -1, 1, -1 ] ], 0 ],
[ [ [ "Rest" ], [ "Rest" ], [ "Rest" ], [ "Rest" ] ], 6.375 ]
]
[ [ -3, 5, -2, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 5, -1, 2, -2, 2 ] ],
[ [ -3, 5, -2, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -4, 5, -2, 1, -2, 2 ] ],
[ [ -3, 5, -2, 1, -2, 2 ], [ -3, 4, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ],
[ [ -3, 5, -2, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ],
[ [ -6, 6, -1, 1, -2, 2 ], [ -4, 6, -1, 1, -2, 2 ], [ -4, 5, -1, 1, -2, 2 ], [ -5, 6, -1, 1, -2, 2 ] ]
]
]
];

Loading…
Cancel
Save