Day 1
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 1 September 2009 Mouse-controlled FM Synth Mouse button: note on-off Mouse X: pitch Mouse Y: modulator frequency ========================================================================== */
// Create FM synth SynthDef ====================================== ( SynthDef("fm-synth", { arg freq = 440, amp = 0, gate = 0; Out.ar(0, Pan2.ar(SinOsc.ar(MouseY.kr(4000, 0) * SinOsc.ar(MouseX.kr(20, 4000), 0, MouseButton.kr(0, 1, 0.2), 0, 0.2)), 0, 0.2)); FreeSelf.kr(1 - gate); // FreeSelf automatically releases on neg-pos transition }).store; ) // Test FM synth using test variable a = Synth('fm-synth');
Day 2
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 2 September 2009 Sequenced FM Synth, with random parameter selection ========================================================================== */
// Create FM synth SynthDef ====================================== ( SynthDef("fm-synth", { arg freq = 440, amp = 0, gate = 1; // Fundamental and modulator frequencies are randomly picked Out.ar(0, Pan2.ar(EnvGen.kr(Env.perc, gate: gate, doneAction: 2) * SinOsc.ar(LinRand(0.0, 4000.0) * SinOsc.ar(LinRand(20.0, 4000.0), 0, 1, 0, 0.2)), 0, 0.2)); }).store; ) // The 'gate' parameter of EnvGen must be => 1 for the envelope not to click ( b = Pbind(\instrument, "fm-synth", \dur, 0.5).play; c = Pbind(\instrument, "fm-synth", \dur, 0.1).play; ) b.stop; c.stop;
/* When \dur is set to anything around 1.2615 I start getting a 'FAILURE n_set Node not found' error when the synth is triggered */
// Tomorrow I'll try to hook Pbind duration to the Mouse X axis...
Day 3
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 3 September 2009 Sequenced FM Synth, with random parameter selection ========================================================================== */
// Create FM synth SynthDef ====================================== ( SynthDef("fm-synth", { arg freq = 440, pan = 0.0, gate = 1; // Fundamental and modulator frequencies are randomly picked Out.ar(0, Pan2.ar(EnvGen.kr(Env.perc, gate: gate, doneAction: 2) * SinOsc.ar(LinRand(0.0, 4000.0) * SinOsc.ar(freq, 0, 1, 0, 0.2)), pan, 0.2)); }).store; t = TempoClock(1); // Create a TempoClock instance, set to 1 trigger a second u = TempoClock(1.5); // Create another TempoClock instance, for the second Pbind ) // The 'gate' parameter of EnvGen must be => 1 for the envelope not to click ( b = Pbind(\instrument, "fm-synth", \freq, Pshuf([110, 220, 440, 880], inf), \pan, -0.75, \dur, Prand([0.2, 0.4, 0.8], inf)); c = Pbind(\instrument, "fm-synth", \freq, Pshuf([100, 200, 400, 800], inf), \pan, 0.75, \dur, Prand([0.1, 0.3, 0.9], inf)); b.play(t); c.play(u); ) // This does not work, probably because this value doesn't constantly update //t.tempo = MouseX.kr(0.75); // Alter two synths' tempos independently t.tempo = 2.0 u.tempo = 3.0; // For some reason I now have to stop the TempoClocks and not the Pbinds t.stop; u.stop;
/* When \dur is set to anything around 1.2615 I start getting a 'FAILURE n_set Node not found' error when the synth is triggered */
// Updated today: added 'pan' argument to SynthDef // the two synths run on independent clocks // added random duration process to Pbinds // constrained fundamental frequency through use of Pshufs // TOMORROW: I will create a new SynthDef
Day 4
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 4 September 2009 Amp-modded sinewave pad ========================================================================== */
// Create SynthDef =============================== ( SynthDef(\sine_osc, { arg amp = 0.1, gate = 1; // I tried to figure out how to use .do for this but it eluded me this time! var freq_array = [Rand(40.0, 2000.0), Rand(40.0, 2000.0), Rand(40.0, 2000.0), Rand(40.0, 2000.0), Rand(40.0, 2000.0)]; var ampmod_array = [MouseX.kr(0.0, 1.0), MouseY.kr(1.0, 0.0)]; // Five SinOscs with randomly selected frequency are created and spread across the stereo image // The amp mod applied to left and right output channels is controlled by mouse position Out.ar(0, SinOsc.ar(ampmod_array, 0, 1.0) * Splay.ar(SinOsc.ar(freq_array, 0, amp))); FreeSelf.kr(1 - gate); }).store; ) d = Synth(\sine_osc); d.free; // TOMORROW: don't know yet, let's see
Day 5
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 5 September 2009 As I felt the need to get some basic SC programming under my belt I attempted the exercises from Nick Collin's SuperCollider tutorials, found: http://www.cogs.susx.ac.uk/users/nc81/courses/cm1/sccourse.zip ========================================================================== */
// 4.4 Exercises rtf
/* ========================================================================== a) Make a function with argument N which returns an array of N random numbers between 1.0 and 10.0. The numbers must have been sorted into decreasing order (hint: try [1,4,3].sort) */
( a = { arg num = 4; var rand_nums = Array.rand(num, 1.0, 10.0); // Create array rand_nums.sort.reverse; // Sort and reverse! }; a.value(6); // Run function with n elements of array )
/* ========================================================================== b) Imagine you have to generate a rhythm for one 4/4 bar (i.e. 4 beats). Write a short program which selects random successive numbers from [1.0, 0.5, 0.25] to fill up one bar's worth of beats. How do you deal with going past the end of the bar? (hint: what does .choose do on an array?) */
( var beat_array = [], last_index = 0; // While the beat_array hasn't reached 4 keep adding a new value to it while({ beat_array.sum < 4 }, { // Choose from the three values of this array beat_array = beat_array.add(#[1.0, 0.5, 0.25].choose); }); // The above may result in an array sum over 4, so now we limit it if above 4 if(beat_array.sum > 4, { // Figure out last array index last_index = beat_array.size - 1; // Chop of excess from last array value and replace value beat_array[last_index] = beat_array[last_index] - (beat_array.sum - 4); }); beat_array.sum.postln; beat_array.postln; )
/* =========================================================================== c) Rewrite the following code as a series of nested ifs i.e. if(condition1, {}, {if (condition2, etc.)}) ( var z; z = 4.rand; switch (z, 0, { \outcome1 }, 1, { \outcome2 }, 2, { \outcome3 }, 3, { \outcome4 } ).postln; ) Then rewrite it as a choice amongst elements of an array. */
// Nested if statements ( var rand_index = 4.rand; if(rand_index == 0, { "Outcome 1".postln; }, { if(rand_index == 1, { "Outcome 2".postln; }, { if(rand_index == 2, { "Outcome 3".postln; }, { "Outcome 4".postln; }) }) }); rand_index.postln; ) // Array choose version c = ["Outcome 1", "Outcome 2", "Outcome 3", "Outcome 4"].choose;
/* ============================================================================ d) Compare each of these lines by running them one at a time: 2.rand 2.0.rand 2.rand2 2.0.rand2 rrand(2,4) rrand(2.0,4.0) exprand(1.0,10.0) Write a program which plots ten outputs from any one of these lines in a row. Advanced: actually allow user selection (via a variable for instance) of which line gets used to generate the ten random numbers. */
( var rand_array = []; 10.do{ rand_array = rand_array.add(2.rand2); }; rand_array.postln; ) ( b = { arg index; var rand_array = []; // Use switch and argument to decide which random function to use switch(index, 0, { 10.do{ rand_array = rand_array.add(2.rand); }}, 1, { 10.do{ rand_array = rand_array.add(2.0.rand); }}, 2, { 10.do{ rand_array = rand_array.add(2.rand2); }}, 3, { 10.do{ rand_array = rand_array.add(2.0.rand2); }}, 4, { 10.do{ rand_array = rand_array.add(rrand(2, 4)); }}, 5, { 10.do{ rand_array = rand_array.add(rrand(2.0, 4.0)); }}, 6, { 10.do{ rand_array = rand_array.add(exprand(1.0, 10.0)); }}, { rand_array = rand_array.add("Wrong argument input") }; ); rand_array.postln; }; b.value(3); ) // TOMORROW: Back to the previous SynthDef
Day 6
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 6 September 2009 First steps towards a multi-source positioning system with GUI ========================================================================== */
// Create GUI window and 2D slider ( var pos_window = Window("Audio Position", Rect(100, 400, 600, 400)).front; var pos_slider = SC2DSlider(pos_window, Rect(0, 0, 400, 400)); var noise_synth; SynthDef(\simple_noise, { |amp = 0.5, pan = 0.0, lp_freq = 20000| Out.ar(0, Pan2.ar(LPF.ar(WhiteNoise.ar(amp), lp_freq), pan)); }).store; noise_synth = Synth(\simple_noise).play; // Slider action callback ---------------------------------------------- pos_slider.action_({ arg pos_sl; // Slider value // Calculate direct distance from bottom centre to slider var hypot = ((pos_sl.x - 0.5).squared.abs + pos_sl.y.squared).sqrt; //["Hypot", hypot, "Amp", 1 - (hypot / 1.2)].postln; noise_synth.set( \pan, (pos_sl.x * 2.0) - 1.0, // X governs pan \amp, 1 - (hypot / 1.2), // Y governs amplitude \lp_freq, ((1 - pos_sl.y) * 19600) + 400); }); // Free synth on window close ------------------------------------------ pos_window.onClose = { noise_synth.free; }; ) // ================================= // TO DO: work on pan algorithm // add reverb on buss // change audio source // set default slider position
Day 7
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 7 September 2009 Amp-modded additive synth pad ========================================================================== */
// Create SynthDef =============================== ( SynthDef(\am_synth, { | fund_freq = 100, gate = 1 | var num_tones = 10; // Array.series is used to create a harmonic series var freq_array = Array.series(num_tones, fund_freq, fund_freq); var ampmod_array = [MouseX.kr(0.0, 1.0), MouseY.kr(1.0, 0.0)]; // The amp mod applied to left and right output channels is controlled by mouse position Out.ar(0, SinOsc.ar(ampmod_array, 0, 1.0) * Splay.ar(SinOsc.ar(freq_array, 0, num_tones.reciprocal))); FreeSelf.kr(1 - gate); }).store; ) d = Synth(\am_synth); // Window creation ( // I am getting a multislider with 16 bars but I only want 10... how do I fix this var synth_window = Window("am_synth:", Rect(100, 400, 200, 200)).front; var partial_slider = SCMultiSliderView(synth_window, Rect(10, 10, 180, 180)); partial_slider.size_(10); partial_slider.elasticMode_(1); partial_slider.thumbSize_(10); partial_slider.isFilled_(true); partial_slider.fillColor_(Color.new255(200, 200, 255)); partial_slider.action = { |partial_amp_arr| partial_amp_arr.value.postln; }; ) d.free; // I ran out of time today, so tomorrow I will attempt to finish this off...
Day 8
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 8 September 2009 Amp-modded additive synth pad ========================================================================== */
// Create SynthDef =============================== ( // Variable declarations ----------------------------------------------------- // I am getting a multislider with 16 bars but I only want 10... how do I fix this? var synth_window = Window("am_synth", Rect(100, 400, 200, 260)).front; var partial_slider = SCMultiSliderView(synth_window, Rect(10, 10, 180, 180)); var freq_slider = SCSlider(synth_window, Rect(10, 200, 150, 20)); var freq_step_slider = SCSlider(synth_window, Rect(10, 230, 150, 20)); var freq_step_reset = SCButton(synth_window, Rect(170, 230, 20, 20)).states_([[""]]); var amp_synth; // Window setup -------------------------------------------------------------- partial_slider.size_(10); partial_slider.elasticMode_(1); partial_slider.thumbSize_(8); partial_slider.isFilled_(true); partial_slider.fillColor_(Color.new255(200, 200, 255)); // SynthDef definition ---------------------------------------------------- SynthDef(\am_synth, { | fund_freq = 100, freq_step = 100, gate = 1, amp_array = #[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | var num_tones = 16; // Array.series is used to create a harmonic series var freq_array = Array.series(num_tones, fund_freq, freq_step); var ampmod_array = [MouseX.kr(0.0, 1.0), MouseY.kr(1.0, 0.0)]; // The amp mod applied to left and right output channels is controlled by mouse position Out.ar(0, SinOsc.ar(ampmod_array, 0, 1.0) * Splay.ar(SinOsc.ar(freq_array, 0, amp_array))); FreeSelf.kr(1 - gate); }).store; // Create synth amp_synth = Synth(\am_synth); // UI CALLBACKS ----------------------------------------------------------- // What to do when multislider is changed partial_slider.action_({ |partial_amp_arr| amp_synth.set(\amp_array, partial_amp_arr.value); }); // What to do when frequency slider is changed freq_slider.action_({ |freq_slid_val| // Fundamental frequency range: 20-3000 amp_synth.set(\fund_freq, (freq_slid_val.value * 2980) + 20); }); // What do to when frequency step value is changed freq_step_slider.action_({ |freq_step_val| // Frequency step range: 1-1000 amp_synth.set(\freq_step, (freq_step_val.value * 1000) + 1); }); // What do to when frequency step reset button is clicked freq_step_reset.action_({ // NOT CONNECTED YET! //amp_synth.set(\freq_step, amp_synth.get(\fund_freq)); }); // Free synth on window close ------------------------------------------ synth_window.onClose = { amp_synth.free; }; ) // TO DO: Improve usability // Add numerics for fund_freq and freq_step sliders // Implement freq_step reset button (reset freq_step to the value of fund_freq)
Day 9
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 9 September 2009 Amp-modded additive synth pad from yesterday, with additional features ========================================================================== */
// Create SynthDef =============================== ( // Variable declarations ----------------------------------------------------- // I am getting a multislider with 16 bars but I only want 10... how do I fix this? var synth_window = Window("add_synth", Rect(100, 400, 200, 280)).front; var partial_slider = SCMultiSliderView(synth_window, Rect(10, 10, 180, 180)); var freq_slider = SCSlider(synth_window, Rect(10, 200, 135, 20)).value_((100 - 20) / 2980); var freq_value = SCNumberBox(synth_window, Rect(150, 200, 40, 20)); var freq_step_slider = SCSlider(synth_window, Rect(10, 225, 135, 20)).value_((100 - 1) / 999); var freq_step_value = SCNumberBox(synth_window, Rect(150, 225, 40, 20)); var freq_step_link = SCButton(synth_window, Rect(10, 250, 50, 20)).states_([ ["Link", Color.black], ["Unlink", Color.black, Color.gray] ]); var amp_synth; // Window setup -------------------------------------------------------------- partial_slider.size_(15); partial_slider.elasticMode_(1); partial_slider.thumbSize_(8); partial_slider.isFilled_(true); partial_slider.fillColor_(Color.new255(200, 200, 255)); // Set UI values freq_value.value = 100; freq_step_value.value = 100; // SynthDef definition ---------------------------------------------------- SynthDef(\add_synth, { | fund_freq = 100, freq_step = 100, gate = 1, amp_array = #[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | var num_tones = 15; // Array.series is used to create a harmonic series var freq_array = Array.series(num_tones, fund_freq, freq_step); var ampmod_array = [MouseX.kr(0.0, 1.0), MouseY.kr(1.0, 0.0)]; // The amp mod applied to left and right output channels is controlled by mouse position Out.ar(0, SinOsc.ar(ampmod_array, 0, 1.0) * Splay.ar(SinOsc.ar(freq_array, 0, amp_array))); FreeSelf.kr(1 - gate); }).store; // Create synth amp_synth = Synth(\add_synth); // UI CALLBACKS ----------------------------------------------------------- // What to do when multislider is changed partial_slider.action_({ |partial_amp_arr| amp_synth.set(\amp_array, partial_amp_arr.value); }); // What to do when frequency slider is changed freq_slider.action_({ |freq_slid_val| // Fundamental frequency range: 20-3000 var freq = (freq_slid_val.value * 2980) + 20; // Set synth argument and number box value amp_synth.set(\fund_freq, freq); freq_value.value = freq; }); // What to do when frequency number box is changed freq_value.action_({ |freq_val| amp_synth.set(\fund_freq, freq_val.value); freq_slider.value = (freq_val.value - 20) / 2980; }); // What do to when frequency step value is changed freq_step_slider.action_({ |freq_step_val| // Frequency step range: 1-1000 var step = (freq_step_val.value * 999) + 1; amp_synth.set(\freq_step, step); freq_step_value.value = step; }); // What to do when frequency step number box is changed freq_step_value.action_({ |freq_step_val| amp_synth.set(\freq_step, freq_step_val.value); freq_step_slider.value = (freq_step_val.value - 1) / 999; }); // What do to when frequency step reset button is clicked freq_step_link.action_({ |freq_step_state| freq_step_state.value.postln; }); // Free synth on window close ------------------------------------------ synth_window.onClose = { amp_synth.free; }; ) // TO DO: Implement freq_step link button
Day 10
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 10 September 2009 Second steps towards a multi-source positioning system with GUI - This one is just for a single set source ========================================================================== */
// Create GUI window and 2D slider ( var pos_window = Window("Audio Position", Rect(100, 400, 600, 400)).front; var pos_slider = SC2DSlider(pos_window, Rect(0, 0, 400, 400)); var depth_valbox = SCNumberBox(pos_window, Rect(410, 0, 40, 20)).value = 10; var depth_valbox_label = SCStaticText(pos_window, Rect(460, 0, 100, 20)).string = "Control depth, m"; var noise_synth; var sound_speed = 340.29; // Speed of sound at sea level in m/s (from Google Calculator) SynthDef(\simple_noise, { |amp = 0.5, pan = 0.0, lp_freq = 20000| Out.ar(0, Pan2.ar(LPF.ar(WhiteNoise.ar(amp), lp_freq), pan)); }).store; noise_synth = Synth(\simple_noise).play; // Slider action callback ---------------------------------------------- pos_slider.action_({ arg pos_sl; // Slider value // Calculate direct distance from bottom centre to slider var hypot = ((pos_sl.x - 0.5).squared.abs + pos_sl.y.squared).sqrt; //["Hypot", hypot, "Amp", 1 - (hypot / 1.2)].postln; noise_synth.set( \pan, (pos_sl.x * 2.0) - 1.0, // X governs pan \amp, 1 - (hypot / 1.2), // Y governs amplitude \lp_freq, ((1 - pos_sl.y) * 19600) + 400); }); // Set default position of slider (front, centre) pos_slider.setXYActive(0.5, 0.0); // Free synth on window close ------------------------------------------ pos_window.onClose = { noise_synth.free; }; // Close windoe on CMD-. ----------------------------------------------- //CmdPeriod.doOnce({ pos_window.close; }); ) // ================================= // TO DO: work on pan/depth algorithm - change to use speed of sound // add reverb on buss // allow changing audio source
Day 11
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 11 September 2009 Third steps towards a multi-source positioning system with GUI - This one is just for a single set source ========================================================================== */
( // Declare and define variables ----------------------------------------------------------------------------- var sound_speed = 340.29; // Speed of sound at sea level in m/s (from Google Calculator) var max_distance = 10; // Distance in metres var max_time = max_distance / sound_speed; // Maximum delay time at max_distance and sound_speed var rel_delay_time = 0.0; // The time source is delayed due to distance from listener var pos_window = Window("Audio Position", Rect(100, 400, 600, 400)).front; var pos_slider = SC2DSlider(pos_window, Rect(0, 0, 400, 400)); var depth_valbox = SCNumberBox(pos_window, Rect(410, 0, 40, 20)).value = max_distance; var depth_valbox_label = SCStaticText(pos_window, Rect(460, 0, 100, 20)).string = "Control depth, m"; var noise_synth; // Define SynthDef ------------------------------------------------------------------------------------------ SynthDef(\simple_noise, { |amps = #[1, 1], lp_freq = 20000, delay_time = 0.0| // Comment out which source shouldn't be used //var source = WhiteNoise.ar(amps); var source = SinOsc.ar(440, 0, amps); Out.ar(0, DelayC.ar(LPF.ar(source, lp_freq), 5.0, delay_time, 1.0)); }).store; noise_synth = Synth(\simple_noise).play; // Slider action callback ---------------------------------------------- pos_slider.action_({ arg pos_sl; // Slider value // Calculate direct distance from bottom centre to slider, and declare amps_lr array var var distance = ((pos_sl.x - 0.5).squared.abs + pos_sl.y.squared).sqrt, amps_lr; amps_lr = [(pos_sl.x.squared + pos_sl.y.squared).sqrt, ((pos_sl.x - 1.0).squared.abs + pos_sl.y.squared).sqrt]; // Calculate delay time from source rel_delay_time = (distance * max_distance) / sound_speed; // Set synth parameters noise_synth.set( \amps, (((amps_lr) - 1.42).abs) * max_distance.reciprocal, \lp_freq, ((1 - pos_sl.y) * 19600) + 400, \delay_time, rel_delay_time); }); // Set default position of slider (front, centre) pos_slider.setXYActive(0.5, 0.0); // Distance value box callback -------------------------------------------- depth_valbox.action_({ |max_dist| max_distance = max_dist.value; // pos_slider.action; }); // Free synth on window close ------------------------------------------ pos_window.onClose = { noise_synth.free; }; // Close windoe on CMD-. ----------------------------------------------- //CmdPeriod.doOnce({ pos_window.close; }); ) // ================================= // TO DO: work max_distance into pan/depth algorithm better // add reverb on buss // allow changing audio source // cure delay 'zipper' noise
Day 12
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 12 September 2009 Fourth step towards a multi-source positioning system with GUI - This one is just for a single set source - max_distance requires more work ========================================================================== */
( // Declare and define variables ----------------------------------------------------------------------------- var sound_speed = 340.29; // Speed of sound at sea level in m/s (from Google Calculator) var max_distance = 10; // Distance in metres var speaker_spread = 5; // Distance between the speakers, in metres var max_time = max_distance / sound_speed; // Maximum delay time at max_distance and sound_speed var rel_delay_time = 0.0; // The time source is delayed due to distance from listener var pos_window = Window("Audio Position", Rect(100, 400, 600, 400)).front; var pos_slider = SC2DSlider(pos_window, Rect(0, 0, 400, 400)); var depth_valbox = SCNumberBox(pos_window, Rect(410, 0, 40, 20)).value = max_distance; var depth_valbox_label = SCStaticText(pos_window, Rect(460, 0, 120, 20)).string = "Control depth, m"; var speaker_spread_valbox = SCNumberBox(pos_window, Rect(410, 25, 40, 20)).value = 5; var speaker_spread_label = SCStaticText(pos_window, Rect(460, 25, 120, 20)).string = "Speaker spread, m"; var speakerL_pos = [0.5 - (speaker_spread / max_distance / 2), 0]; // Set left speaker position var speakerR_pos = [0.5 + (speaker_spread / max_distance / 2), 0]; // Set right speaker position var source_synth; // Define SynthDef ------------------------------------------------------------------------------------------ SynthDef(\simple_source, { |amps = #[1, 1], lp_freq = 20000, delay_time = 0.0| // Comment out which source shouldn't be used //var source = WhiteNoise.ar(amps); var source = SinOsc.ar(440, 0, amps); Out.ar(0, DelayC.ar(LPF.ar(source, lp_freq), 1.0, Ramp.kr(delay_time, 0.05), 1.0)); }).store; source_synth = Synth(\simple_source).play; // Slider action callback ---------------------------------------------- pos_slider.action_({ arg pos_sl; // Slider value // Calculate direct distance from bottom centre to slider, and declare amps_lr array var var distance = ((pos_sl.x - 0.5).squared.abs + pos_sl.y.squared).sqrt, amps_lr; var abs_dist = distance * max_distance; amps_lr = [(pos_sl.x.squared + pos_sl.y.squared).sqrt, ((pos_sl.x - 1.0).squared.abs + pos_sl.y.squared).sqrt]; // Calculate delay time from source rel_delay_time = abs_dist / sound_speed; amps_lr.value.postln; // Set synth parameters source_synth.set( //\amps, (((amps_lr) - 1.42).abs) * max_distance.reciprocal, \amps, (((amps_lr) - 1.42).abs), \lp_freq, ((1 - pos_sl.y) * 19600) + 400, \delay_time, rel_delay_time); }); // Set default position of slider (front, centre) pos_slider.setXYActive(0.5, 0.0); // Distance value box callback -------------------------------------------- depth_valbox.action_({ |max_dist| max_distance = max_dist.value; // pos_slider.action; }); // Free synth on window close ------------------------------------------ pos_window.onClose = { source_synth.free; }; // Close windoe on CMD-. ----------------------------------------------- //CmdPeriod.doOnce({ pos_window.close; }); ) // ================================= // TO DO: work max_distance into pan/depth algorithm better - link in speaker spread parameter // add reverb on buss // allow changing audio source
Day 13
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 13 September 2009 Trying out buffers - plays a random file snippet every execution... but loops don't change :-( ========================================================================== */
( // Open dialog to get path to file ---- CocoaDialog.getPaths({ arg paths; paths.do({ arg file_path; // Declare variables ------------------ var buf, buf_chans, buf_frames, start_frame, end_frame, block_time; // Read buffer using file path ------- buf = Buffer.read(s, file_path, action: { buf_chans = buf.numChannels; buf_frames = buf.numFrames; // Stereo files (couldn't figure out BufChannels.kr) { Out.ar(0, Pan2.ar(BufRd.ar(buf_chans, buf.bufnum, Phasor.ar(0, 1, buf_frames.rand, buf_frames.rand), 1))) }.play; }); }); }, { "Cancelled".postln; }); )
Day 14
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 14 September 2009 Trying out buffers - yesterday's random file section player with UI ========================================================================== */
( // Declare variables var file_path, play_func, buf, buf_chans, buf_frames, start_frame, end_frame, block_time; // Define UI elements var ui_window = SCWindow("File-ulator", Rect(100, 100, 200, 200)); var load_button = SCButton(ui_window, Rect(10, 10, 80, 20)).states_([["Load file"]]); var playstop_button = SCButton(ui_window, Rect(10, 35, 80, 20)) .states_([["Play", Color.black, Color.green], ["Stop", Color.black, Color.red]]); ui_window.front; // Define load button action (get path to audio file) load_button.action_({ // Open dialog to get path to file ---- CocoaDialog.getPaths({ arg paths; paths.do({ arg path; file_path = path; // Free buffer if already filled if(buf != nil, { buf.free; "Buffer freed".postln; }); buf = Buffer.read(s, file_path); }); }, { "File load cancelled".postln; }); }); playstop_button.action_({ |play_state| if(play_state.value == 1, { if(file_path != nil, { "Playing".postln; buf_chans = buf.numChannels; buf_frames = buf.numFrames; play_func = { Out.ar(0, Pan2.ar(BufRd.ar(buf_chans, buf.bufnum, Phasor.ar(0, 1, buf_frames.rand, buf_frames.rand), 1))) }.play; }, { "No file loaded".postln; }); }, { //"Stop".postln; play_func.free; }) }); ) // TO DO: add amplitude envelope to stop loop clicking // have new random values every loop (maybe use routines?)
Day 15
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 15 September 2009 Experimenting with routines. ========================================================================== */
// SynthDef definition =============================================== ( SynthDef(\routine_sine, { var env = EnvGen.ar( Env([0, 1, 1, 0], [0.01, 0.1, 0.2]), levelScale: 0.5, doneAction: 2 // Important to release synth with routines ); Out.ar(0, SinOsc.ar([ExpRand(40, 10000), ExpRand(40, 10000)], 0, 0.5) * env); }).load(s); ) // Routine code ====================================================== ( var rout = Routine.new({ inf.do({ Synth(\routine_sine); 0.0625.wait; // Wait quarter of a second between triggering Synths }); }); rout.play; ) // Don't forget {}.fork, which wraps a given function in a routine and plays it // Fork code (same as routine code) ================================== ( { inf.do({ Synth(\routine_sine); 0.0625.wait; // Wait quarter of a second between triggering Synths }); }.fork; )
Day 16
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 16 September 2009 Integrating routines with buffers ========================================================================== */
( // Declare variables var file_path, buf, play_rout; // Define UI elements var ui_window = SCWindow("Random File-ulator", Rect(100, 100, 200, 200)); var load_button = SCButton(ui_window, Rect(10, 10, 80, 20)).states_([["Load file"]]); var playstop_button = SCButton(ui_window, Rect(10, 35, 80, 20)) .states_([["Play", Color.black, Color.green], ["Stop", Color.black, Color.red]]); ui_window.front; // Define load button action (get path to audio file) load_button.action_({ // Open dialog to get path to file ---- CocoaDialog.getPaths({ arg paths; paths.do({ arg path; file_path = path; // Free buffer if already filled if(buf != nil, { buf.free; "Buffer freed".postln; }); buf = Buffer.read(s, file_path); }); }, { "File load cancelled".postln; }); }); // Define action of play/stop button playstop_button.action_({ |play_state| if(play_state.value == 1, { if(file_path != nil, { "Playing".postln; play_rout = Routine.new({ inf.do({ //Synth(\routine_sine); Synth(\rand_audio_segment, [\bufno, 0]); 0.25.wait; // Wait quarter of a second between triggering Synths }); }); play_rout.play; }, { "No file loaded".postln; }); }, { play_rout.stop; }) }); // SynthDef definition --------------------------------------------------- SynthDef(\rand_audio_segment, { |bufno = 0| var env, bufrd, phasor, buf_frames; env = EnvGen.ar( Env.linen(0.1, 0.8, 0.1, 0.6), levelScale: 0.5, doneAction: 2 // Important to release synth with routines ); phasor = Phasor.ar(0, 1, BufFrames.ir(bufno) * Rand(0.0, 1.0), BufFrames.ir(bufno) * Rand(0.0, 1.0)); bufrd = BufRd.ar(2, bufno, phasor, 0); Out.ar(0, Pan2.ar(bufrd * env)); }).load(s); ) // TO DO: Test a bit
Day 17
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 17 September 2009 Integrating routines with buffers, more from yesterday's code ========================================================================== */
( // Declare variables var file_path, buf, play_rout; // Define UI elements var ui_window = SCWindow("Random File-ulator", Rect(100, 100, 300, 70)); var load_button = SCButton(ui_window, Rect(10, 10, 80, 20)).states_([["Load file"]]); var playstop_button = SCButton(ui_window, Rect(10, 35, 80, 20)) .states_([["Play", Color.black, Color.green], ["Stop", Color.black, Color.red]]); var file_loaded = SCStaticText(ui_window, Rect(100, 10, 120, 20)).string = ""; ui_window.front; // Define load button action (get path to audio file) load_button.action_({ // Open dialog to get path to file ---- CocoaDialog.getPaths({ arg paths; paths.do({ arg path; file_path = path; // Free buffer if already filled if(buf != nil, { buf.free; "Buffer freed".postln; }); buf = Buffer.read(s, file_path); file_loaded.string = file_path.basename; }); }, { "File load cancelled".postln; }); }); // Define action of play/stop button playstop_button.action_({ |play_state| if(play_state.value == 1, { if(file_path != nil, { "Playing".postln; play_rout = Routine.new({ inf.do({ Synth(\rand_audio_segment, [\bufno, 0]); 0.25.wait; // Wait quarter of a second between triggering Synths }); }); play_rout.play; }, { "No file loaded".postln; }); }, { play_rout.stop; }) }); // SynthDef definition --------------------------------------------------- SynthDef(\rand_audio_segment, { |bufno = 0, block_time = 1.0| var env, bufrd, phasor, start_point, end_point; start_point = BufFrames.kr(bufno) * Rand(0.0, 1.0); end_point = BufFrames.kr(bufno) * Rand(0.0, 1.0); env = EnvGen.ar( Env.linen(0.05, block_time - 0.1, 0.05, 0.6), levelScale: 0.5, doneAction: 2 // Important to release synth with routines ); phasor = Phasor.ar(0, 1, start_point, end_point); bufrd = BufRd.ar(2, bufno, phasor, 0); Out.ar(0, Pan2.ar(bufrd * env)); }).load(s); )
Day 18
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 18 September 2009 Audio input field disturber (or something like that...) ========================================================================== */
( // Synth variable (for some reason it has to be up here to work(?)) var ifd_synth; // ControlSpec definitions ---------------------------------------------------- var del_mod_freq_cs = [0.01, 10.0, \exponential, 0.01, 0.01, "Hz"].asSpec; var del_mod_sweep_cs = [0.0, 1.0, \linear, 0.01, 0.1, "secs"].asSpec; // UI setting ----------------------------------------------------------------- var ifd_window, del_mod_freq_l, del_mod_freq_r, del_mod_sweep_l, del_mod_sweep_r; // ---------- UI window ifd_window = Window("Input Field Disturber", Rect(100, 100, 400, 100)).front; ifd_window.view.decorator = FlowLayout(ifd_window.view.bounds); ifd_window.view.decorator.gap = 2@2; // ---------- UI sliders del_mod_freq_l = EZSlider(ifd_window, 392@20, " Delay mod frequency L ", del_mod_freq_cs, unitWidth: 30, numberWidth: 60, labelWidth: 136); del_mod_freq_l.setColors(Color.grey); del_mod_sweep_l = EZSlider(ifd_window, 392@20, " Delay mod sweep L ", del_mod_sweep_cs, unitWidth: 30, numberWidth: 60, labelWidth: 136); del_mod_sweep_l.setColors(Color.grey); del_mod_freq_r = EZSlider(ifd_window, 392@20, " Delay mod frequency R ", del_mod_freq_cs, unitWidth: 30, numberWidth: 60, labelWidth: 136); del_mod_freq_r.setColors(Color.grey); del_mod_sweep_r = EZSlider(ifd_window, 392@20, " Delay mod sweep R ", del_mod_sweep_cs, unitWidth: 30, numberWidth: 60, labelWidth: 136); del_mod_sweep_r.setColors(Color.grey); // SynthDef definition -------------------------------------------------------- SynthDef(\input_field_disturber, { |mod_freq_l = 0.01, mod_freq_r = 0.01, mod_sweep_l = 0.5, mod_sweep_r = 0.5| var input, delays, delay_mod_l, delay_mod_r; // Input source input = SoundIn.ar(0); // Left and right delay time modulators delay_mod_l = SinOsc.ar(mod_freq_l, 0, mod_sweep_l, mod_sweep_l); delay_mod_r = SinOsc.ar(mod_freq_r, 0, mod_sweep_r, mod_sweep_r); // Use multi-channel expansion to make stereo delays = DelayC.ar(input, 1.0, [delay_mod_l, delay_mod_r], 0.6); // Output destination Out.ar(0, delays); }).load(s); // Create synth ifd_synth = Synth(\input_field_disturber); // Slider action functions -------------------------------------------------- del_mod_freq_l.action_({ |mod_freq_l_val| ifd_synth.set(\mod_freq_l, mod_freq_l_val.value); }); del_mod_sweep_l.action_({ |mod_sweep_l_val| ifd_synth.set(\mod_sweep_l, mod_sweep_l_val.value); }); del_mod_freq_r.action_({ |mod_freq_r_val| ifd_synth.set(\mod_freq_r, mod_freq_r_val.value); }); del_mod_sweep_r.action_({ |mod_sweep_r_val| ifd_synth.set(\mod_sweep_r, mod_sweep_r_val.value); }); // Free synth on window close ----------------------------------------------- ifd_window.onClose = { ifd_synth.free; }; ) // Sounds awesome! Especially if used in a controlled-feedback situation.
Day 19
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 19 September 2009 Simple exercise because I couldn't think of anything else to do ========================================================================== */
( // Generate 50 sine waves 1Hz apart var crazy_sines_window, crazy_sines_volume, crazy_sines_synth; // ---------- UI window crazy_sines_window = Window("Crazy sine field", Rect(100, 100, 400, 100)).front; crazy_sines_window.view.decorator = FlowLayout(crazy_sines_window.view.bounds); crazy_sines_window.view.decorator.gap = 2@2; // ---------- UI sliders crazy_sines_volume = EZSlider(crazy_sines_window, 392@20, " Volume ", unitWidth: 30, numberWidth: 60, labelWidth: 136); crazy_sines_volume.setColors(Color.grey); // Syntho-deffo-definitiono SynthDef(\crazy_sine_field, { |volume = 0.0| var n = 50, freq_mod, freq_freq_mod; freq_freq_mod = WhiteNoise.ar(1.0, 1.0); freq_mod = SinOsc.ar(0.25, 0, 1.0, 1.0) + 50; // n mad_modulated sine waves panned across stereo image with Splay Out.ar(0, Splay.ar(SinOsc.ar((((1..n) / freq_freq_mod) + freq_mod), 0.0, 1/n) * volume)); }).load(s); crazy_sines_synth = Synth(\crazy_sine_field); // Slider action ----------------------------------------------------------- crazy_sines_volume.action_({ |vol| crazy_sines_synth.set(\volume, vol.value); }); // Free synth on window close ----------------------------------------------- crazy_sines_window.onClose = { crazy_sines_synth.free; }; ) // Noise crazy sine waves
Day 20
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 20 September 2009 Crazy pitch follower ========================================================================== */
( a = { var input = SoundIn.ar([0, 1]); // Take computer sound in var mouse_x = MouseX.kr(0.0, 0.2, 0).postln; // Mouse gate threshold control var in_gate = Compander.ar(input, input, mouse_x, 10, 1, 0.01, 0.01); var fund_freq = ZeroCrossing.ar(in_gate); // Lo qual pitch tracking // Assign tracked pitch to oscillator SinOsc.ar(fund_freq, 0, 0.5); }.play; ) a.free;
Day 21
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 21 September 2009 Beginnings of a GrainFM synth ========================================================================== */
( // Variable declaration --------------------------------------------------- var grainfm_window, impulse_l_freq, impulse_r_freq, impulse_link, grain_fm_synth; // ControlSpec definitions ------------------------------------------------ var lo_freq_cs = [0.01, 10.0, \exponential, 0.01, 1.0, "Hz"].asSpec; var lo_mid_freq_cs = [0.01, 100.0, \exponential, 0.01, 1.0, "Hz"].asSpec; // UI setting ------------------------------------------------------------- grainfm_window = SCWindow("GrainFM synth", Rect(200, 200, 400, 300)).front; grainfm_window.view.decorator = FlowLayout(grainfm_window.view.bounds); grainfm_window.view.decorator.gap = 2@2; impulse_l_freq = EZSlider(grainfm_window, 392@20, " Impulse L frequency ", lo_mid_freq_cs, unitWidth: 30, numberWidth: 60, labelWidth: 136); impulse_l_freq.setColors(Color.grey); impulse_r_freq = EZSlider(grainfm_window, 392@20, " Impulse R frequency ", lo_mid_freq_cs, unitWidth: 30, numberWidth: 60, labelWidth: 136); impulse_r_freq.setColors(Color.grey); impulse_link = SCButton(grainfm_window, 100@20) .states_([ ["Link impulses"], ["Unlink impulses"] ]); // SynthDef definition ---------------------------------------------------- SynthDef(\grainFM_synth, { |imp_l_freq = 1.0, imp_r_freq = 1.0| var mod_1, mod_2, impulses; // Define variables mod_1 = SinOsc.ar(0.04, 0, 40, 400); mod_2 = SinOsc.ar(0.05, 0, 30, 200); impulses = [Impulse.ar(imp_l_freq), Impulse.ar(imp_r_freq)]; Out.ar(0, GrainFM.ar(2, impulses, 0.05, mod_1, mod_2)); }).load(s); // Set up synth from SynthDef --------------------------------------------- grain_fm_synth = Synth(\grainFM_synth); // UI control actions ----------------------------------------------------- impulse_l_freq.action_({ |imp_l_slider| grain_fm_synth.set(\imp_l_freq, imp_l_slider.value); if(impulse_link.value == 1, { impulse_r_freq.value_(imp_l_slider.value); grain_fm_synth.set(\imp_r_freq, imp_l_slider.value); }) }); impulse_r_freq.action_({ |imp_r_slider| grain_fm_synth.set(\imp_r_freq, imp_r_slider.value); }); impulse_link.action_({ |imp_link_but| if(imp_link_but.value == 1, { impulse_r_freq.view.enabled = false; }, { impulse_r_freq.view.enabled = true; } ); }); // Close window action ---------------------------------------------------- grainfm_window.onClose_({ grain_fm_synth.free }); ) // TO DO: Put in more UI controls
Day 22
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 22 September 2009 GrainFM synth, with multiple parameters ========================================================================== */
( // Variable declaration --------------------------------------------------- var grain_fm_synth, grainfm_window, grain_title, grain_size, mod_title, mod_1_freq, mod_2_freq, mod_1_range, mod_2_range, mod_1_base, mod_2_base, impulse_title, impulse_l_freq, impulse_r_freq, impulse_link, out_title, volume; var ui_point = 392@20, unit_width = 36, number_width = 60, label_width = 136; // ControlSpec definitions ------------------------------------------------ var grain_size_cs = [0.01, 1.0, \linear, 0.01, 0.05, "secs"].asSpec; var lo_freq_cs = [0.01, 10.0, \exponential, 0.01, 1.0, "Hz"].asSpec; var lo_mid_freq_cs = [0.1, 100.0, \exponential, 0.01, 1.0, "Hz"].asSpec; var mod_range_cs = [1, 100.0, \exponential, 0.1, 10.0, "Hz"].asSpec; var mod_base_cs = [20, 4000.0, \exponential, 0.1, 200.0, "Hz"].asSpec; var volume_cs = [0.0, 1.0, \linear, 0.01, 0.6, "level"].asSpec; // UI setting ------------------------------------------------------------- grainfm_window = SCWindow("GrainFM synth", Rect(200, 200, 400, 350)).front; grainfm_window.view.decorator = FlowLayout(grainfm_window.view.bounds); grainfm_window.view.decorator.gap = 2@2; // ------------- Grain section grain_title = SCStaticText(grainfm_window, ui_point).string = " Grain settings "; grain_title.background = Color.black; grain_title.stringColor = Color.grey; grain_size = EZSlider(grainfm_window, ui_point, " Grain size ", grain_size_cs, unitWidth: unit_width, numberWidth: number_width, labelWidth: label_width); grain_size.setColors(Color.grey); // ------------- Modulator section mod_title = SCStaticText(grainfm_window, ui_point).string = " Modulator settings "; mod_title.background = Color.black; mod_title.stringColor = Color.grey; mod_1_freq = EZSlider(grainfm_window, ui_point, " Modulator 1 frequency ", lo_freq_cs, unitWidth: unit_width, numberWidth: number_width, labelWidth: label_width); mod_1_freq.setColors(Color.grey); mod_2_freq = EZSlider(grainfm_window, ui_point, " Modulator 2 frequency ", lo_freq_cs, unitWidth: unit_width, numberWidth: number_width, labelWidth: label_width); mod_2_freq.setColors(Color.grey); mod_1_range = EZSlider(grainfm_window, ui_point, " Modulator 1 range ", mod_range_cs, unitWidth: unit_width, numberWidth: number_width, labelWidth: label_width); mod_1_range.setColors(Color.grey); mod_2_range = EZSlider(grainfm_window, ui_point, " Modulator 2 range ", mod_range_cs, unitWidth: unit_width, numberWidth: number_width, labelWidth: label_width); mod_2_range.setColors(Color.grey); mod_1_base = EZSlider(grainfm_window, ui_point, " Modulator 1 base ", mod_base_cs, unitWidth: unit_width, numberWidth: number_width, labelWidth: label_width); mod_1_base.setColors(Color.grey); mod_2_base = EZSlider(grainfm_window, ui_point, " Modulator 2 base ", mod_base_cs, unitWidth: unit_width, numberWidth: number_width, labelWidth: label_width); mod_2_base.setColors(Color.grey); // ------------- Impulse section impulse_title = SCStaticText(grainfm_window, ui_point).string = " Impulse settings "; impulse_title.background = Color.black; impulse_title.stringColor = Color.grey; impulse_l_freq = EZSlider(grainfm_window, ui_point, " Impulse L frequency ", lo_mid_freq_cs, unitWidth: unit_width, numberWidth: number_width, labelWidth: label_width); impulse_l_freq.setColors(Color.grey); impulse_r_freq = EZSlider(grainfm_window, ui_point, " Impulse R frequency ", lo_mid_freq_cs, unitWidth: unit_width, numberWidth: number_width, labelWidth: label_width); impulse_r_freq.setColors(Color.grey); impulse_link = SCButton(grainfm_window, 100@20) .states_([ ["Link impulses"], ["Unlink impulses"] ]); // -------------- Out section out_title = SCStaticText(grainfm_window, ui_point).string = " Output settings "; out_title.background = Color.black; out_title.stringColor = Color.grey; volume = EZSlider(grainfm_window, ui_point, " Volume ", volume_cs, unitWidth: unit_width, numberWidth: number_width, labelWidth: label_width); volume.setColors(Color.grey); // SynthDef definition ---------------------------------------------------- SynthDef(\grainFM_synth, { |grain_size_secs = 0.05, mod_1_frequency = 1.0, mod_2_frequency = 1.0, mod_1_freq_range = 10.0, mod_2_freq_range = 10.0, mod_1_base_freq = 200.0, mod_2_base_freq = 200.0, imp_l_freq = 1.0, imp_r_freq = 1.0, volume_lev = 0.6| var mod_1, mod_2, impulses; // Define variables mod_1 = SinOsc.ar(mod_1_frequency, 0, mod_1_freq_range, mod_1_base_freq); mod_2 = SinOsc.ar(mod_2_frequency, 0, mod_2_freq_range, mod_2_base_freq); impulses = [Impulse.ar(imp_l_freq), Impulse.ar(imp_r_freq)]; Out.ar(0, GrainFM.ar(2, impulses, grain_size_secs, mod_1, mod_2) * volume_lev); }).load(s); // Set up synth from SynthDef --------------------------------------------- grain_fm_synth = Synth(\grainFM_synth); // UI control actions ----------------------------------------------------- grain_size.action_({ |grain_size_slider| grain_fm_synth.set(\grain_size_secs, grain_size_slider.value); }); mod_1_freq.action_({ |mod_1_freq_slider| grain_fm_synth.set(\mod_1_frequency, mod_1_freq_slider.value); }); mod_2_freq.action_({ |mod_2_freq_slider| grain_fm_synth.set(\mod_2_frequency, mod_2_freq_slider.value); }); mod_1_range.action_({ |mod_1_range_slider| grain_fm_synth.set(\mod_1_freq_range, mod_1_range_slider.value); }); mod_2_range.action_({ |mod_2_range_slider| grain_fm_synth.set(\mod_2_freq_range, mod_2_range_slider.value); }); mod_1_base.action_({ |mod_1_base_slider| grain_fm_synth.set(\mod_1_base_freq, mod_1_base_slider.value); }); mod_2_base.action_({ |mod_2_base_slider| grain_fm_synth.set(\mod_2_base_freq, mod_2_base_slider.value); }); impulse_l_freq.action_({ |imp_l_slider| grain_fm_synth.set(\imp_l_freq, imp_l_slider.value); // Change value of Impulse R as well if linked if(impulse_link.value == 1, { impulse_r_freq.value_(imp_l_slider.value); grain_fm_synth.set(\imp_r_freq, imp_l_slider.value); }) }); impulse_r_freq.action_({ |imp_r_slider| grain_fm_synth.set(\imp_r_freq, imp_r_slider.value); }); impulse_link.action_({ |imp_link_but| // Disable Impulse R slider is linked if(imp_link_but.value == 1, { impulse_r_freq.view.enabled = false; }, { impulse_r_freq.view.enabled = true; } ); }); volume.action_({ |volume_slider| grain_fm_synth.set(\volume_lev, volume_slider.value); }); // Close window action ---------------------------------------------------- grainfm_window.onClose_({ grain_fm_synth.free }); )
Day 23
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 23 September 2009 Sample-to-synth ========================================================================== */
( // Declare variables var file_path, buf, sts_synth; // Define UI elements var sts_window = SCWindow("Samples to synth", Rect(100, 100, 300, 100)); var load_button = SCButton(sts_window, Rect(10, 10, 80, 20)).states_([["Load file"]]); var playstop_button = SCButton(sts_window, Rect(10, 35, 80, 20)) .states_([["Play", Color.black, Color.green], ["Stop", Color.black, Color.red]]); sts_window.front; // DEFINE UI CONTROL ACTIONS ----------------------------------------------- // Define load button action (get path to audio file) load_button.action_({ // Open dialog to get path to file ---- CocoaDialog.getPaths({ arg paths; paths.do({ arg path; file_path = path; // Free buffer if already filled if(buf != nil, { buf.free; "Buffer freed".postln; }); buf = Buffer.read(s, file_path); }); }, { "File load cancelled".postln; }); }); playstop_button.action_({ |play_state| if(play_state.value == 1, { if(file_path != nil, { "Playing".postln; sts_synth = Synth(\samples_to_synth); }, { "No file loaded".postln; play_state.value_(0); }); }, { "Stopped".postln; sts_synth.free; }) }); // DEFINE SYNTHDEF ------------------------------------------------------ SynthDef(\samples_to_synth, { var control = PlayBuf.ar(2, 0, 1.0, loop: 1); Out.ar(0, Pan2.ar(SinOsc.ar(control * 5000, 0.0, 0.5) * control, 0.0)); }).load(s); )
Day 24
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 24 September 2009 Simple Sampler ========================================================================== */
( // Declare variables var sds_buf_time = 10.0, sds_file_path, sds_buf, sds_rec_synth, sds_play_synth, play_button_clock, rec_button_clock; // Define UI elements var sds_window = SCWindow("Simple Sampler", Rect(100, 100, 300, 100)); var record_button = SCButton(sds_window, Rect(10, 10, 80, 20)) .states_([["Record", Color.red], ["Recording", Color.white, Color.red]]); var playstop_button = SCButton(sds_window, Rect(10, 35, 80, 20)) .states_([["Play", Color.black, Color.green], ["Stop", Color.black, Color.blue]]); sds_window.front; // Allocate buffer sds_buf = Buffer.alloc(s, s.sampleRate * sds_buf_time, 1); // SYNTHDEF DEFINITIONS ----------------------------------------- SynthDef(\record_from_in, { |buf_num = 0| RecordBuf.ar(SoundIn.ar(0), buf_num, loop: 1, doneAction: 2); }).load(s); SynthDef(\play_buf, { |buf_num = 0| Out.ar(0,Pan2.ar(PlayBuf.ar(1, buf_num, 1.0, loop: 1, doneAction: 2))); }).load(s); // UI CONTROL ACTIONS ------------------------------------------- record_button.action_({ |record_button_val| if(record_button_val.value == 1, { sds_rec_synth = Synth(\record_from_in); }, { sds_rec_synth.free; }); }); playstop_button.action_({ |playstop_button_val| if(playstop_button_val.value == 1, { sds_play_synth = Synth(\play_buf); }, { sds_play_synth.free; }); }); // WINDOW CLOSE ACTION ------------------------------------------- sds_window.onClose_({ sds_rec_synth.free; sds_play_synth.free; }); ) // TO DO: Fix onClose freeing of synths (as they may already be free) // Play with playback speed
Day 25
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 25 September 2009 Sample-to-synth, with UI ========================================================================== */
( // Declare variables var file_path, buf, sts_synth, sts_window, load_button, playstop_button, sts_freq_mod, sts_volume; // ControlSpec defs ------------------------------------ var sts_freq_mod_cs = [10, 10000.0, \exponential, 0.01, 1000, "Hz"].asSpec; // Define UI elements ---------------------------------- sts_window = SCWindow("Samples to synth", Rect(100, 100, 300, 100)).front; sts_window.view.decorator = FlowLayout(sts_window.view.bounds); sts_window.view.decorator.gap = 2@2; load_button = SCButton(sts_window, Rect(10, 10, 80, 20)).states_([["Load file"]]); playstop_button = SCButton(sts_window, Rect(10, 35, 80, 20)) .states_([["Play", Color.black, Color.green], ["Stop", Color.black, Color.red]]); sts_freq_mod = EZSlider(sts_window, 292@20, " Freq mod ", sts_freq_mod_cs, unitWidth: 30, numberWidth: 50, labelWidth: 60); sts_freq_mod.setColors(Color.grey); sts_volume = EZSlider(sts_window, 292@20, " Volume ", unitWidth: 30, numberWidth: 50, labelWidth: 60).value_(1.0); sts_volume.setColors(Color.grey); // DEFINE UI CONTROL ACTIONS ----------------------------------------------- // Define load button action (get path to audio file) load_button.action_({ // Open dialog to get path to file ---- CocoaDialog.getPaths({ arg paths; paths.do({ arg path; file_path = path; // Free buffer if already filled if(buf != nil, { buf.free; "Buffer freed".postln; }); buf = Buffer.read(s, file_path); }); }, { "File load cancelled".postln; }); }); playstop_button.action_({ |play_state| if(play_state.value == 1, { if(file_path != nil, { "Playing".postln; sts_synth = Synth(\samples_to_synth); }, { "No file loaded".postln; play_state.value_(0); }); }, { "Stopped".postln; sts_synth.free; }) }); sts_freq_mod.action_({ |freq_mod_val| sts_synth.set(\freq_mod, freq_mod_val.value); }); sts_volume.action_({ |vol_val| sts_synth.set(\volume, vol_val.value); }); // DEFINE SYNTHDEF ------------------------------------------------------ SynthDef(\samples_to_synth, { |freq_mod = 1000.0, volume = 1.0| var control = PlayBuf.ar(2, 0, 1.0, loop: 1); Out.ar(0, Pan2.ar(SinOsc.ar(control * freq_mod, 0.0, 0.5) * control * volume, 0.0)); }).load(s); )
Day 26
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 26 September 2009 Beginnings of a Keyboard synth ========================================================================== */
( // Declare variables var ks_window, ks_sine, ks_saw, ks_square, ks_filt_co, ks_filt_res, ks_volume, keyboard_synth; var label_width = 80; // Define ControlSpecs var filter_freq_cs = [10, 16000.0, \exponential, 1.0, 10000.0, "Hz"].asSpec; // Define UI elements ks_window = SCWindow("Keyboard synth", Rect(100, 100, 300, 160)).front; ks_window.view.decorator = FlowLayout(ks_window.view.bounds); ks_window.view.decorator.gap = 2@2; ks_sine = EZSlider(ks_window, 292@20, " Sine ", unitWidth: 30, numberWidth: 50, labelWidth: label_width).value_(1.0); ks_sine.setColors(Color.grey); ks_saw = EZSlider(ks_window, 292@20, " Saw ", unitWidth: 30, numberWidth: 50, labelWidth: label_width); ks_saw.setColors(Color.grey); ks_square = EZSlider(ks_window, 292@20, " Square ", unitWidth: 30, numberWidth: 50, labelWidth: label_width); ks_square.setColors(Color.grey); ks_filt_co = EZSlider(ks_window, 292@20, " Cut off ", filter_freq_cs, unitWidth: 30, numberWidth: 50, labelWidth: label_width); ks_filt_co.setColors(Color.grey); ks_filt_res = EZSlider(ks_window, 292@20, " Resonance ", unitWidth: 30, numberWidth: 50, labelWidth: label_width); ks_filt_res.setColors(Color.grey); ks_volume = EZSlider(ks_window, 292@20, " Volume ", unitWidth: 30, numberWidth: 50, labelWidth: label_width).value_(1.0); ks_volume.setColors(Color.grey); // SYNTHDEF DEFINITIONS ----------------------------------------- SynthDef(\keyboard_synth, { |sine_level = 1.0, saw_level = 0.0, square_level = 0.0, filter_freq = 10000, filter_res = 0.0| var sine = SinOsc.ar(440.0, 0.0, sine_level); var saw = Saw.ar(440.0, saw_level); var square = Pulse.ar(440.0, 0.5, square_level); var mix = Mix.new([sine, saw, square]); Out.ar(0, Pan2.ar(MoogFF.ar(mix, Lag2.kr(filter_freq, 0.3), filter_res))); }).load(s); keyboard_synth = Synth(\keyboard_synth); // UI CONTROL ACTIONS ------------------------------------------- ks_sine.action_({ |sine_val| keyboard_synth.set(\sine_level, sine_val.value); }); ks_saw.action_({ |saw_val| keyboard_synth.set(\saw_level, saw_val.value); }); ks_square.action_({ |square_val| keyboard_synth.set(\square_level, square_val.value); }); ks_filt_co.action_({ |filt_co_val| keyboard_synth.set(\filter_freq, filt_co_val.value); }); ks_filt_res.action_({ |filt_res_val| keyboard_synth.set(\filter_res, filt_res_val.value); }); // WINDOW CLOSE ACTION ------------------------------------------- ks_window.onClose_({ keyboard_synth.free; }); )
Day 27
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 27 September 2009 ASCII keyboard testing ========================================================================== */
( var keyboard_test_window, keyboard_test_label, key_down_state; keyboard_test_window = SCWindow("Keyboard test", Rect(100, 100, 300, 100)).front; keyboard_test_label = SCStaticText(keyboard_test_window, Rect(10, 10, 280, 80)); keyboard_test_label.font = Font("Arial", 42); keyboard_test_label.string = "B"; key_down_state = 0; keyboard_test_window.view.keyDownAction = { |view, char, modifiers, unicode, keycode| // Stops repeating key down message if(key_down_state == 0, { ["Key down", char, keycode].postln; keyboard_test_label.string = [char, keycode, unicode]; key_down_state = 1; }); }; keyboard_test_window.view.keyUpAction = { |view, char, modifiers, unicode, keycode| ["Key up", char, keycode].postln; keyboard_test_label.string = ""; // Reset key down state flag key_down_state = 0; }; )
Day 28
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 28 September 2009 Continuation of Keyboard synth (monophonic) ========================================================================== */
( // Declare variables ---------------------------------------------- var ks_window, ks_sine, ks_saw, ks_square, ks_filt_co, ks_filt_res, ks_volume, keyboard_synth, key_down_state; var label_width = 80; // Define ControlSpecs -------------------------------------------- var filter_freq_cs = [10, 16000.0, \exponential, 1.0, 10000.0, "Hz"].asSpec; // Define UI elements --------------------------------------------- ks_window = SCWindow("Keyboard synth", Rect(100, 100, 300, 160)).front; ks_window.view.decorator = FlowLayout(ks_window.view.bounds); ks_window.view.decorator.gap = 2@2; ks_sine = EZSlider(ks_window, 292@20, " Sine ", unitWidth: 30, numberWidth: 50, labelWidth: label_width).value_(1.0); ks_sine.setColors(Color.grey); ks_saw = EZSlider(ks_window, 292@20, " Saw ", unitWidth: 30, numberWidth: 50, labelWidth: label_width); ks_saw.setColors(Color.grey); ks_square = EZSlider(ks_window, 292@20, " Square ", unitWidth: 30, numberWidth: 50, labelWidth: label_width); ks_square.setColors(Color.grey); ks_filt_co = EZSlider(ks_window, 292@20, " Cut off ", filter_freq_cs, unitWidth: 30, numberWidth: 50, labelWidth: label_width); ks_filt_co.setColors(Color.grey); ks_filt_res = EZSlider(ks_window, 292@20, " Resonance ", unitWidth: 30, numberWidth: 50, labelWidth: label_width); ks_filt_res.setColors(Color.grey); ks_volume = EZSlider(ks_window, 292@20, " Volume ", unitWidth: 30, numberWidth: 50, labelWidth: label_width).value_(1.0); ks_volume.setColors(Color.grey); // SYNTHDEF DEFINITIONS ----------------------------------------- SynthDef(\keyboard_synth, { |sine_level = 1.0, saw_level = 0.0, square_level = 0.0, filter_freq = 10000, filter_res = 0.0, amp = 0.0, freq = 200.0| var sine = SinOsc.ar(freq, 0.0, sine_level); var saw = Saw.ar(freq, saw_level); var square = Pulse.ar(freq, 0.5, square_level); var mix = Mix.new([sine, saw, square]); Out.ar(0, Pan2.ar(MoogFF.ar(mix, Lag2.kr(filter_freq, 0.3), filter_res) * amp)); }).load(s); keyboard_synth = Synth(\keyboard_synth); // UI CONTROL ACTIONS ------------------------------------------- // Set up keyboard functionality -------- key_down_state = 0; ks_window.view.keyDownAction = { |view, char, modifiers, unicode, keycode| // Stops repeating key down message if(key_down_state == 0, { ["Key down", char, keycode].postln; keyboard_synth.set(\amp, 1.0); keyboard_synth.set(\freq, ((unicode - 96) * 50) + 100); key_down_state = 1; }); }; ks_window.view.keyUpAction = { |view, char, modifiers, unicode, keycode| //["Key up", char, keycode].postln; keyboard_synth.set(\amp, 0.0); // Reset key down state flag key_down_state = 0; }; // Sliders ------------------------------ ks_sine.action_({ |sine_val| keyboard_synth.set(\sine_level, sine_val.value); }); ks_saw.action_({ |saw_val| keyboard_synth.set(\saw_level, saw_val.value); }); ks_square.action_({ |square_val| keyboard_synth.set(\square_level, square_val.value); }); ks_filt_co.action_({ |filt_co_val| keyboard_synth.set(\filter_freq, filt_co_val.value); }); ks_filt_res.action_({ |filt_res_val| keyboard_synth.set(\filter_res, filt_res_val.value); }); // WINDOW CLOSE ACTION ------------------------------------------- ks_window.onClose_({ keyboard_synth.free; }); ) // TO DO: keyboard action needs work // selecting another control in the UI messes things up // making it polyphonic would be awesome
Day 29
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 29 September 2009 Something random in one function ========================================================================== */
( { var freqs = #[40, 50, 60, 70]; Splay.ar(Saw.ar(SinOsc.ar(Saw.ar(SinOsc.ar(freqs, 0.0, 1.0)) * freqs, 0.0, 1.0) * 100.0, 1.0)); }.play; )
Day 30
/* ========================================================================== Supercollider a day - for HackPact 2009 ------------------- by Adam Jansch 30 September 2009 Speaking patch (for the farewell) ========================================================================== */
( // Declare UI controls ------------------------------------- var speak_window, speak_text, speak_button; // Define UI controls -------------------------------------- speak_window = SCWindow("Speaking patch", Rect(100, 100, 370, 60)).front; speak_text = SCTextField(speak_window, Rect(10, 10, 280, 40)) .font_(Font.new("Helvetica", 16)).focus(true).string_("Goodbye world!"); speak_button = SCButton(speak_window, Rect(300, 10, 60, 40)) .states_([["Speak", Color.black, Color.green]]); // UI control actions -------------------------------------- speak_text.action_({ |speak_text_val| speak_text_val.value.speak; }); speak_button.action_({ speak_text.value.speak; }); )