{
   "ancestor_list" : [],
   "description" : "tutorial for the panola pattern notation language",
   "name" : "Panola - pattern notation language tutorial",
   "author" : "56228375",
   "code" : "// Panola is a way to extract Pbind keys from a concise specification.\r\n// This makes it easier to compose \"traditional\" music with Pbind, with a lot less \r\n// headache trying to keep the different keys in sync\r\n// It's the type of system I've missed since my day one with supercollider.\r\n\r\n// First things first. To install Panola:\r\n\r\nQuarks.install(\"https://github.com/shimpe/panola\");\r\n\r\n// Now you can get the help document by typing ctrl+D with the cursor on the word\r\n// Panola in the next line\r\n\r\nPanola.new(\"a4\");\r\n\r\n// Let's start with the \"Hello world\" of Panola: a simple scale. \r\n// The numbers indicate octaves. \r\n// You don't need to repeat octave numbers if they don't change between notes.\r\n(\r\n~ex = Panola.new(\"c4 d e f g a b c5\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// asPbind takes a synth name as parameter (which defaults to \\default). \r\n// So the above is equivalent to\r\n(\r\n~ex = Panola.new(\"c4 d e f g a b c5\");\r\n~player = ~ex.asPbind(\\default).play;\r\n)\r\n\r\n// instead of calling a single \"asPbind\" you can also extract all information separately\r\n// like this you have optimal flexibility in what you want to use from Panola\r\n(\r\n~ex = Panola.new(\"c4 d e f g a b c5\");\r\n~pat = Pbind(\\instrument, \\default,\t\\midinote, ~ex.midinotePattern,\t\\dur, ~ex.durationPattern, \\amp, ~ex.volumePattern,\t\\tempo, ~ex.tempoPattern, \\lag, ~ex.lagPattern,\t\\legato, ~ex.pdurPattern);\r\n~player = ~pat.play;\r\n)\r\n\r\n// You can make chords using angular brackets. Only note properties of the first \r\n// note in the chord (other than octave number and note modifier (see later)) are \r\n// taken into account. \r\n(\r\n~ex = Panola.new(\"<c4 e> <e g> <c e g c5>\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// You can use modifiers on the notes:\r\n// # for sharp, x for double sharp, - for flat, -- for double flat\r\n(\r\n~ex = Panola.new(\"c4 d- e f# gx a# b-- c5\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n\r\n// With underscores you can indicate rhythm.\r\n// The last used rhythm value is reused until a new one is specified:\r\n// Here's four quarter notes (_4) followed by four eighth notes (_8).\r\n(\r\n~ex = Panola.new(\"c4_4 d e f g_8 a b c5\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// You can use one or more dots to extend the length of the rhythm, as in traditional notation.\r\n(\r\n~ex = Panola.new(\"c4_4. d_8 e_4 f g_16 a_4.. b_4 c5\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// You can also use multipliers and/or dividers to change the length.\r\n// E.g. here we use it to create a note that lasts for three eighths\r\n// (c4_8*3) and to create tuplets (e_8*2/3 f g). Remember that last\r\n// duration/rhythm indication is reused until a new one is specified.\r\n(\r\n~ex = Panola.new(\"c4_8*3 d_8 e_8*2/3 f g f_16 e f e g_4 b_4 c5\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// You can repeat certain phrases by putting them in brackets and multiply\r\n// them with a number (corresponding to the number of repeats)( )*3 \r\n// repeats can be nested\r\n(\r\n~ex = Panola.new(\"((c4_16 d)*3 (e f)*3)*2 (g a)*3 c5_4\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// Now we come to the animated property system. We can attach properties to the notes and animate them over time.\r\n// For now two types of animation are supported: linear interpolation and fixed value.\r\n// To indicate linear interpolation, use curly brackets {}. E.g. here we let the tempo gradually increase from 80 bpm to 160 bpm:\r\n(\r\n~ex = Panola.new(\"c4\\\\tempo{80} d e f g a b c5\\\\tempo{160}\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// Different properties can be combined. Here we let the volume go up until the middle of the phrase, then let it go down again,\r\n// while tempo is rising from 80 bpm to 160 bpm.\r\n// note: properties can be specified with \\\\propertyname or equivalently with @propertyname\r\n\r\n(\r\n~ex = Panola.new(\"c4@tempo{80}@vol{0.2} d e f g@vol{0.9} a b c5@tempo{160}@vol{0.2}\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// If you want to use the fixed values, use square brackets instead. You can switch between fixed and animated everytime\r\n// you specify a new property value. In the next example, tempo remains at 80 bpm until we come to note a. At that point,\r\n// it jumps to value 100 bpm and gradually increases to 200.\r\n(\r\n~ex = Panola.new(\"c4\\\\tempo[80] d e f g a\\\\tempo{100} b c5 d e f g a b c6\\\\tempo{200}\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// one-shot properties can temporarily override an ongoing animation without disturbing its continuation\r\n// the following example adds an accent on the next to last note in a decrescendo line using a one-shot property\r\n(\r\n~ex = Panola.new(\"c4@vol{0.9} d e f g a b c5 d e f g a b@vol^0.9^ c6@vol{0.1}\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// Using pdur (think: played duration), we can indicate the difference between staccato and legato.\r\n// Here we slowly evolve from very staccato to very legato:\r\n(\r\n~ex = Panola.new(\"c4_8\\\\pdur{0.1} d e f g a b c5 d e f g a b c6\\\\pdur{1}\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// Using lag we can modulate lag. This can be a way of creating a rubato feeling.\r\n// Linear interpolation is not ideal for this purpose, but it's better than nothing at the moment.\r\n\r\n(\r\n~ex = Panola.new(\"a5_8\\\\tempo[120]\\\\lag{0} b c6 a5 e d c5 d e c a4 g#4\\\\lag{0.5} \"\r\n\t\"a4_8 b c5 a4 e d c4 d e c a3 g#3 a b c4 d e g# a_2\\\\lag{0}\");\r\n~player = ~ex.asPbind.play;\r\n)\r\n\r\n// In addition to using predefined properties like tempo and lag, you can also use user \r\n// defined properties, e.g. here we animate a property called \"myprop\".\r\n(\r\n~phrase = Panola.new(\"c d\\\\myprop{0.1} e f g a\\\\myprop{0.6}\");\r\n~pattern = ~phrase.customPropertyPattern(\"myprop\"); // extract only myprop values as a pattern\r\n~stream = ~pattern.asStream;\r\n10.do({\r\n\t| i |\r\n\t~stream.next.postln;\r\n});\r\n)\r\n// make a pbind in which the myprop appears as one of the keys, with a default value of 0 for myprop\r\n(\r\n~phrase = Panola.new(\"c d\\\\myprop{0.1} e f g a\\\\myprop{0.6}\");\r\n~pbind = ~phrase.asPbind(\\default);\r\n~stream = ~pbind.patternpairs[13].asStream;\r\n10.do({\r\n\t| i |\r\n\t~stream.next.postln;\r\n});\r\n)\r\n// make a pbind in which the myprop appears as one of the keys, with a customized default value of 0.4 for myprop\r\n// (such default values are used if no values for myprop are specified yet, e.g. in the beginning of a Panola string,\r\n//  before any myprop is defined).\r\n(\r\n~phrase = Panola.new(\"c d\\\\myprop{0.1} e f g a\\\\myprop{0.6}\");\r\n~pbind = ~phrase.asPbind(\\default, custom_property_defaults:Dictionary.newFrom([\"myprop\", 0.4]));\r\n~stream = ~pbind.patternpairs[13].asStream;\r\n10.do({\r\n\t| i |\r\n\t~stream.next.postln;\r\n});\r\n)\r\n// make pbind in which only the standard panola keys are included\r\n(\r\n~phrase = Panola.new(\"c d\\\\myprop{0.1} e f g a\\\\myprop{0.6}\");\r\n~pbind = ~phrase.asPbind(\\default, include_custom_properties:false);\r\n~pbind.patternpairs.postln;\r\n)\r\n\r\n// These custom properties can be e.g. used to drive synth arguments\r\n// The 303 synth used below is reused from https://sccode.org/1-4Wy \r\n// which in turn is based on code from Lance J. Putnam \r\n(\r\ns.waitForBoot({\r\n\tvar line;\r\n\r\n\tSynthDef (\\sc303 , {  arg  out=0, freq=440, wave=0, ctf=100, res=0.2,\r\n\t\tsus=0, dec=1.0, env=1000, gate=1, vol=0.1;\r\n\t\tvar  filEnv, volEnv, waves;\r\n\t\tvolEnv =  EnvGen .ar( Env .new([10e-10, 1, 1, 10e-10], [0.01, sus, dec],  'exp' ), gate, doneAction:2);\r\n\t\tfilEnv =  EnvGen .ar( Env .new([10e-10, 1, 10e-10], [0.01, dec],  'exp' ), gate);\r\n\t\twaves = [ Saw .ar(freq, volEnv),  Pulse .ar(freq, 0.5, volEnv)];\r\n\t\tOut .ar(out,  RLPF .ar(  Select .ar(wave, waves), ctf + (filEnv * env), res).dup * vol);\r\n\t}).add;\r\n\r\n\ts.sync;\r\n\r\n\tline = Panola.new(\r\n\t\t\"a2_16\\\\wave[0]\\\\vol{0.05}\\\\tempo{120}\\\\res{0.2}\\\\sus{0}\\\\env{1000}\\\\ctf{100} a a a1 a2 a a3 a2 a a a1 a2 a3 a2 b- g\\\\res{0.05} \"\r\n\t\t\"a2_16\\\\wave[0] a a a1 a2 a a3\\\\sus{0.2} a2 a\\\\ctf{3000} a a1 a2 a3 a2 b- g\\\\res{0.2} \"\r\n\t\t\"a2_16\\\\wave[0] a a a1 a2 a a3 a2 a a a1 a2 a3 a2 b- g\\\\res{0.01}\\\\sus{0}\\\\env{10000}\\\\ctf{10} \"\r\n\t);\r\n\t~player = line.asPbind(\\sc303).play;\r\n});\r\n\r\n// example of automating a piano sustain pedal\r\n// by using a custom property ped \r\n// (the point being that property \"ped\" has no special meaning in panola, but we can add the meaning ourself)\r\n// I've chosen argument values 0 - 127 to also allow sending half-pedal values for those pianos that support it\r\n(\r\nvar midiout;\r\nvar chan = 0;\r\nvar pat = ();\r\n\r\nif (MIDIClient.initialized.not) { MIDIClient.init; };\r\nmidiout = MIDIOut.newByName(\"INTEGRA-7\", \"INTEGRA-7 MIDI 1\"); // change as needed for your digital piano\r\n\r\npat[\\score] = Panola(\"c4_4@pdur[0.3]@ped[0] e g c5 c4@ped[127] e g c5 c4_4@ped[0] e g c5 \");\r\npat[\\score_withpedalhandling] = Pbindf(\r\n\tpat[\\score].asMidiPbind(midiout, chan, include_tempo:false), \r\n\t\\handle, Pfunc {\r\n\t\t| ev |\r\n\t\tmidiout.control(ev[\\chan], 64, ev[\\ped].asInteger);\r\n});\r\n\r\npat[\\score_withpedalhandling].play(TempoClock(120/60));\r\n)",
   "id" : "1-5aq",
   "is_private" : null,
   "labels" : [
      "pattern",
      "tutorial",
      "panola",
      "notation"
   ]
}
