{
   "ancestor_list" : [],
   "description" : "Graphical interface to experiment with granular sampling (one sound file at a time).",
   "author" : "Bruno Ruviaro",
   "name" : "Granular Sampling GUI Demo 1",
   "code" : "// ************************************\r\n// Granular Synthesis Demo (GUI)\r\n// Patch 1 - Granular Sampling\r\n// Bruno Ruviaro, 2013-08-20\r\n// ************************************\r\n\r\n/*\r\n\r\nUse the \"Open New File\" button to load a WAVE or AIFF file.\r\nThis granulator needs a mono file. If you open a stereo file,\r\nonly the left channel will be actually used (though you will\r\nsee both channels displayed on the Sound File View).\r\n\r\nTrigger: number of grains being triggered per second.\r\nTransp: rate of transposition in semitones.\r\ngrainDur: duration of individual grains.\r\nPan: distribution of grains in the stereo field (left / right).\r\ngrainAmp: amplitude of individual grains.\r\nReverse: probability of a grain to be played backwards (0-100%).\r\n\r\nGrains will be chosen randomly from anywhere within\r\nthe selected portion of the sound file. You can select\r\nportions of the sound file in two different ways:\r\na) directly on the waveform (click and drag);\r\nb) using the Selection Slider just below the waveform display.\r\n\r\nYou can also zoom in and out the waveform\r\nwith Shift + Right Click + Mouse Up/Down\r\n(Note: the selection slider will not follow the zoom.\r\nThe slider always reflects the position of current\r\nselection in regard to the total duration of the file)\r\n\r\nHow to start: select all (ctrl + A), then evaluate (ctrl + enter).\r\n(on a Mac, use the command key instead of control)\r\n\r\nIf you want to have several windows open to granulate different sounds,\r\ncomment out the lines Window.closeAll and Buffer.freeAll\r\n\r\n*/\r\n\r\ns.waitForBoot({\r\n\tvar win, soundFile, soundFileView, subwin, centerPosSlider, centerPosInSeconds, triggerSlider, transpSlider, transpToRate, durSlider, panSlider, ampSlider, reverseSlider, buffer, synth, startButton, openButton, selectionSpec;\r\n\r\n\r\n\t// FUNCTIONS\r\n\r\n\t// Convert transpSlider values (in semitones)\r\n\t// to rate values for TGrains (1 = no transp):\r\n\ttranspToRate = {arg transp; transp.linexp(-24, 24, 0.25, 4)};\r\n\r\n\t// Convert from centerPosSlider values (0-1)\r\n\t// to actual sound file position in seconds:\r\n\tcenterPosInSeconds = {\r\n\t\t[\r\n\t\t\tcenterPosSlider.lo.linlin(0, 1, 0, soundFile.duration),\r\n\t\t\tcenterPosSlider.hi.linlin(0, 1, 0, soundFile.duration)\r\n\t\t] // returns an array [lo, hi]\r\n\t};\r\n\r\n\tWindow.closeAll;\r\n\tBuffer.freeAll;\r\n\r\n\t// Main window\r\n\twin = Window.new(\"Granular Sampling\", Rect(50, 50, 600, 580), false).front;\r\n\twin.background = Color.grey(0.1, 0.9);\r\n\twin.onClose = {s.freeAll};\r\n\r\n\t// Sound File View\r\n\tsoundFileView = SoundFileView.new(win, Rect(30, 20, 540, 200))\r\n\t// .soundfile_(soundFile)\r\n\t// .read(0, soundFile.numFrames)\r\n\t.gridOn_(false);\r\n\r\n\t// What to do when user selects portion of sound file directly\r\n\t// (i.e., on waveform, not using slider)\r\n\tsoundFileView.mouseUpAction = {arg view;\r\n\t\tvar loFrames, hiFrames, loSlider, hiSlider;\r\n\t\tloFrames = view.selection(0)[0];\r\n\t\thiFrames = view.selection(0)[1] + loFrames;\r\n\t\tloSlider = selectionSpec.unmap(loFrames);\r\n\t\thiSlider = selectionSpec.unmap(hiFrames);\r\n\t\t2.do{centerPosSlider.setSpanActive(loSlider, hiSlider)}; // 2.do = hack...\r\n\t};\r\n\r\n\t// Open Button\r\n\topenButton = Button.new(win, Rect(460, 20, 110, 30))\r\n\t.states_([[\"open new file\", Color.black, Color.gray]])\r\n\t.action_({\r\n\r\n\t\t\"HELLO\".postln;\r\n\t\t// Stop whatever is playing\r\n\t\ts.freeAll;\r\n\r\n\t\tstartButton.value = 0;\r\n\r\n\t\tDialog.openPanel(\r\n\t\t\tokFunc: { |path|\r\n\t\t\t\tsoundFile = SoundFile.new;\r\n\t\t\t\tsoundFile.openRead(path);\r\n\t\t\t\t// Load sound into buffer\r\n\t\t\t\tbuffer = Buffer.readChannel(s, path, channels: [0]);\r\n\t\t\t\t// Display sound on View\r\n\t\t\t\tsoundFileView.soundfile_(soundFile);\r\n\t\t\t\tsoundFileView.read(0, soundFile.numFrames);\r\n\t\t\t\t// ControlSpec (slider 0-1 <=> numFrames)\r\n\t\t\t\tselectionSpec = ControlSpec(0, soundFile.numFrames);\r\n\t\t\t\t// selectionSpec.postln;\r\n\t\t\t\t// Set initial selection on View\r\n\t\t\t\tsoundFileView.setSelection(0, selectionSpec.map([0.1, 0.2]));\r\n\t\t\t\t// Update slider\r\n\t\t\t\tsoundFileView.mouseUpAction.value(soundFileView);\r\n\t\t\t},\r\n\t\t\tcancelFunc: {\"cancelled\"}\r\n\t\t);\r\n\r\n\r\n\r\n\t});\r\n\r\n\r\n\t// Sub view to group all sliders\r\n\tsubwin = CompositeView.new(win, Rect(20, 225, 560, 360))\r\n\t// .background_(Color.red(0.4))\r\n\t;\r\n\tsubwin.decorator = FlowLayout(subwin.bounds, margin: 0@0, gap: 5@10);\r\n\r\n\tcenterPosSlider = RangeSlider(subwin, 560@50)\r\n\t.lo_(0.1)\r\n\t.hi_(0.3)\r\n\t.action_({ |v|\r\n\t\tvar lo, hi, size;\r\n\t\tlo = selectionSpec.map(v.lo);\r\n\t\thi = selectionSpec.map(v.hi);\r\n\t\tsize = hi - lo;\r\n\t\tsoundFileView.setSelection(0, [lo, size]);\r\n\t\tif(startButton.value==1, {synth.set(\r\n\t\t\t\\centerPosLo, centerPosInSeconds.value[0],\r\n\t\t\t\\centerPosHi, centerPosInSeconds.value[1])});\r\n\t\t// [\"uau\", v.lo, v.hi, lo, hi].postln;\r\n\t});\r\n\r\n\ttriggerSlider = EZRanger(\r\n\t\tparent: subwin,\r\n\t\tbounds: 560@30,\r\n\t\tlabel: \"Trigger  \",\r\n\t\tcontrolSpec: ControlSpec(\r\n\t\t\tminval:\t0.5,\r\n\t\t\tmaxval: 50,\r\n\t\t\twarp: 'exp',\r\n\t\t\tstep: 0.1,\r\n\t\t\tunits: \" t/s\"),\r\n\t\taction: {|v|\r\n\t\t\tif(startButton.value==1, {synth.set(\\triggerLo, v.lo, \\triggerHi, v.hi)})},\r\n\t\tinitVal: [1, 2],\r\n\t\tlabelWidth: 60,\r\n\t\tunitWidth: 30)\r\n\t.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);\r\n\r\n\ttranspSlider = EZRanger(\r\n\t\tparent: subwin,\r\n\t\tbounds: 560@30,\r\n\t\tlabel: \"Transp  \",\r\n\t\tcontrolSpec: ControlSpec(\r\n\t\t\tminval:\t-24, // two octaves below\r\n\t\t\tmaxval: 24, // two octaves above\r\n\t\t\twarp: 'lin',\r\n\t\t\tstep: 1, // step by semitones\r\n\t\t\tunits: \" ST\"),\r\n\t\taction: {|v|\r\n\t\t\tif(startButton.value==1, {\r\n\t\t\t\tsynth.set(\r\n\t\t\t\t\t\\rateLo, transpToRate.value(v.lo),\r\n\t\t\t\t\t\\rateHi, transpToRate.value(v.hi))})},\r\n\t\tinitVal: [0, 0],\r\n\t\tlabelWidth: 60,\r\n\t\tunitWidth: 30)\r\n\t.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);\r\n\r\n\tdurSlider = EZRanger(\r\n\t\tparent: subwin,\r\n\t\tbounds: 560@30,\r\n\t\tlabel: \"grainDur  \",\r\n\t\tcontrolSpec: ControlSpec(\r\n\t\t\tminval:\t0.1,\r\n\t\t\tmaxval: 2,\r\n\t\t\twarp: 'lin',\r\n\t\t\tstep: 0.1,\r\n\t\t\tunits: \"sec\"),\r\n\t\taction: {|v|\r\n\t\t\tif(startButton.value==1, {synth.set(\\durLo, v.lo, \\durHi, v.hi)})},\r\n\t\tinitVal: [0, 0],\r\n\t\tlabelWidth: 70,\r\n\t\tunitWidth: 30)\r\n\t.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);\r\n\r\n\tpanSlider = EZRanger(\r\n\t\tparent: subwin,\r\n\t\tbounds: 560@30,\r\n\t\tlabel: \"Pan     \",\r\n\t\tcontrolSpec: ControlSpec(\r\n\t\t\tminval:\t-1,\r\n\t\t\tmaxval: 1,\r\n\t\t\twarp: 'lin',\r\n\t\t\tstep: 0.1,\r\n\t\t\tunits: \"L/R\"),\r\n\t\taction: {|v|\r\n\t\t\tif(startButton.value==1, {synth.set(\\panLo, v.lo, \\panHi, v.hi)})},\r\n\t\tinitVal: [0, 0],\r\n\t\tlabelWidth: 60,\r\n\t\tunitWidth: 30)\r\n\t.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);\r\n\r\n\tampSlider = EZRanger(\r\n\t\tparent: subwin,\r\n\t\tbounds: 560@30,\r\n\t\tlabel: \"grainAmp \",\r\n\t\tcontrolSpec: ControlSpec(\r\n\t\t\tminval:\t0.0,\r\n\t\t\tmaxval: 1,\r\n\t\t\twarp: 'lin',\r\n\t\t\tstep: 0.01,\r\n\t\t\tunits: \"amp\"),\r\n\t\taction: {|v|\r\n\t\t\tif(startButton.value==1, {synth.set(\\ampLo, v.lo, \\ampHi, v.hi)})},\r\n\t\tinitVal: [0.2, 0.4],\r\n\t\tlabelWidth: 73,\r\n\t\tunitWidth: 35)\r\n\t.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);\r\n\r\n\treverseSlider = EZSlider(\r\n\t\tparent: subwin,\r\n\t\tbounds: 560@30,\r\n\t\tlabel: \"Reverse  \",\r\n\t\tcontrolSpec: ControlSpec(\r\n\t\t\tminval:\t0,\r\n\t\t\tmaxval: 100,\r\n\t\t\twarp: 'lin',\r\n\t\t\tstep: 1,\r\n\t\t\tunits: \"%\"),\r\n\t\taction: {|v|\r\n\t\t\tif(startButton.value==1, {synth.set(\\reverseProb, v.value/100)});\r\n\t\t},\r\n\t\tinitVal: 0.0,\r\n\t\tlabelWidth: 63,\r\n\t\tunitWidth: 35)\r\n\t.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);\r\n\r\n\tstartButton = Button.new(subwin, 560@40)\r\n\t.states_([[\"START\"], [\"STOP\", Color.black, Color.gray]])\r\n\t.action_({arg button;\r\n\t\tif(button.value==1,\r\n\t\t\t{\r\n\t\t\t\tsynth = Synth(\"granular-sampling\", [\r\n\t\t\t\t\t\\triggerLo, triggerSlider.lo,\r\n\t\t\t\t\t\\triggerHi, triggerSlider.hi,\r\n\t\t\t\t\t\\rateLo, transpToRate.value(transpSlider.lo),\r\n\t\t\t\t\t\\rateHi, transpToRate.value(transpSlider.hi),\r\n\t\t\t\t\t\\centerPosLo, centerPosInSeconds.value[0],\r\n\t\t\t\t\t\\centerPosHi, centerPosInSeconds.value[1],\r\n\t\t\t\t\t\\durLo, durSlider.lo,\r\n\t\t\t\t\t\\durHi, durSlider.hi,\r\n\t\t\t\t\t\\panLo, panSlider.lo,\r\n\t\t\t\t\t\\panHi, panSlider.hi,\r\n\t\t\t\t\t\\ampLo, ampSlider.lo,\r\n\t\t\t\t\t\\ampHi, ampSlider.hi,\r\n\t\t\t\t\t\\reverseProb, reverseSlider.value,\r\n\t\t\t\t\t\\bufnum, buffer.bufnum]);\r\n\t\t\t},\r\n\t\t\t{synth.free});\r\n\t});\r\n\r\n\r\n\t// SynthDef\r\n\tSynthDef(\"granular-sampling\", {\r\n\t\targ triggerLo, triggerHi, rateLo, rateHi, centerPosLo, centerPosHi, durLo, durHi, panLo, panHi, ampLo, ampHi, reverseProb, bufnum;\r\n\r\n\t\tvar trig, trigFreqMess, rate, centerPos, dur, pan, amp, coin, reverse, snd;\r\n\t\t// var bufdur = BufDur.kr(buffer);\r\n\r\n\t\ttrigFreqMess = LFNoise2.kr(12).range(0.5, 1);\r\n\t\ttrig = Impulse.kr(LFNoise0.kr(trigFreqMess).range(triggerLo, triggerHi));\r\n\r\n\t\trate = Dwhite(rateLo, rateHi);\r\n\t\tcenterPos = Dwhite(centerPosLo, centerPosHi);\r\n\t\tdur = Dwhite(durLo, durHi);\r\n\t\tpan = Dwhite(panLo, panHi);\r\n\t\tamp = Dwhite(ampLo, ampHi);\r\n\t\tcoin = CoinGate.kr(reverseProb, trig);\r\n\t\treverse = Select.kr(coin, [1, -1]);\r\n\t\t// reverse.poll(trig);\r\n\r\n\t\tDemand.kr(trig, 0, [rate, centerPos, dur, pan, amp]);\r\n\r\n\t\tsnd = TGrains.ar(\r\n\t\t\tnumChannels: 2,\r\n\t\t\ttrigger: trig,\r\n\t\t\tbufnum: bufnum,\r\n\t\t\trate: rate * reverse,\r\n\t\t\tcenterPos: centerPos,\r\n\t\t\tdur: dur,\r\n\t\t\tpan: pan,\r\n\t\t\tamp: amp);\r\n\r\n\t\tOut.ar(0, snd);\r\n\r\n\t}).add;\r\n\r\n}); // end of block",
   "is_private" : null,
   "id" : "1-4UF",
   "labels" : [
      "gui",
      "synthesis techniques",
      "granular synthesis",
      "sampling"
   ]
}
