Showing posts with label moog. Show all posts
Showing posts with label moog. Show all posts

Wednesday, March 4, 2009

Adding LFO modulation

Another addition to my Moog style synth, LFO amplitude modulation.

Here's the code,

(
SynthDef("Moog",{

arg oscType =0, oscType2 = 0, pan = 0, level = 0.5, cutoff = 500, gain = 3.3,
attack = 0.1, decay = 0.1, sust = 0.7, rel = 0.2, attackf = 0.1, decayf = 0.1,
sustf = 0.9, relf = 0.2, gate = 1, freq =440, lagLev = 0.2, lfo1Rate = 12,
lfo2Rate =4, lfo3Rate = 6;

var lfo1 = Lag2.kr(LFSaw.kr(lfo1Rate), 0.1);
var lfo2 = Lag2.kr(LFTri.kr(lfo2Rate), 0.1);
var lfo3 = Lag2.kr(SinOsc.kr(lfo3Rate), 0.1);

var oscArray = [Saw.ar(Lag.kr(freq, lagLev)), SinOsc.ar(Lag.kr(freq, lagLev)),
Pulse.ar(Lag.kr(freq, lagLev)),Saw.ar(Lag.kr(freq, lagLev), lfo1),
SinOsc.ar(Lag.kr(freq, lagLev),0, lfo1), Pulse.ar(Lag.kr(freq, lagLev), lfo1),
Saw.ar(Lag.kr(freq, lagLev),lfo2), SinOsc.ar(Lag.kr(freq, lagLev), 0,lfo2),
Pulse.ar(Lag.kr(freq, lagLev), lfo2), Saw.ar(Lag.kr(freq, lagLev), lfo3),
SinOsc.ar(Lag.kr(freq, lagLev), 0, lfo3), Pulse.ar(Lag.kr(freq, lagLev), 0, lfo3)];

var oscArray2 = [Saw.ar(Lag.kr(freq, lagLev)), SinOsc.ar(Lag.kr(freq, lagLev)),
Pulse.ar(Lag.kr(freq, lagLev)),Saw.ar(Lag.kr(freq, lagLev), lfo1),
SinOsc.ar(Lag.kr(freq, lagLev),0, lfo1), Pulse.ar(Lag.kr(freq, lagLev), lfo1),
Saw.ar(Lag.kr(freq, lagLev),lfo2), SinOsc.ar(Lag.kr(freq, lagLev), 0,lfo2),
Pulse.ar(Lag.kr(freq, lagLev), lfo2), Saw.ar(Lag.kr(freq, lagLev), lfo3),
SinOsc.ar(Lag.kr(freq, lagLev), 0, lfo3), Pulse.ar(Lag.kr(freq, lagLev), 0, lfo3)];

var ampEnv = EnvGen.ar(Env.adsr(attack, decay, sust, rel), gate, doneAction:2);
var filterEnv = EnvGen.ar(Env.adsr(attackf, decayf, sustf, relf), gate, doneAction:2);
var osc1 = Select.ar(oscType, oscArray);
var osc2 = Select.ar(oscType2, oscArray2);
var fade = Pan2.ar(XFade2.ar(osc1, osc2, pan , level * ampEnv, 0));
var filter = MoogFF.ar(fade, cutoff * filterEnv, gain);
Out.ar(0,filter)

}).store
)







And here's a download link

I'll talk a bit more about this later.

Hail Atlantis.

Tuesday, February 24, 2009

Gooey

And now a bit more explanation of what I'm doing with my Moog GUI. 

There are a few different ways of creating GUIs and controlling synths in SuperCollider, for now I've gone with a simple approach using Pattern Proxies and the standard Slider class, but I might try something different as I add features. 

Here's some of my GUI code again, 

(
var window = Window.new("Moog",Rect(400, 400, 140, 100)).front;
var cutoffSlider, cutoffRef, resgainSlider;


~cutoffRef = PatternProxy();



cutoffSlider = Slider.new(window,Rect(10, 25, 100, 20));
 cutoffSlider.action_{
 var val;
 val = (10000*(cutoffSlider.value));
 val.postln;
 ~cutoffRef.source_(val);
  };


StaticText.new(window,Rect(10, 5, 100, 20))
 .string_("Cutoff")
 .action_{|v| };


)
This is the bit that creates the window and the filter cutoff slider. 

The first thing I've done is create a window, the parameters passed to it are the title, the initial position it appears in on the screen and the size of the window itself. 

Then I've created a Pattern Proxy, this is the thing that allows me to control my synth with both a GUI and a pattern.  

A Pattern Proxy is an object that can be placed in in a pattern and be changed whilst the pattern is playing. In this case I'm using a GUI to change the value of the Pattern Proxy as the pattern plays. I've set it as a global variable with a ~ so I can use it outside of the function it's created in.

I then create a slider that controls the value of the Pattern Proxy. It's instantiated with the name of the window it is to appear in and values setting it's size and position in the window. 

The action_ method controls the action the slider performs when it's moved. In this case it takes the value of the slider object and multiplies it by 10000. Slider values move between 0 and 1, so to turn it into something usable by the synth I need to change the range. For simple linear values multiplying the output works fine, but for more complex stuff you can use a ControlSpec. 

I then set the modified value to be the source of the Pattern Proxy, the object it takes it's values from. 

After that there's a static text box, created in a similar way to the slider, as a label. 

To actually make use of the Pattern Proxy, I need a pattern, so here it is again. 

(
Pmono("Moog",
 \freq, Pseq([440, 550, 660, 770, 660, 880], inf),
 \dur, 0.2,
 \oscType, Pseq([1,0,1,0,1], inf),
 \oscType2, Pseq([0,0,2,2,1], inf),
 \cutoff, (~cutoffRef),
 \gain, (~resgainRef)

).play
) 

All I've done is drop in the proxies as I would do with any other pattern streams. 

This time I've used a Pmono, which creates only one instance of the synth on ther server and feeds it all the values in turn, instead of creating new ones with each note. This sounds a tad more like a an authentic Moog, plus I need to use a mono pattern with my new version of the synth that features portamento. 

Shazam. 

Sunday, February 22, 2009

A simple GUI

Controlling a synth with text isn't always intuitive, so I've decided to start working towards creating a GUI for my little Moogesque synth. 

To begin with I've created a very simple interface with two sliders that allow me to control the filter cutoff frequency and the resonance gain. 

Here's the Moog synthdef again. 

( 
 SynthDef("Moog",{

arg oscType =0, oscType2 = 1, pan = 0, level = 0.5, cutoff = 500, gain = 3.3, attack = 0.1, decay = 0.1, sust = 0.7, rel = 0.2, attackf = 0.1, decayf = 0.1, sustf = 0.9, relf = 0.2, gate = 1, freq =440;


var oscArray = [Saw.ar(freq ), SinOsc.ar(freq), Pulse.ar(freq)];
var oscArray2 = [Saw.ar(freq), SinOsc.ar(freq), Pulse.ar(freq)];
var ampEnv = EnvGen.ar(Env.adsr(attack, decay, sust, rel), gate, doneAction:2);
var filterEnv = EnvGen.ar(Env.adsr(attackf, decayf, sustf, relf), gate, doneAction:2);
var osc1 = Select.ar(oscType, oscArray);
var osc2 = Select.ar(oscType2, oscArray2);
var fade = Pan2.ar(XFade2.ar(osc1, osc2, pan , level * ampEnv, 0));
var filter = MoogFF.ar(fade, cutoff * filterEnv, gain);
Out.ar(0,filter)

}).store
)

I've added a panner to it to center the sound, but other than that it's the same for now. 

This is my GUI code. 

It should be cross platform but I've only tried it on OS X.  

(
var window = Window.new("",Rect(400, 400, 140, 100)).front;
var cutoffSlider, cutoffRef, resgainSlider;

~resgainRef = PatternProxy(3);
~cutoffRef = PatternProxy(440);



cutoffSlider = Slider.new(window,Rect(10, 25, 100, 20));
 cutoffSlider.action_{
 var val;
 val = (10000*(cutoffSlider.value));
 val.postln;
 ~cutoffRef.source_(val);
  };


StaticText.new(window,Rect(10, 5, 100, 20))
 .string_("Cutoff")
 .action_{|v| };


resgainSlider = Slider.new(window,Rect(10, 65, 100, 20));
 resgainSlider.action_{
 var val;
 val = (4*(resgainSlider.value));
 val.postln;
 ~resgainRef.source_(val);
  };


StaticText.new(window,Rect(10, 45, 100, 20))
 .string_("Resonance Gain")
 .action_{|v| };
)

and here's a pattern incorporating the GUI elements I've created. 

(
Pmono("Moog",
 \freq, Pseq([440, 550, 660, 770, 660, 880], inf),
 \dur, 0.2,
 \oscType, Pseq([1,0,1,0,1], inf),
 \oscType2, Pseq([0,0,2,2,1], inf),
 \cutoff, (~cutoffRef),
 \gain, (~resgainRef)

).play
) 

This time I've used a Pmono for a more authentic sound, but more on that later...

Monday, February 9, 2009

Moooog

Last post I showed of my wonderfully entertaining Moog style synth. This time I'm going to go into some of it in  more detail. 

Envelopes have troubled me for a while and mental images of stationary have not helped me understand what they do.  After much study I have learned they are in fact structures that control a particular aspect of a sound over time, usually the amplitude or volume, but also filters and effects.

I use two in this synth, one to control the amplitude of the oscillators and one to control the filter.  

(
SynthDef("Moog",{

arg oscType =0, oscType2 = 1, pan = 0, level = 0.5, cutoff = 500, gain = 3.3, attack = 0.1, decay = 0.1, sust = 0.7, rel = 0.2, attackf = 0.1, decayf = 0.1, sustf = 0.9, relf = 0.2, gate = 1, freq =440;


var oscArray = [Saw.ar(freq ), SinOsc.ar(freq), Pulse.ar(freq)];
var oscArray2 = [Saw.ar(freq), SinOsc.ar(freq), Pulse.ar(freq)];
var ampEnv = EnvGen.ar(Env.adsr(attack, decay, sust, rel), gate, doneAction:2);
var filterEnv = EnvGen.ar(Env.adsr(attackf, decayf, sustf, relf), gate, doneAction:2);
var osc1 = Select.ar(oscType, oscArray);
var osc2 = Select.ar(oscType2, oscArray2);
var fade = XFade2.ar(osc1, osc2, pan , level * ampEnv);
var filter = MoogFF.ar(fade, cutoff * filterEnv, gain);
Out.ar(0,filter)

}).store
)

This here is the SynthDef.  I've created two arrays of oscillators which are selected by the arg osc type being passed to the Select ugen. 

The envelopes are created by these two lines, 

var ampEnv = EnvGen.ar(Env.adsr(attack, decay, sust, rel), gate, doneAction:2);
var filterEnv = EnvGen.ar(Env.adsr(attackf, decayf, sustf, relf), gate, doneAction:2);

I create a new envelope generator object and pass it an adsr (attack, decay, sustain release) evelope specification. The variables attack, decay, sustain and release contain the time in seconds.

var fade = XFade2.ar(osc1, osc2, pan , level * ampEnv);
var filter = MoogFF.ar(fade, cutoff * filterEnv, gain);

Here I times the output of the evnvelopes by the level of the cross fade and the cuttoff frequency of the moog filter giving me a output which is changed over time by the envelope. 

Saturday, February 7, 2009

Moog Thing

This is a blog about SuperCollider.

Whilst supercollider isn't my first language, I'm not a hugely experienced programmer, so this is going to be very much from a newbies perspective.

Lets start at the beginning.

This is the first real SuperCollider program that I managed to get working, very closely aided by my mate Dan who is very good at Supercollider indeed.


(
SynthDef("Moog",{

arg oscType =0, oscType2 = 1, pan = 0, level = 0.5, cutoff = 500, gain = 3.3, attack = 0.1, decay = 0.1, sust = 0.7, rel = 0.2, attackf = 0.1, decayf = 0.1, sustf = 0.9, relf = 0.2, gate = 1, freq =440;


var oscArray = [Saw.ar(freq ), SinOsc.ar(freq), Pulse.ar(freq)];
var oscArray2 = [Saw.ar(freq), SinOsc.ar(freq), Pulse.ar(freq)];
var ampEnv = EnvGen.ar(Env.adsr(attack, decay, sust, rel), gate, doneAction:2);
var filterEnv = EnvGen.ar(Env.adsr(attackf, decayf, sustf, relf), gate, doneAction:2);
var osc1 = Select.ar(oscType, oscArray);
var osc2 = Select.ar(oscType2, oscArray2);
var fade = XFade2.ar(osc1, osc2, pan , level * ampEnv);
var filter = MoogFF.ar(fade, cutoff * filterEnv, gain);
Out.ar(0,filter)

}).store
)

it's a synth. A simple Moog inspired thing, with two oscillators, which can be either saw, sin or square/pulse waves and a mixer to mix them. It's also got a filter and two envelopes, one controlling the filter and one controlling the amplitude.

here's a pattern to play it with.

(
Pbind(
\instrument, "Moog",
\freq, Pseq([440, 550, 660, 770, 660, 330, 880], inf),
\dur, Pseq([0.2, 0.4, 0.1, 0.2, 0.2], inf),
\oscType, Pseq([0,0,0,0,0], inf),
\oscType2, Pseq([0,0,2,2,1], inf),
\cutoff, Pseq([100,599,1000,20,800], inf),
\pan, Pseq([1], inf)

).play
)


I'll go into more details of it's workings later...