Example 5

From CSWiki
Jump to: navigation, search

This melodic pattern is taken from the Streams-Patterns-Events-3 help file in SuperCollider. It's a melodic pattern in 3 parts: a bass run, a middle 4-note figure, and an ending melody of 3-9 notes - each iteration through the melody is slightly different thanks to randomness.

The SC3 code is modified from the original example: the reverb effect has been pulled out of the main sounding SynthDef and given its own SynthDef to make the CPU load lighter, and to illustrate signal path in SC. Other values have been tweaked slightly, as well. I've put all the melodic decision-making inside a Pbind rather than generate a stream and step through it in a Task, since this is more akin to what SC3 code would probably look like. Pbind is part of SC3's extensive "patterns library," about which more can be learned from SC3's "Streams-Patterns-Events" docs & associated help files.

Filters in SC3 and ChucK differ from each other in their behaviour - in this case, the SC3 Resonant Low-Pass Filter (RLPF) is okay with random filter settings at frequencies between midinotes 36 and 110, but ChucK's LPF seems to prefer the range 48-110 - 36 is sometimes too low, and cuts notes out of the texture.

the SuperCollider code

( // run these first
SynthDef("spaceySynth", { arg freq, out;
	var x, env;
	x = RLPF.ar(
		LFSaw.ar( freq, mul: EnvGen.kr( Env.perc, levelScale: 0.3, doneAction: 2 ) ),
		LFNoise1.kr(2, 36, 110).midicps,
		0.2
	);
	Out.ar(out, x);
}).store;

SynthDef("reverb", {arg in;
	var x;
	x = In.ar(in);
	6.do({ x = AllpassN.ar(x, 0.05, [0.05.rand, 0.05.rand], 4) });
	Out.ar(0, x);
}).store;
)

(
var bus, groups;
bus = Bus.audio(s,1);
groups = Array.fill(2, {Group.new(s,\addToTail)});
Synth("reverb", [\in, bus.index], groups[1]); 

Pbind(
	\instrument, "spaceySynth",
	\freq, Pseq( // Pseq = sequenced pattern
		[
			// bass run, happens half the time
			Prand([nil, Pseq(#[24, 31, 36, 43, 48, 55])]),

 			// middle bit - happens 2 to 5 times
			Pseq([60, Prand(#[63, 65]), 67, Prand(#[70, 72, 74]) ], {rrand(2, 5)}),

			// ending melody of 3 to 9 notes
			Prand(#[74, 75, 77, 79, 81], {rrand(3, 9)})
		].midicps,
	inf),
	\dur, 0.13,
	\group, groups[0].nodeID,
	\out, bus.index
).play;
)

the ChucK version

SawOsc saw => LPF filter => ADSR env => Gain mix => NRev reverb;
env => dac;
0.4 => mix.gain;
reverb => dac;
env.set(10::ms, 18::ms, 0.5, 1::ms);
0.4 => env.gain; 
5 => filter.Q;
130::ms => dur pulse;

while (true)
{
	// bass run, happens half the time
	if (Std.rand2(0,100) < 50)
	{
		[24,31,36,43,48,55] @=> int fifths[];
		for( 0 => int i; i < fifths.cap(); i++)
		{
			Std.mtof(fifths[i]) => saw.freq;
			Std.mtof(Std.rand2(48,110)) => filter.freq;

			env.keyOn();
			1::pulse => now;
			env.keyOff();
		}
	}; // end bass run
	
	// middle diddly melodic bit, happens 2 to 5 times
	Std.rand2(2,5) => int midRand;
	for (midRand => int i; i > 0; i--)
	{
		int repeatingBit[4]; // 4 notes in the middle bit
		60 => repeatingBit[0]; // first one is always 60
		
		// next one could be 63 or 65 
		if (Std.rand2(0,100) < 50) 
		{
			63 => repeatingBit[1];
		}
		else
		{
			65 => repeatingBit[1];
		};
		
		67 => repeatingBit[2]; // third one's always 67
		
		// last one could be 70, 72, or 74
		if (Std.rand2(0,100) < 33)
		{
			70 => repeatingBit[3];
		}
		else
		{
			if (Std.rand2(0,100) < 50)
			{
				72 => repeatingBit[3];
			}
			else
			{
				74 => repeatingBit[3];
			}
		};
		for (0 => int i; i < repeatingBit.cap(); i++)
		{
			Std.mtof(repeatingBit[i]) => saw.freq;
			Std.mtof(Std.rand2(48,110)) => filter.freq;
			env.keyOn();
			1::pulse => now;
			env.keyOff();
		};
	}; // end middle bit  

	// ending melody of 3 to 9 notes
	Std.rand2(3,9) => int endRand; 
	for (0 => int i; i < endRand; i++)
	{
		[74,75,77,79,81] @=> int endNotes[];
		Std.rand2(0,4) => int index;
		Std.mtof(endNotes[index]) => saw.freq;
		Std.mtof(Std.rand2(48,110)) => filter.freq;
		env.keyOn();
		1::pulse => now;
		env.keyOff();
	}; // end ending bit
};