Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente Prochaine révision Les deux révisions suivantes | ||
openatelier:projet:sequences_etranges [2020/06/02 01:08] emoc |
openatelier:projet:sequences_etranges [2020/06/02 01:24] emoc [petites choses utiles] |
||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
+ | {{tag>audio processing chuck em}} | ||
+ | |||
====== Séquences étranges ====== | ====== Séquences étranges ====== | ||
Ligne 11: | Ligne 13: | ||
En vidéo, ça donne | En vidéo, ça donne | ||
- | {{http://emoc.org/ATELIER/processing3/2020_KI/sequences_etranges/sequence_etrange_trois_001/test2.webm|exemple vidéo}} | + | {{http://emoc.org/ATELIER/processing3/2020_KI/sequences_etranges/sequence_etrange_trois_001/test2.webm?800x400|exemple vidéo}} |
+ | |||
+ | ==== code ==== | ||
+ | |||
+ | Un script processing pour l'interface graphique et un script chuck pour le granulateur, les deux communiquent par OSC | ||
+ | |||
+ | <accordion> | ||
+ | <panel title="sequence_etrange_trois_001.pde (cliquer pour afficher le code)"> | ||
+ | <code java sequence_etrange_trois_001.pde> | ||
+ | /* | ||
+ | Discussions entre processing et chuck | ||
+ | Lire en boucle plusieurs grains de sons d'un même fichier | ||
+ | Quimper, Dour Ru, 20200601 / pierre@lesporteslogiques.net | ||
+ | Processing 3.5.3 + ControlP5 2.2.6 + OscP5 0.9.9 | ||
+ | chuck version: 1.4.0.1 linux (pulse) 64-bit | ||
+ | @ kirin / Debian Stretch 9.5 | ||
+ | */ | ||
+ | |||
+ | import oscP5.*; | ||
+ | import netP5.*; | ||
+ | OscP5 oscP5; | ||
+ | NetAddress myRemoteLocation; | ||
+ | |||
+ | ArrayList<Grain> grains = new ArrayList<Grain>(); | ||
+ | |||
+ | int id = 0; | ||
+ | float duree_morceau = 58.16; // en secondes | ||
+ | float dur; | ||
+ | |||
+ | PImage wave; | ||
+ | |||
+ | void setup() { | ||
+ | size (800, 400); | ||
+ | oscP5 = new OscP5(this, 12000); | ||
+ | myRemoteLocation = new NetAddress("127.0.0.1", 12012); | ||
+ | wave = loadImage("wf.png"); | ||
+ | } | ||
+ | |||
+ | void draw() { | ||
+ | |||
+ | background(0); | ||
+ | image(wave,0,0); | ||
+ | |||
+ | // Montrer la position et le fragment bouclé | ||
+ | fill(128, 50); | ||
+ | stroke(128, 50); | ||
+ | strokeWeight(0.5); | ||
+ | dur = (((duree_morceau * 44100) / width) / ((mouseY / (float)height) * (3 * 44100))); | ||
+ | float pixels_par_seconde = (float)width / duree_morceau; // x pixel = 1 seconde | ||
+ | float duree_extrait = (1 - (mouseY / (float)height)) * 3 ; // 3 secondes max | ||
+ | dur = pixels_par_seconde * duree_extrait; | ||
+ | |||
+ | line(0, mouseY, width, mouseY); | ||
+ | rect(mouseX, 0, dur, height); | ||
+ | for (int i = grains.size() - 1; i >= 0; i--) { | ||
+ | Grain g = grains.get(i); | ||
+ | g.miseajour(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void keyPressed() { | ||
+ | if (key == 'p') ajouterGrain(); | ||
+ | if (key == 'd') supprimerGrain(mouseX, mouseY); | ||
+ | if (key == 'c') resetGrain(); | ||
+ | } | ||
+ | |||
+ | void ajouterGrain() { | ||
+ | id ++; | ||
+ | if (id < 100) { | ||
+ | grains.add( new Grain(mouseX, mouseY, id) ); | ||
+ | |||
+ | OscMessage myMessage = new OscMessage("/sequence_etrange_trois"); | ||
+ | float xn = mouseX / (float)width; // normaliser les valeurs | ||
+ | float yn = mouseY / (float)height; // normaliser les valeurs | ||
+ | myMessage.add(1); | ||
+ | myMessage.add(id); | ||
+ | myMessage.add(xn); | ||
+ | myMessage.add(1 - yn); // inverser, c'est plus intuitif, le zéro est en bas! | ||
+ | oscP5.send(myMessage, myRemoteLocation); | ||
+ | } else { | ||
+ | background(255, 0, 0); | ||
+ | println("trop de fragments!"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void supprimerGrain(float x, float y) { | ||
+ | for (int i = grains.size() - 1; i >= 0; i--) { | ||
+ | Grain g = grains.get(i); | ||
+ | if (dist(x, y, g.x, g.y) < 6) { | ||
+ | grains.remove(i); | ||
+ | OscMessage myMessage = new OscMessage("/sequence_etrange_trois"); | ||
+ | myMessage.add(0); | ||
+ | myMessage.add(g.id); | ||
+ | myMessage.add(0); | ||
+ | myMessage.add(0); | ||
+ | oscP5.send(myMessage, myRemoteLocation); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void resetGrain() { | ||
+ | for (int i = grains.size() - 1; i >= 0; i--) { | ||
+ | Grain g = grains.get(i); | ||
+ | grains.remove(i); | ||
+ | OscMessage myMessage = new OscMessage("/sequence_etrange_trois"); | ||
+ | myMessage.add(0); | ||
+ | myMessage.add(g.id); | ||
+ | myMessage.add(0); | ||
+ | myMessage.add(0); | ||
+ | oscP5.send(myMessage, myRemoteLocation); | ||
+ | } | ||
+ | id = 0; | ||
+ | } | ||
+ | |||
+ | class Grain { | ||
+ | |||
+ | float x, y; // coordonnées à l'écran (en pixels) | ||
+ | int id; | ||
+ | |||
+ | Grain(float x_, float y_, int id_) { | ||
+ | x = x_; | ||
+ | y = y_; | ||
+ | id = id_; | ||
+ | } | ||
+ | |||
+ | void miseajour() { | ||
+ | noFill(); | ||
+ | stroke(255, 200); | ||
+ | strokeWeight(1); | ||
+ | line(x, y-5, x, y+5); | ||
+ | line(x-5, y, x+5, y); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | </panel> | ||
+ | </accordion> | ||
+ | |||
+ | <accordion> | ||
+ | <panel title="sequence_etrange_trois_recepteur.ck (cliquer pour afficher le code)"> | ||
+ | <code sequence_etrange_trois_recepteur.ck> | ||
+ | // Debian 9.5 @ kirin | ||
+ | // Chuck 1.4.0.1 linux (pulse) 64-bit | ||
+ | // 20200601 / pierre@lesporteslogiques.net | ||
+ | |||
+ | OscIn oin; // définir le récepteur OSC | ||
+ | 12012 => oin.port; // port de réception | ||
+ | OscMsg msg; | ||
+ | |||
+ | oin.addAddress( "/sequence_etrange_trois" ); | ||
+ | |||
+ | int fragments[100]; // Pour stocker les id et les numéros de shred... | ||
+ | |||
+ | while(true) { | ||
+ | oin => now; | ||
+ | |||
+ | while (oin.recv(msg) != 0) { | ||
+ | msg.getInt(0) => int action; | ||
+ | msg.getInt(1) => int index; | ||
+ | msg.getFloat(2) => float start; | ||
+ | msg.getFloat(3) => float dur; | ||
+ | |||
+ | if (action == 0) { // Supprimer le shred associé à cet id | ||
+ | <<< "supprimer index " , index, "fragments : ", fragments[index] >>>; | ||
+ | Machine.remove(fragments[index]); | ||
+ | } | ||
+ | |||
+ | if (action == 1) { // Démarrer un nouveau shred | ||
+ | Shred s; | ||
+ | spork ~ grain(start, dur) @=> s; | ||
+ | <<< "Index : " , index, " > nouveau shred : " , s.id() >>>; | ||
+ | s.id() => fragments[index]; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | fun void grain(float start, float dur) { | ||
+ | |||
+ | SndBuf gra => dac; | ||
+ | me.dir() + "/kabuki_sound_effects.wav" => gra.read; | ||
+ | while(1) { | ||
+ | |||
+ | (dur * 3 * 44100) $ int => int gradur; | ||
+ | (start * gra.samples()) $ int => gra.pos; | ||
+ | if (gra.pos() < 0) 0 $ int => gra.pos; | ||
+ | gradur :: samp => now; | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | </panel> | ||
+ | </accordion> | ||
+ | |||
+ | ==== petites choses utiles ==== | ||
+ | |||
+ | L'image de la forme d'onde est créée avec [[https://github.com/bbc/audiowaveform|audiowaveform]] (nécessaire d'indiquer la durée du son) | ||
+ | # 20200601 debian 9.5 @ kirin | ||
+ | audiowaveform -i ./son.wav -s 0 -e 58.16 --background-color 000000 --waveform-color dddddd --no-axis-labels -w 800 -h 100 -o wf.png | ||
+ | |||
+ | La capture vidéo est faite avec ffmpeg | ||
+ | # ffmpeg version 3.2.14-1~deb9u1 | ||
+ | # dans les controles de pulseaudio, dans l'onglet "Enregistrement" il faut régler "Monitor of audio interne analogique" | ||
+ | ffmpeg -video_size 800x400 -framerate 25 -f x11grab -i :0.0+465,21 -f pulse -ac 2 -i default test2.mp4 | ||
+ | |||
+ | Les coordonnées de la fenêtre sont récupérées par | ||
+ | sleep 5s && xdotool getactivewindow getwindowgeometry | ||
+ | En fait ça n'est pas tout à fait la position mais je n'ai pas cherché plus loin, j'ai juste enlevé 22 pixels à la position verticale pour que ce soit à peu près bien cadré... | ||
+ | |||
+ | |||
+ | |||
+ | |||