Livecoding

De Pontão Nós Digitais

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));