220A HW5 - Alex Han

I had a lot of fun designing this instrument! I made something that felt more expressive and controllable to me, borrowing from familiar parameters and interfaces from synthesizers I've played. I re-mapped most of the controls as follows:

I removed the timbre switching, instead just using a single timbre of 60:40 ratio sine:sawtooth because I liked the sound. I made the frequency follow 12-TET to give more natural control of discrete pitch. The color mapping uses the mouse X, Y, and scroll values. The biggest change was binding note onset/release to the mouse click. I originally had both mouse buttons mapped so that there would be a variety of articulation options, but sadly the right clicks kept bringing up the dropdown menu so it wasn't practical. That being said, I made press-and-hold a legato articulation and short clicks add a small bump of gain to allow for quick staccato notes. Both articulations follow smooth envelopes. The vibrato works by using a LFO, and the scroll wheel allows control of its rate and depth (simultaneously). Sweeping the LPF cutoff quickly allows for some fun "meows" and "wah"s, which can be heard towards the end of my demo. I am totally going to re-use a lot of this ChucK code in my 256A synthesizer video game!

Click here to listen to demo

live code
global float mouseW, trackW, mouseX, mouseY; global float red, green, blue; global Event MOUSEDOWN_R; global Event MOUSEUP_R; global Event MOUSEDOWN_L; global Event MOUSEUP_L; global Event CLICK; int mouseStateR; int mouseStateL; float cutoff; float vibrato; // SYNTH INIT Pan2 pan; // stereo panner, set separate mono reverbs for each channel Gain g; pan.chan(0) => NRev revLeft => dac.chan(0); pan.chan(1) => NRev revRight => dac.chan(1); .05 => revLeft.mix; .05 => revRight.mix; // bank of oscillators SawOsc saw => LPF lpf => g => pan; SinOsc sin => lpf; SinOsc lfo => lpf; .4 => saw.gain; .6 => sin.gain; 0.9 => lfo.freq; .2 => g.gain; 5 => lpf.Q; //PulseOsc pul => pan; //SqrOsc sqr => pan; //TriOsc tri => pan; //SawOsc saw => pan; // envelopes for ramping gestures between gesture updates 50::ms => dur updateRate; Step unity => Envelope freqEnv => blackhole; unity => Envelope ampEnv => blackhole; unity => Envelope filterEnv => blackhole; unity => Envelope lfoEnv => blackhole; Envelope accent => blackhole; Envelope legato => blackhole; 0.10 => accent.target; 0.5 => legato.target; filterEnv.duration(updateRate); freqEnv.duration(updateRate); ampEnv.duration(updateRate); lfoEnv.duration(updateRate); fun void updateFromGestures() { while( true ) { // frequency from mouseX Math.round(mouseX*16) $ int => int pitch; Std.mtof( pitch + 80 ) => float freq; freqEnv.target(freq); // amplitude from mouseY mouseY => float amp; if ((amp >= 0.0) && (amp <= 1.0)) ampEnv.target(amp); // filter cutoff from trackW 500 + trackW * 2500.0 => cutoff; filterEnv.target(cutoff); // lfo for vibrato ((trackW / 1.0)) * 5.0 => vibrato; lfoEnv.target(vibrato); // display all three in rgb color space trackW*256 => red; mouseY*256*mouseStateL => blue; mouseX*256*-1.0 => green; updateRate => now; } } fun void updateOscillators() { while( true ) { lfo.sfreq( lfoEnv.last() ); saw.freq( freqEnv.last() + lfo.phase()); sin.freq( freqEnv.last() + lfo.phase()); saw.gain(((legato.value() * mouseY*mouseStateL )+ accent.value())*mouseY*mouseStateL); sin.gain(((legato.value() * mouseY*mouseStateL )+ accent.value())*mouseY*mouseStateL); lpf.freq(cutoff); 1::samp => now; } } // Listener functions fun void ListenClick() { while(true) { CLICK => now; 0.25 => accent.target; 15::ms => accent.duration; accent.keyOn(); 550::ms => accent.duration; accent.keyOff(); } } fun void ListenMouseDownL() { while(true) { MOUSEDOWN_L => now; 1 => mouseStateL; 100::ms => legato.duration; legato.keyOn(); } } fun void ListenMouseUpL() { while(true) { MOUSEUP_L => now; 0 => mouseStateL; 500::ms => legato.duration; legato.keyOff(); } } spork ~ updateFromGestures(); spork ~ updateOscillators(); spork ~ ListenClick(); spork ~ ListenMouseDownL(); spork ~ ListenMouseUpL(); while(true) { 1::second => now; }





output is a stereo .wav file