{
   "name" : "GrainOTec",
   "author" : "Dindoléon",
   "ancestor_list" : [],
   "description" : "A GUI module to produce granular synthesis textures. Controls are : amplitude, trigger rate, grain duration, number of simultaneous grains, frequency offset between simultaneous grains, random panning and enveloppe.",
   "labels" : [
      "gui",
      "granular",
      "grain",
      "module"
   ],
   "code" : "(\r\n// GrainOTec module for SuperCollider, by Dindoléon\r\n// licensed under GNU GPL v3\r\n// Have fun, but take care with the DBs !\r\n\r\nvar win, rout, draw_slider, font;\r\n\r\nvar volume, volume_slider, volume_value, volume_label, volume_color;\r\nvar lifetime, lifetime_slider, lifetime_value, lifetime_label, lifetime_color;\r\nvar env, env_array, env_points, env_slider, env_duration, env_multiSlider, env_value, env_label, env_color;\r\nvar freq, base_freq, freq_value, freq_slider, freq_mul, freq_mul_value, freq_mul_slider, freq_label, freq_mul_label, freq_color, freq_mul_color;\r\nvar pan, pan_value, pan_slider, pan_label, pan_color;\r\n\r\nvar icon_size = 10, stroke_size = 2, outline_size = 15;\r\n\r\nfont = Font( size: 20 );\r\n\r\nbase_freq = 220;\r\nfreq = [base_freq];\r\nfreq_value = 0;\r\n\r\nfreq_mul = 1;\r\nfreq_mul_value = 0;\r\n\r\nvolume = 0;\r\nvolume_value = 0;\r\n\r\nlifetime = 0.005;\r\nlifetime_value = 0.6;\r\n\r\npan = 0;\r\npan_value = 0;\r\n\r\nenv_duration = 0.005;\r\nenv_value = 0.6;\r\n\r\nenv_points = 8;\r\nenv_array = Array.fill(env_points+2, 0);\r\n\r\nvolume_color = Color( 0.8, 0, 0.3 );\r\nlifetime_color = Color( 0, 0.3, 0.8 );\r\nenv_color = Color( 0, 0.8, 0.3 );\r\nfreq_color = Color( 0.8, 0.3, 0 );\r\nfreq_mul_color = Color( 0.3, 0, 0.8 );\r\npan_color = Color( 0.3, 0.8, 0 );\r\n\r\nenv = Env.new(\r\n\tlevels: env_array,\r\n\ttimes: Array.fill(env_points+1, env_duration/(env_points+1))\r\n);\r\n\r\nSynthDef(\\grain, { | freq = 220 |\r\n\tvar snd, env, envctl, envgen, pan, amp;\r\n\r\n\tenv = Env.newClear( 10 );\r\n\tenvctl = \\env.kr( env.asArray );\r\n\tenvgen = EnvGen.ar( envctl, 1, doneAction: 2 );\r\n\tsnd = LinPan2.ar( SinOsc.ar( freq ) * envgen * \\amp.kr(1), \\pan.ar(0) );\r\n\r\n\tOut.ar( 0, snd ); }).add;\r\n\r\nrout = Routine {\r\n\tloop {\r\n\t\tfreq.do( { |f| Synth(\\grain, [\\freq, f, \\amp, volume/freq.size, \\env, env, \\pan, pan.asFloat.rand] ) });\r\n\t\tlifetime.yield;\r\n\t};\r\n}.play();\r\n\r\nwin = Window(\"GrainOTec\", Rect( 5, 5, 305, 300 ), false );\r\nwin.background_(Color.black);\r\nwin.front;\r\n\r\n// Volume Slider\r\nvolume_slider = UserView( win, Rect( 5, 5, 45, 190 ));\r\nvolume_slider.drawFunc = { draw_slider.value( volume_slider, volume_value, volume_color ) };\r\nvolume_slider.mouseDownAction = { | volume_slider, x, y, m |\r\n\tvolume_value = (y).linlin( 0, volume_slider.bounds.height, 1, 0 );\r\n\tvolume = volume_value;\r\n\tvolume_slider.refresh };\r\nvolume_slider.mouseMoveAction = volume_slider.mouseDownAction;\r\nvolume_label = StaticText( volume_slider, Rect( 25, 165, 28, 28 ));\r\nvolume_label.string_(\"a\");\r\nvolume_label.font_(font);\r\nvolume_label.stringColor_(Color(1,1,1,0.75));\r\n\r\n// Lifetime Slider\r\nlifetime_slider = UserView( win, Rect( 55, 5, 45, 190 ));\r\nlifetime_slider.drawFunc = { draw_slider.value( lifetime_slider, lifetime_value, lifetime_color ) };\r\nlifetime_slider.mouseDownAction = { | lifetime_slider, x, y, m |\r\n\tlifetime_value = (y).linlin( 0, lifetime_slider.bounds.height, 1, 0 );\r\n\tlifetime = lifetime_value.linexp( 0, 1, 0.1, 0.001 );\r\n\tlifetime_slider.refresh };\r\nlifetime_slider.mouseMoveAction = lifetime_slider.mouseDownAction;\r\nlifetime_label = StaticText( lifetime_slider, Rect( 25, 165, 28, 28 ));\r\nlifetime_label.string_(\"t\");\r\nlifetime_label.font_(font);\r\nlifetime_label.stringColor_(Color(1,1,1,0.75));\r\n\r\n// Env Slider\r\nenv_slider = UserView( win, Rect( 105, 5, 45, 190 ));\r\nenv_slider.drawFunc = { draw_slider.value( env_slider, env_value, env_color ) };\r\nenv_slider.mouseDownAction = { | env_slider, x, y, m |\r\n\tenv_value = (y).linlin( 0, env_slider.bounds.height, 1, 0 );\r\n\tenv_duration = env_value.linexp( 0, 1, 0.1, 0.001 );\r\n\tenv.times = Array.fill(env_points+1, env_duration/(env_points+1));\r\n\tenv_slider.refresh };\r\nenv_slider.mouseMoveAction = env_slider.mouseDownAction;\r\nenv_label = StaticText( env_slider, Rect( 25, 165, 28, 28 ));\r\nenv_label.string_(\"d\");\r\nenv_label.font_(font);\r\nenv_label.stringColor_(Color(1,1,1,0.75));\r\n\r\n// Freq Slider\r\nfreq_slider = UserView( win, Rect( 155, 5, 45, 190 ));\r\nfreq_slider.drawFunc = { draw_slider.value( freq_slider, freq_value, freq_color ) };\r\nfreq_slider.mouseDownAction = { | freq_slider, x, y, m |\r\n\tfreq_value = (y).linlin( 0, freq_slider.bounds.height, 1, 0 );\r\n\tfreq = Array.fill(freq_value.linlin( 0, 1, 1, 7 ).asInt, base_freq);\r\n\tif( freq_value.linlin( 0, 1, 1, 7 ).asInt > 1, { for( 1, freq_value.linlin( 0, 1, 1, 7 ).asInt -1, { |i| freq[i] = freq[i-1] * freq_mul; } ) });\r\n\tfreq_slider.refresh };\r\nfreq_slider.mouseMoveAction = freq_slider.mouseDownAction;\r\nfreq_label = StaticText( freq_slider, Rect( 25, 165, 28, 28 ));\r\nfreq_label.string_(\"h\");\r\nfreq_label.font_(font);\r\nfreq_label.stringColor_(Color(1,1,1,0.75));\r\n\r\n// Freq Mul Slider\r\nfreq_mul_slider = UserView( win, Rect( 205, 5, 45, 190 ));\r\nfreq_mul_slider.drawFunc = { draw_slider.value( freq_mul_slider, freq_mul_value, freq_mul_color ) };\r\nfreq_mul_slider.mouseDownAction = { | freq_slider, x, y, m |\r\n\tfreq_mul_value = (y).linlin( 0, freq_slider.bounds.height, 1, 0 );\r\n\tfreq_mul = 1 + freq_mul_value;\r\n\tfreq = Array.fill(freq_value.linlin( 0, 1, 1, 7 ).asInt, base_freq);\r\n\tif( freq_value.linlin( 0, 1, 1, 7 ).asInt > 1, { for( 1, freq_value.linlin( 0, 1, 1, 7 ).asInt -1, { |i| freq[i] = freq[i-1] * freq_mul; } ) });\r\n\tfreq_mul_slider.refresh };\r\nfreq_mul_slider.mouseMoveAction = freq_mul_slider.mouseDownAction;\r\nfreq_mul_label = StaticText( freq_mul_slider, Rect( 25, 165, 28, 28 ));\r\nfreq_mul_label.string_(\"m\");\r\nfreq_mul_label.font_(font);\r\nfreq_mul_label.stringColor_(Color(1,1,1,0.75));\r\n\r\n// Pan Slider\r\npan_slider = UserView( win, Rect( 255, 5, 45, 190 ));\r\npan_slider.drawFunc = { draw_slider.value( pan_slider, pan_value, pan_color ) };\r\npan_slider.mouseDownAction = { | lifetime_slider, x, y, m |\r\n\tpan_value = (y).linlin( 0, lifetime_slider.bounds.height, 1, 0 );\r\n\tpan = pan_value;\r\n\tpan_slider.refresh };\r\npan_slider.mouseMoveAction = pan_slider.mouseDownAction;\r\npan_label = StaticText( pan_slider, Rect( 25, 165, 28, 28 ));\r\npan_label.string_(\"p\");\r\npan_label.font_(font);\r\npan_label.stringColor_(Color(1,1,1,0.75));\r\n\r\n// Enveloppe MultiSlider\r\nenv_multiSlider = MultiSliderView( win, Rect( 5, 200, 295, 90 ) );\r\nenv_multiSlider.value = Array.fill(env_points, {0.0});\r\nenv_multiSlider.isFilled = true;\r\nenv_multiSlider.elasticMode_(true);\r\nenv_multiSlider.fillColor = Color(0,0,0.1);\r\nenv_multiSlider.strokeColor = Color.red;\r\nenv_multiSlider.background_(Color(0,0,0.2));\r\nenv_multiSlider.gap = 0;\r\nenv_multiSlider.drawRects = false; // Display as bar charts\r\nenv_multiSlider.drawLines = true; // Display as plot\r\n\r\nenv_multiSlider.action = { arg multi;\r\n\tvar index = multi.index;\r\n\tvar value = multi.currentvalue;\r\n\tenv_array[(index+1)] = value;\r\n\tenv.levels = env_array; };\r\n\r\n// Slider Draw Function\r\ndraw_slider = { | slider, value, color |\r\n\tPen.width = stroke_size;\r\n\r\n\t// Draw the frame\r\n\tPen.strokeColor = Color.white;\r\n\tPen.fillColor = Color.black;\r\n\tPen.addRect(Rect(0, 0, slider.bounds.width,slider.bounds.height));\r\n\tPen.draw(3);\r\n\r\n\t// Draw the losange\r\n\tPen.moveTo( ( slider.bounds.width/2 ) @ ( ( slider.bounds.height - ( slider.bounds.height * value) ) - icon_size ) );\r\n\tPen.lineTo( ( slider.bounds.width/2 -icon_size ) @ ( slider.bounds.height - (slider.bounds.height*value) ) );\r\n\tPen.lineTo( ( slider.bounds.width/2 ) @ ( ( slider.bounds.height - ( slider.bounds.height * value) ) + icon_size ) );\r\n\tPen.lineTo( ( slider.bounds.width/2 + icon_size ) @ ( slider.bounds.height - (slider.bounds.height*value) ) );\r\n\tPen.lineTo( ( slider.bounds.width/2 ) @ ( ( slider.bounds.height - ( slider.bounds.height * value) ) - icon_size ) );\r\n\r\n\tPen.fillColor = color;\r\n\tPen.fill;\r\n\r\n\tPen.moveTo( ( slider.bounds.width/2 ) @ ( ( slider.bounds.height - ( slider.bounds.height * value) ) - outline_size ) );\r\n\tPen.lineTo( ( slider.bounds.width/2 -outline_size ) @ ( slider.bounds.height - (slider.bounds.height*value) ) );\r\n\tPen.lineTo( ( slider.bounds.width/2 ) @ ( ( slider.bounds.height - ( slider.bounds.height * value) ) + outline_size ) );\r\n\tPen.lineTo( ( slider.bounds.width/2 + outline_size ) @ ( slider.bounds.height - (slider.bounds.height*value) ) );\r\n\tPen.lineTo( ( slider.bounds.width/2 ) @ ( ( slider.bounds.height - ( slider.bounds.height * value) ) - outline_size ) );\r\n\r\n\tPen.moveTo( ( slider.bounds.width/2 ) @ 0 );\r\n\tPen.lineTo( ( slider.bounds.width/2 ) @ ( ( slider.bounds.height - ( slider.bounds.height * value) ) - outline_size ) );\r\n\r\n\tPen.moveTo( ( slider.bounds.width/2 ) @ ( slider.bounds.height ) );\r\n\tPen.lineTo( ( slider.bounds.width/2 ) @ ( ( slider.bounds.height - ( slider.bounds.height * value) ) + outline_size ) );\r\n\r\n\tPen.strokeColor = color;\r\n\tPen.stroke;\r\n};\r\n)",
   "is_private" : null,
   "id" : "1-5bb"
}
