Skip to content

Instantly share code, notes, and snippets.

@markwheeler
Last active January 2, 2021 19:23
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markwheeler/b88b4f7b0f2870567b55cbc36abbd5ea to your computer and use it in GitHub Desktop.
Save markwheeler/b88b4f7b0f2870567b55cbc36abbd5ea to your computer and use it in GitHub Desktop.
Poly synth SC engine template
// CroneEngine_PolyTemplate
//
// v1.0.0 Mark Eats
Engine_PolyTemplate : CroneEngine {
classvar maxNumVoices = 3;
var voiceGroup;
var voiceList;
var pitchBendRatio = 1;
var channelPressure = 0;
var channelTimbre = 0;
*new { arg context, doneCallback;
^super.new(context, doneCallback);
}
alloc {
voiceGroup = Group.new(context.xg);
voiceList = List.new();
// Synth voice
SynthDef(\simpleSine, {
arg out, freq = 440, pitchBendRatio = 1, gate = 0, killGate = 1, amp = 1;
var signal, envelope, killEnvelope;
killGate = killGate + Impulse.kr(0); // Make sure doneAction fires
envelope = EnvGen.ar(envelope: Env.adsr( 0.01, 0.3, 0.3, 3.0), gate: gate, doneAction: Done.freeSelf);
killEnvelope = EnvGen.ar(envelope: Env.asr( 0, 1, 0.01), gate: killGate, doneAction: Done.freeSelf);
signal = SinOsc.ar(freq: freq * pitchBendRatio) * envelope * killEnvelope;
Out.ar(out, signal.dup * 0.3 * amp);
}).add;
// Commands
// noteOn(id, freq, vel)
this.addCommand(\noteOn, "iff", { arg msg;
var id = msg[1], freq = msg[2], vel = msg[3];
var voiceToRemove, newVoice;
// Remove voice if ID matches or there are too many
voiceToRemove = voiceList.detect{arg item; item.id == id};
if(voiceToRemove.isNil && (voiceList.size >= maxNumVoices), {
voiceToRemove = voiceList.detect{arg v; v.gate == 0};
if(voiceToRemove.isNil, {
voiceToRemove = voiceList.last;
});
});
if(voiceToRemove.notNil, {
voiceToRemove.theSynth.set(\killGate, 0);
voiceList.remove(voiceToRemove);
});
// Add new voice
newVoice = (id: id, theSynth: Synth.new(defName: \simpleSine, args: [
\out, context.out_b,
\freq, freq,
\pitchBendRatio, pitchBendRatio,
\gate, 1,
\amp, vel.linlin(0, 1, 0.5, 1)
], target: voiceGroup).onFree({ voiceList.remove(newVoice); }), gate: 1);
voiceList.addFirst(newVoice);
});
// noteOff(id)
this.addCommand(\noteOff, "i", { arg msg;
var voice = voiceList.detect{arg v; v.id == msg[1]};
if(voice.notNil, {
voice.theSynth.set(\gate, 0);
voice.gate = 0;
});
});
// noteOffAll()
this.addCommand(\noteOffAll, "", { arg msg;
voiceGroup.set(\gate, 0);
voiceList.do({ arg v; v.gate = 0; });
});
// noteKill(id)
this.addCommand(\noteKill, "i", { arg msg;
var voice = voiceList.detect{arg v; v.id == msg[1]};
if(voice.notNil, {
voice.theSynth.set(\killGate, 0);
voiceList.remove(voice);
});
});
// noteKillAll()
this.addCommand(\noteKillAll, "", { arg msg;
voiceGroup.set(\killGate, 0);
voiceList.clear;
});
// pitchBend(id, ratio)
this.addCommand(\pitchBend, "if", { arg msg;
var voice = voiceList.detect{arg v; v.id == msg[1]};
if(voice.notNil, {
voice.theSynth.set(\pitchBendRatio, msg[2]);
});
});
// pitchBendAll(ratio)
this.addCommand(\pitchBendAll, "f", { arg msg;
pitchBendRatio = msg[1];
voiceGroup.set(\pitchBendRatio, pitchBendRatio);
});
// pressure(id, pressure)
this.addCommand(\pressure, "if", { arg msg;
var voice = voiceList.detect{arg v; v.id == msg[1]};
if(voice.notNil, {
// voice.theSynth.set(\pressure, msg[2]);
});
});
// pressureAll(pressure)
this.addCommand(\pressureAll, "f", { arg msg;
channelPressure = msg[1];
// voiceGroup.set(\pressure, channelPressure);
});
// timbre(id, timbre)
this.addCommand(\timbre, "if", { arg msg;
var voice = voiceList.detect{arg v; v.id == msg[1]};
if(voice.notNil, {
// voice.theSynth.set(\timbre, msg[2]);
});
});
// timbreAll(timbre)
this.addCommand(\timbreAll, "f", { arg msg;
channelTimbre = msg[1];
// voiceGroup.set(\timbre, channelTimbre);
});
}
free {
voiceGroup.free;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment