SCGrains, SuperCollider UI Test

SCGrains

2 Granular synthesizers that use an audio file as source. These two can be crossfaded or bin-wiped with each other to produce nice evolving textures. The basis are two TGrains2 buffer granulator UGens by BhobUGens (included with the sc3-plugins package for SuperCollider). This was made some time ago to test building an user interface in SuperCollider.

Sound example:

Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.

// synth 1: Buffer granulator binwiped with an other buffer granulator, with GUI
(
b = Buffer.alloc(s, 44100);
c = Buffer.alloc(s, 2048, 1);
d = Buffer.alloc(s, 2048, 1);
e = Buffer.alloc(s, 44100);

a = SynthDef(\synthOne, {|out = 0, bufnum = 0, trate = 10, rate1 = 1.0, rate2 = 1.0, amount = 10, centerPos = 0, centerPos2 = 0, binWipe = 0.5, time = 1, ampLow = 0.8, ampHigh = 0.99, gain = 0.5,type = 0, dur = 2.0, dur2 = 2.0, pan = 1.0, fadeType = 0, crossFade, crossFade2, att = 0.1, att2 = 0.1, dec = 0.1, dec2 = 0.1, shapeType = 0, ctrlSpeed = 0, ctrlReach = 0, shapeType2 = 0, ctrlSpeed2 = 0, ctrlReach2 = 0|
	var clk, width, amp, granu, granu2, chainA, chainB, chainout, chain, sig, granuMix, prosOut, chainoutPan, shapeControl, shapeControl2;

	clk = Select.kr(type,
		[Dust.kr(amount), Impulse.kr(amount)]);
	amp = TRand.kr(ampLow, ampHigh, clk);

	shapeControl = Select.kr(shapeType,[
		SinOsc.kr(ctrlSpeed, ctrlReach * 0.5, ctrlReach),
		LFTri.kr(ctrlSpeed, ctrlReach * 0.5, ctrlReach),
		LFSaw.kr(ctrlSpeed, ctrlReach * 0.5, ctrlReach),
		WhiteNoise.kr(ctrlReach * 0.5, ctrlReach)]
	);
	shapeControl2 = Select.kr(shapeType2,[
		SinOsc.kr(ctrlSpeed2, ctrlReach2 * 0.5, ctrlReach2),
		LFTri.kr(ctrlSpeed2, ctrlReach2 * 0.5, ctrlReach2),
		LFSaw.kr(ctrlSpeed2, ctrlReach2 * 0.5, ctrlReach2),
		WhiteNoise.kr(ctrlReach2 * 0.5, ctrlReach)]
	);
	granu = TGrains2.ar(2, clk, b.bufnum, rate1, (centerPos / 44100) + shapeControl, (dur / 44100), WhiteNoise.kr(pan), amp, att, dec, 4);
	granu2 = TGrains2.ar(2, clk, e.bufnum, rate2, (centerPos2 / 44100) + shapeControl2, (dur2 / 44100), WhiteNoise.kr(pan), amp, att2, dec2, 4);
	granuMix = LinXFade2.ar(granu, granu2, crossFade);

		chainA = FFT(c.bufnum, granu);
		chainB = FFT(d.bufnum, granu2);
		chain = PV_RandWipe(chainA, chainB, binWipe, clk);
		chainout = IFFT(chain);
		chainoutPan =  Pan2.ar(chainout, WhiteNoise.kr(pan));
		prosOut = LinXFade2.ar(chainoutPan, granuMix, crossFade2);

	Out.ar(out, gain * prosOut);
}).memStore;
)

// GUI code
(
var w, a, rate1Knob, rate2Knob, centerSlid, center2Slid, grainAmount, attackBox, ampLowSlid, opendialog1, ampHighSlid, panSlid, gainSlid, titel1, trigtext, replaceBufbutton, replaceBufbutton2, typeSlider, fadetypeSlider,  soundView1, soundView2, introtext, fadething, balanceFadeSlid, fadextext, fadeytext, fadeinf, cs, attKnob, decKnob, att2Knob, dec2Knob, ctrlShapeButton, ctrlSpeedKnob, ctrlReachKnob, shapeText, ctrlShape2Button, ctrlSpeed2Knob, ctrlReach2Knob;
	a = Synth(\synthOne);
	w = SCWindow.new("Synth One",Rect(350, 100, 510, 810)).front;
	w.view.decorator = FlowLayout(w.view.bounds);

		w.view.decorator.nextLine;
		typeSlider = EZSlider(w, 140@24, "TrigType", ControlSpec(0, 1, 'lin', 1),
		{|ez| s.sendMsg(\n_set, 1000, \type, ez.value)}, 0);

		trigtext = StaticText(w, Rect(10, 10, 200, 20));
	 	trigtext.string = "0 = Dust, 1 = Impulse";

		w.view.decorator.nextLine;
	 	replaceBufbutton = Button(w, Rect(20, 20, 60, 20));
	 		replaceBufbutton.states = [["Audio 1"]];
	 		replaceBufbutton.action = {|state|
	 			if(state.value == 0, {
	 					CocoaDialog.getPaths({ |paths|
							paths.do({ |file|
							if (b.notNil, {b.free});
							b = Buffer.read(s, file.postln);

							f = SoundFile.new;
	 						f.openRead(b.path);
	 						soundView1.soundfile = f;
	 						soundView1.read(0, f.numFrames);
	 						soundView1.refresh;
	 						//how to re-calc "~j" -> ControlSpec for update "Reach" param. -> check objectSpec
							})

						})
				});
		};

	 	titel1 = StaticText(w, Rect(10, 10, 100, 20));
	 	titel1.string = "Granulator 1";

		introtext = StaticText(w, Rect(10, 10, 300, 20));
	 	introtext.string = "open file and make a selection in audio to start";

	 	w.view.decorator.nextLine;
	 	soundView1 = SCSoundFileView.new(w, Rect(20, 20, 500, 60));
	 	soundView1.action_({ arg view;
	 	var where;
	 	where = (view.selections[0]);
	 	where.postln;
	 	s.sendMsg(\n_set, 1000, \centerPos, where[0], \dur, where[1]);
	 	});

	 	w.view.decorator.nextLine;
	 	shapeText = StaticText(w, Rect(10, 10, 300, 20));
	 	shapeText.string = "Auto scrub buffer position with shape";
	 	w.view.decorator.nextLine;
	 	ctrlShapeButton = Button(w, Rect(20, 20, 60, 20))
	 		.states_([
	 			["Sine", Color.black, Color.rand],
	 			["Triangle", Color.black, Color.rand],
	 			["Saw", Color.black, Color.rand],
	 			["Random", Color.black, Color.rand]
	 		])
	 		.action_({ |state|
	 			if (state.value == 0,
	 				{ s.sendMsg(\n_set, 1000, \shapeType, 0)});
	 			if (state.value == 1,
	 				{ s.sendMsg(\n_set, 1000, \shapeType, 1)});
	 			if (state.value == 2,
	 				{ s.sendMsg(\n_set, 1000, \shapeType, 2)});
	 			if (state.value == 3,
	 				{ s.sendMsg(\n_set, 1000, \shapeType, 3)});
	 		});

		ctrlSpeedKnob = EZKnob(w, 181@32, "speed 1", ControlSpec(0.0, 1.0, 'lin', 0.001, 0.0, 'Hz'),
		{|ez| s.sendMsg(\n_set, 1000, \ctrlSpeed, ez.value)}, unitWidth:30, layout:\horz)
			.setColors(Color.grey, Color.white, Color.grey(0.7), Color.grey, Color.white, Color.yellow);
	 	ctrlShape2Button = Button(w, Rect(20, 20, 60, 20))
	 		.states_([
	 			["Sine", Color.black, Color.rand],
	 			["Triangle", Color.black, Color.rand],
	 			["Saw", Color.black, Color.rand],
	 			["Random", Color.black, Color.rand]
	 		])
	 		.action_({ |state|
	 			if (state.value == 0,
	 				{ s.sendMsg(\n_set, 1000, \shapeType2, 0)});
	 			if (state.value == 1,
	 				{ s.sendMsg(\n_set, 1000, \shapeType2, 1)});
	 			if (state.value == 2,
	 				{ s.sendMsg(\n_set, 1000, \shapeType2, 2)});
	 			if (state.value == 3,
	 				{ s.sendMsg(\n_set, 1000, \shapeType2, 3)});
	 		});

		ctrlSpeed2Knob = EZKnob(w, 181@32, "speed 2", ControlSpec(0.0, 1.0, 'lin', 0.001, 0.0, 'Hz'),
		{|ez| s.sendMsg(\n_set, 1000, \ctrlSpeed2, ez.value)}, unitWidth:30, layout:\horz)
			.setColors(Color.grey, Color.white, Color.grey(0.7), Color.grey, Color.white, Color.yellow);

		~j = [0.0, b.numFrames / 44100, 'lin', 0.01, 0.0, "sec"].asSpec; //is dit goed? (global variable) -> check serveroptions (architecture)
		w.view.decorator.nextLine;	//so reach doesn't update because the ControlSpec doesn't update ->

		//Server.local.options.blockSize

		ctrlReachKnob = EZKnob(w, 245@32, "reach 1", j,
		{|ez| s.sendMsg(\n_set, 1000, \ctrlReach, ez.value)}, unitWidth:30, layout:\horz)
			.setColors(Color.grey, Color.white, Color.grey(0.7), Color.grey, Color.white, Color.yellow);

	 	ctrlReach2Knob = EZKnob(w, 245@32, "reach 2", ControlSpec(0.0, e.numFrames / 44100, 'lin', 0.01, 0.0, 'sec'),
		{|ez| s.sendMsg(\n_set, 1000, \ctrlReach2, ez.value)}, unitWidth:30, layout:\horz)
			.setColors(Color.grey, Color.white, Color.grey(0.7), Color.grey, Color.white, Color.yellow);

		w.view.decorator.nextLine;
	 	StaticText(w, Rect(10, 10, 500, 10));

	 	w.view.decorator.nextLine;
		rate1Knob = EZKnob(w, 245@32, "pitch 1", ControlSpec(0.1, 5.0, 'lin', 0.01, 1.0, 'rate'),
		{|ez| s.sendMsg(\n_set, 1000, \rate1, ez.value)}, unitWidth:30, layout:\horz)
			.setColors(Color.grey, Color.white, Color.grey(0.7), Color.grey, Color.white, Color.yellow);

		rate2Knob = EZKnob(w, 245@32, "pitch 2", ControlSpec(0.1, 5.0, 'lin', 0.01, 1.0, 'rate'),
		{|ez| s.sendMsg(\n_set, 1000, \rate2, ez.value)}, unitWidth:30, layout: \horz)
			.setColors(Color.grey, Color.white, Color.grey(0.7), Color.grey, Color.white, Color.yellow);

		w.view.decorator.nextLine;
		attKnob = EZKnob(w, 245@32, "attack 1", ControlSpec(0.01, 0.5, 'lin', 0.01, 0.1, 'sec'),
		{|ez| s.sendMsg(\n_set, 1000, \att, ez.value)}, unitWidth:30, layout:\horz)
			.setColors(Color.grey, Color.white, Color.grey(0.7), Color.grey, Color.white, Color.yellow);

		att2Knob = EZKnob(w, 245@32, "attack 2", ControlSpec(0.01, 0.5, 'lin', 0.01, 0.1, 'sec'),
		{|ez| s.sendMsg(\n_set, 1000, \att2, ez.value)}, unitWidth:30, layout:\horz)
			.setColors(Color.grey, Color.white, Color.grey(0.7), Color.grey, Color.white, Color.yellow);

		w.view.decorator.nextLine;
		decKnob = EZKnob(w, 245@32, "decay 1", ControlSpec(0.01, 0.5, 'lin', 0.01, 0.1, 'sec'),
		{|ez| s.sendMsg(\n_set, 1000, \dec, ez.value)}, unitWidth:30, layout:\horz)
			.setColors(Color.grey, Color.white, Color.grey(0.7), Color.grey, Color.white, Color.yellow);

		dec2Knob = EZKnob(w, 245@32, "decay 2", ControlSpec(0.01, 0.5, 'lin', 0.01, 0.1, 'sec'),
		{|ez| s.sendMsg(\n_set, 1000, \dec2, ez.value)}, unitWidth:30, layout:\horz)
			.setColors(Color.grey, Color.white, Color.grey(0.7), Color.grey, Color.white, Color.yellow);

	 	w.view.decorator.nextLine;
	 	replaceBufbutton2 = Button(w, Rect(20, 20, 60, 20));
	 		replaceBufbutton2.states = [["Audio 2"]];
	 		replaceBufbutton2.action = {|state|
	 			if(state.value == 0, {
	 				CocoaDialog.getPaths({ |paths|
						paths.do({ |file|
						if (e.notNil, {e.free});
						e = Buffer.read(s, file.postln);

						g = SoundFile.new;
	 					g.openRead(e.path);
	 					soundView2.soundfile = g;
	 					soundView2.read(0, g.numFrames);
	 					soundView2.refresh;
						})
					})
				})
			};

		titel1 = StaticText(w, Rect(10, 10, 200, 20));
	 	titel1.string = "Granulator 2";

	 	w.view.decorator.nextLine;
	 	soundView2 = SCSoundFileView.new(w, Rect(20, 20, 500, 60));
	 	soundView2.action_({ arg view;
	 	var where2;

	 	where2 = (view.selections[0]);
	 	where2.postln;
	 	s.sendMsg(\n_set, 1000, \centerPos2, where2[0], \dur2, where2[1]);
	 	});

		titel1 = StaticText(w, Rect(10, 10, 200, 20));
	 	titel1.string = "Shared parameters";

		w.view.decorator.nextLine;
		grainAmount = EZSlider(w, 500@24, "Grains", ControlSpec(1, 100, 'lin', 1),
		{|ez| s.sendMsg(\n_set, 1000, \amount, ez.value)}, 10);

		w.view.decorator.nextLine;
		panSlid = EZSlider(w, 500@24, "spread", ControlSpec(0.0, 1.0, 'lin', 0.01),
		{|ez| s.sendMsg(\n_set, 1000, \pan, ez.value)}, 0.6);

		w.view.decorator.nextLine;
		ampLowSlid = EZSlider(w, 500@24, "min amp", ControlSpec(0.01, 1.0, 'lin', 0.01),
		{|ez| s.sendMsg(\n_set, 1000, \ampLow, ez.value)}, 0.3);

		w.view.decorator.nextLine;
		ampHighSlid = EZSlider(w, 500@24, "max amp", ControlSpec(0.01, 1.0, 'lin', 0.01),
		{|ez| s.sendMsg(\n_set, 1000, \ampHigh, ez.value)}, 0.5);

		w.view.decorator.nextLine;
		fadeinf = StaticText(w, Rect(10, 10, 200, 20));
	 	fadeinf.string = "Balance between Bin Wipe & XFade";

		w.view.decorator.nextLine;
		balanceFadeSlid = EZSlider(w, 500@24, "Y<->X", ControlSpec(-1.0, 1.0, 'lin', 0.01),
		{|ez| s.sendMsg(\n_set, 1000, \crossFade2, ez.value)}, 0.0);

	 	w.view.decorator.nextLine;
		fadething = Slider2D(w, Rect(0, 40, 240, 120), ControlSpec(0.0, 1.0, 'lin', 0.01))
				.y_(0.5)
				.x_(0.5)
				.knobColor_(Color.rand);
			cs = ControlSpec(-1.0, 1.0, 'lin', 0.0, 1.0);
				fadething.action_({|sl|
					a.set(\crossFade, cs.map(sl.x), \binWipe, sl.y);
				});

		fadeytext = StaticText(w, Rect(10, 10, 200, 20));
	 	fadeytext.string = "Y = Bin Wipe";

		fadextext = StaticText(w, Rect(10, 10, 200, 20));
	 	fadextext.string = "X = CrossFade";

		w.view.decorator.nextLine;
		gainSlid = EZSlider(w, 500@24, "GAIN", ControlSpec(0.0, 5.0, 'lin', 0.01),
		{|ez| s.sendMsg(\n_set, 1000, \gain, ez.value)}, 0.5);
		gainSlid.setColors(Color.red, Color.white);

	CmdPeriod.doOnce({w.close});
)

First solo performance mp3

ffweb

Here’s a recording of my first solo performance at the Fine Fleur Festival 2009 in The Hague organized by Vrijhaven.
The first half is a piece of my called NVT and the second half is improvised.
dur: 18.33

Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.

Den Haag Field Recording

Field recording mix I made some time ago of The Hague

Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.

New/Old Work: Dwalen

I’ve just uploaded my latest piece which I made for my Sonology Bachelors exam. This composition was presented at the Royal Conservatory in The Hague on the 21st of june 2011.

Titel: Dwalen
Duration: 25 minutes

It’s an imaginary soundwalk through some of my work.
– moeizame start
1: Volgens mij weet ik waar we zijn
– Tussen ruimte
– Verkleur Collage
2: Ik weet waar we zijn
– 5 minuten door Den Haag
– Exoterisch
3: Ik heb geen idee waar we zijn
– Niet Van Toepassing
– Trapped
– Eruit

Field Recording @ Hubertus Park Den Haag

Following a soundwalk workshop directed by Justin Bennett.

One of the field recordings: 

Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.

This is the first version for my soundwalk:

Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.