{"id":333,"date":"2009-05-11T15:27:00","date_gmt":"2009-05-11T14:27:00","guid":{"rendered":"http:\/\/www.celesteh.com\/blog\/2009\/05\/11\/some-source-code\/"},"modified":"2015-06-19T00:23:50","modified_gmt":"2015-06-18T23:23:50","slug":"some-source-code","status":"publish","type":"post","link":"https:\/\/www.celesteh.com\/blog\/2009\/05\/11\/some-source-code\/","title":{"rendered":"Some Source Code"},"content":{"rendered":"<p><a href=\"http:\/\/www.celesteh.com\/blog\/2009\/05\/10\/buffertoo\/\">Yesterday, I posted<\/a> some links to a supercollider class, <a href=\"http:\/\/www.berkeleynoise.com\/celesteh\/code\/BufferTool\/BufferTool.sc\">BufferTool<\/a> and it&#8217;s <a href=\"http:\/\/www.berkeleynoise.com\/celesteh\/code\/BufferTool\/BufferTool.html\">helpfile<\/a>.  I thought maybe I should also post an example of using the class.<br \/>\nI wrote one piece, <a href=\"http:\/\/www.celesteh.com\/music\/cc-old\/rush-excuse.mp3\">&#8220;Rush to Excuse<\/a>,&#8221; in 2004 that uses most of the features of the class.  <a href=\"http:\/\/www.berkeleynoise.com\/celesteh\/podcast\/?p=15\">Program notes<\/a> are posted at my <a href=\"http:\/\/www.berkeleynoise.com\/celesteh\/podcast\">podcast<\/a>.  And, The code is below.  It requires two audio files, <a href=\"http:\/\/www.berkeleynoise.com\/celesteh\/samples\/geneva-rush.wav\">geneva-rush.wav<\/a> and <a href=\"http:\/\/www.berkeleynoise.com\/celesteh\/samples\/limbaugh-dog.aiff\">limbaugh-dog.aiff<\/a>  You will need to modify the source code to point at your local copy of those files.<br \/>\nThe piece chops up the dog file into evenly sized pieces and finds the average pitch for each of them.  It also finds phrases in Rush Limbaugh&#8217;s speech and intersperses his phrases with the shorter grains.  This piece is several years old, but I think it&#8217;s a good example to post because the code is all cleaned up to be in my MA thesis.  Also, listening to this for the first time in a few years makes me feel really happy. Americans finally seem to agree that torture is bad! Yay! (Oh alas, that it was ever a conversation.)<\/p>\n<pre>\n(\n\n \/\/ first run this section\n\n var sdef, buf;\n \n \n \/\/ a callback function for loading pitches\n  \n c = {\n\n  var callback, array, count;\n\n    array = g.grains;\n    count = g.grains.size - 1;\n     \n    callback = { \n   \n     var next, failed;\n      \n     failed = true;\n      \n     {failed == true}. while ({\n    \n      (count > 0 ). if ({\n    \n       count = count -1;\n       next = array.at(count);\n    \n       (next.notNil).if ({\n        next.findPitch(action: callback);\n        failed = false;\n       }, {\n        \/\/ this is bad. \n        \"failed\".postln;   \n        failed = true;\n       });\n      }, { \n       \/\/ we've run out of grains, so we must have succeeded\n       failed = false;\n       \"pitch finding finished\".postln;\n      });\n     });\n    };\n   \n   };\n\n \n \/\/ buffers can take a callback function for when they finish loading\n \/\/ so when the buffer loads, we create the BufferTools and then\n \/\/ analyze them\n  \n   buf = Buffer.read(s, \"sounds\/pundits\/limbaugh-dog.aiff\", action: {\n  \n    g = BufferTool.grain(s, buf);\n    h = BufferTool.grain(s, buf);\n    \"buffers read!\".postln;\n   \n  g.calc_grains_num(600, g.dur);\n    g.grains.last.findPitch(action: c.value);\n    h.prepareWords(0.35, 8000, true, 4000);\n \n   });\n \n   i = BufferTool.open(s, \"sounds\/pundits\/geneva-rush.wav\");\n\n  \n   sdef = SynthDef(marimba, {arg out=0, freq, dur, amp = 1, pan = 0;\n  \n   var ring, noiseEnv, noise, panner, totalEnv;\n   noise = WhiteNoise.ar(1);\n   noiseEnv = EnvGen.kr(Env.triangle(0.001, 1));\n     ring = Ringz.ar(noise * noiseEnv, freq, dur*5, amp);\n     totalEnv = EnvGen.kr(Env.linen(0.01, dur*5, 2, 1), doneAction:2);\n     panner = Pan2.ar(ring * totalEnv * amp, pan, 1);\n     Out.ar(out, panner);\n    }).writeDefFile;\n   sdef.load(s);\n   sdef.send(s);\n\n   SynthDescLib.global.read;  \/\/ pbinds and buffers act strangely if this line is omitted\n\n)\n\n\/\/ wait for: pitch finding finished\n\n(\n\n \/\/ this section runs the piece\n\n var end_grains, doOwnCopy;\n \n end_grains = g.grains.copyRange(g.grains.size - 20, g.grains.size);\n \n\n \/\/ for some reason, Array.copyRange blows up\n \/\/ this is better anyway because it creates copies of\n \/\/ the array elements\n\n \/\/ also:  why not stress test the garbage collector?\n \n doOwnCopy = { arg arr, start = 0, end = 10, inc = 1;\n \n  var new_arr, index;\n  \n  new_arr = [];\n  index = start.ceil;\n  end = end.floor;\n  \n  {(index < end) &#038;&#038; (index < arr.size)}. while ({\n  \n   new_arr = new_arr.add(arr.at(index).copy);\n   index = index + inc;\n  });\n  \n  new_arr;\n };\n\n \n \n Pseq( [\n\n\n  \/\/ The introduction just plays the pitches of the last 20 grains\n  \n  Pbind(\n \n   instrument, marimba,\n   amp,   0.4,\n   pan,   0,\n   \n   grain,   Pseq(end_grains, 1),\n   \n   [freq, dur],\n      Pfunc({ arg event;\n     \n       var grain;\n      \n       grain = event.at(grain);\n       [ grain.pitch, grain.dur];\n      })\n  ),\n  Pbind(\n  \n   grain, Prout({\n   \n      var length, loop, num_words, loop_size, max, grains, filler, size,\n       grain;\n      \n      length = 600;\n      loop = 5;\n      num_words = h.grains.size;\n      loop_size = num_words \/ loop;\n      filler = 0.6;\n      size = (g.grains.size * filler).floor;\n      \n      \n      grains = g.grains.reverse.copy;\n\n      \/\/ then play it straight through with buffer and pitches\n\n      {grains.size > 0} . while ({\n        \n       \/\/\"pop\".postln;\n       grain = grains.pop;\n       (grain.notNil).if({\n        grain.yield;\n       });\n      });\n      \n      \n      loop.do ({ arg index;\n      \n       \"looping\".postln;\n      \n\n       \/\/ mix up some pitched even sizes grains with phrases\n\n       max = ((index +2) * loop_size).floor;\n       (max > num_words). if ({ max = num_words});\n       \n       grains = \n         \/\/g.grains.scramble.copyRange(0, size) ++\n         doOwnCopy.value(g.grains.scramble, 0, size) ++\n         \/\/h.grains.copyRange((index * loop_size).ceil, max);\n         doOwnCopy.value(h.grains, (index * loop_size).ceil, max);\n         \n       \n\n       \/\/ start calculating for the next pass through the loop\n       \n       length = (length \/ 1.5).floor;\n       g.calc_grains_num(length, g.dur);\n       g.grains.last.findPitch(action: c.value);\n       \n       grains = grains.scramble;\n       \n\n       \/\/ ok, play them\n       \n       {grains.size > 0} . while ({\n        \n        \/\/\"pop\".postln;\n        grain = grains.pop;\n        (grain.notNil).if({\n         grain.yield;\n        });\n       });\n      });\n      \n      i.yield;\n      \"end\".postln;\n     }),\n   [bufnum, dur, grainDur, startFrame, freq, instrument], \n    Pfunc({arg event;\n    \n     \/\/ oddly, i find it easier to figure out the grain in one step\n     \/\/ and extract data from it in another step\n     \n     \/\/ this gets all the data you might need\n    \n     var grain, dur, pitch;\n     \n     grain = event.at(grain);\n     dur = grain.dur - 0.002;\n     \n     pitch = grain.pitch;\n     \n     (pitch == nil).if ({\n      pitch = 0;\n     });\n     \n     [\n      grain.bufnum,\n      dur,\n      grain.dur,\n      grain.startFrame,\n      pitch,\n      grain.synthDefName\n     ];\n     \n    }),\n      \n      \n   amp,   0.6,\n   pan,   0,\n   xPan,   0,\n   yPan,   0,\n   rate,   1,\n   \n   \n   twoinsts, Pfunc({ arg event;\n       \n     \/\/ so how DO you play two different synths in a Pbind\n     \/\/ step 1: figure out all the data you need for both\n     \/\/ step 2: give that a synthDef that will get invoked no matter what\n     \/\/ step 3: duplicate the event generated by the Pbind and tell it to play\n       \n       var evt, pitch;\n       \n       pitch = event.at(freq);\n       \n       (pitch.notNil). if ({\n\n        \/\/ the pitches below 20 Hz do cool things to the \n        \/\/ speakers, but they're not really pitches,\n        \/\/ so screw 'em\n        \n        (pitch > 20). if ({\n         evt = event.copy;\n         evt.put(instrument, marimba);\n         evt.put(amp, 0.4);\n         evt.play;\n         true;\n        }, {\n         false;\n        })\n       }, {\n        \/\/ don't let a nil pitch cause the Pbind to halt\n        event.put(freq, rest);\n        false;\n       });\n      })\n        \n  )      \n      \n       \n ], 1).play\n)\n <\/pre>\n<p>This code is under a Creative Commons Share Music License<\/p>\n<div class=\"powerpress_player\" id=\"powerpress_player_336\"><audio class=\"wp-audio-shortcode\" id=\"audio-333-1\" preload=\"none\" style=\"width: 100%;\" controls=\"controls\"><source type=\"audio\/mpeg\" src=\"http:\/\/www.celesteh.com\/music\/cc-old\/rush-excuse.mp3?_=1\" \/><a href=\"http:\/\/www.celesteh.com\/music\/cc-old\/rush-excuse.mp3\">http:\/\/www.celesteh.com\/music\/cc-old\/rush-excuse.mp3<\/a><\/audio><\/div><p class=\"powerpress_links powerpress_links_mp3\" style=\"margin-bottom: 1px !important;\">Podcast: <a href=\"http:\/\/www.celesteh.com\/music\/cc-old\/rush-excuse.mp3\" class=\"powerpress_link_pinw\" target=\"_blank\" title=\"Play in new window\" onclick=\"return powerpress_pinw('https:\/\/www.celesteh.com\/blog\/?powerpress_pinw=333-podcast');\" rel=\"nofollow\">Play in new window<\/a> | <a href=\"http:\/\/www.celesteh.com\/music\/cc-old\/rush-excuse.mp3\" class=\"powerpress_link_d\" title=\"Download\" rel=\"nofollow\" download=\"rush-excuse.mp3\">Download<\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Yesterday, I posted some links to a supercollider class, BufferTool and it&#8217;s helpfile. I thought maybe I should also post an example of using the class. I wrote one piece, &#8220;Rush to Excuse,&#8221; in 2004 that uses most of the features of the class. Program notes are posted at my podcast. And, The code is &hellip; <a href=\"https:\/\/www.celesteh.com\/blog\/2009\/05\/11\/some-source-code\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Some Source Code<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[1],"tags":[76,65,64],"class_list":["post-333","post","type-post","status-publish","format-standard","hentry","category-uncategorised","tag-celesteh","tag-coding","tag-supercollider"],"_links":{"self":[{"href":"https:\/\/www.celesteh.com\/blog\/wp-json\/wp\/v2\/posts\/333","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.celesteh.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.celesteh.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.celesteh.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.celesteh.com\/blog\/wp-json\/wp\/v2\/comments?post=333"}],"version-history":[{"count":2,"href":"https:\/\/www.celesteh.com\/blog\/wp-json\/wp\/v2\/posts\/333\/revisions"}],"predecessor-version":[{"id":4428,"href":"https:\/\/www.celesteh.com\/blog\/wp-json\/wp\/v2\/posts\/333\/revisions\/4428"}],"wp:attachment":[{"href":"https:\/\/www.celesteh.com\/blog\/wp-json\/wp\/v2\/media?parent=333"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.celesteh.com\/blog\/wp-json\/wp\/v2\/categories?post=333"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.celesteh.com\/blog\/wp-json\/wp\/v2\/tags?post=333"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}