Modifying and compiling synthdefs

#1

I’m starting a new topic to carry on the tangent I started in another topic over here.

For background, I noticed that the piano synth, which in Sonic Pi only supports whole midi notes, actually has a tune parameter that looks like it should allow setting fractional notes (here in the Supercollider source).

So, I wanted to try compiling a synthdef that connected up the tune input and see if I could get it working. However, I have no experience with Supercollider/Overtone/synthdefs etc., so there’s a bit of a learning curve.

After a bit of trial and error I managed to get the existing piano synthdef recompiled (I created a new Clojure Leiningen project with a dependency on overtone, and eval’d this line in a repl after pulling in overtone.live, which wrote a new sonic-pi-piano.scsyndef file).

My initial try at deriving the tune parameter from the fractional part of the note input caused it to fail to compile, with:

CompilerException java.lang.ClassCastException:
overtone.sc.machinery.ugen.sc_ugen.ControlProxy cannot be cast to java.lang.Character,
compiling:(sonic_pi/synths/traditional.clj:19:1)

I’m not sure exactly what that means, bit I think it means I can’t just use standard Clojure functions in the synthdef; is that the case?

In any case, to verify that the tune parameter actual does what I suspect/hope, I decided for now to just add a parameter to the synthdef and wire it directly to the same parameter in the Supercollider synth. After recompiling the synthdef I copied the resulting file over the one in my downloaded Sonic Pi app, but changing the tune parameter didn’t seem to do anything to the sound. I also tried modifying synthinfo.rb to add the parameter but that didn’t help. The changes I made are here, and the code I tried in Sonic Pi is:

[-1, 0, 0.5, 1, 2].each do |t|
  synth :piano, note: :c4, tune: t
  sleep 0.2
end

I’m not sure that the parameter I’m setting in Sonic Pi is actually making it into the synth. Do I have to do anything else to make Sonic Pi aware of the new synth param?
Can I just patch my changes into a downloaded Sonic Pi release as I did, or do I need to compile it myself with the changes? I’ve spent a bit of time trying to get the build working, but have been unsuccessful so far.

Any help/pointers would be appreciated.

Thanks,
Emlyn

1 Like

Algorithic music on alternative tuning
#2

My first bit of advice would be to avoid Overtone altogether and just focus on SuperCollider code for defining synthdefs. We’ll be moving over to SuperCollider going forward as it’s way easier to set up and has a lot more community support.

2 Likes

#3

What Sam said. I’m in the process of designing several new synths and FX myself, and the idea is that from now on they will all be designed using SuperCollider’s language directly. I’m happy to do what I can if you’d like any assistance in that direction.

3 Likes

#4

Overtone seemed less daunting as I’m already familiar with Clojure, but I’ve had a bit of a look into SuperCollider and managed to get a basic synthdef working, with most of the parameters hardcoded for now, but with the tune parameter set from the fractional part of the note. I’ve loaded it into Sonic Pi with load_synthdefs, and it can play fractional tuning!

My synthdef so far looks like:

(
SynthDef(\testPiano, {|
	note = 52, decay = 0, release = 1,
	velcurve = 0.8, stereo_width = 0,
	out_bus = 0 |

	var n = round(note, 1);
	var tune = note - n + 0.5;
	var snd = MdaPiano.ar(freq: n.midicps, tune: tune, gate: 1, vel: 64,
		decay: decay, release: release, hard: 0.5, velhard: 0.8,
		muffle: 0.8, velmuff: 0.8, velcurve: velcurve, stereo: stereo_width,
		random: 0, stretch: 0, sustain: 0.1);
	Out.ar(out_bus, snd)}
).writeDefFile("/output/path/")
)

I still need to implement the rest of the functionality from the built-in piano synth, but it’s looking promising :smiley:. I don’t suppose you’ve got an example I could use as a reference for how things like the varlag, clipping/scaling, envelope etc. would be done in SuperCollider?

Thanks a lot for your help!
Emlyn

1 Like

#5

OK, i think I’ve got it working! There was quite a bit of trial and error involved, so it might not be 100% correct and/or might not follow best practise, but it seems to work alright in my limited testing.
@ethancrawford / @samaaron does this look reasonable:

(
SynthDef(\testPiano, {|
	note = 52, amp = 1, amp_slide = 0, amp_slide_shape = 1, amp_slide_curve = 0,
	pan = 0, pan_slide = 0, pan_slide_shape = 1, pan_slide_curve = 0,
	attack = 0, decay = 0, sustain = 0, release = 1,
	attack_level = 1, decay_level = -1, sustain_level = 1, env_curve = 1,
	vel = 0.2, hard = 0.5, velcurve = 0.8, stereo_width = 0,
	out_bus = 0 |

	var note_ = round(note, 1);
	var tune = note - note_ + 0.5;
	var amp_ = amp.varlag(amp_slide, amp_slide_curve, amp_slide_shape);
	var pan_ = amp.varlag(pan_slide, pan_slide_curve, pan_slide_shape);
	var decay_level_ = Select.kr(decay_level = -1, [decay_level, sustain_level]);
	var vel_ = vel.clip(0, 1).linlin(0, 1, 0, 4 * 127);
	var hard_ = hard.clip(0, 1).linlin(0, 1, -3, 3);
	var snd = MdaPiano.ar(freq: note_.midicps, tune: tune, gate: 1, vel: vel_,
		decay: decay, release: release, hard: hard_, velhard: 0.8,
		muffle: 0.8, velmuff: 0.8, velcurve: velcurve, stereo: stereo_width,
		random: 0, stretch: 0, sustain: 0.1);
	var snd_ = Balance2.ar(snd[0], snd[1], pan, amp);
	var env = EnvGen.kr(Env.new([0, attack_level, decay_level_, sustain_level, 0],
		                        [attack, decay, sustain, release],
		                        env_curve), doneAction: 2);
	Out.ar(out_bus, env * snd_)}
).writeDefFile("/Users/emcorrin/dev/personal/synthdefs/compiled/")
)

If it looks OK, I’ll open a PR on Sonic Pi to replace the existing :piano synth with this. In which directory should I put it, etc/synthdefs/designs? Do I need to generate an updated dot file somehow, or is that not possible with SuperCollider synthdefs?

0 Likes

#6

Apologies for the delay - looks good so far! Have added a few comments on your PR. Also, maybe I just don’t remember, but I’ve been using the Varlag.kr() command instead of .varlag() - so I learnt something new today haha :+1:

1 Like