Vos actions : Créer un document, voir la page générale.

Cultures numériques

Cours de Bachelor 1

Pas à pas : charger un document avec loadBytes

LoadBytes est une fonction de Processing qui permet de charger n’importe quel type de fichier et d’en lire les données brutes. Un bon point de départ pour écrire avec Processing quelques lignes de code.

Processing est un logiciel qui permet d’écrire des outils. Dans notre cas, nous nous nous en servons pour créer du son.
Il y a plusieurs types d’information récupérable par Processing et pour ce workshop il y en a 3 principaux : données brutes, texte (sous forme de phrase, mots et lettres) et pixels d’un image.

Les premières lignes de Processing

Ecrire avec Processing commence souvent par les deux fonctions de base :

void setup(){
  // ce qui est écrit ici s'exécute une fois, au début du programme
}

void draw(){
  // ce qui est écrit ici s'exécute de manière répétitive et rapide 
  // tant que le programme est actif
}

(A propos, deux slashes permettent d’écrire un commentaire, qui ne sera pas considéré comme du code)

Charger le contenu d’un fichier avec loadBytes

Pour pouvoir lire un fichier, on passe par trois étapes :
1) on créer un espace de mémoire pour stocker ce fichier
2) on charge le fichier dedans
3) on lit les informations

1) Tout en haut du script, on va donc créer cet espace de mémoire pour stocker le fichier.

byte b[];

C’est ce qu’on appelle une variable. Le mot "byte" signifie que c’est une variable faite pour stocker des.. bytes. Les accolades signalent qu’on ne va charger un byte mais plusieurs bytes (des millions probablement, en fait).

2) Ensuite, nous allons charger l’information dans cette variable ’b’. Pour ça, on place dans la partie "setup()" la commande suivante :

b = loadBytes("monfichier.txt");

loadbytes est une fonction qui peut lire le contenu du fichier qu’on lui indique et le stocke dans un variable de type byte. Une fois cette ligne de code lue, hop, le fichier est chargé dans la variable.

3) pour lire l’information, on va mettre en place une autre variable, qu’on appellera "compteur", qui permettra de demander le byte 1, puis le byte 2, puis 3, etc. Cette variable est un chiffre entier, on ajoute donc en tête du programme la ligne

int compteur=0;

Cette fois on a créé la variable et directement mis quelque chose dedans : le chiffre 0.
Du coup, dans la fonction "draw()" on peut ajouter le code suivant

int chiffre = b[compteur] & 0xff;

Ce code récupère dans une variable ’chiffre’ qui est de type chiffre (int signifie chiffre entier) la valeur du byte numéro 0 (car notre variable compteur vaut 0). Mais comme un byte a une valeur allant de -128 to 127, la partie étrange "& 0xff" est faite pour convertir en un chiffre de 0 à 255, plus facilement utilisable.

Il ne nous reste plus qu’à afficher ce chiffre dans un premier temps, puis en faire ce qu’on veut. Dans notre cas, ce sera produire un son.
On va ajouter un peu de mise en page, et on obtient ça :

byte b[];
int compteur=0;

void setup(){
  // ce qui est écrit ici s'exécute une fois, au début du programme
  size(400,200); // la taille de la fenêtre
  textAlign(CENTER,CENTER); // pour centrer le texte
  textSize(30); // on agrandit la typo
  b = loadBytes("photo.jpg"); 
}

void draw(){
  // ce qui est écrit ici s'exécute de manière répétitive et rapide 
  // tant que le programme est actif
  background(0); // couleur de fond noire
  int chiffre = b[compteur] & 0xff;
  text(chiffre, width/2,height/2); // afficher le chiffre au milieu 
}

N’oubliez pas de placer un document à lire dans le dossier de Processing et de spécifier son nom dans le script !

Passer d’une information à l’autre

Pour passer au byte suivant, il suffit de changer la valeur du compteur. Même si il y a probablement des milliers et même des millions d’informations dans le document lu par Processing, il vaut mieux contrôler le compteur pour qu’il ne dépasse pas le nombre de bytes disponibles, ce qui ferait crasher le programme. Dans notre cas, on va remettre le compteur à 0 si on dépasse le nombre d’éléments en ajoutant le code suivant après l’affichage

compteur++;
  if(compteur > b.length){
    compteur=0;
  }

Jouer une onde sur base des bytes

ce programme lit maintenant à très grand vitesse des chiffres allant de 0 à 255. Comme ce workshop s’occupe de transformation de chiffres en son, on va faire ça.
La plus simple est de générer un son directement avec Processing (plutôt que de déclencher des sons préenregistrés). Pour ça on va procéder en trois temps de nouveau :
1) charger une librairie dans Processing capable de générer du son
2) créer objet (un espace de mémoire spécifique) pour le générateur
3) instancier l’objet (c’est à dire remplir l’espace avec le générateur choisi)
4) démarrer le son et le moduler avec les bytes

Voici le code complet

import processing.sound.*;
TriOsc triangle;

byte b[];
int compteur=0;

void setup(){
  // ce qui est écrit ici s'exécute une fois, au début du programme
  size(400,200); // la taille de la fenêtre
  textAlign(CENTER,CENTER); // pour centrer le texte
  textSize(30); // on agrandit la typo
  b = loadBytes("photo.jpg"); 
  
  triangle = new TriOsc(this);
  triangle.play();
}

void draw(){
  // ce qui est écrit ici s'exécute de manière répétitive et rapide 
  // tant que le programme est actif
  background(0); // couleur de fond noire
  int chiffre = b[compteur] & 0xff;
  float f=map(chiffre,0,255,300,600);
  triangle.freq(f);
  text(chiffre, width/2,height/2); // afficher le chiffre au milieu 
  compteur++;
  if(compteur > b.length){
    compteur=0;
  }
}

Quelques remarques

 L’onde est une onde triangulaire. Sound, la librairie choisie, permet aussi de générer des ondes carrés, en dent de scie, en oscillation. Il y a juste une ligne à changer pour tester ça.
 une fonction mathématique, map(), permet de changer le chiffre (qui va de 0 à 255) en un chiffre plus facilement utilisable pour le générateur d’onde, qui va de 300 à 600. Ces chiffres peuvent être modifiés pour produire des notes plus variées, plus graves ou plus aigües.
 le script lit aussi vite qu’il le peux les chiffres, ce qui fait des variations très rapides. On peut le ralentir de plusieurs manières, dans notre cas par exemple en changeant le frameRate() dans le setup(). Par exemple :

frameRate(4);

pour 4 notes par secondes.

Par Stéphane Noël, 3 décembre 2017