You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
581 lines
17 KiB
Plaintext
581 lines
17 KiB
Plaintext
(
|
|
// helper funcs
|
|
var hsArrayToCents, pDist, hdSum, hsChordalDistance, hsArrayToFreq;
|
|
|
|
// score funcs
|
|
var isInRange, spacingScore, rangeScore, intervalScore, inclusionScore;
|
|
|
|
// subroutines
|
|
var genTuples, initVoices, genOrder, genSubMotif, updateVoices;
|
|
|
|
// primary routines
|
|
var genMotif, genSecondarySeq;
|
|
|
|
// audition funcs
|
|
var genPatterns, genMidiPatterns;
|
|
|
|
// resource management funcs
|
|
var writeResources, prettifyArray, setSeeds, sanityCheck, msgInterpret;
|
|
|
|
// global vars (many set by OSC funcs at bottom)
|
|
var refSeed, seed, lastXChanges, popSize, exPath, dir, primes, dims, tuples, ranges, durFunc, seq, group, player;
|
|
|
|
|
|
//------helper funcs
|
|
|
|
hsArrayToCents = {
|
|
arg hsArray;
|
|
hsArray.collect({arg dist, p; dist * 1200 * log2(primes[p][0]/primes[p][1])}).sum
|
|
};
|
|
|
|
pDist = {
|
|
arg array1, array2, signed = false;
|
|
var pDistance;
|
|
pDistance = hsArrayToCents.value(array1) - hsArrayToCents.value(array2);
|
|
if(signed, {pDistance}, {abs(pDistance)})
|
|
};
|
|
|
|
hdSum = {
|
|
arg hsArrays;
|
|
var size, distances, mean;
|
|
size = hsArrays.size;
|
|
distances = (size - 1).collect({arg i;
|
|
((i + 1)..(size - 1)).collect({arg j;
|
|
abs(hsArrays[i] - hsArrays[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
|
|
});
|
|
}).flat;
|
|
mean = distances.sum / distances.size;
|
|
distances.sum
|
|
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
|
|
};
|
|
|
|
hsChordalDistance = {
|
|
arg hsArrays1, hsArrays2;
|
|
var size, distances, mean;
|
|
size = hsArrays1.size;
|
|
distances = hsArrays1.size.collect({arg i;
|
|
hsArrays2.size.collect({arg j;
|
|
abs(hsArrays1[i] - hsArrays2[j]).collect({arg dist, p; dist * log2(primes[p].product)}).sum
|
|
});
|
|
}).flat;
|
|
mean = distances.sum / distances.size;
|
|
distances.sum
|
|
//mean + ((1 / sqrt((pow(distances - mean, 2)).sum / distances.size)) * mean)
|
|
};
|
|
|
|
hsArrayToFreq = {
|
|
arg array;
|
|
array.collect({arg dim, d; pow(primes[d][0]/primes[d][1], dim)}).product
|
|
};
|
|
|
|
|
|
//------score funcs
|
|
|
|
/*
|
|
isInRange = {
|
|
arg hsArray, min, max;
|
|
var cents;
|
|
cents = hsArrayToCents.value(hsArray);
|
|
(cents >= min) && (cents <= max)
|
|
};
|
|
*/
|
|
|
|
spacingScore = {
|
|
arg hsArrays, min;
|
|
var centsArray;
|
|
centsArray = hsArrays.collect({arg hsArray; hsArrayToCents.value(hsArray)}).sort({arg a, b; a < b});
|
|
centsArray.differentiate.drop(1).collect({arg pDistance; if(pDistance >= min, {1}, {0.01})}).sum;
|
|
};
|
|
|
|
rangeScore = {
|
|
arg hsArray1, hsArray2, min, max, low, signed = false;
|
|
var pDistance;
|
|
pDistance = pDist.value(hsArray1, hsArray2, signed);
|
|
if((pDistance >= min) && (pDistance <= max), {1}, {low});
|
|
};
|
|
|
|
intervalScore = {
|
|
arg hsArray1, hsArray2, mean, sd, signed = false;
|
|
var pDistance;
|
|
pDistance = pDist.value(hsArray1, hsArray2, signed);
|
|
pDistance.gaussCurve(1, mean, sd)
|
|
};
|
|
|
|
inclusionScore = {
|
|
arg array, test, min = 0.01;
|
|
if(array.collect({arg v; v.hash}).includes(test.hash), {min}, {1});
|
|
};
|
|
|
|
|
|
//------subroutines
|
|
|
|
genTuples = {
|
|
var tuples;
|
|
tuples = dims.collect({[-1, 0, 1]}).allTuples.select({arg tuple; (abs(tuple.drop(1)).sum <= 1) && (tuple[0] == 0)});
|
|
tuples = tuples ++ tuples.collect({arg tuple; [-3, -2, -1, 1, 2, 3].collect({arg octTrans; tuple.deepCopy.put(0, octTrans)})}).flatten;
|
|
};
|
|
|
|
initVoices = {
|
|
var init, voicesInit;
|
|
voicesInit = popSize.collect({dims.collect({0})});
|
|
/*
|
|
voicesInit = [dims.collect({0})];
|
|
(popSize - 1).do({
|
|
arg rep, new;
|
|
rep = dims.rand;
|
|
new = voicesInit.last.deepCopy;
|
|
new[rep] = new[rep] + [-1, 1].choose();
|
|
voicesInit = voicesInit.add(new);
|
|
});
|
|
*/
|
|
voicesInit.deepCopy;
|
|
};
|
|
|
|
genOrder = {arg minLength = 0, maxLength = 5;
|
|
var noProgIns, noSusIns, noSilentIns, prog, sus, silent, order;
|
|
noProgIns = (popSize - 1).rand + 1;
|
|
noSusIns = (popSize - noProgIns).rand + 1;
|
|
noSilentIns = popSize - noSusIns - noProgIns;
|
|
|
|
# prog, sus, silent = (0..(popSize-1)).scramble.clumps([noProgIns, noSusIns, noSilentIns]);
|
|
|
|
prog = (prog.scramble ++ ((maxLength - minLength).rand + minLength).collect({prog.choose}).scramble);
|
|
if(silent == nil, {silent = []});
|
|
[sus.scramble, prog, silent.scramble]
|
|
};
|
|
|
|
updateVoices = {arg ins, sus;
|
|
var voices, candidates, nWeights, nProbs, sel;
|
|
|
|
voices = lastXChanges.deepCopy.last;
|
|
|
|
candidates = sus.collect({arg v; tuples.collect({arg t; voices[v] + t})}).flatten;
|
|
candidates = difference(candidates.asSet, voices.asSet).asList;
|
|
nProbs = candidates.collect({arg candidate;
|
|
var stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore;
|
|
|
|
//stepScore = intervalScore.value(voices[ins], candidate, 30, 400, 0.1);
|
|
stepScore = intervalScore.value(voices[ins], candidate, 100, 100);
|
|
recentlySoundedScore = inclusionScore.value(lastXChanges.flop[ins], candidate, 0);
|
|
isInRangeScore = rangeScore.value(candidate, candidate.collect({0}), ranges[ins][0], ranges[ins][1], 0, true);
|
|
regScore = spacingScore.value(voices.deepCopy.put(ins, candidate), 300);
|
|
hdScore = 1/pow(hdSum.value(voices.deepCopy.put(ins, candidate)), 2);
|
|
//maybe what you want here is a vector to another root and then favoring movement towards it.
|
|
//distScore = pow(hsChordalDistance.value(voices, voices.put(ins, candidate)), 2);
|
|
|
|
[stepScore, recentlySoundedScore, isInRangeScore, regScore, hdScore]
|
|
});
|
|
|
|
nWeights = [1, 1, 1, 1, 1];
|
|
|
|
//this handles nWeights of 0; mainly for testing
|
|
nProbs = nProbs.flop.select({arg scores, s; nWeights[s] != 0}).flop;
|
|
nWeights = nWeights.select({arg weight; weight != 0});
|
|
nProbs = nProbs.flop.collect({arg scores, s;
|
|
if(scores.sum == 0, {scores}, {scores.normalizeSum * nWeights[s]})
|
|
});
|
|
nProbs = nProbs.flop.collect({arg scores, s; scores.product}).normalizeSum;
|
|
|
|
sel = candidates.wchoose(nProbs);
|
|
|
|
voices[ins] = sel;
|
|
lastXChanges = lastXChanges.add(voices).keep(-5);
|
|
};
|
|
|
|
genSubMotif = {arg order, lastState, repeatLast = false, startFromLast = false, isLastOrder = false;
|
|
var sus, prog, silent, res, lastIns, lastXChangesHold, voices, adder;
|
|
# sus, prog, silent = order;
|
|
lastXChangesHold = lastXChanges.deepCopy;
|
|
voices = lastState.deepCopy;
|
|
lastIns = nil;
|
|
res = [];
|
|
"------generating motif".postln;
|
|
//need to figure out here if voices move between motifs
|
|
(silent ++ sus ++ prog).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;
|
|
//dur = [durFunc.value(), 0].wchoose([1, 0].normalizeSum);
|
|
dur = durFunc.value(lastIns, ins);
|
|
voices[ins] = adder;
|
|
res = res.add([voices.deepCopy.postln, dur.round(0.125)]);
|
|
});
|
|
|
|
lastIns = ins;
|
|
});
|
|
|
|
// pad ending
|
|
if(isLastOrder, {
|
|
(0..(popSize-1)).scramble.do({arg ins;
|
|
if(res.last.first[ins] != ["Rest"], {
|
|
var dur;
|
|
voices[ins] = ["Rest"];
|
|
//dur = [durFunc.value(), 0].wchoose([1, 0].normalizeSum);
|
|
dur = durFunc.value(lastIns, ins);
|
|
res = res.add([voices.deepCopy.postln, dur.round(0.125)]);
|
|
});
|
|
lastIns = ins;
|
|
});
|
|
});
|
|
|
|
//format and return
|
|
if(startFromLast, {lastXChanges = lastXChangesHold});
|
|
res;
|
|
};
|
|
|
|
|
|
//------primary routines
|
|
|
|
genMotif = {arg inOrders;
|
|
var orders, repeats, fSeq;
|
|
|
|
repeats = 1;
|
|
fSeq = [];
|
|
|
|
repeats.do({arg index;
|
|
var motif;
|
|
|
|
motif = [];
|
|
orders = inOrders;
|
|
|
|
orders.do({arg order, o;
|
|
var lastState, subMotif;
|
|
lastState = if(o == 0, {popSize.collect({["Rest"]})}, {motif.last.last.first});
|
|
subMotif = genSubMotif.value(order, lastState, isLastOrder: o == (orders.size - 1));
|
|
motif = motif.add(subMotif);
|
|
|
|
});
|
|
|
|
sanityCheck.value(motif, index);
|
|
|
|
fSeq = fSeq.add(motif);
|
|
});
|
|
fSeq
|
|
};
|
|
|
|
genSecondarySeq = {arg seq;
|
|
var curdles, fSeq;
|
|
curdles = [];
|
|
while({curdles.sum < seq.size}, {curdles = curdles ++ [3.rand + 1]});
|
|
|
|
fSeq = seq.clumps(curdles).collect({arg clump, m;
|
|
var repeats, paddedSeq;
|
|
|
|
//add rest
|
|
paddedSeq = clump.add([[[popSize.collect({["Rest"]}), 0.5.rand]]]);
|
|
|
|
//implement repeats
|
|
repeats = [0.rand + 1, 1].wchoose([1, 0].normalizeSum);
|
|
repeats.collect({paddedSeq});
|
|
});
|
|
fSeq
|
|
};
|
|
|
|
|
|
//------audition funcs
|
|
|
|
genPatterns = {arg seq;
|
|
var voices, durs, patterns, res;
|
|
# voices, durs = seq.flatten2(seq.maxDepth - 5).flop;
|
|
res = Ppar(
|
|
voices.flop.collect({arg voice;
|
|
var clumps, hdScores, freqs, fDurs;
|
|
clumps = voice.separate({arg a, b; a != b });
|
|
freqs = clumps.collect({arg clump; if(clump[0] != ["Rest"], {(60.midicps * hsArrayToFreq.value(clump[0]))}, {Rest(0)})});
|
|
fDurs = durs.clumps(clumps.collect({arg clump; clump.size})).collect({arg clump; clump.sum});
|
|
|
|
Pbind(
|
|
\instrument, \test,
|
|
\group, group,
|
|
\freq, Pseq(freqs, 1),
|
|
\dur, Pseq(fDurs, 1),
|
|
\sustain, Pseq(fDurs, 1)
|
|
);
|
|
});
|
|
);
|
|
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
|
|
|
|
setSeeds = {arg inRefSeed, inSeed;
|
|
refSeed = if(inRefSeed.isNumber, {inRefSeed.asInteger}, {nil});
|
|
seed = if(inSeed > 1, {inSeed.asInteger}, {rrand(100000, 999999)});
|
|
thisThread.randSeed = seed;
|
|
};
|
|
|
|
prettifyArray = {arg data, finDepth = 1;
|
|
var prettyString = "", rCount = 0, writeArray;
|
|
|
|
writeArray = {arg array;
|
|
var depth, indent;
|
|
depth = array.maxDepth;
|
|
indent = rCount.collect({" "}).join("");
|
|
prettyString = prettyString ++ indent ++ "[\n";
|
|
rCount = rCount + 1;
|
|
if(depth > 5, {
|
|
array.do({arg subArray;
|
|
writeArray.value(subArray);
|
|
});
|
|
}, {
|
|
array.do({arg data, d;
|
|
prettyString = prettyString ++ indent ++ " " ++ data.asCompileString ++ if(d != (array.size - 1), {",\n"}, {""});
|
|
});
|
|
});
|
|
rCount = rCount - 1;
|
|
if(rCount < (finDepth - 1), {prettyString = prettyString.drop((finDepth - 1).neg)});
|
|
//if(rCount == 0, {prettyString = prettyString.drop((finDepth - 1).neg)});
|
|
prettyString = prettyString ++ "\n" ++ indent ++ "]" ++ if(rCount > 0, {",\n"}, {""});
|
|
};
|
|
|
|
writeArray.value(data);
|
|
prettyString
|
|
};
|
|
|
|
writeResources = {arg seq, path;
|
|
var dir, file, resString;
|
|
file = File(path,"w");
|
|
|
|
resString = "{\nmusic_data:\n";
|
|
resString = resString ++ prettifyArray.value(seq, 3);
|
|
|
|
resString = resString ++ ",\nlast_changes:\n";
|
|
resString = resString ++ prettifyArray.value(lastXChanges, 1);
|
|
|
|
resString = resString ++ ",\nseed: " ++ seed ++ ",\nref_seed: " ++ refSeed ++ "\n}";
|
|
|
|
file.write(resString);
|
|
file.close;
|
|
};
|
|
|
|
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;
|
|
var res;
|
|
res = in.asCompileString;
|
|
res = res.replace(" ", "").replace("\n", "").replace("\t", "");
|
|
res = res.replace("\'", "").replace("\"", "").replace("Rest", "\"Rest\"");
|
|
res.interpret
|
|
};
|
|
|
|
|
|
//------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();
|
|
refSeed = nil;
|
|
group = Group.new;
|
|
|
|
|
|
//------OSC funcs
|
|
|
|
OSCdef(\gen, {arg msg, time, addr, port;
|
|
var orders, condition;
|
|
msg.postln;
|
|
durFunc = nil;
|
|
|
|
addr.sendMsg("/STATE/SEND");
|
|
|
|
{
|
|
while({durFunc == nil}, {0.1.wait});
|
|
setSeeds.value(msg[1].postln, msg[2]);
|
|
|
|
lastXChanges = if(refSeed == nil, {
|
|
[initVoices.value().deepCopy];
|
|
}, {
|
|
var file;
|
|
file = File((dir +/+ "resources" +/+ refSeed ++ "_music" ++ ".json").standardizePath, "r");
|
|
msgInterpret.value(file.readAllString.parseJSON["last_changes"]);
|
|
});
|
|
|
|
if(msg.size == 4, {
|
|
orders = msgInterpret.value(msg[3]);
|
|
}, {
|
|
var minLength, maxLength;
|
|
minLength = msg[3];
|
|
maxLength = msg[4];
|
|
orders = ((maxLength - minLength).rand + minLength).collect({genOrder.value(msg[5], msg[6])});
|
|
});
|
|
|
|
orders.postln;
|
|
seed.postln;
|
|
refSeed.postln;
|
|
|
|
seq = genMotif.value(orders);
|
|
//patterns = genPatterns.value(seq);
|
|
addr.sendMsg("/current_seed", seed);
|
|
addr.sendMsg("/order", prettifyArray.value(orders, 1));
|
|
addr.sendMsg("/mus_seq", prettifyArray.value(seq, 3));
|
|
}.fork;
|
|
|
|
}, \gen);
|
|
|
|
OSCdef(\commit, {arg msg, time, addr, port;
|
|
var ledgerPath, oldLedger, newLedger, musSeq;
|
|
//msg.postln;
|
|
seed.postln;
|
|
//File.copy(exPath, (dir +/+ "resources" +/+ seed ++ "_code" ++ ".scd").standardizePath);
|
|
//addr.sendMsg("/SESSION/SAVE", (dir +/+ "resources" +/+ seed ++ "_gui_session" ++ ".json").standardizePath);
|
|
//addr.sendMsg("/STATE/SAVE", (dir +/+ "resources" +/+ seed ++ "_gui_state" ++ ".state").standardizePath);
|
|
|
|
writeResources.value(seq, (dir +/+ "resources" +/+ seed ++ "_music" ++ ".json").standardizePath);
|
|
|
|
ledgerPath = (dir +/+ "resources" +/+ "piece_ledger" ++ ".json").standardizePath;
|
|
oldLedger = File(ledgerPath, "r");
|
|
musSeq = msgInterpret.value(oldLedger.readAllString.parseJSON["ledger"]);
|
|
oldLedger.close;
|
|
File.delete(ledgerPath ++ "_bak");
|
|
File.copy(ledgerPath, ledgerPath ++ "_bak");
|
|
File.delete(ledgerPath);
|
|
newLedger = File(ledgerPath, "w");
|
|
musSeq = musSeq.add(seed);
|
|
newLedger.write("{\nledger:\n" ++ prettifyArray.value(musSeq, 1) ++ "\n}");
|
|
newLedger.close;
|
|
|
|
//refSeed = seed;
|
|
}, \commit);
|
|
|
|
OSCdef(\transport, {arg msg, time, addr, port;
|
|
msg.postln;
|
|
if(msg[1] == 0, {
|
|
player.stop;
|
|
group.set(\gate, 0);
|
|
}, {
|
|
var cSize, ledgerPath, ledger, patterns, pSeq;
|
|
ledgerPath = (dir +/+ "resources" +/+ "piece_ledger" ++ ".json").standardizePath;
|
|
ledger = msgInterpret.value(File(ledgerPath, "r").readAllString.parseJSON["ledger"]);
|
|
pSeq = [];
|
|
if(msg[2].asString != "all", {ledger = ledger.keep(msg[2].asInteger - 1)});
|
|
ledger.do({arg rSeed;
|
|
var file;
|
|
file = File((dir +/+ "resources" +/+ rSeed.postln ++ "_music" ++ ".json").standardizePath, "r");
|
|
pSeq = pSeq.add(msgInterpret.value(file.readAllString.parseJSON["music_data"]));
|
|
file.close;
|
|
});
|
|
pSeq = pSeq.add(seq);
|
|
patterns = genPatterns.value(pSeq);
|
|
player = Pfset(pattern: patterns, cleanupFunc: {
|
|
addr.sendMsg("/transport", 0);
|
|
});
|
|
player = player.play
|
|
});
|
|
}, \transport);
|
|
|
|
OSCdef(\range, {arg msg;
|
|
msg.postln;
|
|
ranges[msg[1]][msg[2]] = msg[3]
|
|
}, \range);
|
|
|
|
OSCdef(\dur_probs_env, {arg msg;
|
|
var env, pTable, min, max, cProb;
|
|
msg.postln;
|
|
env = Env.pairs([[0, 0]] ++ msg[4..].clump(2) ++ [[1, 0]]).asSignal(256).asList.asArray;
|
|
pTable = env.asRandomTable;
|
|
min = msg[1];
|
|
max = msg[2];
|
|
cProb = msg[3];
|
|
durFunc = {arg lIns, cIns;
|
|
if(lIns.postln == cIns.postln, {
|
|
pTable.tableRand * (max - min) + min
|
|
}, {
|
|
if(1.0.rand < cProb.postln, {0}, {pTable.tableRand * (max - min) + min}).postln;
|
|
});
|
|
};
|
|
}, \dur_probs_env);
|
|
)
|
|
|
|
(
|
|
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
|
|
var trig, exc, sig1, sig2, noHarms;
|
|
noHarms = 30;
|
|
exc = Saw.ar(freq, TRand.ar(0.5, 1, Impulse.ar(freq))) * 0.001 + Dust.ar(10000, 0.01);
|
|
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
|
|
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
|
|
Array.fill(noHarms, {rrand(1, 2)}) ], exc) * 0.5).softclip;
|
|
sig1 = HPF.ar(sig1, 300);
|
|
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
|
|
}).add;
|
|
)
|
|
|
|
(
|
|
SynthDef(\test, {arg freq, gate = 1, sustain, amp, dur;
|
|
var trig, exc, sig1, sig2, noHarms, freqFinal, start, end;
|
|
noHarms = 30;
|
|
freq = WhiteNoise.ar * 3 + freq;
|
|
freqFinal = Duty.ar((1/freq), 0, freq);
|
|
trig = Changed.ar(freqFinal);
|
|
start = Demand.ar(trig, 0, Dwhite(-1, -0.75));
|
|
end = Demand.ar(trig, 0, Dwhite(0.75, 1));
|
|
exc = Phasor.ar(trig, (end - start) * freqFinal / SampleRate.ir, start, end, 0) * 0.001 + Dust.ar(10000, 0.01);
|
|
|
|
sig1 = (Klank.ar(`[ Array.series(noHarms, freq, freq),
|
|
Array.geom(noHarms, 1, 0.2) + Array.fill(noHarms, {rrand(0.01, 0.03)}),
|
|
Array.fill(noHarms, {rrand(2, 3)}) ], exc) * 0.5).softclip;
|
|
sig1 = HPF.ar(sig1, 300);
|
|
Out.ar([0, 1], sig1 * EnvGen.kr(Env.adsr(0.3, 0.3, 0.9, 0.5, 0.9), gate, doneAction: 2));
|
|
}).add;
|
|
)
|
|
|
|
|
|
File((~dir +/+ "resources" +/+ 517313 ++ "_music" ++ ".json").standardizePath, "r").readAllString.parseJSON["last_changes"].asString.interpret[0][0][0].isNumber
|
|
|
|
"{\"a\": 1}".parseYAML["a"].asInteger;
|
|
"{\"a\": 1}".parseJSON["a"].isNumber; |