Table de Mixage pour Glitcher une images

Porteur(s) du projet : Flora Vander Poorte (DSAA DG2), Damien MUTI (Prof. de Numérique)

Date : 06/2021

Contexte : Macro-Projet

Fichiers :

Liens :

Capteurs/Actionneurs :

3 potentiomètres

2 boutons Grove

1 carte Seeeduino

Intentions : explication du projet et objectifs

Ce dispositif est une table de mixage avec différents boutons et potentiomètres afin que les visiteurs puissent créer des images et modifier le son. C’est un peu comme un Photoshop tangible. Ce dispositif est composé de différents boutons qui modifient certains paramètres comme l’ajout d’image, la colorimétrie, l’ajout d’un son, et la possibilité de glitcher les images. On peut manipuler la matière numérique et altérer les pixels.

Pour cela j’ai utilisé une carte Seeduino, Processing, deux boutons et trois potentiomètres.

Algorithme

La carte Arduino mesure la valeur donnée par chacun des 3 potentiomètres et 2 boutons. Elle envoie ensuite chacune des valeurs via le port série vers le programme Processing qui gère le visuel. Le programme Processing récupère les 5 valeurs envoyées par la carte et les considère chacune comme 5 paramètres permettant de faire varier la teinte d'une image (pour les valeurs correspondant aux potentiomètres), lancer aléatoirement du son et faire varier aléatoirement l'affichage d'images (pour les deux boutons).

Montage Arduino

Câblage

Le montage comportant 3 potentiomètres et 2 boutons est le suivant :

Programmes Arduino

Le code permettant de mesurer les valeurs sur les 5 potentiomètres et de les envoyer via le port série est le suivant :

mixage_son_img_arduino_3.zip

int capteurs[] = {0, 0, 0, 0, 0}; // valeur des capteurs.5 capteurs. 0,1,2 : potentiomètres; 3,4 : boutons
byte bouton[] = {2, 3}; // pate des boutons
byte potPin[] = {0, 2, 5};
byte Ncapteurs = 5, Npotentiometres = 3, Nboutons = 2;
int inByte = 0; // incoming serial byte
// mode debug
boolean debug = false; // mettre "false" pour envyer les données à Procssing
void setup() {
// initialisation pattes boutons
for (byte i = 0; i < Nboutons; i++) {
pinMode(bouton[i], INPUT);
}
// start serial port at 9600 bps:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// établir le contact avec Processing
establishContact(); // send a byte to establish contact until receiver responds
}
void loop() {
// if we get a valid byte, read analog ins:
if (Serial.available() > 0) {
// get incoming byte:
inByte = Serial.read();
if (inByte == 'A') {
// read first analog input, divide by 4 to make the range 0-255:
// lecture des donées siur les potars
for (byte i = 0; i < Npotentiometres ; i++) { //Npotentiometre=3
capteurs[i] = analogRead(potPin[i]) / 4;
// delay 10ms to let the ADC recover:
delay(10);
}
// lecture des données sur les boutons (à partir de capteur[3])
// read switch, map it to 0 or 255
for (byte i = 0; i < Nboutons; i++) {
capteurs[i + 3] = map(digitalRead(bouton[i]), 0, 1, 0, 255);
}
// send sensor values:
if (debug) {
Serial.println("val capteurs : ");
for (byte i = 0; i < Npotentiometres + Nboutons; i++) { //Npotentiometres + Nboutons = 5
Serial.print(capteurs[i]);
Serial.print(" ");
}
Serial.println("");
}
else { ///////////////////Envoie des octets bruts à PROCESING //////////////////////
for (byte i = 0; i < Npotentiometres + Nboutons; i++) { //Npotentiometres + Nboutons = 5
Serial.write(capteurs[i]);
}
}
}
}
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.print('A'); // send a capital A
delay(300);
}
}

Programme Processing

Le programme Processing permettant de récupérer les données envoyées par la cartes et de les considérer comme des paramètres permettant “Glitcher” une images, et de lancer aléatoirement du son et l'affichage d'image est le suivant :

mixage_son_img_processing_4.zip

Programme principal :

/** Affiche tactile interactive -
* Quand on appuie sur une touche (UP, DOWN, RIGHT, LEFT et espace ' '), cela lance une image, une vidéo, une annim, un son, etc...
*/
/// librairies
import processing.sound.*;
import processing.video.*;
import processing.serial.*;
// bouton image active ? // est-ce que l'image est active ? Si oui, on affiche l'image
boolean animation_active = false; // true ou false (2 valleurs possibles) => 1 bit (0 ou 1)
// bouton son actif ?
boolean son_actif = false;
float tempsDebutSon = 0; // temps du début de la musique a été joué
// bouton video active ?
boolean video_active = false;
//potar teinte
int potVal = 0;
int redVal = 0;
/// dialogue avec la carte Arduino
Serial myPort; // Create object from Serial class
int inBuffer; // Data received from the serial port
int donneePortSerie; // entier converti de la chaine de caractère reçue sur le port série
// seuil de détection
float seuil = 300;
// port serie
int nCapteurs = 5;
int[] capteurs = new int[nCapteurs]; // données reçues via la carte Arduino
int serialCount = 0; // compteur de données reçues
boolean firstContact = false; // Whether we've heard from the microcontroller
// média
int nImages = 3;
String[] nomImages = new String[nImages];
PImage[] images = new PImage[nImages];
int nSon = 3;
String[] nomSon=new String[nSon];
SoundFile[] son; // un son - un seul lecteur CD audio
//Movie vid; // une vidéo - un seul lecteur DVD vidéo
// annim : glitch
PImage imageAffichee, imageInitiale;
int mode=0;
Glitch glitch;
// mode debug
boolean debug=true;
void setup() { // initialisation des paramètres d'affichage & chargement des sons, vidéos, etc.
size(1000, 800);
noStroke();
background(0);
colorMode(HSB);
// initialisation des variables globales
// capteurs
for (int i=0; i<nCapteurs; i++) {
capteurs[i]=0;
}
// nom son
nomSon[0]= "sons/son2.mp3";
//nomSon[1]= "sons/Armstrong.wav";
//nomSon[2]= "sons/beat.aiff";
// nom images
nomImages[0]= "images/img1.jpg";
nomImages[1]= "images/img2.jpg";
nomImages[2]= "images/img3.jpg";
// images
for (int i=0; i<nImages; i++) {
images[i]=loadImage(nomImages[i]);
}
// chargement des sons
son =new SoundFile[nCapteurs];
for (int i=0; i<nSon; i++) {
son[i] = new SoundFile(this, nomSon[i]);
}
/// Port série
// Print a list of the serial ports, for debugging purposes:
printArray(Serial.list());
String portName = Serial.list()[2];
myPort = new Serial(this, portName, 9600);
// intstanciation de la classe Glitch
//glitch = new Glitch();
//glitch = new Glitch("images/fond3.jpg");
imageInitiale = loadImage("images/fond3.jpg");
imageAffichee = imageInitiale.copy();
glitch = new Glitch(imageAffichee);
}
void draw() {
// chargement des pixels de l'image affichee
imageAffichee.loadPixels();
//loadPixels();
//arrayCopy(pixels, imageAffichee.pixels);
///////////////////////// interactivités liées aux capteurs
// potentiomètres : capteurs[0]-> capteurs[2]
// potar 0: teinte
tint(capteurs[0],255,255, capteurs[2]);
// potar 1: glitch
glitch.mode = floor(map(capteurs[1], 0, 255, 0, 2)); // sélection du mode de glitch : 0,1 2
if (debug) {
println("glitch.mode="+glitch.mode);
}
glitch.draw(imageAffichee);
// potar 2: sound
// interactivité liée aux boutons capteurs[3] et capteurs[4]
if (capteurs[3]==255 && !son[0].isPlaying()) { // capteurs[3] ->son
son[0].play();
}
if (capteurs[4]==255) { // capteurs[4] ->img
for (int i=0; i<nImages; i++) {
//float x = random(0, images[i].width);
//float y = random(0, images[i].height);
//image(images[i], x, y);
float x = random(0, 400);
float y = random(0, 400);
image(images[i], x, y, 400, 400);
// enregistrement de l'image dessinée dans imageAffichee
}
imageAffichee.updatePixels();
}
}

serialEvent :

void serialEvent(Serial myPort) {
// read a byte from the serial port:
int inByte = myPort.read();
// if this is the first byte received, and it's an A,
// clear the serial buffer and note that you've
// had first contact from the microcontroller.
// Otherwise, add the incoming byte to the array:
if (firstContact == false) {
if (inByte == 'A') {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
myPort.write('A'); // ask for more
println("Communication avec la carte établie");
}
} else {
// Add the latest byte from the serial port to array:
capteurs[serialCount] = inByte;
serialCount++;
// If we have nCapteurs=5 bytes:
if (serialCount > nCapteurs-1 ) {
// print the values (for debugging purposes only):
if (debug) {
for (int i =0; i<nCapteurs; i++) {
print("capteur_" + i + "="+ capteurs[i]+ " ");
}
println("");
}
// Send a capital A to request new sensor readings:
myPort.write('A');
// Reset serialCount:
serialCount = 0;
}
}
}

Gestion Interactivité :

//////////////////////////////////////////////// animation ///////////////////////////////////////////////////
void gestionAnimation() {
if (donneePortSerie > 100) { // on appuie sur la touche "espace" => lancer l'animation "image"
animation_active = true;
} else {
animation_active = false;
}
}
void lancerAnimation() {
float x = 30 + random(-20, 20); // random sur la position
float y = 30 + random(-20, 20);
//image(im, x, y, 200, 200);
}

Class “Glitch” parmettant de glitcher une image. Ce programme est un sketch du site OpenProcessing :

asdfpixelglitch2.zip

/** Affiche tactile interactive -
* Quand on appuie sur une touche (UP, DOWN, RIGHT, LEFT et espace ' '), cela lance une image, une vidéo, une annim, un son, etc...
*/
/// librairies
import processing.sound.*;
import processing.video.*;
import processing.serial.*;
// bouton image active ? // est-ce que l'image est active ? Si oui, on affiche l'image
boolean animation_active = false; // true ou false (2 valleurs possibles) => 1 bit (0 ou 1)
// bouton son actif ?
boolean son_actif = false;
float tempsDebutSon = 0; // temps du début de la musique a été joué
// bouton video active ?
boolean video_active = false;
//potar teinte
int potVal = 0;
int redVal = 0;
/// dialogue avec la carte Arduino
Serial myPort; // Create object from Serial class
int inBuffer; // Data received from the serial port
int donneePortSerie; // entier converti de la chaine de caractère reçue sur le port série
// seuil de détection
float seuil = 300;
// port serie
int nCapteurs = 5;
int[] capteurs = new int[nCapteurs]; // données reçues via la carte Arduino
int serialCount = 0; // compteur de données reçues
boolean firstContact = false; // Whether we've heard from the microcontroller
// média
int nImages = 3;
String[] nomImages = new String[nImages];
PImage[] images = new PImage[nImages];
int nSon = 3;
String[] nomSon=new String[nSon];
SoundFile[] son; // un son - un seul lecteur CD audio
//Movie vid; // une vidéo - un seul lecteur DVD vidéo
// annim : glitch
PImage imageAffichee, imageInitiale;
int mode=0;
Glitch glitch;
// mode debug
boolean debug=true;
void setup() { // initialisation des paramètres d'affichage & chargement des sons, vidéos, etc.
size(1000, 800);
noStroke();
background(0);
colorMode(HSB);
// initialisation des variables globales
// capteurs
for (int i=0; i<nCapteurs; i++) {
capteurs[i]=0;
}
// nom son
nomSon[0]= "sons/son2.mp3";
//nomSon[1]= "sons/Armstrong.wav";
//nomSon[2]= "sons/beat.aiff";
// nom images
nomImages[0]= "images/img1.jpg";
nomImages[1]= "images/img2.jpg";
nomImages[2]= "images/img3.jpg";
// images
for (int i=0; i<nImages; i++) {
images[i]=loadImage(nomImages[i]);
}
// chargement des sons
son =new SoundFile[nCapteurs];
for (int i=0; i<nSon; i++) {
son[i] = new SoundFile(this, nomSon[i]);
}
/// Port série
// Print a list of the serial ports, for debugging purposes:
printArray(Serial.list());
String portName = Serial.list()[2];
myPort = new Serial(this, portName, 9600);
// intstanciation de la classe Glitch
//glitch = new Glitch();
//glitch = new Glitch("images/fond3.jpg");
imageInitiale = loadImage("images/fond3.jpg");
imageAffichee = imageInitiale.copy();
glitch = new Glitch(imageAffichee);
}
void draw() {
// chargement des pixels de l'image affichee
imageAffichee.loadPixels();
//loadPixels();
//arrayCopy(pixels, imageAffichee.pixels);
///////////////////////// interactivités liées aux capteurs
// potentiomètres : capteurs[0]-> capteurs[2]
// potar 0: teinte
tint(capteurs[0],255,255, capteurs[2]);
// potar 1: glitch
glitch.mode = floor(map(capteurs[1], 0, 255, 0, 2)); // sélection du mode de glitch : 0,1 2
if (debug) {
println("glitch.mode="+glitch.mode);
}
glitch.draw(imageAffichee);
// potar 2: sound
// interactivité liée aux boutons capteurs[3] et capteurs[4]
if (capteurs[3]==255 && !son[0].isPlaying()) { // capteurs[3] ->son
son[0].play();
}
if (capteurs[4]==255) { // capteurs[4] ->img
for (int i=0; i<nImages; i++) {
//float x = random(0, images[i].width);
//float y = random(0, images[i].height);
//image(images[i], x, y);
float x = random(0, 400);
float y = random(0, 400);
image(images[i], x, y, 400, 400);
// enregistrement de l'image dessinée dans imageAffichee
}
imageAffichee.updatePixels();
}
}

Réalisation de la maquette et visuels

Pour la maquette, j'ai utilisé une planche de bois MDH 3mm et j'ai fais mon fichier sur AI pour utiliser la découpe laser. Il faut bien séparer les éléments qu'on veut découper et les éléments qu'on veut graver en deux couleurs distinctes.

Ci-joint mon fichier :

Pour que votre fichier soit valide, referez au fichier exemple de la découpe laser.

Références :