Livecoding
Live coding como pratica musical coletiva
Geralmente as produções/performances que envolvem o laptop como instrumento acabam impossibilitando o acompanhamento do que está sendo executado realmente pelo intérprete. O programa de computador, ou o patch, ou a lista de comandos que está sendo programada pelo intérprete ao vivo acaba oculta ao público. Buscando quebrar essa barreira intérprete-público, criou-se o movimento conhecido como livecoding (http://www.toplap.org). Em uma sessão de livecoding os intérpretes utilizam projetores para exibir ao público o código-fonte do programa de computador que eles estarão usando para produzir o áudio ao vivo. Um virtuosi em um instrumento musical qualquer acaba transmitindo ao seu público as sensações de sua performance, mesmo esse público não sabendo sequer como tocar tal instrumento. Da mesma forma, o público não necessariamente precisa entender o código do programa que está sendo exibido para capturar as sensações do intérprete/programador. O projeto consiste em um duo de músicos que apresentarão performances em torno deste conceito de livecoding, com a proposta de entrar em contato com interessados nessa forma de interpretar, buscando divulgar a cena de livecoding que ainda é incipiente em nosso país. Exemplos de performances em livecoding podem ser vistos nos documentários recente "Show Us Your Screens" (http://vimeo.com/20241649) e "Programming, meet music" (http://news.bbc.co.uk/1/hi/technology/8221235.stm). Outras ótimas referências em: http://toplap.org/index.php/Videos,_Articles_and_Papers
Tecnologias
SuperCollider (http://supercollider.sourceforge.net/), ChucK (http://toplap.org/index.php/ChucK), Audiolet (http://github.com/oampo/Audiolet), ABT (http://trac.assembla.com/audioexperiments/browser/ABeatDetector), live-processing (http://automata.cc/live-processing), ixi lang (http://www.ixi-audio.net/ixilang/), Extempore (http://github.com/digego/extempore), Overtone (http://project-overtone.org/), Text (http://yaxu.org/category/text), Fluxus (http://toplap.org/index.php/Fluxus) e ambientes de controle alternativo como IanniX (http://iannix.org).
Além de ser utilizado toda a plataforma de áudio JACK (http://jackaudio.org) em sistema GNU/Linux e demais ferramentas para possíveis edições e processamento sonoro (Ardour: http://ardour.org, Audacity: http://audacity.sourceforge.net, variados plugins LADSPA: http://ladspa.org).
Mais em http://toplap.org
Scripts criados um-por-dia preparatório para FooBarBaz
http://www.inclusiveimprov.co.uk/doku.php/events:creativepact_2011#lab_macambira
Dia 1, 17/09/2011
Script para tocar o baixo em loop com uma pausa.
// duracao do compasso: 2.6746 segundos // script toca o audio do baixo e faz uma // pausa de um ou alguns compassos // sound file "a.wav" => string filename; 2 => int compassos_pausa; // the patch SndBuf buf => dac; // load the file filename => buf.read; // time loop while( true ) { 1 => buf.rate; 39*441 => buf.pos; 10.6985::second => now; 0 => buf.rate; (compassos_pausa*2.6746)::second => now; } // Std.rand2f(.2,.9) => buf.gain; // Std.rand2f(.5,1.5) => buf.rate; // if( me.args() ) me.arg(0) => filename;
Utilizando uma pulsação qualquer:
// Sincronizando 0.5::second => T; T - (now%T) => now; // Pegando o áudio SndBuf buf => dac; "data/kick.wav" => buf.read; // Loop infinito while(1) { 0 => buf.pos; T => now; }
Tocando um arquivo inteiro com o máximo de simplicidade. Amostra por amostra:
SndBuf buf => dac; "a.wav" => dac; while(1) 1::samp => now;
Em SuperCollider, tocando o arquivo durante 22 compassos
TempoClock.default.tempo = 1; b = Buffer.read(s, "/home/vilson/Samples/ginzburg.wav"); ( SynthDef(\player, { | out=0, bufnum=0, rate=1, start=0, dur=1, amp=0.8 | var signal = PlayBuf.ar(1, bufnum, BufRateScale.kr(bufnum)*rate, startPos:start); signal = signal * amp * EnvGen.kr(Env.linen(0.01, dur, 0.01), doneAction:2); Out.ar(out, signal ! 2) }).store; ) Pdef(\p1, Pbind(\instrument, \player, \dur, Pseq([22],inf))) Pdef(\p1).play Pdef(\p1).stop
Modificando rate e duração, acrescentando novos patterns para tocar o mesmo buffer
Pdef(\p1, Pbind(\instrument, \player, \dur, Pseq([2],inf), \start, Pseq([44100*24], inf), \rate, 0.2)) Pdef(\p1).play Pdef(\p1).stop Pdef(\p2, Pbind(\instrument, \player, \dur, Pseq([2],inf), \start, Pseq([44100*23], inf), \rate, Pseq([0.3, 0.3, 0.3, 0.3, 0.4, 0.4], inf))) Pdef(\p2).play Pdef(\p2).stop Pdef(\p3, Pbind(\instrument, \player, \dur, Pseq([8],inf), \start, Pseq([44100*46], inf), \rate, 0.4)) Pdef(\p3).play Pdef(\p3).stop
Dia 2, 18/09/2011
Em ChucK, soltar estas duas linhas em alguma música bem ritmada e deixar os padrões à vontade com este arco maior:
// stupidly rising SinOsc s1 => Gain g => g => s1 => dac; 2 => s1.sync; while(second => now); // crazy wind through a window Noise s1 => Gain g1 => g1 => SinOsc s2 => dac; 2 => s2.sync; while(second => now);
Em SuperCollider, thrasheira:
http://soundcloud.com/aut0mata/day2
TempoClock.default.tempo= 1 // drum ( SynthDef(\kick, { | out=0, amp=0.2, atk=0.03, rel=1, pan=0, freq=100 | var sig = Mix(SinOsc.ar([freq, freq+1.01, freq+5, freq+1.02])); var env = EnvGen.ar(Env.perc(atk, rel, amp), doneAction:2); Out.ar(out, Pan2.ar(sig*env, pan)); }).store ) // snare ( SynthDef(\snare, { | out=0, amp=0.1, atk=0.02, rel=0.2, pan=0 | var sig = HPF.ar(WhiteNoise.ar, 5000); var env = EnvGen.ar(Env.perc(atk, rel, amp), doneAction:2); Out.ar(out, Pan2.ar(sig*env, pan)); }).store ) // hat ( SynthDef(\hat, { | out=0, amp=0.1, atk=0.03, rel=0.2, pan=0, freq=4000 | var sig = BPF.ar(GrayNoise.ar, freq, 0.1, 10); var env = EnvGen.ar(Env.perc(atk, rel, amp)); Out.ar(out, Pan2.ar(sig*env, pan)); }).store ) // bass ( SynthDef(\bass, { | out=0, freq=220, amp=0.8, atk=0.05, rel=1, pan=0 | var sig = BPF.ar(Mix(Saw.ar([freq, freq+1.01, freq+3]))*SinOsc.ar(3, 0, 1), 500); var env = EnvGen.ar(Env.perc(atk, rel, amp)); Out.ar(out, Pan2.ar(sig*env, pan)); }).store ) Pdef(\p_kick, Pbind(\instrument, \kick, \freq, Pseq([\rest,60], inf), \dur, 1/2)) Pdef(\p_snare, Pbind(\instrument, \snare, \freq, Pseq([1, \rest], inf), \dur, 1/2)) Pdef(\p_hat, Pbind(\instrument, \hat, \freq, Pseq([\rest, 3000], inf), \dur, 1/2)) ( Pdef(\p_bass, Pbind(\instrument, \bass, \note, Pseq([0.5, 1.5,0.5,0.5,0.5, 0.5, 1.5,0.5,0.5,0.5, 0.5, 5, 7,1.5], inf), \octave, 4, \dur, Pseq([1/2, 1/4,1/4,1/4,1/4, 1/2, 1/4,1/4,1/4,1/4, 1/4,1/4,1/4,3/4], inf))) ) Ppar([Pdef(\p_kick), Pdef(\p_snare), Pdef(\p_bass)]).play
Dia 3, 20/09/2011
Em ChucK, fazendo a pira de tocar o instante do som. A ideia simples colocada desta maneira: imagina o som com sua forma de onda, uns 3 segundos de som. Escolhe qualquer pedaço do som e fica ouvindo a sonoridade daquele pedaço. É isso.
fun void voice(int n) { while( true ) { position => buf[n].pos; Std.rand2f(.6 - rand_gain, .6 + rand_gain) => buf[n].gain; 1 + Std.rand2f(-rand_rate,rand_rate) => buf[n].rate; ( size + Std.rand2f(0,rand_dur) )::samp => now; } }
O lance é fazer ficar com várias vozes simultâneas, com separações de durações regulares ou randômicas. Cada voz possui uma mesma cópia do trecho do som que foi escolhido. As vozes são equivalentes, com fades controláveis ao início e ao fim do trecho. Pode-se inserir controles como pitch e pitch randômico. Este procedimento é inspirado em ideias que vi melhor implementado no plugin Freeze do GRM Tools.
Penso em fazer isso EM LIVECODING (talvez simplificado) com um wiimote ou controles do gt-video, controlando onde no som, através do horizontal. A duração através da vertical. Outros controles apertando no teclado do lap ou com gestos.
Antes de começar, pode ser útil utilizar:
Gain g => dac; 0 => g.gain; SndBuf buf[20]; Shred shreds[20]; "bleu.wav" => string filename; for(0=> int i; i < 20; i++) { filename => buf[i].read; 0 => buf[i].rate; buf[i] => g; } // starts playing the hole sound file buf[0].samples() => int size => int file_size; 0 => int position;
O código eu achei de coisas antigas, aqui:
http://trac.assembla.com/audioexperiments/browser/Freeze/freeze.ck
--
Em SuperCollider (usando JITlib), minimalista:
// Usando JITlib // Criamos um proxy e enviamos o servidor já booted s p = ProxySpace.push(s); // Definimos o tempo p.clock = TempoClock.default; p.quant = 1.0; // Kick ( SynthDef(\kick, { | basefreq=50, ratio=7, sweeptime=0.05, preamp=1, amp=1, decay1=0.4, decay1L=0.8, decay2=0.15, out | var fcurve = EnvGen.kr(Env([basefreq * ratio, basefreq], [sweeptime], \exp)), env = EnvGen.kr(Env([1, decay1L, 0], [decay1, decay2], -4), doneAction: 2), sig = SinOsc.ar(fcurve, 0.5pi, preamp).distort * env * amp; Out.ar(out, sig ! 2) }).add; ) ( SynthDef(\snare, { | out=0, amp=0.1, atk=0.02, rel=0.2, pan=0 | var sig = HPF.ar(WhiteNoise.ar, 5000); var env = EnvGen.ar(Env.perc(atk, rel, amp), doneAction:2); Out.ar(out, Pan2.ar(sig*env, pan)); }).add ) ( SynthDef(\hh, { | out=0, attack=0.03, decay=0.03, amp=0.5 | var sig = BPF.ar(PinkNoise.ar(1), 1000), env = EnvGen.kr(Env.perc(attack, decay, amp), doneAction:2); Out.ar(out, Pan2.ar(sig * env) ! 2); }).add; ) ( SynthDef(\bass, { | out=0, freq=30, attack=2, decay=0.1, amp=0.05 | var sig = BPF.ar(Saw.ar([freq, freq+1]), 300), env = EnvGen.kr(Env.perc(attack, decay, amp), doneAction:2); Out.ar(out, Pan2.ar(sig * env) ! 2); }).add; ) ~p1.play; ~p1.stop; ~p1 = Pbind(\instrument, \kick, \note, Pseq([\rest, 0], inf), \dur, Pseq([1/2, 1/4, 1], inf)) ~p2.play; ~p2.stop; ~p2 = Pbind(\instrument, \snare, \note, Pseq([0, \rest], inf), \dur, Pseq([1/2], inf)) ~p3.play; ~p3.stop; ~p3 = Pbind(\instrument, \hh, \dur, Pseq([2, 4, 1/2, 1/4], inf)); ~p4.play; ~p4.stop; ~p4 = Pbind(\instrument, \bass, \freq, Pseq([30, 32, 32, 33], inf), \dur, Pseq([4, 2], inf));