Last active
November 7, 2017 07:18
-
-
Save telephon/49f0634cb6b7aa31f9942eb17d6633fd to your computer and use it in GitHub Desktop.
completely flopping dictionaries might be more efficient after all
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
( | |
var flop = { |dict, keys| | |
var values, size; | |
keys = keys ?? { dict.keys.asArray }; // in terms of performance, this is the main bottleneck | |
values = keys.collect { |x| dict.at(x) }; // and this. | |
values = values.flop: | |
size = values.first.size; | |
values.collect { |xs| | |
var each = dict.copy; | |
keys.do { |key, i| | |
each.put(key, xs.at(i)); | |
each.put(\voiceID, i); | |
each.put(\voiceSize, size); | |
}; | |
each | |
} | |
}; | |
Event.addEventType(\flop, { |server| | |
var all; | |
~server = server; | |
~type = ~kind ? \singleNote; | |
all = flop.value(currentEnvironment, ~flopArgs); | |
all.do { |each| each.play } | |
}); | |
Event.addEventType(\singleNote, | |
#{|server| | |
var freqs, lag, strum, sustain; | |
var msg, addAction, sendGate, id; | |
var msgFunc, instrumentName, offset, strumOffset; | |
freqs = ~detunedFreq.value; | |
// msgFunc gets the synth's control values from the Event | |
msgFunc = ~getMsgFunc.valueEnvir; | |
instrumentName = ~synthDefName.valueEnvir; | |
// determine how to send those commands | |
// sendGate == false turns off releases | |
sendGate = ~sendGate ? ~hasGate; | |
// update values in the Event that may be determined by functions | |
~freq = freqs; | |
~amp = ~amp.value; | |
~sustain = sustain = ~sustain.value; | |
lag = ~lag; | |
offset = ~timingOffset; | |
strum = ~strum; | |
~server = server; | |
~isPlaying = true; | |
addAction = Node.actionNumberFor(~addAction); | |
// compute the control values and generate OSC commands | |
~id = id = server.nextNodeID; | |
msg = msgFunc.valueEnvir; | |
msg = [9 /* \s_new */, instrumentName, id, addAction, ~group] ++ msg; | |
msg = msg.asOSCArgArray; | |
// schedule when the bundles are sent | |
// strum can still be implemented, simply using offsets and ~voiceSize + ~voiceID | |
~schedBundleArray.(lag, offset, server, [msg], ~latency); // todo: replace ~schedBundleArray | |
if (sendGate) { | |
~schedBundleArray.( | |
lag, | |
sustain + offset, | |
server, | |
[[15 /* \n_set */, id, \gate, 0]], | |
~latency | |
) | |
}; | |
}) | |
) | |
( | |
SynthDef(\sin, { | out=0, freq=440, sustain=0.05 | | |
var env = EnvGen.kr(Env.perc(0.01, sustain, 0.2), doneAction: Done.freeSelf); | |
Out.ar(out, SinOsc.ar(freq, 0, env)) | |
}).add; | |
SynthDef(\saw, { | out=0, freq=440, sustain=0.05 | | |
var env = EnvGen.kr(Env.perc(0.01, sustain, 0.2), doneAction: Done.freeSelf); | |
Out.ar(out, Saw.ar(freq, env)) | |
}).add; | |
) | |
( | |
Pbind( | |
\type, \flop, | |
\instrument, [\sin, \saw], | |
\freq, [900, 50], | |
).play; | |
) | |
s.quit; | |
// for multichannel events, it is quite a bit faster | |
bench { 100.do { (type: \flop, note: [2, 7, 8, 1], sustain: [1, 2]).play } }; // 0.015595672000927 seconds. | |
bench { 100.do { (type: \note, note: [2, 7, 8, 1], sustain: [1, 2]).play } }; // 0.019294231999083 seconds. | |
// for mono events, not. | |
bench { 100.do { (type: \flop, note: 2, sustain: 1).play } }; // 0.0066223279991391 seconds. | |
bench { 100.do { (type: \note, note: 2, sustain: 1).play } }; // 0.00321578600051 seconds. | |
// so if we had a primitive that could tell us quickly if we should flop or not, this would be perfect. | |
// also the code is much simpler. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment