//========================================================== // SONIC SHREDDING MACHINE v0.2 //---------------------------------------------------------- // May 2011 - Joe Mariglio - www.joemariglio.com //========================================================== // // //========================================================== // // SONIC SHREDDER consists of 3 main components: // SHRED (4x) - granular instruments capable of // chopping, looping, and scrubbing soundfiles. // // SHATTER - a filterbank (with 8 bandpass filters) // each of which feeds a separate granulator and // separate delay line, useful for shattering a // sound into prickly particles or dense streams. // // SPIT - a 3-layer waveshaping distortion unit which // uses low-frequency sinusoids as its transfer // functions. // // Together with comprehensive MIDI support and preset // management, the SONIC SHREDDER is capable of a // nauseating universe of extreme sonic oblivion. // // // //---------------------------------------------------------- // **MASTER LEVELS** //---------------------------------------------------------- // // these default to 0, which is muted. there is one fader // for each module, and one fader (SUM) for the total // output of the SONIC SHREDDER. these may be // assigned to midi controllers and their values // stored in presets. // //---------------------------------------------------------- // **SHRED** (grains) //---------------------------------------------------------- // // amp - amplitude of the granular instrument. this gets // scaled by the SHRED master level fader at the // bottom left of the panel. // rate - the speed at which the cursor tracks through the // soundfile. in tracking mode, press either the ">" // or "<" button to determine the direction the cursor // will go. // pitch - the pitch of the grains. this gets modulated by // the "jpitch" parameter. // trate - the rate of new grains. new grains may be muted // randomly by the "prob" parameter. // dens - the duration of each grain in seconds. // prob - the probability that a new grain will occur at // trigger time. // pan - the pan position of the grains. -1 is left, 1 is // right. // width - randomness applied to pan position. // jpos - randomness applied to the position of the cursor // in the soundfile. // jpitch - randomness applied to pitch. // send_a - a pre-fader send to the SHATTER module. // send_b - a pre-fader send to the SPIT module. // scrb / trk - toggle scrubbing versus tracking mode. // in tracking mode, the cursor moves according to // the "rate" parameter, in the direction indicated // by the "<" and ">" buttons. it will loop over the // area defined by the blue range slider beneath the // cursor. // in scrubbing mode, you may manually move the cursor // over interesting parts of the soundfile. to enable // midi control over this parameter, you must be in // scrubbing mode. // ON - turns the granular unit on. you must have selected // a valid soundfile to granulate *and* a valid grain // envelope file (located beneath presets on the // top right of the panel). // //---------------------------------------------------------- // **SHATTER** (filterbank) //---------------------------------------------------------- // // freq - frequency of the bandpass filter, relative to a // fundamental. this value gets multiplied by the // "fund" parameter at the bottom of the filterbank. // rq - reciprocal of Q of the bandpass filter. Q is // defined as the frequency over the bandwidth, so // rQ is the bandwidth over the frequency. // Q = (fℴ / Δf) , so rQ = (Δf / fℴ) . // as rQ approaches zero, the resonance increases. // since filterbank this uses constant-Q filters, // the bandwidth will stay proportional to the // frequency. // del - delay time in seconds of the comb filter (delay). // this gets saled by the master "del" fader at the // bottom. // dec - 60 dB decay time in seconds of the comb filter. // // there are 8 of these filters, arranged in parallel. // after each filtering stage, there is a granulation // stage, where the probability of a grain passing // through is determined by the "prob" parameter. // SHATTER uses a hanning window for its grains. // the master control of "del" scales all of the individual // delay times in the filterbank. // send_b - a pre-fader send to the SPIT module. // // //---------------------------------------------------------- // **SPIT** (waveshaper) //---------------------------------------------------------- // // a waveshaper produces distortion by indexing into the // phase of a transfer function. the SPIT module uses // three independently tuneable sinusoids as its // transfer functions. these are applied in parallel, // and then summed together. // // f0, f1, f2 - the frequencies of each sinusoid. 0 Hz is // permitted (and is more or less the simplest case // to model with mathematics). // o0, o1, o2 - the phase offset of each sinusoid. // assuming frequency = 0 Hz, an offset of 0 will // provide odd harmonic distortion, because you are // indexing into a sine wave. an offset of π/2 will // provide even harmonic distortion, because you are // indexing into a cosine wave. all phases are // permitted. // pre0, pre1, pre2 - the pre-gain of each distortion // layer. think of this as the index of modulation // in Frequency Modulation synthesis. // post0, post1, post2 - the post-gain of each distortion // layer. think of this as the volume of the layer. // // these layers are summed, and their output is scaled by // the "SPIT" master level at the bottom left of // the panel. // //---------------------------------------------------------- // **PRESETS & MIDI** //---------------------------------------------------------- // // the SONIC SHREDDER is capable of storing preset scenes // which contain all fader values, all file paths, and // all midi routing data. these are stored as legal // supercollider code, to allow for easy manual // editing and debugging. // // saving & loading: // // to save a preset, simply click the "save" button, // locate a directory, and name the file in the // dialog. to load a preset, click the "load" button, // locate a previously saved preset, and open it. to // make your changes apply to the panel, hit the // "load" button again, which will now read "apply". // // no paths / load paths: // // sometimes, during playback, changing the path of the // soundfiles or the envelope file will cause stress // to the synthesis server, and could cause a crash. // to prevent the preset from loading these paths, // click the "no paths" button. it will toggle into // a "load paths" button. to safely load a new // soundfile or envelope, turn off the SHRED module you // wish to modify before making changes. if you would // like to make changes to the envelope file path, // you must turn off all SHRED modules. the SPIT and // SHATTER modules will not be affected. // // midi learn mode: // // to control a fader with a midi controller, simply // select the desired fader (not the number box or // label!) and hit the "L" key on your keyboard. // (shift is not necessary.) then wiggle the desired // controller. the fader should move with the // controller now. you must hit the "L" key once more // before moving any other controller or selecting any // other fader. // the controller you use must send midi cc messages and // cannot be a key or button. panel buttons cannot be // linked to midi devices at this time. you may assign // multiple faders to one controller, but assigning // multiple controllers to one fader may cause errors. // to be safe, i would not recommend doing either, // but whatever... :) // //---------------------------------------------------------- // // really the best way to learn how this shit works is by // playing with it. make sure your speakers or // headphones are loud enough for you to enjoy it // for reals. don't be a wuss. // // // // if you have questions, bug reports, or comments, please // contact me @ joe (dot) mariglio (at) gmail (dot) com // if you have feature requests, be prepared to give me // some kind of compensation. :$ feel free to // distribute this software. i only ask that you // include my pithy comments and documentation // contained in this header. also, if you haven't yet, // you should check out my website for more software, // circuit schematics, free music, and other oddities. // // //---------------------------------------------------------- //CC-BY-NC-SA //---------------------------------------------------------- //This work is licensed under the Creative Commons //Attribution-NonCommercial-ShareAlike 3.0 Unported License. //To view a copy of this license, visit //http://creativecommons.org/licenses/by-nc-sa/3.0/ //or send a letter to Creative Commons, // 444 Castro Street, // Suite 900, // Mountain View, California, 94041, USA. //---------------------------------------------------------- ( var w; SynthDef(\shred, { arg rate = 1, rate_scale = 1, amp = 1, amp_scale = 1, pos = 0, jitp = 0, pan = 0, pan_scale = 0, width = 1, out = 0, senda = 16, sendb = 18, vol = 1, vola = 0, volb = 0, sndbuf = 0, trate = 1, trate_scale = 1, freq = 1, freq_scale = 1, gdur = 2, genv = 1, asyn = 0, prob = 100, bst = 1, rst = 0, jitf = 0, scrub = 0, dir = 1, lo = 0, hi = 1, a0 = 1, a1 = 1, a2 = 1, a3 = 1, a4 = 1, a5 = 1, a6 = 1, a7 = 1, a8 = 1, a9 = 1; var sync, frames, trig, pitch, mask, rmask, position, grains, env; frames = BufFrames.kr(sndbuf); sync = WhiteNoise.ar(asyn); mask = LFPulse.ar(((trate*trate_scale + sync))/(bst+rst), 0, (bst/(bst+rst))); trig = Impulse.ar((trate*trate_scale + sync)); rmask = TRand.ar(0, 100, trig) < prob; pitch = Demand.ar(trig*rmask, 0, Drand([a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]*freq*freq_scale, inf)); pitch = pitch+WhiteNoise.ar(jitf); position = Phasor.ar(scrub*trig, dir*rate/frames, lo, hi, pos); position = position + WhiteNoise.ar(jitp); grains = GrainBuf.ar(2, trig*rmask, gdur, sndbuf, pitch, position, 4, (ClipNoise.ar(width)+pan+pan_scale).clip(-0.99, 0.99), genv); Out.ar(senda, grains*vola); Out.ar(sendb, grains*volb); Out.ar(out, grains*vol*amp) }).store; SynthDef(\shatter, { arg f0 = 1, f1 = 2, f2 = 3, f3 = 4, f4 = 5, f5 = 6, f6 = 7, f7 = 8, rq0 = 1, rq1 = 1, rq2 = 1, rq3 = 1, rq4 = 1, rq5 = 1, rq6 = 1, rq7 = 1, fund = 400, rq = 1, prob = 50, gdur = 0.0375, trate = 256, genv = -1, width = 1, in = 16, out = 0, vol = 1, senda = 18, vola = 1, dec = 1, del = 1, dec0 = 1, dec1 = 1, dec2 = 1, dec3 = 1, dec4 = 1, dec5 = 1, dec6 = 1, dec7 = 1, del0 = 0.1, del1 = 0.2, del2 = 0.3, del3 = 0.4, del4 = 0.5, del5 = 0.6, del6 = 0.7, del7 = 0.8 ; var input, fs, rqs, decs, dels, imp, trig, filt, delay; fs = [f0, f1, f2, f3, f4, f5, f6, f7]; rqs = [rq0, rq1, rq2, rq3, rq4, rq5, rq6, rq7]; decs = [dec0, dec1, dec2, dec3, dec4, dec5, dec6, dec7]; dels = [del0, del1, del2, del3, del4, del5, del6, del7]; imp = Impulse.ar(trate); trig = imp * 8.collect{|x| (TRand.ar(0, 100, imp) < prob)}; input = Mix.ar([InFeedback.ar(in), InFeedback.ar(in+1)]); filt = 8.collect{|x| BPF.ar(input, (fs[x]*fund).clip(20, 22050), rqs[x]*rq)}; filt = 8.collect{|x| GrainIn.ar(2, trig[x], gdur, filt[x]*128, WhiteNoise.ar(width), genv) }; delay = 8.collect{|x| CombC.ar(filt[x], 1, (dels[x]*del).clip(0.001, 1), decs[x]*dec)}; delay = Limiter.ar(Mix.ar(delay), 0.9); Out.ar(senda, delay*vola); Out.ar(out, delay*vol) }).store; SynthDef(\spit, { arg vol = 1, vola = 0, in = 18, out = 0, outa = 16, f0 = 0, f1 = 0, f2 = 0, o0 = 0, o1 = 0, o2 = 0, post0 = 1, post1 = 1, post2 = 1, pre0 = 0, pre1 = 0, pre2 = 0; var synth, line; line = InFeedback.ar([in, in+1]); synth = [ SinOsc.ar(f0, (o0+pre0)*line, post0), SinOsc.ar(f2, (o2+pre2)*line, post2) ] + (SinOsc.ar(f1, (o1+pre1)+line, post1)/4); /* synth = DynKlang.ar(`[ [f0, f1, f2], [post0, post1, post2], [o0, o1, o2] + ([pre0, pre1, pre2]*line) ]); */ synth = synth * vol; Out.ar(outa, (synth*vola).softclip); Out.ar(out, synth.softclip) }).store; SynthDef(\limi, {|in = 20, out = 0, vol = 1| var sig; sig = InFeedback.ar([in, in+1]); sig = Limiter.ar(sig, 0.9); Out.ar(out, sig*vol); }).store; w = ~window = Window.new("sonic_shredder",Rect(0, 0, 1280, 779)).front; ~sections = [ //- a section... // ~order = (0..11) ++ ["on", "path", "scrub", "range", "browse", "fb"]; ~a_section = [ ~a0 = [ Slider.new(w,Rect(20, 60, 20, 150)), //slider 0 NumberBox.new(w,Rect(10, 220, 40, 20)), StaticText.new(w,Rect(10, 40, 50, 20)).string_("amp"), ], ~a1 = [ Slider.new(w,Rect(60, 60, 20, 150)), NumberBox.new(w,Rect(50, 220, 40, 20)), StaticText.new(w,Rect(50, 40, 50, 20)).string_("rate"), ], ~a2 = [ Slider.new(w,Rect(100, 60, 20, 150)), NumberBox.new(w,Rect(90, 220, 40, 20)), StaticText.new(w,Rect(90, 40, 50, 20)).string_("pitch"), ], ~a3 = [ Slider.new(w,Rect(140, 60, 20, 150)), NumberBox.new(w,Rect(130, 220, 40, 20)), StaticText.new(w,Rect(130, 40, 50, 20)).string_("trate"), ], ~a4 = [ Slider.new(w,Rect(180, 60, 20, 150)), NumberBox.new(w,Rect(170, 220, 40, 20)), StaticText.new(w,Rect(170, 40, 50, 20)).string_("dens"), ], ~a5 = [ Slider.new(w,Rect(220, 60, 20, 150)), NumberBox.new(w,Rect(210, 220, 40, 20)), StaticText.new(w,Rect(210, 40, 50, 20)).string_("prob"), ], ~a6 = [ Slider.new(w,Rect(260, 60, 20, 150)), NumberBox.new(w,Rect(250, 220, 40, 20)), StaticText.new(w,Rect(250, 40, 50, 20)).string_("pan"), ], ~a7 = [ Slider.new(w,Rect(300, 60, 20, 150)), NumberBox.new(w,Rect(290, 220, 40, 20)), StaticText.new(w,Rect(290, 40, 50, 20)).string_("width"), ], ~a8 = [ Slider.new(w,Rect(340, 60, 20, 150)), NumberBox.new(w,Rect(330, 220, 40, 20)), StaticText.new(w,Rect(330, 40, 50, 20)).string_("jpos"), ], ~a9 = [ Slider.new(w,Rect(380, 60, 20, 150)), NumberBox.new(w,Rect(370, 220, 40, 20)), StaticText.new(w,Rect(370, 40, 50, 20)).string_("jpitch"), ], ~a10 = [ Slider.new(w,Rect(420, 60, 20, 150)), NumberBox.new(w,Rect(410, 220, 40, 20)), StaticText.new(w,Rect(410, 40, 50, 20)).string_("send_a"), ], ~a11 = [ Slider.new(w,Rect(460, 60, 20, 150)), NumberBox.new(w,Rect(450, 220, 40, 20)), StaticText.new(w,Rect(450, 40, 50, 20)).string_("send_b"), ], ~on_a = Button.new(w,Rect(10, 10, 40, 20)).states_([["ON", Color.green, Color.black], ["OFF", Color.black, Color.red]]), //on ~path_a = TextField.new(w,Rect(60, 10, 370, 20)).string_("~/path/to/file"), ~scrub_a = Slider.new(w,Rect(40, 250, 410, 20)), // scrubber ~range_a = RangeSlider.new(w,Rect(40, 280, 410, 10)).lo_(0).hi_(1), ~browse_a = Button.new(w,Rect(440, 10, 30, 20)).states_([["find", Color.black, Color.white]]), //browse ~fb_a = [ Button.new(w,Rect(10, 250, 30, 20)).states_([[">", Color.black, Color.green], ["[]", Color.black, Color.red]]), // fwd Button.new(w,Rect(450, 250, 30, 20)).states_([["<", Color.black, Color.green], ["[]", Color.black, Color.red]]), // bck ], ~scrub_a_toggle = Button.new(w, Rect(10, 270, 30, 20)).states_([["scrb", Color.black, Color.white], ["trck", Color.white, Color.black]]), ], //- b section... // ~order = (0..11) ++ ["on", "path", "scrub", "range", "browse", "fb"]; ~b_section = [ ~b0 = [ Slider.new(w,Rect(550, 60, 20, 150)), //slider 0 NumberBox.new(w,Rect(540, 220, 40, 20)), StaticText.new(w,Rect(540, 40, 50, 20)).string_("amp"), ], ~b1 = [ Slider.new(w,Rect(590, 60, 20, 150)), NumberBox.new(w,Rect(580, 220, 40, 20)), StaticText.new(w,Rect(580, 40, 50, 20)).string_("rate"), ], ~b2 = [ Slider.new(w,Rect(630, 60, 20, 150)), NumberBox.new(w,Rect(620, 220, 40, 20)), StaticText.new(w,Rect(620, 40, 50, 20)).string_("pitch"), ], ~b3 = [ Slider.new(w,Rect(670, 60, 20, 150)), NumberBox.new(w,Rect(660, 220, 40, 20)), StaticText.new(w,Rect(660, 40, 50, 20)).string_("trate"), ], ~b4 = [ Slider.new(w,Rect(710, 60, 20, 150)), NumberBox.new(w,Rect(700, 220, 40, 20)), StaticText.new(w,Rect(700, 40, 50, 20)).string_("dens"), ], ~b5 = [ Slider.new(w,Rect(750, 60, 20, 150)), NumberBox.new(w,Rect(740, 220, 40, 20)), StaticText.new(w,Rect(740, 40, 50, 20)).string_("prob"), ], ~b6 = [ Slider.new(w,Rect(790, 60, 20, 150)), NumberBox.new(w,Rect(780, 220, 40, 20)), StaticText.new(w,Rect(780, 40, 50, 20)).string_("pan"), ], ~b7 = [ Slider.new(w,Rect(830, 60, 20, 150)), NumberBox.new(w,Rect(820, 220, 40, 20)), StaticText.new(w,Rect(820, 40, 50, 20)).string_("width"), ], ~b8 = [ Slider.new(w,Rect(870, 60, 20, 150)), NumberBox.new(w,Rect(860, 220, 40, 20)), StaticText.new(w,Rect(860, 40, 50, 20)).string_("jpos"), ], ~b9 = [ Slider.new(w,Rect(910, 60, 20, 150)), NumberBox.new(w,Rect(900, 220, 40, 20)), StaticText.new(w,Rect(900, 40, 50, 20)).string_("jpitch"), ], ~b10 = [ Slider.new(w,Rect(950, 60, 20, 150)), NumberBox.new(w,Rect(940, 220, 40, 20)), StaticText.new(w,Rect(940, 40, 50, 20)).string_("send_a"), ], ~b11 = [ Slider.new(w,Rect(990, 60, 20, 150)), NumberBox.new(w,Rect(980, 220, 40, 20)), StaticText.new(w,Rect(980, 40, 50, 20)).string_("send_b"), ], ~on_b = Button.new(w,Rect(540, 10, 40, 20)).states_([["ON", Color.green, Color.black], ["OFF", Color.black, Color.red]]), // on ~path_b = TextField.new(w,Rect(590, 10, 370, 20)).string_("~/path/to/file"), //path ~scrub_b = Slider.new(w,Rect(570, 250, 410, 20)), // scrubber ~range_b = RangeSlider.new(w,Rect(570, 280, 410, 10)).lo_(0).hi_(1), ~browse_b = Button.new(w,Rect(970, 10, 30, 20)).states_([["find", Color.black, Color.white]]), ~fb_b = [ Button.new(w,Rect(540, 250, 30, 20)).states_([[">", Color.black, Color.green], ["[]", Color.black, Color.red]]), Button.new(w,Rect(980, 250, 30, 20)).states_([["<", Color.black, Color.green], ["[]", Color.black, Color.red]]) ], ~scrub_b_toggle = Button.new(w, Rect(540, 270, 30, 20)).states_([["scrb", Color.black, Color.white], ["trck", Color.white, Color.black]]), ], //- c section... // ~order = (0..11) ++ ["on", "path", "scrub", "range", "browse", "fb"]; ~c_section = [ ~c0 = [ Slider.new(w,Rect(20, 380, 20, 150)), //slider 0 NumberBox.new(w,Rect(10, 540, 40, 20)), StaticText.new(w,Rect(10, 360, 50, 20)).string_("amp"), ], ~c1 = [ Slider.new(w,Rect(60, 380, 20, 150)), NumberBox.new(w,Rect(50, 540, 40, 20)), StaticText.new(w,Rect(50, 360, 50, 20)).string_("rate"), ], ~c2 = [ Slider.new(w,Rect(100, 380, 20, 150)), NumberBox.new(w,Rect(90, 540, 40, 20)), StaticText.new(w,Rect(90, 360, 50, 20)).string_("pitch"), ], ~c3 = [ Slider.new(w,Rect(140, 380, 20, 150)), NumberBox.new(w,Rect(130, 540, 40, 20)), StaticText.new(w,Rect(130, 360, 50, 20)).string_("trate"), ], ~c4 = [ Slider.new(w,Rect(180, 380, 20, 150)), NumberBox.new(w,Rect(170, 540, 40, 20)), StaticText.new(w,Rect(170, 360, 50, 20)).string_("dens"), ], ~c5 = [ Slider.new(w,Rect(220, 380, 20, 150)), NumberBox.new(w,Rect(210, 540, 40, 20)), StaticText.new(w,Rect(210, 360, 50, 20)).string_("prob"), ], ~c6 = [ Slider.new(w,Rect(260, 380, 20, 150)), NumberBox.new(w,Rect(250, 540, 40, 20)), StaticText.new(w,Rect(250, 360, 50, 20)).string_("pan"), ], ~c7 = [ Slider.new(w,Rect(300, 380, 20, 150)), NumberBox.new(w,Rect(290, 540, 40, 20)), StaticText.new(w,Rect(290, 360, 50, 20)).string_("width"), ], ~c8 = [ Slider.new(w,Rect(340, 380, 20, 150)), NumberBox.new(w,Rect(330, 540, 40, 20)), StaticText.new(w,Rect(330, 360, 50, 20)).string_("jpos"), ], ~c9 = [ Slider.new(w,Rect(380, 380, 20, 150)), NumberBox.new(w,Rect(370, 540, 40, 20)), StaticText.new(w,Rect(370, 360, 50, 20)).string_("jpitch"), ], ~c10 = [ Slider.new(w,Rect(420, 380, 20, 150)), NumberBox.new(w,Rect(410, 540, 40, 20)), StaticText.new(w,Rect(410, 360, 50, 20)).string_("send_a"), ], ~c11 = [ Slider.new(w,Rect(460, 380, 20, 150)), NumberBox.new(w,Rect(450, 540, 40, 20)), StaticText.new(w,Rect(450, 360, 50, 20)).string_("send_b"), ], ~on_c = Button.new(w,Rect(10, 330, 40, 20)).states_([["ON", Color.green, Color.black], ["OFF", Color.black, Color.red]]), // on ~path_c = TextField.new(w,Rect(60, 330, 370, 20)).string_("~/path/to/file"), ~scrub_c = Slider.new(w,Rect(40, 570, 410, 20)), //scrubber ~range_c = RangeSlider.new(w,Rect(40, 600, 410, 10)).lo_(0).hi_(1), ~browse_c = Button.new(w,Rect(440, 330, 30, 20)).states_([["find", Color.black, Color.white]]), ~fb_c = [ Button.new(w,Rect(10, 570, 30, 20)).states_([[">", Color.black, Color.green], ["[]", Color.black, Color.red]]), Button.new(w,Rect(450, 570, 30, 20)).states_([["<", Color.black, Color.green], ["[]", Color.black, Color.red]]) ], ~scrub_c_toggle = Button.new(w, Rect(10, 590, 30, 20)).states_([["scrb", Color.black, Color.white], ["trck", Color.white, Color.black]]), ], //- d section... // ~order = (0..11) ++ ["on", "path", "scrub", "range", "browse", "fb"]; ~d_section = [ ~d0 = [ Slider.new(w,Rect(550, 380, 20, 150)), //slider 0 NumberBox.new(w,Rect(540, 540, 40, 20)), StaticText.new(w,Rect(540, 360, 50, 20)).string_("amp"), ], ~d1 = [ Slider.new(w,Rect(590, 380, 20, 150)), NumberBox.new(w,Rect(580, 540, 40, 20)), StaticText.new(w,Rect(580, 360, 50, 20)).string_("rate"), ], ~d2 = [ Slider.new(w,Rect(630, 380, 20, 150)), NumberBox.new(w,Rect(620, 540, 40, 20)), StaticText.new(w,Rect(620, 360, 50, 20)).string_("pitch"), ], ~d3 = [ Slider.new(w,Rect(670, 380, 20, 150)), NumberBox.new(w,Rect(660, 540, 40, 20)), StaticText.new(w,Rect(660, 360, 50, 20)).string_("trate"), ], ~d4 = [ Slider.new(w,Rect(710, 380, 20, 150)), NumberBox.new(w,Rect(700, 540, 40, 20)), StaticText.new(w,Rect(700, 360, 50, 20)).string_("dens"), ], ~d5 = [ Slider.new(w,Rect(750, 380, 20, 150)), NumberBox.new(w,Rect(740, 540, 40, 20)), StaticText.new(w,Rect(740, 360, 50, 20)).string_("prob"), ], ~d6 = [ Slider.new(w,Rect(790, 380, 20, 150)), NumberBox.new(w,Rect(780, 540, 40, 20)), StaticText.new(w,Rect(780, 360, 50, 20)).string_("pan"), ], ~d7 = [ Slider.new(w,Rect(830, 380, 20, 150)), NumberBox.new(w,Rect(820, 540, 40, 20)), StaticText.new(w,Rect(820, 360, 50, 20)).string_("width"), ], ~d8 = [ Slider.new(w,Rect(870, 380, 20, 150)), NumberBox.new(w,Rect(860, 540, 40, 20)), StaticText.new(w,Rect(860, 360, 50, 20)).string_("jpos"), ], ~d9 = [ Slider.new(w,Rect(910, 380, 20, 150)), NumberBox.new(w,Rect(900, 540, 40, 20)), StaticText.new(w,Rect(900, 360, 50, 20)).string_("jpitch"), ], ~d10 = [ Slider.new(w,Rect(950, 380, 20, 150)), NumberBox.new(w,Rect(940, 540, 40, 20)), StaticText.new(w,Rect(940, 360, 50, 20)).string_("send_a"), ], ~d11 = [ Slider.new(w,Rect(990, 380, 20, 150)), NumberBox.new(w,Rect(980, 540, 40, 20)), StaticText.new(w,Rect(980, 360, 50, 20)).string_("send_b"), ], ~on_d = Button.new(w,Rect(540, 330, 40, 20)).states_([["ON", Color.green, Color.black], ["OFF", Color.black, Color.red]]), ~path_d = TextField.new(w,Rect(590, 330, 370, 20)).string_("~/path/to/file"), ~scrub_d = Slider.new(w,Rect(570, 570, 410, 20)), //scrubber ~range_d = RangeSlider.new(w,Rect(570, 600, 410, 10)).lo_(0).hi_(1), ~browse_d = Button.new(w,Rect(970, 330, 30, 20)).states_([["find", Color.black, Color.white]]), ~fb_d = [ Button.new(w,Rect(540, 570, 30, 20)).states_([[">", Color.black, Color.green], ["[]", Color.black, Color.red]]), Button.new(w,Rect(980, 570, 30, 20)).states_([["<", Color.black, Color.green], ["[]", Color.black, Color.red]]), ], ~scrub_d_toggle = Button.new(w, Rect(540, 590, 30, 20)).states_([["scrb", Color.black, Color.white], ["trck", Color.white, Color.black]]), ] ]; //- presets: ~pres_label = StaticText(w, Rect(1080, 10, 100, 20)).string_("presets:"); ~pre_save = Button.new(w, Rect(1080, 30, 50, 20)).states_([["save", Color.black, Color.white]]); ~pre_load = Button.new(w, Rect(1140, 30, 50, 20)).states_([["load", Color.black, Color.white], ["apply", Color.white, Color.black]]); ~load_paths = Button.new(w, Rect(1200, 30, 70, 20)).states_([["no paths", Color.white, Color.black], ["load paths", Color.black, Color.white]]); //- env section: ~env_label = StaticText(w, Rect(1080, 50, 100, 20)).string_("grain envelope:"); ~env_browser = [ TextField.new(w, Rect(1080, 70, 100, 20)).string_("~/path/to/env"), Button.new(w, Rect(1190, 70, 30, 20)).states_([["find", Color.black, Color.white]]) ]; ~faders = [~a_section[0..11], ~b_section[0..11], ~c_section[0..11], ~d_section[0..11]]; ~ranges = [~range_a, ~range_b, ~range_c, ~range_d]; ~args = #[vol, rate, freq, trate, gdur, prob, pan, width, jitp, jitf, vola, volb]; ~specs = [ \amp.asSpec, //amp ControlSpec(0.01, 8, \exp, 0, 1),//rate ControlSpec(0.01, 8, \exp, 0, 1),//freq ControlSpec(4, 64, \exp, 0, 16),//trate ControlSpec(0, 2, \lin, 0, 1), //gdur ControlSpec(0, 100, \lin, 0, 100),//prob \pan.asSpec,//pan ControlSpec(0, 1, 0, 0),//width ControlSpec(0, 1, 0, 0),//jitp ControlSpec(0, 1, 0, 0),//jitf ControlSpec(0, 1, 0, 0),//vola ControlSpec(0, 1, 0, 0),//volb ]; ~defaults = [ 0, //amp 1/2, //rate 1/2, //freq 1/2, //trate 1/2, //gdur 1, //prob 1/2, //pan 0,//width 0,//jitp 0,//jitf 0,//vola 0,//volb ]; ~shatter_faders = 8.collect{|index| [ [ Slider.new(w, Rect(1100, 110 + (index * 70), 20, 30)), NumberBox.new(w, Rect(1090, 140 + (index * 70), 40, 20)), StaticText.new(w, Rect(1090, 90 + (index * 70), 50, 20)) ], [ Slider.new(w, Rect(1140, 110 + (index * 70), 20, 30)), NumberBox.new(w, Rect(1130, 140 + (index * 70), 40, 20)), StaticText.new(w, Rect(1130, 90 + (index * 70), 50, 20)) ], [ Slider.new(w, Rect(1180, 110 + (index * 70), 20, 30)), NumberBox.new(w, Rect(1170, 140 + (index * 70), 40, 20)), StaticText.new(w, Rect(1170, 90 + (index * 70), 50, 20)) ], [ Slider.new(w, Rect(1220, 110 + (index * 70), 20, 30)), NumberBox.new(w, Rect(1210, 140 + (index * 70), 40, 20)), StaticText.new(w, Rect(1210, 90 + (index * 70), 50, 20)) ] ] }; ~shatter_labels = #[freq, rq, del, dec]; ~shatter_faders.do{|x, i| x.do{|y, j| y.do{|z, k| if(k==2, { z.string_(~shatter_labels[j].asString); }); }; }; }; ~shatter_specs = [ ControlSpec(1, 16), //freq \rq.asSpec, //rq ControlSpec(0.01, 1), //del ControlSpec(0, 100) //dec ]; ~shatter_master_faders = [ [ Slider.new(w, Rect(1090, 690, 40, 50)), NumberBox.new(w, Rect(1090, 740, 40, 20)), StaticText.new(w, Rect(1090, 670, 50, 20)) ], [ Slider.new(w, Rect(1130, 690, 40, 50)), NumberBox.new(w, Rect(1130, 740, 40, 20)), StaticText.new(w, Rect(1130, 670, 50, 20)) ], [ Slider.new(w, Rect(1170, 690, 40, 50)), NumberBox.new(w, Rect(1170, 740, 40, 20)), StaticText.new(w, Rect(1170, 670, 50, 20)) ], [ Slider.new(w, Rect(1210, 690, 40, 50)), NumberBox.new(w, Rect(1210, 740, 40, 20)), StaticText.new(w, Rect(1210, 670, 50, 20)) ] ]; ~spit_args = #[[f0, f1, f2], [o0, o1, o2], [pre0, pre1, pre2], [post0, post1, post2]]; ~spit_faders = 4.collect{|x| [ [ Slider.new(w, Rect(380 + (x*200), 640, 100, 20)), NumberBox.new(w, Rect(340 + (x*200), 640, 35, 20)), StaticText.new(w, Rect(300 + (x*200), 640, 50, 20)).string_(~spit_args[x][0].asString) ], [ Slider.new(w, Rect(380 + (x*200), 660, 100, 20)), NumberBox.new(w, Rect(340 + (x*200), 660, 35, 20)), StaticText.new(w, Rect(300 + (x*200), 660, 50, 20)).string_(~spit_args[x][1].asString) ], [ Slider.new(w, Rect(380 + (x*200), 680, 100, 20)), NumberBox.new(w, Rect(340 + (x*200), 680, 35, 20)), StaticText.new(w, Rect(300 + (x*200), 680, 50, 20)).string_(~spit_args[x][2].asString) ] ] }; ~master_faders = [ [ Slider.new(w, Rect(10, 660, 50, 80)), NumberBox.new(w, Rect(10, 740, 50, 20)), StaticText.new(w, Rect(12, 640, 50, 20)).string_("SHRED") ], [ Slider.new(w, Rect(80, 660, 50, 80)), NumberBox.new(w, Rect(80, 740, 50, 20)), StaticText.new(w, Rect(77, 640, 60, 20)).string_("SHATTER") ], [ Slider.new(w, Rect(150, 660, 50, 80)), NumberBox.new(w, Rect(150, 740, 50, 20)), StaticText.new(w, Rect(160, 640, 50, 20)).string_("SPIT") ], [ Slider.new(w, Rect(220, 660, 50, 80)), NumberBox.new(w, Rect(220, 740, 50, 20)), StaticText.new(w, Rect(230, 640, 50, 20)).string_("SUM") ] ]; ~spit_specs = [ [ ControlSpec(0, 30, default: 0), //f0 ControlSpec(0, 30, default: 0), //f1 ControlSpec(0, 30, default: 0) //f2 ], [ ControlSpec(0, 2pi, default: 0), //o0 ControlSpec(0, 2pi, default: 0), //o1 ControlSpec(0, 2pi, default: 0) //o2 ], [ ControlSpec(0, 16, default: 1), //pre0 ControlSpec(0, 16, default: 1), //pre1 ControlSpec(0, 16, default: 1) //pre2 ], [ ControlSpec(0, 16, default: 0), //post0 ControlSpec(0, 16, default: 0), //post1 ControlSpec(0, 16, default: 0) //post2 ] ]; ~shatter_master_fader_args = #[fund, prob, del, vola]; ~shatter_master_faders.do{|x, i| x.do{|y, j| if(j==2, { var label; label = ~shatter_master_fader_args[i].asString; if(i==3, {label = "send_b"}); y.string_(label); }); }; }; ~shatter_master_specs = [ \freq.asSpec, //fund ControlSpec(0.001, 100, 'exp', default:50), //prob ControlSpec(0.1, 1, default:1), //del \amp.asSpec //vola ]; ~shatter_master_faders.do{|x, i| x.do{|y, j| j.switch( 0, { //slider y.action_({|obj| x[1].value = ~shatter_master_specs[i].map(obj.value).postln; ~shatter.set(~shatter_master_fader_args[i], ~shatter_master_specs[i].map(obj.value)); }); y.keyDownAction_({|view, char, mod, uni, key| [view, char, mod, uni, key].do{|x| x.postln; }; if(char==$l, { ~learnmode = ~learnmode + 1; ~learnmode = ~learnmode % 2; ~learnmode.switch( 1, { CCResponder({|src, chan, num, val| ~input = [src, chan, num].postln; { y.valueAction_(val.postln/128); }.defer; }).learn; }, 0, { ~shatter_master_fader_midi_responders.put(i, ~input); "learned to connect: ".post; ~input.post; " to: ".post; (~shatter_master_fader_args[i].asString++i).postln; } ); } ); }); }, 1, { //number y.action_({|obj| x[0].valueAction = ~shatter_master_specs[i].unmap(obj.value).postln; }); } ); }; }; ~shatter_master_faders.do{|x, i| x[0].value = ~shatter_master_specs[i].unmap(~shatter_master_specs[i].default); x[1].value = ~shatter_master_specs[i].map(x[0].value); }; ~shatter_fader_args = 8.collect{|x| ["f"++x, "rq"++x, "del"++x, "dec"++x]}; ~shatter_faders.do{|x, i| x.do{|y, j| y.do{|z, k| k.switch( 0, { //slider z.action_({|obj| y[1].value = ~shatter_specs[j].map(obj.value).postln; ~shatter.set(~shatter_fader_args[i][j], ~shatter_specs[j].map(obj.value)); }); z.keyDownAction_({|view, char, mod, uni, key| [view, char, mod, uni, key].do{|x| x.postln; }; if(char==$l, { ~learnmode = ~learnmode + 1; ~learnmode = ~learnmode % 2; ~learnmode.switch( 1, { CCResponder({|src, chan, num, val| ~input = [src, chan, num].postln; { z.valueAction_(val.postln/128); }.defer; }).learn; }, 0, { ~shatter_fader_midi_responders.put([i, j, k], ~input); "learned to connect: ".post; ~input.post; " to: ".post; (~shatter_labels[j].asString++i).postln; } ); } ); }); }, 1, { //number z.action_({|obj| y[0].valueAction = ~shatter_specs[j].unmap(obj.value).postln; }); } ); }; }; }; ~shatter_faders.do{|x| x.do{|y, i| y[0].value = ~shatter_specs[i].unmap(~shatter_specs[i].default); y[1].value = ~shatter_specs[i].map(y[0].value); } }; ~learnmode = 0; ~faders.do{|x, k| x.do{|y, j| y.do{|z, i| i.switch( 0, { //slider z.action_({|obj| y[1].value = ~specs[j].map(obj.value).postln; if(~synths[k].notNil, { ~synths[k].set(~args[j], ~specs[j].map(obj.value)); }); }); z.keyDownAction_({|view, char, mod, uni, key| [view, char, mod, uni, key].do{|x| x.postln}; if(char==$l, { ~learnmode = ~learnmode + 1; ~learnmode = ~learnmode % 2; ~learnmode.switch( 1, { var key; key = ~args[j].asString++k; key.postln; CCResponder({|src, chan, num, val| ~input = [src, chan, num].postln; { z.valueAction_(val.postln/128); }.defer; }).learn; }, 0, { ~fader_midi_responders.put([k, j, i], ~input); "learned to connect: ".post; ~input.post; " to: ".post; (~args[j].asString++k).postln;} ); }); }); }, 1, { //number z.action_({|obj| y[0].valueAction = ~specs[j].unmap(obj.value).postln; }); } ); }; }; }; ~faders.do{|x| x.do{|y, i| y[0].value = ~specs[i].unmap(~specs[i].default); y[1].value = ~specs[i].map(y[0].value); } }; ~spit_faders.do{|x, k| x.do{|y, j| y.do{|z, i| i.switch( 0, { //slider z.action_({|obj| y[1].value = ~spit_specs[k][j].map(obj.value).postln; ~spit.set(~spit_args[k][j], ~spit_specs[k][j].map(obj.value)); }); z.keyDownAction_({|view, char, mod, uni, key| [view, char, mod, uni, key].do{|x| x.postln}; if(char==$l, { ~learnmode = ~learnmode + 1; ~learnmode = ~learnmode % 2; ~learnmode.switch( 1, { var key; key = ~spit_args[k][j].asString++k; key.postln; CCResponder({|src, chan, num, val| ~input = [src, chan, num].postln; { z.valueAction_(val.postln/128); }.defer; }).learn; }, 0, { ~spit_fader_midi_responders.put([k, j, i], ~input); "learned to connect: ".post; ~input.post; " to: ".post; (~spit_args[k][j].asString).postln;} ); }); }); }, 1, { //number z.action_({|obj| y[0].valueAction = ~spit_specs[k][j].unmap(obj.value).postln; }); } ); }; }; }; ~spit_faders.do{|x, i| x.do{|y, j| y[0].value = ~spit_specs[i][j].unmap(~spit_specs[i][j].default); y[1].value = ~spit_specs[i][j].map(y[0].value); } }; ~browsers = [~browse_a, ~browse_b, ~browse_c, ~browse_d]; ~paths = [~path_a, ~path_b, ~path_c, ~path_d]; ~browsers.do{|x, i| x.action_({ Dialog.getPaths({|paths| paths.do{|y, j| ~paths.wrapAt(i+j).valueAction_(y.postln); }; }); }); }; ~env_browser[1].action_({ Dialog.getPaths({|y| ~env_browser[0].valueAction_(y[0]); }); }); ~env_browser[0].action_({|field| ~envbuf.free; ~envbuf = Buffer.read(s, field.value.postln); ~synths.do{|synth, i| if(synth.notNil, { synth.set(\envbuf, ~envbuf.bufnum); }); }; }); ~sndbufs = nil!4; ~envbuf = Buffer.read(s, "/Users/josephmariglio/Music/samples/envelopes/perc.wav"); ~paths.do{|x, i| x.action_({ if(~sndbufs[i].notNil, { ~sndbufs[i].free; ~sndbufs[i] = nil; } ); ~sndbufs[i] = Buffer.readChannel(s, ~paths[i].value, channels:[0]); }) }; ~fwds = [~fb_a[0], ~fb_b[0], ~fb_c[0], ~fb_d[0]]; ~bcks = [~fb_a[1], ~fb_b[1], ~fb_c[1], ~fb_d[1]]; ~fwds.do{|x, i| x.action_{|but| but.value.switch( 0, { if(~synths[i].notNil, {~synths[i].set(\dir, ~fwds[i].value - ~bcks[i].value)}); }, 1, { if(~synths[i].notNil, {~synths[i].set(\dir, ~fwds[i].value - ~bcks[i].value)}); ~bcks[i].valueAction_(0); } ) } }; ~bcks.do{|x, i| x.action_{|but| but.value.switch( 0, { if(~synths[i].notNil, {~synths[i].set(\dir, ~fwds[i].value - ~bcks[i].value)}); }, 1, { if(~synths[i].notNil, {~synths[i].set(\dir, ~fwds[i].value - ~bcks[i].value)}); ~fwds[i].valueAction_(0); } ) } }; ~cursors = [~scrub_a, ~scrub_b, ~scrub_c, ~scrub_d]; ~cursors.do{|x| x.enabled = false;}; ~ons = [~on_a, ~on_b, ~on_c, ~on_d]; ~synths = [nil, nil, nil, nil]; ~toggles = [~scrub_a_toggle, ~scrub_b_toggle, ~scrub_c_toggle, ~scrub_d_toggle]; ~toggles.do{|x, i| x.action_({|but| but.value.switch( 0, { ~cursors[i].enabled = false; if(~synths[i].notNil, {~synths[i].set(\scrub, 0)}); }, 1, { ~cursors[i].enabled = true; if(~synths[i].notNil, {~synths[i].set(\scrub, 1)}); } ) }); }; ~steps = ~cursors.collect{|x, i| Task{ loop{ var dur; dur = if(~sndbufs[i].notNil, {~sndbufs[i].numFrames / ~sndbufs[i].sampleRate }); { if(~toggles[i].value==0, {x.valueAction = (x.value + (((~fwds[i].value - ~bcks[i].value) / dur) * ~specs[1].map(~sections[i][1][0].value))).wrap(~sections[i][15].lo, ~sections[i][15].hi)}); }.defer; wait(1); } }; }; ~cursors.do{|cursor, index| cursor.action_{ if(~synths[index].notNil, {~synths[index].set(\pos, cursor.value)}); cursor.value.postln; } }; ~ons.do{|x, i| x.action_({|but| but.value.switch( 0, { ~synths[i].free; ~synths[i] = nil; ~steps[i].pause; }, 1, { ~synths[i] = Synth.before(~shatter, \shred, [\sndbuf, ~sndbufs[i].bufnum, \genv, ~envbuf.bufnum, \out, 20, \amp, ~master_faders[0][0].value]); ~args.do{|y, j| ~synths[i].set(y, ~faders[i][j][1].value)}; ~synths[i].set(\dir, ~fwds[i].value-~bcks[i].value); ~synths[i].set(\pos, ~cursors[i].value); ~synths[i].set(\lo, ~sections[i][15].lo); ~synths[i].set(\hi, ~sections[i][15].hi); ~synths[i].set(\scrub, ~toggles[i].value); ~steps[i].play; } ); }); }; ~sections.do{|section, i| section[15].action_{|slider| if(~synths[i].notNil, { ~synths[i].set(\lo, slider.lo); ~synths[i].set(\hi, slider.hi); }); } }; ~cursors.do{|x, i| x.keyDownAction_({|view, char, mod, uni, key| [view, char, mod, uni, key].do{|y| y.postln;}; if(char==$l, { ~learnmode = ~learnmode + 1; ~learnmode = ~learnmode % 2; ~learnmode.switch( 1, { var key; key = "cursor"++i; key.postln; CCResponder({|src, chan, num, val| ~input = [src, chan, num].postln; { x.valueAction_(val.postln/128); }.defer; }).learn; }, 0, { ~cursor_midi_responders.put(i, ~input); "learned to connect: ".post; ~input.post; " to: ".post; ("cursor"++i).postln; } ); } ); }); }; ~master_faders.do{|x, i| var spec; spec = \amp.asSpec; x.do{|y, j| j.switch( 0, { //slider y.action_({|obj| x[1].value = spec.map(obj.value).postln; i.switch( 0, {~synths.do{|shred| if(shred.notNil, {shred.set(\amp, spec.map(obj.value))})}}, 1, {~shatter.set(\vol, spec.map(obj.value))}, 2, {~spit.set(\vol, spec.map(obj.value))}, 3, {~limi.set(\vol, spec.map(obj.value))} ); }); y.keyDownAction_({|view, char, mod, uni, key| [view, char, mod, uni, key].do{|in| in.postln}; if(char==$l, { ~learnmode = ~learnmode + 1; ~learnmode = ~learnmode % 2; ~learnmode.switch( 1, { var key; key = x[2].string; key.postln; CCResponder({|src, chan, num, val| ~input = [src, chan, num].postln; { y.valueAction_(val.postln/128); }.defer; }).learn; }, 0, { ~master_fader_midi_responders.put(i, ~input); "learned to connect: ".post; ~input.post; " to: ".post; (x[2].string).postln;} ); }); }); }, 1, { //number y.action_({|obj| x[0].valueAction = spec.unmap(obj.value).postln; }); } ); }; }; ~master_faders.do{|x| x[0].valueAction_(0)}; ~master_faders.do{|x| x[1].valueAction_(0)}; ~fader_midi_responders = Dictionary.new; ~cursor_midi_responders = Dictionary.new; ~shatter_fader_midi_responders = Dictionary.new; ~shatter_master_fader_midi_responders = Dictionary.new; ~spit_fader_midi_responders = Dictionary.new; ~master_fader_midi_responders = Dictionary.new; ~controls = ~faders.collect{|section, i| section.collect{|fader, j| (~args[j].asString++i).asSymbol } }; ~pre_save.action_( { Dialog.savePanel( {|path| var string, file; // midi settings string = "~saved_faders = " ++ ~fader_midi_responders.asCompileString; string = string ++ ";" ; string = string + "~saved_cursors = " ++ ~cursor_midi_responders.asCompileString; string = string ++ ";" ; string = string ++ "~saved_shatter_faders = " ++ ~shatter_fader_midi_responders.asCompileString; string = string ++ ";" ; string = string ++ "~saved_shatter_master_faders = " ++ ~shatter_master_fader_midi_responders.asCompileString; string = string ++ ";" ; string = string ++ "~saved_spit_faders = " ++ ~spit_fader_midi_responders.asCompileString; string = string ++ ";" ; string = string ++ "~saved_master_faders = " ++ ~master_fader_midi_responders.asCompileString; string = string ++ ";" ; // values ~saved_fader_values = ~faders.collect{|section| section.collect{|fader| fader[0].value } }; string = string + "~saved_fader_values = " ++ ~saved_fader_values.asCompileString; string = string ++ ";"; ~saved_cursor_values = ~cursors.collect{|cursor| cursor.value; }; string = string + "~saved_cursor_values = " ++ ~saved_cursor_values.asCompileString; string = string ++ ";"; ~saved_range_values = ~ranges.collect{|x, i| [x.lo, x.hi] }; string = string + "~saved_range_values = " ++ ~saved_range_values.asCompileString; string = string ++ ";"; ~saved_paths = ~paths.collect{|x, i| x.value; }; string = string + "~saved_paths = " ++ ~saved_paths.asCompileString; string = string ++ ";"; ~saved_env_path = ~env_browser[0].value; string = string + "~saved_env_path = " ++ ~saved_env_path.asCompileString; string = string ++ ";"; ~saved_shatter_fader_values = ~shatter_faders.collect{|section| section.collect{|fader| fader[0].value; } }; string = string + "~saved_shatter_fader_values = " ++ ~saved_shatter_fader_values.asCompileString; string = string ++ ";"; ~saved_shatter_master_fader_values = ~shatter_master_faders.collect{|fader| fader[0].value; }; string = string ++ "~saved_shatter_master_fader_values = " ++ ~saved_shatter_master_fader_values.asCompileString; string = string ++ ";" ; ~saved_spit_fader_values = ~spit_faders.collect{|section| section.collect{|fader| fader[0].value; } }; string = string ++ "~saved_spit_fader_values = " ++ ~saved_spit_fader_values.asCompileString; string = string ++ ";"; ~saved_master_fader_values = ~master_faders.collect{|x| x[0].value}; string = string ++ "~saved_master_fader_values = " ++ ~saved_master_fader_values.asCompileString; string = string ++ ";"; // file i/o file = File(path, "w"); file.write(string); file.close; }, {} ); } ); ~pre_load.action_( {|button| button.value.switch( 1, { Dialog.getPaths({|path| var file, string; file = File(path[0], "r"); string = file.readAllString.postln; file.close; string.interpret; }, { ~pre_load.value_(0); "load operation cancelled".postln;}); }, 0, { //midi settings ~saved_faders.pairsDo{|key, value| CCResponder({|src, chan, num, val| {(~faders[key[0]][key[1]][key[2]]).valueAction_(val.postln/128);}.defer}, value[0], value[1], value[2], nil ); }; ~saved_cursors.pairsDo{|key, value| CCResponder({|src, chan, num, val| {(~cursors[key]).valueAction_(val.postln/128);}.defer}, value[0], value[1], value[2], nil ); }; ~saved_shatter_faders.pairsDo{|key, value| CCResponder({|src, chan, num, val| {(~shatter_faders[key[0]][key[1]][key[2]]).valueAction_(val.postln/128);}.defer}, value[0], value[1], value[2], nil ); }; ~saved_shatter_master_faders.pairsDo{|key, value| CCResponder({|src, chan, num, val| {(~shatter_master_faders[key][0]).valueAction_(val.postln/128);}.defer}, value[0], value[1], value[2], nil ); }; ~saved_spit_faders.pairsDo{|key, value| CCResponder({|src, chan, num, val| {(~spit_faders[key[0]][key[1]][key[2]]).valueAction_(val.postln/128);}.defer}, value[0], value[1], value[2], nil ); }; ~saved_master_faders.pairsDo{|key, value| CCResponder({|src, chan, num, val| {~master_faders[key][0].valueAction_(val.postln/128); }.defer}, value[0], value[1], value[2], nil ); }; //values ~saved_fader_values.do{|x, i| x.do{|y, j| ~faders[i][j][0].valueAction_(y) } }; ~saved_cursor_values.do{|x, i| ~cursors[i].valueAction_(x); }; ~saved_range_values.do{|x, i| ~ranges[i].setSpanActive(x[0], x[1]) }; if(~load_paths.value == 0, { ~saved_paths.do{|x, i| ~paths[i].valueAction_(x); }; ~env_browser[0].valueAction_(~saved_env_path); }); ~saved_shatter_fader_values.do{|x, i| x.do{|y, j| ~shatter_faders[i][j][0].valueAction_(y); } }; ~saved_shatter_master_fader_values.do{|x, i| ~shatter_master_faders[i][0].valueAction_(x); }; ~saved_spit_fader_values.do{|x, i| x.do{|y, j| ~spit_faders[i][j][0].valueAction_(y); } }; ~saved_master_fader_values.do{|x, i| ~master_faders[i][0].valueAction_(x); }; //responders ~fader_midi_responders = ~saved_faders; ~cursor_midi_responders = ~saved_cursors; ~shatter_fader_midi_responders = ~saved_shatter_faders; ~spit_fader_midi_responders = ~saved_spit_faders; ~shatter_master_fader_midi_responders = ~saved_shatter_master_faders; ~master_fader_midi_responders = ~saved_master_faders; } ) } ); ~filterbank_label = StaticText.new(~window, Rect(1080, 0, 8, 700)).string_("FILTERBANK:"); ~filterbank_master_label = StaticText.new(~window, Rect(1090, 660, 210, 20)).string_("FILTERBANK MASTER CONTROLS:"); ~waveshaper_label = StaticText.new(~window, Rect(300, 620, 200, 20)).string_("WAVESHAPER:"); ~grains_label = StaticText.new(~window, Rect(500, 300, 100, 20)).string_("GRAINS:"); ~master_label = StaticText.new(~window, Rect(10, 620, 500, 20)).string_("MASTER LEVELS:"); ~shatter = Synth(\shatter, [\out, 20, \vol, ~master_faders[1][0].value]); ~spit = Synth.after(~shatter, \spit, [\out, 20, \vol, ~master_faders[2][0].value]); ~limi = Synth.after(~spit, \limi, [\vol, ~master_faders[3][0].value]); ~window.onClose_({ CCResponder.removeAll; ~synths.do{|x| if(x.notNil, {x.free})}; ~shatter.free; ~spit.free; ~limi.free; ~steps.do{|x| if(x.notNil, {x.free})}; }); ) ਊ