• jon@schemawound.com
Disquiet Junto
Disquiet Junto 0050: Telegraph Incantation

Disquiet Junto 0050: Telegraph Incantation

This was the assignment for this week:
This week’s project explores invokes Morse Code for its rhythmic content. The instructions are as follows: Select a word or phrase.
Encode that word or phrase by the Morse method. Record a rhythmic foundation in which the dash is represented by a long beat and the
dot by a brief one. Use that rhythmic foundation as a loop for the length of your track, at the speed you desire — speed can vary over
the length of the recording. Record accompanying drone/melodic material that takes the underlying rhythm as its compositional foundation.

I instantly knew that for this composition I wanted to make a supercollider script that would generate a listenable version of the track no matter what phrase was entered. I wrote a text to morse code translator and then used a Prout to encode this rhythmically. All parts of the song work dynamically based off the length of the phrase entered.

To generate your own telegraph incantation change the variable phrase.

/*
Telegraph Incantation [disquiet0050-morsebeat]
By Schemawound

All code by Jonathan Siemasko

Blog post about this track: https://schemawound.com/post/38127291200/telegraph-incantation-disquiet0050-morsebeat

DESCRIPTION:
This week’s project explores invokes Morse Code for its rhythmic content. The instructions are as follows: Select a word or phrase. 
Encode that word or phrase by the Morse method. Record a rhythmic foundation in which the dash is represented by a long beat and the 
dot by a brief one. Use that rhythmic foundation as a loop for the length of your track, at the speed you desire — speed can vary over 
the length of the recording. Record accompanying drone/melodic material that takes the underlying rhythm as its compositional foundation.

More on this 50th Disquiet Junto project at: http://disquiet.com/2012/12/13/disquiet0050-morsebeat/

More details on the Disquiet Junto at: http://soundcloud.com/groups/disquiet-junto/info/
*/

(
fork{
	var phrase = "LYRA";
	var fxSynth, group, bus, mainOut, patBass, patBassLoop, patMorse, patMorseDeci, patMorseDeciLoop, patMorseFast, patKick, patPad, patKickAndPad, patMainLoop, patFullSong;
	var morse;  //Holds the main object used by the song
	var songClock = TempoClock(11);
	var createMorse = {|inString, spaceBetweenLetters = 3, spaceBetweenWords = 7|
		/* Function to take a string and convert it an event that can create morse code duration streams. Handles a-z, A-Z and 0-9.
		   Parameters allow you to adjust the space between letters and words. These parameters default to international morse code as shown on http://en.wikipedia.org/wiki/Morse_code
		   NOTE: outEvent.wordSpace must be equal to or greater than outEvent.letterSpace. */

		var charToMorse;
		var outEvent = (message: inString, code: "", letterSpace: "", wordSpace: "");

		//Fill letterSpace and wordspace per number specified in input args.
		//outEvent.wordSpace reduced by the size of outEvent.letterSpace to account for that will occur before it.
		(spaceBetweenLetters - 1).do{outEvent.letterSpace = outEvent.letterSpace ++ " "};
		(spaceBetweenWords - spaceBetweenLetters).do{outEvent.wordSpace = outEvent.wordSpace ++ " "};

		//Function to convert a single character to morse code
		charToMorse = {|inChar|
			switch(inChar,
				$A, {".-"},		$B, {"-..."},	$C, {"-.-."},	$D, {"-.."},	$E, {"."},	    $F, {"..-."},  $G, {"--."},    $H, {"...."},
				$I, {".."},		$J, {".---"},	$K, {"-.-"},	$L, {".-.."},   $M, {"--"},		$N, {"-."},	   $O, {"---"},	   $P, {".--."},
				$Q, {"--.-"},	$R, {".-."},    $S, {"..."},	$T, {"-"},		$U, {"..-"},	$V, {"...-"},  $W, {".--"},    $X, {"-..-"},
				$Y, {"-.--"},	$Z, {"--.."},   $1, {".----"},	$2, {"..---"},	$3, {"...--"},	$4, {"....-"}, $5, {"....."},  $6, {"-...."},
				$7, {"--..."},	$8, {"---.."},	$9, {"----."},	$0, {"-----"},  $ , {outEvent.wordSpace}
			);
		};

		//Take the input string, convert to uppercase and convert one letter at a time.  Add outEvent.letterSpace between letters
		inString.toUpper.do{|char, i|
			var isFinalChar = (i != (inString.size - 1));
			var isWordSpace = (char != $ );
			outEvent.code = outEvent.code ++ charToMorse.(char);
			//Include outEvent.letterSpace after each character except outEvent.wordSpaces and the final letter.
			if(isFinalChar && isWordSpace, {outEvent.code = outEvent.code + outEvent.letterSpace});
		};

		//Create a Prout that duration streams can be generated from
		outEvent.prout = Prout{|in|
			inf.do{|i|
				var char = outEvent.code.wrapAt(i);
				switch(char,
					$., {in = 1.embedInStream(in)},
					$-, {in = 3.embedInStream(in)},
					$ , {in = Rest(1).embedInStream(in)}
				);
			};
		};

		//Function to create a new duration stream
		outEvent.durStream = {outEvent.prout.asStream;};

		//Count number of events in the stream
		outEvent.numEvents = outEvent.code.size;

		//Calculate the number of beats in the stream
		outEvent.numBeats = 0;
		outEvent.code.do{|val,i|
			var char = outEvent.code[i];
				switch(char,
					$., {outEvent.numBeats = outEvent.numBeats + 1},
					$-, {outEvent.numBeats = outEvent.numBeats + 3},
					$ , {outEvent.numBeats = outEvent.numBeats + 1}
				);
			};


		//Return event
		outEvent;
	};

	//--------------------SynthDef--------------------
	SynthDef(\morseTone, {|out = 0, freq = 400, gate = 1, pan = 0, wobbleDepth = 10, wobbleRate = 3, amp = 1, attack = 0.03, decay = 0.03, release = 0.03|
		var env = EnvGen.ar(Env.adsr(attack, decay, 1, release), gate, doneAction: 2);
		var wobble = SinOsc.ar(wobbleRate).range(0, wobbleDepth);
		var osc = SinOsc.ar(freq) * SinOsc.ar(freq + 1 + wobble);
		var output = Pan2.ar(osc * env, pan, amp);
		Out.ar(out, output);
	}).add;

	SynthDef(\AEKick, {|
		out = 0, amp = 1,
		attack = 0.01, decay = 0.7, curve = 3,
		pEnvMul = 20, pEnvAdd = 40, pEnvAtk = 0.01, pEnvDecay = 0.25, pEnvCurve = -4
		fmAmp = 1, fmpEnvMul = 100, fmpEnvAdd = 10, fmpEnvAtk = 0.001, fmpEnvDecay = 0.10, fmpEnvCurve = -2
		|
		var ampEvn = EnvGen.ar(Env.perc(attack, decay, amp, curve), doneAction: 2);
		var pitchEnv = EnvGen.kr(Env.perc(pEnvAtk, pEnvDecay, pEnvMul, pEnvCurve)) + pEnvAdd;
		var fmpitchEnv = EnvGen.kr(Env.perc(fmpEnvAtk, fmpEnvDecay, fmpEnvMul, fmpEnvCurve)) + fmpEnvAdd;
		var fmMod = SinOsc.ar(fmpitchEnv) * fmAmp;
		var sin = SinOsc.ar(pitchEnv) * fmMod;
		sin = sin + (LFNoise0.ar(10000) * EnvGen.ar(Env.perc(0.01, 0.02, 0.001, 0)));
		Out.ar(out, sin * ampEvn!2);
	}).add;

	SynthDef(\slowPad, {
		|
		    out = 0, gate = 1, freq = 400, amp = 0.1,
		    sawLfoAmount = 0.1, sawLfoLFreq = 0.1, sawLfoRFreq = 0.25, sawAmp = 0.5,
		    squareLfoDepth = 0.4, squareLfoFreq = 0.034, squareDetune = -0.3, squareAmp = 0.5,
		    combFreqMult = 0.0003, combDecay = 0.5,
		    filterMult = 4, filterAttack = 7, filterDecay = 5, filterSustain = 0.5, filterRelease = 3, filterRQ = 1, filterAmp = 0.5,
		    ampAttack = 2, ampDecay = 4, ampSustain = 0.5, ampRelease = 0.8
		|
	    //Saws
	    var sawLfo = SinOsc.kr([sawLfoLFreq, sawLfoRFreq]).range(sawLfoAmount * -1, sawLfoAmount);
	    var saws = (Saw.ar(freq) + Saw.ar((freq.cpsmidi + sawLfo).midicps)) * sawAmp;
	    //Square
		var defaultSquarePW = 0.5;
	    var squareLfo = SinOsc.kr(squareLfoFreq).range(defaultSquarePW - squareLfoDepth, defaultSquarePW + squareLfoDepth);
	    var square = PulseDPW.ar(freq + squareDetune, squareLfo) * squareAmp;
	    //Comb
		var combMaxDecay = 1;
		var comb = CombC.ar(saws + square, combMaxDecay, combFreqMult * freq, combDecay) + (saws + square);
		var comb2 = CombC.ar(comb, combMaxDecay, (combFreqMult / 3) * freq, combDecay / 2) + comb;
		//Filter
		var filterEnv = EnvGen.kr(Env.adsr(filterAttack, filterDecay, filterSustain, filterRelease), gate) * filterMult;
		var filter = BLowPass.ar(comb2, freq * filterEnv, filterRQ) * filterAmp;
		//Out
		var ampEnv = EnvGen.kr(Env.adsr(ampAttack, ampDecay, ampSustain, ampRelease), gate, doneAction:2) * amp;
		Out.ar(out, filter * ampEnv);
    }).add;

	SynthDef(\slowFX, {|out = 0, in, amp = 0.1|
		var inSig = In.ar(in, 2);
		inSig = GVerb.ar(inSig);
		inSig = Compander.ar(inSig, inSig, 0.5, 1, 1/16);
		inSig = HPF.ar(inSig, 100) * SinOsc.ar(80);
		Out.ar(out, inSig * amp);
	}).add;

	SynthDef(\verb, {|out = 0, in, amp = 0.3, roomsize = 10, revtime = 3|
		var inSig = In.ar(in, 2);
		inSig = inSig + (GVerb.ar(inSig, roomsize, revtime) * 0.3);
		inSig = Compander.ar(inSig, inSig, 0.5, 1, 1/16);
		Out.ar(out, inSig * amp);
	}).add;

	SynthDef(\deciVerb, {|out = 0, in, amp = 0.2|
		var inSig = In.ar(in, 2);
		inSig = Decimator.ar(inSig, 5e3, 16);
		inSig = Compander.ar(inSig, inSig, 0.5, 1, 1/16);
		Out.ar(out, inSig * amp);
	}).add;

	//--------------------Sync--------------------
	s.sync;

	//--------------------Create Morse--------------------
	morse = createMorse.(phrase);

	//-----Groups and Busses-----
	group = ();
	group.synths = Group.new;
    group.fx = Group.after(group.synths);
    mainOut = 0;
	bus = ();
	bus.modVerb = Bus.audio(s, 2);
	bus.smallVerb = Bus.audio(s, 2);
	bus.verb = Bus.audio(s, 2);
	bus.deciVerb = Bus.audio(s, 2);

	//--------------------Cleanup--------------------
	CmdPeriod.doOnce{
		bus.modVerb.free;
		bus.verb.free;
		bus.deciVerb.free;
		bus.smallVerb.free;
	};

	//--------------------FX Synths--------------------
	fxSynth = ();
	fxSynth.deciVerb = Synth(\deciVerb, [\in, bus.deciVerb, \out, mainOut], target: group.fx);
	fxSynth.modVerb = Synth(\slowFX, [\in, bus.modVerb, \out, mainOut], target: group.fx);
	fxSynth.smallVerb = Synth(\verb, [\in, bus.smallVerb, \out, mainOut, \roomsize, 10, \revtime, 1.5], target: group.fx);
	fxSynth.verb = Synth(\verb, [\in, bus.verb, \out, mainOut], target: group.fx);

	//--------------------Pattern--------------------
	patBass = Pbind(*[instrument: \morseTone, freq: 60, wobbleDepth: 0, dur: morse.durStream * 0.25, amp: 0.3, pan: Pseq((1!morse.numEvents).add(-1!morse.numEvents).flatten, 4), out: bus.deciVerb ]);
	patMorse = Pbind(*[instrument: \morseTone, wobbleDepth: Pwhite(3.0, 10.0), dur: morse.durStream, amp: 0.3, pan: Pseq((1!morse.numEvents).add(-1!morse.numEvents).flatten, 2), out: bus.smallVerb ]);
	patMorseFast = Pbind(*[instrument: \morseTone, freq: 600, wobbleDepth: Pwhite(3.0, 10.0), dur: morse.durStream * 0.5, amp: 0.2, pan: Pseq((1!morse.numEvents).add(-1!morse.numEvents).flatten, 4), out: bus.smallVerb]);
	patMorseDeci = Pbind(*[instrument: \morseTone, wobbleDepth: Pwhite(3.0, 10.0), dur: morse.durStream, amp: 0.2, pan: Pseq((1!morse.numEvents).add(-1!morse.numEvents).flatten, 2), out: bus.deciVerb ]);
	patKick = Pbind(*[instrument: \AEKick, dur: Pseq((morse.numBeats/2!2).add(Rest(morse.numBeats/2)!2).flatten, 4), amp: 0.2, decay: 0.3, out: bus.verb]);
	patPad = Pbind(*[instrument: \slowPad, dur: Pn(morse.numBeats * 4, 2), amp: 0.7, out: bus.modVerb]);
	patKickAndPad = Ppar([patKick, patPad]);
	patMainLoop = Ptpar([
		000.0, patMorse,
		000.0, patKick,
		000.0, patPad,
		morse.numBeats * 4, patMorse,
		morse.numBeats * 4, patMorseFast
	]);
	patBassLoop = Ptpar([
		000.0, patBass,
		morse.numBeats * 4, patBass
	]);
	patMorseDeciLoop = Ptpar([
		000.0, patMorseDeci,
		morse.numBeats * 4, patMorseDeci
	]);
	patFullSong = Ptpar([
		000.0, patKickAndPad,
		morse.numBeats * 8, patMainLoop,
		morse.numBeats * 16, patMainLoop, morse.numBeats * 16, patBassLoop,
		morse.numBeats * 24, patMainLoop, morse.numBeats * 24, patBassLoop, morse.numBeats * 24, patMorseDeciLoop,
		morse.numBeats * 32, patPad, morse.numBeats * 32, patMorseDeciLoop
	]);

	//--------------------Output--------------------
	'-----MORSE-----'.postln; morse.dopostln;
	'-----GROUPS-----'.postln; group.dopostln;
	'-----BUSSES-----'.postln; bus.dopostln;
	'-----FX SYNTHS-----'.postln; fxSynth.dopostln;

	//--------------------Play--------------------
	patFullSong.play(songClock)
}
)
Tags :