{
   "description" : "A slightly modified version of my sampler (https://scsynth.org/t/sorting-list-of-dictionaries-by-keys/705, https://scsynth.org/t/dictionary-and-array-inside-patterns/747, https://scsynth.org/t/orchestral-texture-v1/994/3).\r\n\r\nI made it to test it with some beautiful pan pipe sound files\r\nrecorded by timohanes (@ https://freesound.org/people/timohanes/packs/4159/ )\r\nand released under CC0.",
   "ancestor_list" : [],
   "author" : "nicolaariutti",
   "name" : "panflute sampler",
   "id" : "1-5c4",
   "is_private" : null,
   "code" : "/*\r\n* A test on creating a sampler for some beautiful pan pipe sound files\r\n* recorded by timohanes (@ https://freesound.org/people/timohanes/packs/4159/ )\r\n* and released under CC0.\r\n*/\r\n\r\n// first of all start the server\r\ns.boot;\r\n\r\n// the following dictionary will contain all information\r\n// related to the instruments like:\r\n// * sample buffers\r\n// * corresponding MIDI notes\r\n// * lowest MIDI of the recoded samples\r\n~panflute_sampler = Dictionary.new();\r\n\r\n// the path where the samples are stored\r\n~samples_path = \"path-to-the-samples-folder\";\r\n// following global contains a string which is contained in all the samples names\r\n~file_name_body = \"__timohanes__pan-pipe-\";\r\n\r\n\r\n// fill the dictionary with ordered data from the samples\r\n(\r\nvar tmp_buffers;\r\nvar tmp_array;\r\nvar path;\r\n\r\n// 1. load samples from a folder extracting only one channel from the stereo files\r\npath = PathName(~sample_path);\r\npath.entries.do{\r\n\t|item|\r\n\tif( item.fileName.contains(),\r\n\t\t{\r\n\t\t\t// load only a single channel from the audiofile (MONO)\r\n\t\t\ttmp_buffers = tmp_buffers.add( Buffer.readChannel(s, item.fullPath, channels:1));\r\n\t\t},{\r\n\t\t\t//do nothing\r\n\t\t}\r\n\t);\r\n};\r\n\r\n\r\n// 2. create an array of dictionaries\r\ntmp_array = Array.newClear();\r\n\r\ntmp_buffers.do{\r\n\t|item, index|\r\n\tvar d = Dictionary.new;\r\n\tvar string = PathName(item.path).fileNameWithoutExtension;\r\n\tvar output = string.findRegexp(\"[abcdefgABCDEFG]#?[0123456789]\");\r\n\tif( output.isEmpty.not, {\r\n\t\tvar noteNameAll = output[0][1];\r\n\t\tvar octNumber = noteNameAll.rotate(1)[0].asString.asInteger;\r\n\t\tvar noteName = noteNameAll[0].asString;\r\n\t\tvar isSharp = noteNameAll.contains(\"#\"); // boolean\r\n\t\t//[noteNameAll, noteName, octNumber, isSharp].postln;\r\n\t\tvar midiNumber = (octNumber +1) * 12;\r\n\t\tswitch( noteName,\r\n\t\t\t\"c\", { midiNumber = midiNumber+0; },\r\n\t\t\t\"d\", { midiNumber = midiNumber+2; },\r\n\t\t\t\"e\", { midiNumber = midiNumber+4; },\r\n\t\t\t\"f\", { midiNumber = midiNumber+5; },\r\n\t\t\t\"g\", { midiNumber = midiNumber+7; },\r\n\t\t\t\"a\", { midiNumber = midiNumber+9; },\r\n\t\t\t\"b\", { midiNumber = midiNumber+11; },\r\n\t\t);\r\n\t\tif(isSharp, {midiNumber = midiNumber + 1;});\r\n\t\t[noteNameAll, noteName, isSharp, octNumber, midiNumber].postln;\r\n\t\td.add(\\midi -> midiNumber.asInteger);\r\n\t\td.add(\\note -> noteNameAll);\r\n\t\td.add(\\buffer -> item);\r\n\t\ttmp_array = tmp_array.add(d);\r\n\t},\r\n\t{\r\n\t\toutput.postln;\r\n\t});\r\n};\r\n\r\ntmp_array.sortBy(\\midi);\r\n\r\n~panflute_sampler.put( \"lowest_note\", tmp_array[0][\\midi] );\r\n~panflute_sampler.put(   \"buffers\", Array.newClear() );\r\n~panflute_sampler.put( \"midinotes\", Array.newClear() );\r\n\r\ntmp_array.do{\r\n\t|item, index|\r\n\t[index, item.values].postln;\r\n\t~panflute_sampler.put( \"buffers\",   ~panflute_sampler.at(\"buffers\").add(item[\\buffer]) );\r\n\t~panflute_sampler.put( \"midinotes\", ~panflute_sampler.at(\"midinotes\").add(item[\\midi]) );\r\n};\r\n)\r\n\r\n// print something to check if the dictionary has been\r\n// succesfully created and filled with data\r\n~panflute_sampler.at(\"lowest_note\");\r\n~panflute_sampler.at(\"buffers\").do({|item| item.postln});\r\n~panflute_sampler.at(\"midinotes\").do({|item| item.postln});\r\n\r\n\r\n// define some synth to play the samples\r\n\r\n// SIMPLE PLAYER\r\n// A synth to play the sample as it is.\r\n(\r\nSynthDef(\\simple_player, {\r\n\t|\r\n\tout=0, amp=0.5, gate=1, buf, rate=1.0, pan=0.0,\r\n\tatk=0.01, dcy=0.2, sus=0.7, rel=0.1\r\n\t|\r\n\tvar sig, env;\r\n\tenv = EnvGen.ar(Env.adsr(atk, dcy, sus, rel), gate, doneAction:2);\r\n\tsig = PlayBuf.ar(1, buf, BufRateScale.ir(buf)*rate, 1, doneAction:0);\r\n\tsig = sig * amp * env;\r\n\tsig = HPF.ar(sig, 400);\r\n\tsig = LeakDC.ar(sig);\r\n\tOut.ar(out, Pan2.ar(sig, pan));\r\n}).add;\r\n)\r\n\r\n\r\n// GRAIN PLAYER\r\n// a synth to play buffers in a granular fashion\r\n(\r\nSynthDef(\\grain_player, {\r\n\t|\r\n\tout=0, gate=1, amp=0.9, buf, rate=1, pan=0.0,\r\n\tatk=5, dcy=0.2, sus=0.7, rel=5\r\n\t|\r\n    var sig, env;\r\n\r\n\tvar density = LFNoise0.kr(25).range(1, 5);\r\n\tvar trigger = Impulse.kr( density );\r\n\tvar pos = 0.5 + TRand.kr(trigger, -0.35, 0.35);\r\n\tvar length = 1 + TRand.kr(trigger, 0.25, 0.35);\r\n\r\n\tenv = EnvGen.kr(Env.adsr(atk, dcy, sus, rel), gate, doneAction:2);\r\n\r\n    sig = GrainBuf.ar(2,\r\n\t\ttrigger,\r\n\t\tlength,\r\n\t\tbuf,\r\n\t\trate,\r\n\t\tpos,\r\n\t\t2,\r\n\t\tpan: pan);\r\n\r\n\tsig = sig * amp * env;\r\n\tsig = HPF.ar(sig, 400);\r\n\tsig = LeakDC.ar(sig);\r\n\tOut.ar(out, sig);\r\n}).add;\r\n)\r\n\r\n\r\n// HYBRID PLAYER\r\n// A synth which make use of the initial section of the sample in order to get a sharper attack,\r\n// then it moves automatically to the sustain section (made with a granular Ugen)\r\n// to make the tail of the sound indipendent from the sample duration.\r\n(\r\nSynthDef(\\hybrid_player, {\r\n\t|\r\n\tout=0, gate=1, amp=0.9, buf, rate=1, pan=0.0,\r\n\tatk=5, dcy=0.1, sus=0.7, rel=5\r\n\t|\r\n    var sig, sig1, sig2, env;\r\n\r\n\tvar density = LFNoise0.kr(25).range(1, 5);\r\n\tvar trigger = Impulse.kr( density );\r\n\tvar pos = 0.5 + TRand.kr(trigger, -0.35, 0.35);\r\n\tvar length = 1 + TRand.kr(trigger, 0.25, 0.35);\r\n\r\n\tenv = EnvGen.kr(Env.adsr(atk, dcy, sus, rel), gate, doneAction:2);\r\n\r\n\tsig1 = PlayBuf.ar(1, buf, BufRateScale.ir(buf)*rate, 1, doneAction:0);\r\n\r\n    sig2 = GrainBuf.ar(2,\r\n\t\ttrigger,\r\n\t\tlength,\r\n\t\tbuf,\r\n\t\trate,\r\n\t\tpos,\r\n\t\t2,\r\n\t\tpan: 0);\r\n\r\n\tsig = SelectX.ar(Line.kr(0.0, 1.0, 0.2), [sig1, sig2]);\r\n\r\n\tsig = sig * amp * env;\r\n\t//sig = HPF.ar(sig, 400);\r\n\tsig = LeakDC.ar(sig);\r\n\tOut.ar(out, Pan2.ar(sig, pan));\r\n}).add;\r\n)\r\n\r\n\r\n\r\n// Play with these synths and samples using some Pbind.\r\n\r\n(\r\nPbindef(\\panflute_pattern,\r\n\t\\index, Pfunc { |e| ((e.use{ ~midinote.()} - ~panflute_sampler.at(\"lowest_note\")-1)/3).floor },\r\n\t\\buf, Pindex(~panflute_sampler.at(\"buffers\"), Pkey(\\index)),\r\n\t\\rate, (Pfunc{ |e| e.use {~midinote.()}} - Pindex(~panflute_sampler.at(\"midinotes\"), Pkey(\\index))).midiratio,\r\n\t\\instrument, Prand([\\simple_sampler, \\grain_sampler], inf),\r\n\t\\scale, Scale.major,\r\n\t\\octave, 4,\r\n\t\\degree, Pseq([1,2,3,4,5,6,7,8]-1, inf),\r\n\t\\amp, Pwhite(0.3, 0.5, inf),\r\n\t\\dur, 1,\r\n\t\\atk, 0.01,\r\n\t\\rel, 0.1,\r\n\t\\legato, 1,\r\n\t\\out, 0,\r\n\t\\pan, Pwhite(-0.2, 0.2, inf)\r\n);\r\n)\r\n\r\n(\r\nPbindef(\\panflute_pattern,\r\n\t\\index, Pfunc { |e| ((e.use{ ~midinote.()} - ~panflute_sampler.at(\"lowest_note\")-1)/3).floor },\r\n\t\\buf, Pindex(~panflute_sampler.at(\"buffers\"), Pkey(\\index)),\r\n\t\\rate, (Pfunc{ |e| e.use {~midinote.()}} - Pindex(~panflute_sampler.at(\"midinotes\"), Pkey(\\index))).midiratio,\r\n\t\\instrument, \\hybrid_sampler,\r\n\t\\scale, Scale.minor,\r\n\t\\octave, 4,\r\n\t\\degree, Pseq([0,1,2,3,4,5,6,7], inf),\r\n\t\\amp, 0.3, //Pwhite(0.3, 0.5, inf),\r\n\t\\dur, 10,\r\n\t\\atk, 0.1,\r\n\t\\dcy, 0.2,\r\n\t\\sus, 0.7,\r\n\t\\rel, 0.2,\r\n\t\\legato, 1,\r\n\t\\out, 0,\r\n\t\\pan, Pwhite(-0.2, 0.2, inf)\r\n);\r\n)\r\n\r\n(\r\nPbindef(\\panflute_pattern,\r\n\t\\index, Pfunc { |e| ((e.use{ ~midinote.()} - ~panflute_sampler.at(\"lowest_note\")-1)/3).floor },\r\n\t\\buf, Pindex(~panflute_sampler.at(\"buffers\"), Pkey(\\index)),\r\n\t\\rate, (Pfunc{ |e| e.use {~midinote.()}} - Pindex(~panflute_sampler.at(\"midinotes\"), Pkey(\\index))).midiratio,\r\n\t\\instrument, \\hybrid_sampler,\r\n\t\\scale, Scale.minorPentatonic,\r\n\t\\octave, Pwrand([2,3,4], [0.5,1,3].normalizeSum, inf),\r\n\t\\degree, Prand([0,1,2,3,4,5,6,7], inf),\r\n\t\\amp, Pwhite(0.3, 0.5, inf),\r\n\t\\dur, Prand([0.25, 0.5, 1], inf),\r\n\t\\atk, 0.1,\r\n\t\\dcy, 0.2,\r\n\t\\sus, 0.7,\r\n\t\\rel, 0.2,\r\n\t\\legato, 1,\r\n\t\\out, 0,\r\n\t\\pan, Pwhite(-0.2, 0.2, inf)\r\n);\r\n)\r\n\r\nPbindef(\\panflute_pattern).play;\r\nPbindef(\\panflute_pattern).stop;",
   "labels" : [
      "sampler",
      "samples"
   ]
}
