You can create a group for each synth (\kick, \snare, etc) and choke all voices with e.g. ~group.set(\gate, 0).

You might consider avoiding some of the complexity here by simply running a fixed number of voices for each Synth at all times - run them all at once, and just trigger them. This is generally how software instruments (non-SuperCollider) handle voices. Then switching to a new voice (vs. retriggering) would involve sending e.g. a [\gate, -1] to the current voice, incrementing your voice by 1 % numVoices, and sending a new [\trig, 1, \gate, 1] to the next one.

1 Like

I started working on a drum synth voice, too, a while back.

I found the best way was to simply only have the one synth per voice, and retrigger its envelopes, rather than creating multiple voices.

This approach obviates the need to check for existing voices, and potentially makes it easier to restart the envelope in different ways.

I have’t read the whole thread, so apologies if this has been mentioned already.

1 Like

IIRC this is only for envelopes that can sustain - that is, envelopes with a releaseNode defined. Env.perc works fine because it doesn’t have a releaseNode. Env.adsr does not tend to work well for re-triggering, though it’s easy enough to just build an envelope that wil - the “extra initial node” trick is good one.

1 Like

I agree. The complexity involved in forcing monophonic behavior out of polyphonic synths is a bit much for my lazy tastes.

Oh, you may be right. I remember trying to solve almost the same problem and my envelope was utterly busted until I added the “dummy” node. I’ll go check my synth code to confirm. It’s foolish of me to type SC advice on my phone :slight_smile:

Careful! This does not work (or, works very very badly…) for kicks. Kicks are usually implemented with, at least in part, a low frequency SinOsc or similar. The phase of the oscillator is not reset if you use a continuously running voice, so triggering it will start at a random place in the oscillators cycle, which can result in very different attacks. Sadly, there are not so many osc’s in SC whose phase can be reset, which makes this use case sorta difficult :frowning:

It’s also a good approach because the number of voices can quickly become out of control with fast triggers and longer release/decay times.

And, it’s pretty rare (outside of prog rock :slight_smile: ) that a drummer has 16 kicks that they play in perfect round-robin style to preserve the separate decay of each one… Monophonic percussion is what our ears are used to, in general.

2 Likes

Ah, I wasn’t aware of that gotcha. I wonder if a set of phase-resettable basic waveform custom UGens would be useful.

2 Likes

Interesting! I actually like the sound of the phase being different between notes so I seem to ignore this. Are there Osc UGens that let you reset the phase? For example, you could use the .sin of a phasor.

Synth kicks often have an initial impulse sound that may mask the phase variation of the “body” sound.

1 Like

I don’t think there are any that take a trigger to reset the phase. For SinOsc, you can set the freq to zero and drive it with a Phasor in the phase argument - this is much faster than .sin, at least. A bunch of the core oscs don’t have a phase argument you can adjust, which is too bad. This would be the better thing to implement than a resetable phase, I think.

1 Like

You’re kinda just shifting the problem though. You still need to reset the phase of the phasor…

It does look like I had to use the dummy node, even without a release. Here’s a snippet of the Synth I mentioned, where I’m using the Env as a sample index lookup for a BufRd (the comment was already there!):

	// need extra node at beginning
	// because EnvGen ONLY hits first ONCE
	// also MIND YOUR RELEASE node (OR lack thereof)
	var envSpec = Env.new(
		[ 0, 0, buffer.numFrames, 0],
		[ 0, (buffer.numFrames) / buffer.sampleRate / playSpeed, 0 ],
		0);
	var index = EnvGen.ar(envSpec, gate: impulse);

Coincidentally, this successfully uses an envelope as a Phasor here. Thus, along with some trig plumbing and/or looping, this might go at least part way to providing a Phasor with resettable phase.

Hmm - this synth behaves exactly the same for me if I delete the first node and first time value. I wonder if this was a bug in an older version of EnvGen that has since been fixed? There were some VERY subtle issues that have been fixed in the last few years…

(
SynthDef(\env, {
	var envSpec = Env.new([0, 1, 0], [1, 0], 10);
	//var envSpec = Env.new([0, 0, 1, 0], [0, 1, 0], 10);
	Out.ar(
		\out.kr,
		WhiteNoise.ar * envSpec.kr(gate:\trig.tr)
	)
}).add;

Pdef(\env, Pmono(
	\env,
	\dur, 1, \trig, 1,
)).play
)

Weird, it definitely works differently (i.e. not correctly) when I delete those nodes. I just tested it twice. For reference, buffer.numFrames was set to 18196 - maybe it works differently with larger values?

I just tested an older version of SC (3.8) and this was indeed broken back then - so It must’ve been fixed since!

2 Likes

Huh! I’m on 3.11.1 here.

Just thought I’d post this here cause it’s awesome. I finally got VST plug-ins working in SuperCollider thanks to this package extension from IEM’s repo:

Made a short video about how to run a VST plugin in SuperCollider thought it might be useful for folks to see:

14 Likes

OMG. Thanks for posting this! Will try this out later today.

1 Like