Différences
Ci-dessous, les différences entre deux révisions de la page.
| Prochaine révision | Révision précédente | ||
|
openatelier:projet:sequences_etranges [2020/06/02 01:02] emoc créée |
openatelier:projet:sequences_etranges [2021/07/26 12:26] (Version actuelle) emoc [séquence étrange trois] |
||
|---|---|---|---|
| Ligne 1: | Ligne 1: | ||
| + | {{tag>audio processing chuck em}} | ||
| + | |||
| ====== Séquences étranges ====== | ====== Séquences étranges ====== | ||
| (Notes... 1er juin 2020) | (Notes... 1er juin 2020) | ||
| - | Jouets sonores. | + | Jouets sonores. Croquis de code pour des petites interfaces graphiques. Fonctionnels, mais sûrement avec des bugs surprises cachés dans les coins... Documentation minimale type prise de note |
| ===== séquence étrange trois ===== | ===== séquence étrange trois ===== | ||
| + | juillet 2021 : publication de ce projet amélioré sur github : [[https://github.com/emoc/bouclette|bouclette]] \\ | ||
| Boucles de samples type granulaire : à partir du même fichier sonore, boucler des petits fragments rapidement. | Boucles de samples type granulaire : à partir du même fichier sonore, boucler des petits fragments rapidement. | ||
| En vidéo, ça donne | En vidéo, ça donne | ||
| - | {{http://emoc.org/ATELIER/processing3/2020_KI/sequences_etranges/sequence_etrange_trois_001/test2.mp4|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 (cf. https://trac.ffmpeg.org/wiki/Capture/Desktop) | ||
| + | # 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 (cf. https://unix.stackexchange.com/q/14159) | ||
| + | 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é... | ||
| + | |||
| + | ===== Ressources ===== | ||
| + | * ChucK doc : https://chuck.cs.princeton.edu/doc/language/ | ||
| + | * ChucK ugens : https://chuck.cs.princeton.edu/doc/program/ugen_full.html | ||
| + | |||
| + | |||