______________________________ CP => LIVE CODING WITH CHUCK Scott Hewitt ______________________________ 2014 - 2015 1 Live Coding Performance ========================= 1.1 Live Coding Performance ~~~~~~~~~~~~~~~~~~~~~~~~~~~ A notation ---------- the process of rehearsing shifts from "studying notes" to get to know, "how the system works" \cite{winkler2004realtime} An Instrument ------------- ...even acting not only as instruments, but almost as performers, composers or conductors. \cite{chadabe1984interactive} Live Algorithms --------------- * Voyager (G. Lewis) * Swarms (M. Young) The Interface ------------- * live rewiring allows the diversion of control and generation to whatever pathway is desired \cite{collins_generative_2003} Live Coding ----------- * TOPLAP * Alex McLean * Dan Stowell * Slub * Nick Collins Observation ----------- * there was a lot of extra musical content, and was skeptical (like many of us) about the depth of programming possible under pesky realtime constraints. David Wessel in \cite{nilson2007live} * My current feeling is that live coding and conventional instrumental control are simply different, and should be celebrated for that. \cite{nilson2007live} Why --- * live coding allows us to keep a sense of challenge and improvisation about electronic music-making. * We certainly contend that music-making is more compelling with elements of risk and reference to the performance environment, and that the human participant is essential to social musical activities. \cite{collins_live_2003} Pros and Cons ------------- \cite{collins_live_2003} Pros and potential ------------------ * Flexibility; the next section can be anything * A great intellectual challenge * Arbitrarily complex changes of structure at performance time * A new form of improvisation * Normal performance programs like Reason look dull if the screen is projected – but the arcane text coding systems have allure * It’s rewarding to see real efforts translated into sound * Computer languages are immensely rich infinite grammars Cons and Dangers ---------------- * You forget the current audio or just take too long while you prepare the next section * Your concentration halves with the adrenalin/stress/beer of a gig * It’s risky to just run code! No debugging or testing is available * You must accept some failures and ugly moments of sound; there is a trade-off between preparation and gig specificity * Deliberate obfuscation is no great criteria for art! * You apply lots of effort for little payback; you must have back-up code in case inspiration is not forthcoming * Typing is hardly the most visually exciting interfacing method – you’ll be bent over a screen for the night unless you code in further external controllers Alternative ----------- In the practice of the Cybernetic Orchestra we have often done exactly the opposite, starting from screens full of code, upon which orchestra members then begin to operate, transforming it in various ways and with various intentions \cite{ogborn2012composing} 2 First Chuckin Steps ===================== 2.1 First Chuckin Steps ~~~~~~~~~~~~~~~~~~~~~~~ Key Language ------------ * ; ends line * White Space unimportant * // single line comment Key Method ---------- => UGen ---- * Name * Reference eg. SinOsc s DSP Chain --------- SinOSc s => Gain g => dac Must be connected to either dac or blackhole. Making Noise ------------ * Time has to pass * dur => now; eg 100::ms => now; Reference Sources ----------------- * UGEN List [http://chuck.cs.princeton.edu/doc/program/ugen.html] * Language Spec [http://chuck.cs.princeton.edu/doc/language/] * Examples [http://chuck.cs.princeton.edu/doc/examples/] [http://chuckaday.ablelemon.co.uk/] 3 ChucK Sporking Functions ========================== 3.1 Sporkin Functions UGENS ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions --------- fun void functionname(){ } Sporking Revisited ------------------ spork ~ functionname(); Example ------- Sporking percussive parts and passing values to shreds. ,---- | //Number 12 | //Chuck a day 2009 | //by Scott Hewitt | //www.ablelemon.co.uk/chuckaday | | //main called function | function void drum (dur beat, int max, float dec){ | Shakers s => dac; | 11 => s.objects; | dec => s.decay; | <<< s.objects() >>>; | for (0 => int i; i < max; i++){ | 1 => s.noteOn; | beat => now; | 0 => s.noteOff; | <<< now, me.id() >>>; | } | } | | 0.5 => float decc; | | 1100::ms => dur gap; | 11 => int hits; | spork ~ drum(gap, hits, decc); | 1000::ms => gap; | 12 => hits; | spork ~ drum(gap, hits, decc); | | gap * hits => now; | | // http://chuckaday.ablelemon.co.uk/code/12.ck `---- examples/12.ck LFOs ---- The Blackhole FM -- Simple FM Synthesis ,---- | //FM Synthesis Demo | //@scotthewitt | | //Audio | SinOsc s => dac; | | //LFO | SinOsc lfo => blackhole; | 5 => lfo.freq; | | function void lfoosc (){ | while(1){ | lfo.last() * 10 + 440 => s.freq; | 1::ms => now; | } | } | | spork ~ lfoosc(); | | 1000::ms => now; `---- examples/simpleFM.ck AM -- Simple AM Synthesis ,---- | //Simple AM Synthesis Demo | //@scotthewitt | | //Audio | SinOsc s => dac; | | //LFO | SinOsc lfo => blackhole; | 7 => lfo.freq; | | function void lfoosc (){ | while(1){ | lfo.last() * 0.9 => s.gain; | 1::ms => now; | } | } | | 1000::ms => now; | | spork ~ lfoosc(); | | 1000::ms => now; `---- examples/simpleAM.ck FM -- Simple FM Synthesis ,---- | //FM Synthesis Demo | //@scotthewitt | | //Audio | SinOsc s => dac; | | 300.0 => float pitch => s.freq; | | 10.0 => float moddepth; | | //LFO | SinOsc lfo => blackhole; | 4 => lfo.freq; | | function void lfoosc (){ | while(1){ | lfo.last() * moddepth + pitch => s.freq; | 1::ms => now; | } | } | | spork ~ lfoosc(); | | 1000::ms => now; | | //600 => pitch; | 200 => moddepth; | | 1000::ms => now; `---- examples/intFM.ck Arrays ------ ,---- | //FM Synthesis Demo | //@scotthewitt | | | //Audio | SinOsc s => Gain g => dac; | | 300.0 => float pitch => s.freq; | | 10.0 => float moddepth; | | //LFO | SinOsc lfo => blackhole; | 9 => lfo.freq; | | function void lfoosc (){ | while(1){ | lfo.last() * moddepth + pitch => s.freq; | 1::ms => now; | } | } | | spork ~ lfoosc(); | | // array of int tune | [ 70, 75, 73, 74, 78, 74 ] @=> int tune[]; | [ 1000, 750, 2000, 500, 500, 1200 ] @=> int length[]; | [ 0.5, 0.7, 0.2, 0.2, 0.9, 0.8 ] @=> float volume[]; | | // loop over the entire array | for( 0 => int i; i < tune.cap(); i++ ) | { | Std.mtof(tune[i]) => pitch; | <<< pitch >>>; | volume[i] => g.gain; | length[i] * 1::ms => now; | | } `---- examples/tuneFM.ck UGEN Hunting ------------ [http://chuck.cs.princeton.edu/doc/program/ugen.html] 4 Events, UGENs and the STKs - synthesis to effects =================================================== 4.1 Events, UGENS and STKs ~~~~~~~~~~~~~~~~~~~~~~~~~~ Events ------ ,---- | SinOsc s => Envelope e => Gain g => dac; | | 100::ms => e.duration; | | 0.3 => g.gain; | | Event ee; | | function void beep (){ | while(1){ | ee => now; | e.keyOn(); | ee => now; | e.keyOff(); | e.duration() => now; | } | } | | spork ~ beep(); | | while(1) | { | ee.broadcast(); | 100::ms => now; | } `---- Events II --------- ,---- | SinOsc s => Envelope e => Gain g => dac; | | 100::ms => e.duration; | | 0.3 => g.gain; | | Event ee; | | function void beep (Event onoff){ | while(1){ | onoff => now; | e.keyOn(); | onoff => now; | e.keyOff(); | e.duration() => now; | } | } | | spork ~ beep(ee); | | while(1) | { | ee.broadcast(); | 500::ms => now; | } `---- Events With Values ------------------ ,---- | SinOsc s => Envelope e => Gain g => dac; | | public class Eventfloat extends Event{ | float value; | } | 100::ms => e.duration; | | 0.3 => g.gain; | | Eventfloat ee; | | function void beep (Eventfloat onoff){ | while(1){ | onoff.value * 1::ms => now; | e.keyOn(); | onoff.value * 1::ms => now; | e.keyOff(); | e.duration() => now; | } | } | | spork ~ beep(ee); | | while(1) | { | Std.rand2f(10,500) => ee.value; | ee.broadcast(); | 500::ms => now; | } `---- System Wide Events (With Values) -------------------------------- * To send event with value ,---- | //System Wide Events with values | | //Section 1 | //Extend Event Class | public class E extends Event{ | int value; | } `---- ,---- | //System Wide Events with values | | //Section 2 | //Create VM wide extended event | public class F{ | static E @ value; | } | new E @=> F.value; `---- ,---- | //System Wide Events with values | | //Section 3 | //Send extended events with ints | function void s (){ | while (true){ | Std.rand2(100,300) => F.value.value; | F.value.broadcast(); | 500::ms => now; | <<<"sent">>>; | } | } | | spork ~ s(); | | while (true){ | 1::day => now; | } `---- * Recieve event with value ,---- | //System Wide Events with values | | //Section 4 | //print recieved event int values | while (true){ | F.value => now; | <<< F.value.value >>>; | <<<"got">>>; | } `---- * Full code for reference ,---- | //Number 32 | //Chuck a day 2009 | //by Scott Hewitt | //www.ablelemon.co.uk/chuckaday | | //Each section should be added to the ChucK VM in turn | | //Section 1 | //Extend Event Class | public class E extends Event{ | int value; | } | | //Section 2 | //Create VM wide extended event | public class F{ | static E @ value; | } | new E @=> F.value; | | //Section 3 | //Send extended events with ints | function void s (){ | while (true){ | Std.rand2(100,300) => F.value.value; | F.value.broadcast(); | 500::ms => now; | <<<"sent">>>; | } | } | | //spork ~ r(); | spork ~ s(); | | while (true){ | 1::day => now; | } | | //Section 4 | //print recieved event int values | while (true){ | F.value => now; | <<< F.value.value >>>; | <<<"got">>>; | } `---- UGEN Hacks ---------- UGEN Method Cast ---------------- ,---- | //Number 19 | //Chuck a day 2009 | //by Scott Hewitt | //www.ablelemon.co.uk/chuckaday | | //thanks to Kassen for help with this | | fun void setFreq(UGen u) | { | Std.rand2f(200,600) => float freq; | //Cast resolves issues issue of no .freq in UGen | freq => (u $ SinOsc).freq; | } | | TriOsc s => dac; | SinOsc k => dac; | SawOsc f => dac; | | setFreq(s); | setFreq(k); | setFreq(f); | | 1000::ms => now; `---- UGEN Audio Buss Hacking ----------------------- ,---- | //Number 16 | //Chuck a day 2009 | //by Scott Hewitt | //www.ablelemon.co.uk/chuckaday | | //increase the size of the array to get more channels | public class bus | { | static Gain @ chan[8]; | } | new Gain[8] @=> bus.chan; | | | function void test(UGen u){ | SinOsc s => u; | 440 => s.freq; | 1000::ms => now; | } | | spork ~ test(bus.chan[1]); | | bus.chan[1] => dac; | 2000::ms => now; `---- The UGEN Hunt ------------- [http://chuck.cs.princeton.edu/doc/program/ugen.html] Into the STK ------------ [http://chuck.cs.princeton.edu/doc/program/stdlib.html]