Skip to content

Instantly share code, notes, and snippets.

@telephon
Last active November 7, 2017 07:18
Show Gist options
  • Save telephon/49f0634cb6b7aa31f9942eb17d6633fd to your computer and use it in GitHub Desktop.
Save telephon/49f0634cb6b7aa31f9942eb17d6633fd to your computer and use it in GitHub Desktop.
completely flopping dictionaries might be more efficient after all
(
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