Randrum – a weighted random drum sequencer

Randrum is a drum sequencer that uses weighted random values to trigger audio samples. The idea came from programming drum patterns using Pbind in SuperCollider (SC). In SC there is a pattern object called Pwrand (SC description: “Returns one item from the list at random for each repeat, the probability for each item is determined by a list of weights which should sum to 1.0.”) which I really liked and wanted to see how that would work in Max. Randrum is the result of this experimentation.

It is still very much a work in progress, so I will share my code in a later stage I guess.

 

RandrumScreenshot

Control stuff with M4L – update [26-05-2015]

I have made some stuff in MaxForLive to integrate SuperCollider and the Roland JP8000 synthesizer more into my workflow in Ableton Live.

– SuperCollider SynthDef control: Send values from Ableton Live to a SynthDef in SuperCollider. Map MaxForLive device dials to SynthDef arguments using the openObject Quark. M4L dials can be automated in Live, so you can automate your SynthDef parameters in your composition.

Download

The SuperCollider_SynthDefCtrl M4L device has at its top left corner a text field where the  publish name of the SynthDef should be entered. To map a dial to a SynthDef argument simply change param_name into the SynthDef’s arg name. Each dial has its own lower and upper boundaries (default set to 0. to 1.0) and a lag value.

// to install OpenObject Quark:
Quarks.gui;
// Find and check the OpenObject Quark and hit Apply

// to start OpenObject Quark in SuperCollider:
s.boot;
OpenObject.start;

// I always use a gate arg, it's not mandatory though.
// You can change the gate argument in the M4L device
// to something else.

(
SynthDef(\synthie, {| gate=0, arg1, arg2, arg3... |

// some awesome SynthDef code

}).send(s)
)

a = Synth(\synthie); // create a synth
a.publish(\synthie_or_something_else); // publish name

SuperColliderSynthDefControl

– Automate Roland JP8000 synth parameters in Ableton Live (not updated – 10-2014): Download

JP8000_midiCtrl

 

 

 

Max object: mxj pandorabot

Pandorabot mxj object for Max, to chat with pandora bots.

Pandorabot java source and class file on github.

Here is a Max patch where two bots talk to each other: Pandorabot.zip This max patch also uses the external [flite~] (to do text-to-speech, so it sounds like the two bots are having a conversation out loud), and my [mxj htmlsource]. Mxj htmlsource is used to get all the ID’s of the available bots you can chat with. Not all bots work correctly atm, because of the way they use/named html forms.

Here is a short video of one of their conversations: [vimeo https://vimeo.com/97649674]

 

Max Twitter Stream [update 26-09-2013]

TwitterMap_worldMap

I have just made my first two mxj objects for Max, using Twitter4j, a java library for the Twitter API. You can filter the live Twitter stream by using keywords, users or locations. I made this for a sonification project I am working on at the moment. Next to the live stream you can also search twitter data, view timelines, direct message friends and some other cool stuff. This is my first time using Java (next to some stuff made in Processing), most of the code is a slightly modified version of the Twitter4j examples. The mxj objects where made in Eclipse, you can find a short tutorial on how to set up Eclipse to start developing mxj objects here, and check the WritingMaxExternalsInJava.pdf located in the Max applications folder under java-doc. The idea of combining Twitter stream location data with a world map came from this project. If you want to use this code you have to get a Twitter Consumer key/secret and access token/secret, and put it in your java code at the ConfigurationBuilder stuff, highlighted in the code below. Maybe i will implement this into the code in the future to streamline this process, but for now you can find some info on how to get these keys on the Twitter developer forum.

Here is a short video:

[update 26-09-2013] :

  • Added Sentiment Analysis, with LingPipe, which is a toolkit for processing text using computational linguistics. Tweets are analyzed and categorized, the dot on the world map, representing the location of the Tweet, wil have a corresponding color (positive=blue/neutral=green/negative=red). Amount of pos/neu/neg Tweets are counted (so you can see the overall sentiment on topics or area’s). (Only works on Tweets written in English)
  • Added a daylight layer, which is a world map showing day/night around the globe and cloud coverage. You can change the opacity of the normal (grey scale) map, and the opacity of the daylight map.
  • Added search location by name rather than bounding box coordinates. Location names are converted to bounding box coordinates using the website: http://isithackday.com/geoplanet-explorer/ For this to work I created an extra MXJ object that imports a websites source into Max.

You can download the Max MXJ objects here: https://github.com/Haighton/mxj-objects

And the Max patches here.

Some SuperCollider code for the bored – sinGrain

sinGrain

Granular synthesis with sinusoidal grains + a simple GUI.
Its a Synthdef using sinGrainB (a ugen from the SC3-plugins package) by Josh. You can set boundaries for random values for grain- amplitudes, durations, panning and frequencies. Frequency can be split, so only two frequencies are played instead of random frequencies in between the two values. Frequencies can be set using number boxes or a range slider. Grains can be triggered periodically (by choosing Impulse) or irregular (choosing Dust from the trigger menu), both use the spd slider for their speed.

// SinGrain with Interface

(
// grain envelope
z = Env([0,1,0], [1,1], \sine).asSignal(1024);
s.sendMsg(\b_alloc, b = s.bufferAllocator.alloc(1), 1024, 1, [\b_setn, b, 0, 1024] ++ z);
)

(
SynthDef(\sinGrain, {|out=0, envbuf, gate=1, atk=0.5, dec=0.2, sus=0.9, rel=0.5, ttype=0, tspeed=5, durMin=1.25, durMax=1.5, freqType=1, freqMin=220, freqMax=220, ampMin=0.8, ampMax=1, panMin=0, panMax=0, gain=0.65|
 var env, source, trigger, pan, dur, amp, freq;
 trigger = Select.kr(ttype, [Impulse.kr(tspeed), Dust.kr(tspeed)]);
 env = EnvGen.kr(Env.adsr(atk, dec, sus, rel), gate, doneAction:2);
 amp = TRand.kr(ampMin, ampMax, trigger);
 dur = TRand.kr(durMin, durMax, trigger);
 pan = TRand.kr(panMin, panMax, trigger);
 freq = Select.kr(freqType, [
 Demand.kr(trigger, 0, Drand([freqMin, freqMax], inf)),
 TRand.kr(freqMin, freqMax, trigger)
 ]);
 source = SinGrainB.ar(trigger, dur, freq, envbuf, amp);
 source = Pan2.ar(source, pan, gain);
 Out.ar(out, source * env);
}).send(s);
)

/*
s.sendMsg(\s_new, \sinGrain, x=s.nextNodeID, 0, 0, \out, 0);
s.sendMsg(\n_set, \panMin, -1, \panMax, 1);
s.sendMsg(\n_set, x, \gate, 0);
*/

/**************************************** GUI ****************************************/
(
var synthNode = 3000;
w = Window("sinGrain", 370@320, false, true);
w.front;

Button(w, Rect(0, 0, 370, 40))
.states_([
 ["push", Color.rand, Color.rand],
 ["push", Color.rand, Color.rand]
])
.action_({|button|
 if(button.value == 1, {
 s.sendMsg(\s_new, \sinGrain, synthNode, 0, 0, \gate, 1)
 },{
 s.sendMsg(\n_set, synthNode, \gate, 0)
 }
 );
});

//Trigger type
g = EZPopUpMenu(w, Rect(-22, 50, 180, 20), "trigger");
g.addItem(\Impulse, {|a| (s.sendMsg(\n_set, synthNode, \ttype, 0))});
g.addItem(\Dust, {|a| (s.sendMsg(\n_set, synthNode, \ttype, 1))});
g.value = 0;

// Trigger speed
EZSlider(w, Rect(-22, 80, 365, 20), "spd", [0, 30, \lin, 0.1, 5].asSpec, {|slider| s.sendMsg(\n_set, synthNode, \tspeed, slider.value)}, nil, true, 60, 0, 0, 20, \horz);

StaticText(w, Rect(10, 110, 30, 20)).string_("amp");
//Amplitude Range Slider
RangeSlider(w, Rect(40, 110, 300, 20))
.lo_(0.8)
.hi_(1.0)
.action_({|amp| s.sendMsg(\n_set, synthNode, \ampMin, amp.lo, \ampMax, amp.hi)});

StaticText(w, Rect(10, 140, 30, 20)).string_("dur");
//Duration Range Slider
RangeSlider(w, Rect(40, 140, 300, 20))
.lo_(0.4)
.hi_(0.5)
.action_({|dur| s.sendMsg(\n_set, synthNode, \durMin, [0, 3.0, \lin, 0.01].asSpec.map(dur.lo), \durMax, [0, 3.0, \lin, 0.01].asSpec.map(dur.hi))});

StaticText(w, Rect(10, 170, 30, 20)).string_("pan");
//Panning Range Slider
RangeSlider(w, Rect(40, 170, 300, 20))
.lo_(0.5)
.hi_(0.5)
.action_({|pan| s.sendMsg(\n_set, synthNode, \panMin, [-1, 1.0, \lin, 0.01].asSpec.map(pan.lo), \panMax, [-1, 1.0, \lin, 0.01, 0].asSpec.map(pan.hi))});

//Trigger type
h = EZPopUpMenu(w, Rect(-13, 200, 180, 20), "split freq");
h.addItem(\split, {|a| (s.sendMsg(\n_set, synthNode, \freqType, 0))});
h.addItem(\random, {|a| (s.sendMsg(\n_set, synthNode, \freqType, 1))});
h.value = 1;

// FREQUENCY IS SET BY TWO NUMBER BOXES OR RANGE SLIDER

//Freq Min Max boxes
EZNumber(w, Rect(5, 230, 130, 20), "freq min", [20, 20000, \lin, 1, 220, "Hz"].asSpec, {|fmin| s.sendMsg(\n_set, 3000, \freqMin, fmin.value)});
EZNumber(w, Rect(150, 230, 130, 20), "freq max", [20, 20000, \lin, 1, 220, "Hz"].asSpec, {|fmax| s.sendMsg(\n_set, 3000, \freqMax, fmax.value)}, labelHeight:20);

StaticText(w, Rect(10, 260, 30, 20)).string_("freq");
//Frequency Range Slider
RangeSlider(w, Rect(40, 260, 300, 20))
.lo_(0.5)
.hi_(0.5)
.action_({|freq| s.sendMsg(\n_set, synthNode, \freqMin, [20, 20000, \exp, 1, 220].asSpec.map(freq.lo), \freqMax, [20, 20000, \exp, 1, 220].asSpec.map(freq.hi))});

// Trigger speed
EZSlider(w, Rect(-22, 290, 365, 20), "gain", [0, 1, \lin, 0.01, 0.65].asSpec, {|volume| s.sendMsg(\n_set, synthNode, \gain, volume.value)}, nil, true, 60, 0, 0, 20, \horz);

CmdPeriod.doOnce({w.close});
)
<pre>

Musical Scale Generator

Simple MIDI note generator application made in Max 6.
Generates MIDI notes based on different musical scales (major, minor, dorian phrygian, lydian, mixolydian and locrian).
The user has the ability to choose between different ways to play the generated note patterns (up, down, up/down, random and sequence). Notes can be turned off or on.
A sequence can be played forward, backwards or both. Up to 12 sequences can be stored. Time intervals and octave can be set and randomised with constraints.
At every parameter there is a green check box which randomises the parameter after a specified amount of measures or by a push of a button.

download MIDINoteGenerator_1.0.mxf

Simple Musical Scale Gen
Simple Musical Scale Gen

You need Max Runtime to run this application.

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});
)

Deteq LFO [update 1.0]

DeteqLFO1.0_1

I’ve just updated my LFO (Low Frequency Oscillator) application for automating VST/AU parameters (or any other software that communicates with MIDI CC or OSC data).
It has 4 LFO’s and 4 MIDI + OSC output channels. The LFO’s can run by a given frequency, in sync with a Rewire host or synced by an incoming MIDI clock signal. Each LFO can be modulated (FM/AM) by any of the other LFO’s.  Available waveforms :

  • Sine
  • Triangle/Saw
  • Square
  • Random hold
  • Drawing (draw a waveform)

Download: DeteqLFO1.0.zip

This slideshow requires JavaScript.