Continuous envelopes and free-floating oscillators

I’m new to supercollider and I’m having a blast. I’m a live playing guy, and unsatisfied with the offering of current offering of Analog / VA synths that fit my measly budget. So I want to create my own which can do whatever I want! I’m reading lots of info on VA modelling and non-linearity and hope to build my own VA synth in SC, which I can then miniaturize into a desktop synth to accompany my stage piano. But I’m not in a rush, this will probably take a while. I do have some questions about conventions and best-practices.

Continuous envelopes
On many poly and monosynths envelopes are not continuous and don’t reset on each key. This applies particularly to monosynths. If you’re playing a piece on a mono, the envelope usually continues from the last voltage it was at when newly gated on keypress. For example; The key I press it at the decay stage. When I press a new key and the envelope is in ‘attack’, the attack continues from the value it was in the decay stage instead of starting from 0 (which would result in an audible ‘pop’). Is it possible to give a starting point to an envelope generator where it picks up instead of a simple add?

Free-floating oscillators
What I mean with free-floating oscillators is the following. I have 8 oscillator banks (or more if processing power allows it) of 2 oscillators each for 8 voices of polyphony or 8 voice unison. It would be more realistic to keep these 8 banks in existence, but from tutorials and other posts on these forum I gathered that the convention is to create a new Synthdef each time a key is pressed via Midi and terminate the when the envelopes are done. Is running the banks (and their accompanying VCF’s, envelopes and VCA’s) running continuously possible and implementable, or would I have to jump through a lot of hoops? Keeping them running continuously would help non-linearity and the continuous envelopes, as I could keep track of the envelopes per voice.

Thanks a lot,
Wouter

SC’s envelope generator works the same.

An envelope segment does not consist of a starting value, a target value, a time and a curve. It’s tempting to read it this way, but that’s not a correct inference.

Envelope segments are defined as target value – time – curve. So, where does each envelope segment begin? It begins with the EG’s current output level.

This works great except for the first segment, where there is no current output level yet.

So Env specifies a starting value. The starting value is used once and only once, at the beginning of the synth. When you re-trigger the envelope, this is no longer the beginning of the synth, so the EG does not reset to that starting value. Instead, it moves to the first envelope segment, which is defined as the first target value (second value in the “levels” array) + time + curve.

TL;DR it already does what you want.

Run the oscillators as independent nodes, outputting to audio or control buses.

hjh

1 Like

I don’t have much to say, except that code and SC are both extraordinary black holes…

~xyc =
((
	Env.xyc // [time, level, curve], [time, level, curve]
	
	([
		[0.0, 0.0, \lin] , // zero node with linear interpolation into attack
		[0.1, 1.0, \sin] , // full attack in 0.1 sec. & sinewave interpolated 
		[0.7, 0.0, \exp] , // & released at: 0.7 sec. ( \exp curve unused )
	])
	
	.circle // call on any Env.created to make it a cyclical envelope, see docs...
	
	// and finally, read up on but this will wrap an EnvGen for you with reversed *args
	
	.ar // creates 'audio rate' EnvGen
	
	(
		doneAction: Done.freeSelf // free the synth when done 
		
		// , gate: \gate.ar ( 1 ) // for .release, used within synthdef

	)
))

; s.boot 

;

((
	MIDIClient.init;
	MIDIIn.connectAll;
	// MIDIdef.trace
	~synths = IdentityDictionary [
		
	]
	;
	// trick shot
	MIDIdef.noteOn(\x, { |v n| // velocity # 
		
		~synths.put 
		(
			msgNum // key
			(
				MIDIdef.noteOff
				(
					n, 
					{
						~synths[n].release // zeros gate
					}
					,n
				)
				.oneShot 
			)
			
			, // -> 
			
			Synth 
			(
				\default         // SynthDescLib.global[\default]
				,
				[
					\freq, midicps
					(
						n
					)
				]
			)
		)
	})
))

// MIDIIn.doNoteOnAction(num: 72, veloc: 127)
// MIDIIn.doNoteOffAction(num: 72, veloc: 0)

I believe there is a way to make any segment of the envelope cyclical by specifying the Env’s loopNode, I too, would… love…

2 Likes

Oh awesome and thanks! Coding with control and audio streams still feels a bit odd to me, I’m still adjusting my head to SC’s paradigm. I’ll give it a try!

I have an example of it in this tutorial 21: Inventing ways to play an instrument - Musical Sound Design In Supercollider - YouTube
It might be not easy to get from first watching because the video is part 4.
If so, here is the link to the whole playlist so far
MIDI based music production (Supercollider, jackd, Ardour) - YouTube
The code is in description

3 Likes

Thanks, this is great!

Edit: I didn’t see you’re the actual person that created these tutorials. I’m binging them as we speak, keep up the good work man.

1 Like

They are really good.

1 Like