OSC <
Index >
Le Temps
Buffers
- un buffer est un tableau ordonné de 'floats' (valeurs numériques à virgule flottante) sur le serveur
- meilleur moyen de stocker des données sur le serveur
- peut être simple ou multi-canal
- utilisation principale: stockage de fichiers sons
- le nombre de buffers disponibles est défini dans ServerOptions∞ [voir défaut]
- ils sont indexés
- il est nécessaire de leur 'allouer' de la mémoire pour les utiliser (allocate)
- leur accès est global, atteignable par tout synth
- plusieurs synths peuvent accéder au même buffer
- on peut écrire dans, voire changer la taille d'un buffer, même pendant qu'il est lu
l'objet Buffer dans le langage
- il est la représentation d'un buffer sur le serveur
- rends simple et plus sûr l'allocation et l'accès du buffer
création d'un objet Buffer, allocation de la mémoire
- la méthode .alloc crée et alloue de la mémoire à un buffer
s.boot;
b = Buffer.alloc(s, 100, 2); // alloue deux canaux et 100 frames
b.free; // libération de la mémoire et de l'ID
- la commande ci-dessus crée un buffer de deux canaux et lui alloue 100 frames
- ! le nombre de valeurs réel stocké dans ce buffer est de numChannels * numFrames, donc 2*100
b = Buffer.alloc(s, s.sampleRate * 8.0, 2); // un buffer de 8 secondes Stéréo
b.free;
- la méthode free libère la mémoire allouée sur le serveur; l'index est liberé pour une nouvelle allocation
Buffer et fichiers sons
- la méthode read permet de lire un fichier son dans la mémoire vive, et retourne l'objet (instance de Buffer)
- utilisation principale, en combinaison avec l'UGen PlayBuf
// lire un fichier
b = Buffer.read(s, "sounds/a11wlk01.wav");
// le jouer
(
x = SynthDef("tutorial-PlayBuf",{ arg out = 0, bufnum;
Out.ar( out,
PlayBuf.ar(1, bufnum, BufRateScale.kr(bufnum))
)
}).play(s,[\bufnum, b.bufnum ]);
)
x.free; b.free;
PlayBuf
PlayBuf.ar(
1, // nombre de canaux
bufnum, // numéro du buffer
BufRateScale.kr(bufnum) // vitesse
)
- nombre de canaux: argument statique, correspondant au nombre de canaux du buffer utilisé
- index du buffer: les buffers sont indexés, en commendant par 0 (l'index peut être retourné avec la méthode Buffer.bufnum)
- vitesse d'exécution : 1= vitesse normale, 2 = vitesse * 2, etc.
[exemples]
[mini-GUI]
SynthDef(\pb, {|index, vitesse, volume|
Out.ar(0, PlayBuf.ar(1, index, vitesse, loop: 1) * volume)
}).send(s);
w = GUI.window.new.front;
l = FlowLayout(w.bounds);
w.view.decorator = l;
g = GUI.button.new(w, Rect(0, 0, 150, 20))
.states_([["donne moi un son"], ["ok"]]);
g.action_({ File.openDialog("", {|path| b = Buffer.read(s, path)}, {"echec"}) });
p = GUI.button.new(w, Rect(180, 0, 50, 20)).states_([["play"], ["stop"]]);
p.action_({ |bt|
if( bt.value==1) {z = Synth(\pb, [\index, b.bufnum]) }
{z.free }
});
l.nextLine;
f = GUI.slider.new(w, Rect(0, 0, 100, 20))
.action_({|me| z.set(\vitesse, me.value + 1 * 4) });
v = GUI.slider.new(w, Rect(0, 0, 100, 20))
.action_({|me| z.set(\volume, me.value ) })
Streaming
- utilisation de l'UGen DiskIn, et de la méthode Buffer.cueSoundFile
(
SynthDef("tutorial-Buffer-cue",{ arg out=0,bufnum;
Out.ar(out,
DiskIn.ar( 1, bufnum )
)
}).send(s);
)
b = Buffer.cueSoundFile(s,"sounds/a11wlk01-44_1.aiff", 0, 1);
y = Synth.new("tutorial-Buffer-cue", [\bufnum,b.bufnum], s);
b.free; y.free;
- moins flexible que PlayBuf (pas de contrôle de vitesse
- permet de travailler avec des fichiers indéfiniment long (peu d'allocation mémoire)
information sur le buffer
méthodes (
getter methods )définies sur l'objet Buffer:
- bufnum
- numFrames
- numChannels
- sampleRate
- free
// regarder la 'console'
b = Buffer.read(s, "sounds/a11wlk01.wav");
b.bufnum;
b.numFrames;
b.numChannels;
b.sampleRate;
b.free;
UGens
- on dispose d'autres sources d'informations, données par le serveur:
- ces informations sont accessibles avec les UGens "descendant" de InfoUGenBase
- pour voir la liste complète de ces Ugens, évaluez
InfoUGenBase.dumpClassSubtree
// et
BufInfoUGenBase.dumpClassSubtree
- ces UGens permettent d'utiliser les caractéristiques du buffer dans l'UGenGraphFunction:
SynthDef("aLoopingSamplePlayer", { arg outBus = 0, bufnum = 0, rateScale = 1, mul = 1;
Out.ar(
outBus,
PlayBuf.ar(
1,
bufnum,
BufRateScale.kr(bufnum) * rateScale + LFNoise1.kr(2.reciprocal, 0.05),
loop: 1 // infini
)
*
mul
)
}).load(s);
action functions
- la structure client/serveur implique une latence liée à l'envoi des messages
- certaines méthodes de l'objet Buffer peuvent prendre en argument une fonction, qui sera exécutée seulement lorsque le serveur aura confirmé la reception du message, et lorsque lorsque l'instance de l'objet Buffer aura mis à jour ses variables en fonction [~]
// avec action function
// noter que les variables ne sont pas immédiatement mises à jour
(
b = Buffer.read(s, "sounds/a11wlk01.wav", action: { arg buffer;
("numFrames after update:" + buffer.numFrames).postln;
x = { PlayBuf.ar(1, buffer.bufnum, BufRateScale.kr(buffer.bufnum)) }.play;
});
// la ligne suivante s'exécutera AVANT l'action function
("numFrames before update:" + b.numFrames).postln;
)
x.free; b.free;
écriture dans un buffer (Recording)
RecordBuf
b = Buffer.alloc(s, s.sampleRate * 5, 1); // un buffer de 5 secondes, mono
// enregistrement 4 secondes
(
x = SynthDef("tutorial-RecordBuf",{ arg out=0,bufnum=0;
var noise;
noise = PinkNoise.ar(0.3);
RecordBuf.ar(noise, bufnum); // loop par défaut
}).play(s,[\out, 0, \bufnum, b.bufnum]);
)
// libérer le synth après quelques secondes
x.free;
// playback
(
SynthDef("tutorial-playback",{ arg out=0,bufnum=0;
var playbuf;
playbuf = PlayBuf.ar(1,bufnum);
FreeSelfWhenDone.kr(playbuf); // le synth se libère lorsque la fin du fichier est atteinte
Out.ar(out, playbuf);
}).play(s,[\out, 0, \bufnum, b.bufnum]);
)
b.free;
Accès au données
méthodes définies sur l'objet Buffer
- permettent d'écrire et de lire un point précis( à un index donné ) du buffer
- ! un Buffer multicanal stocke ses données en 'interleaved' :
index 0 = frame1-chan1, index 1 = frame1-chan2, index 2 = frame2-chan1
, etc.
- get peut recevoir une action function
b = Buffer.alloc(s, 8, 1);
b.set(7, 0.5); // la valeur à l'index 7 est mise à 0.5
b.get(7, {|msg| msg.postln}); // obtention de la valeur stockée à l'id 7, et affichage
b.free;
- setn
- getn
- opèrent sur des valeurs adjacentes du buffer
- getn peut recevoir une action function
b = Buffer.alloc(s,16);
b.setn(0, [1, 2, 3]); // définir les trois premières valeurs
b.getn(0, 3, {|msg| msg.postln}); // les obtenir, les afficher
b.setn(0, Array.fill(b.numFrames, {1.0.rand})); // remplir le buffer avec des valeurs aléatoires
b.getn(0, b.numFrames, {|msg| msg.postln}); // les obtenir
b.free;
- loadCollection
- loadToFloatArray (un FloatArray est un Array ne pouvant contenir que des *floats* )
- permettent de contourner le problème de limite dans la taille d'envoi de données: le protocole UDP permet par exemple un paquet de taille maximum 1633 [~]
(
// bruit blanc, par le placement de valeurs aléatoires
v = FloatArray.fill(44100, {1.0.rand2});
b = Buffer.alloc(s, 44100);
)
(
// chargement du ""FloatArray"" dans b, exécution
b.loadCollection(v, action: {|buf|
x = { PlayBuf.ar(buf.numChannels, buf.bufnum, BufRateScale.kr(buf.bufnum), loop: 1)
* 0.2 }.play;
});
)
x.free;
// récupération du FloatArray, comparaison avec v: la comparaison retourne 'true'
// les arguments 0 et -1 indiquent le remplissage de tout le buffer depuis l'index 0
b.loadToFloatArray(0, -1, {|floatArray| (floatArray == v).postln });
b.free;
Visualisation et Ecoute
// visualisation de la forme d'onde (sur mac)
b = Buffer.read(s,"sounds/a11wlk01.wav");
b.plot;
// exécution du contenu
b.play; // se libère automatiquement
x = b.play(true); // loop: donc pas de libération
x.free; b.free;
Autres utilisation des buffers
rappel: un buffer est avant tout un ensemble de floats stocké sur le serveur
Waveshaping
b = Buffer.alloc(s, 512, 1);
b.cheby([1,0,1,1,0,1]);
(
x = play({
Shaper.ar(
b.bufnum,
SinOsc.ar(300, 0, Line.kr(0,1,6)),
0.5
)
});
)
x.free; b.free;
- la methode cheby écrit dans le buffer des series de polynômes de Chebyshev
- l'UGen Shaper exécute du waveshaping sur un source, à l'aide des données d'un buffer
Enregistrement de contrôles
b = Buffer.alloc(s, 44100);
{RecordBuf.ar(K2A.ar(MouseX.kr(0, 1000)), b.bufnum, loop:0); SinOsc.ar(PlayBuf.ar(1, b.bufnum, loop:1)) }.play
b.plot(minval:0, maxval:1000); //sur mac
Séquence sur le serveur
b = Buffer.alloc(s, 8, 1);
{
var lfo;
lfo = LFSaw.ar(1).range(0, b.numFrames).floor; //le lfo parcourt le buffer en 1 sec, par palier (floor = troncation)
Out.ar(0,SinOsc.ar(BufRd.kr(1, b.bufnum, lfo,1, 0).midicps,0, 0.1)!2);
}.play;
b.setn(0, [0,1,4,5,6,9,10,12]+60);
b.setn(0, [0,2,4,5,7,9,11,12]+60);
b.setn(0, (0..23).scramble[..7] + 60);
b.plot(minval: 60, maxval: 84); //sur mac
Voir aussi:
Buffer∞
PlayBuf∞
RecordBuf∞
SynthDef∞
BufRateScale∞
Shaper∞
OSC <
Index >
Le Temps
There are no comments on this page. [Add comment]