Skip to content

Instantly share code, notes, and snippets.

@madskjeldgaard
Last active July 1, 2024 11:38
Show Gist options
  • Save madskjeldgaard/67d286651b574565dedb8bd50b4c25f6 to your computer and use it in GitHub Desktop.
Save madskjeldgaard/67d286651b574565dedb8bd50b4c25f6 to your computer and use it in GitHub Desktop.
A safer version of Alejandro Olartes benjolin
/*
Instrument inspired from Rob Hordijk's Benjolin, it requires sc3-plugins (PulseDPW, SVF and DFM1)
outSignal:
1-triangle osc1,
2-square osc1,
3-triangle osc2,
4-pulse osc2,
5-XOR output,
6-Filter output
Original by Alejandro Olarte (see https://scsynth.org/t/benjolin-inspired-instrument/1074/4)
Modified by Mads Kjeldgaard
*/
(
Ndef(\benjolis,{ |freq1= 40, freq2=4, scale=1, rungler1=0.16, rungler2=0.0, runglerFilt=9, loop=0, filtFreq=40, q=0.82, gain=1, filterType=0, outSignal=6, amp=1|
var osc1, osc2, tri1, tri2, sh0, sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8=1, rungler, pwm, filt, output;
var sr;
var osc2freq, buf, bufR;
bufR = LocalIn.ar(2,0);
rungler = bufR.at(0);
buf = bufR.at(1);
sr = SampleDur.ir;
//sr = ControlDur.ir;
tri1 = LFTri.ar((rungler*rungler1)+freq1);
tri2 = LFTri.ar((rungler*rungler2)+freq2);
osc1 = PulseDPW.ar((rungler*rungler1)+freq1);
osc2 = PulseDPW.ar((rungler*rungler2)+freq2);
//pwm = tri1 > tri2;
pwm = BinaryOpUGen('>', (tri1 + tri2),(0));
osc1 = ((buf*loop)+(osc1* (loop* -1 +1)));
sh0 = BinaryOpUGen('>', osc1, 0.5);
sh0 = BinaryOpUGen('==', (sh8 > sh0), (sh8 < sh0));
sh0 = (sh0 * -1) + 1;
sh1 = DelayN.ar(Latch.ar(sh0,osc2),0.01,sr);
sh2 = DelayN.ar(Latch.ar(sh1,osc2),0.01,sr*2);
sh3 = DelayN.ar(Latch.ar(sh2,osc2),0.01,sr*3);
sh4 = DelayN.ar(Latch.ar(sh3,osc2),0.01,sr*4);
sh5 = DelayN.ar(Latch.ar(sh4,osc2),0.01,sr*5);
sh6 = DelayN.ar(Latch.ar(sh5,osc2),0.01,sr*6);
sh7 = DelayN.ar(Latch.ar(sh6,osc2),0.01,sr*7);
sh8 = DelayN.ar(Latch.ar(sh7,osc2),0.01,sr*8);
//rungler = ((sh6/8)+(sh7/4)+(sh8/2)); //original circuit
//rungler = ((sh5/16)+(sh6/8)+(sh7/4)+(sh8/2));
rungler = ((sh1/2.pow(8))+(sh2/2.pow(7))+(sh3/2.pow(6))+(sh4/2.pow(5))+(sh5/2.pow(4))+(sh6/2.pow(3))+(sh7/2.pow(2))+(sh8/2.pow(1)));
buf = rungler;
rungler = (rungler * scale.linlin(0,1,0,127));
rungler = rungler.midicps;
LocalOut.ar([rungler,buf]);
filt = Select.ar(filterType, [
RLPF.ar(pwm,(rungler*runglerFilt)+filtFreq,q* -1 +1,gain),
//BMoog.ar(pwm,(rungler*runglerFilt)+filtFreq,q,0,gain),
RHPF.ar(pwm,(rungler*runglerFilt)+filtFreq,q* -1 +1,gain),
SVF.ar(pwm,(rungler*runglerFilt)+filtFreq,q,1,0,0,0,0,gain),
DFM1.ar(pwm,(rungler*runglerFilt)+filtFreq,q,gain,1)
]);
output = Select.ar(outSignal, [
tri1, osc1, tri2, osc2, pwm, sh0, filt
]);
output = LeakDC.ar(output, 0.99).tanh;
output * amp ! 2
}
).play;
// add ranges for controlling with a GUI
Spec.add(\freq1, ControlSpec( 20.0, 14000.0, \exp, 0, 70, "Hz") );
Spec.add(\freq2, ControlSpec( 0.1, 14000.0, \exp, 0, 4, "Hz") );
Spec.add(\filtFreq, ControlSpec( 20.0, 20000.0, \exp, 0, 40, "Hz") );
Spec.add(\q, ControlSpec( 0.0, 1.0, \lin, 0, 0.82) );
Spec.add(\gain, ControlSpec( 0.0, 3.0, \lin, 0, 1) );
Spec.add(\filterType, ControlSpec( 0.0, 3.0, \lin, 1, 0) );
Spec.add(\rungler1, ControlSpec( 0.0, 1.0, \lin, 0, 0.16) );
Spec.add(\rungler2, ControlSpec( 0.0, 1.0, \lin, 0, 0) );
Spec.add(\runglerFilt, ControlSpec( 0.0, 1.0, \lin, 0, 9) );
Spec.add(\loop, ControlSpec( 0.0, 1.0, \lin, 0, 1) );
Spec.add(\scale, ControlSpec( 0.0, 1.0, \lin, 0, 1) );
Spec.add(\outSignal, ControlSpec( 0.0, 6.0, \lin, 1, 6) );
);
// Control it using gui
Ndef(\benjolis).gui;
Ndef(\benjolis).pause;
Ndef(\benjolis).resume;
Ndef(\benjolis).play;
Ndef(\benjolis).clear;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment