Page créée le 9 septembre 2020
Transformation d'une platine disque en séquenceur optique : des capteurs posés le long du bras de la platine mesurent la lumière qu'ils reçoivent. Le disque est en carton/papier sur lequel sont tracées des formes au feutre.
La platine est une Pioneer PL-X11Z. Elle est conçu pour être alimentée en étant connectée à la chaine hifi par un mini-jack, en 12V. Elle fonctionne mais il manque la courroie. Dans un premier temps, on remplace la courroie manquante par un élastique assez grand, à section carrée.
Petits calculs
Un tour complet du plateau s'effectue en 1333.33 millisecondes (en position 45 tours/minute) et 1818 millisecondes en position 33 tours/minute Avec un disque de 30 cm, la circonférence extérieure est de 94 cm ( 2 * pi * r)
En 33 tours / minute :
Si on divise le disque en 4 parties égales, chacune occupe 454 millisecondes soit un tempo de 132 BPM (60 / 0.454ms), en deux parties égales : BPM 66, etc.
En 45 tours minute :
4 parties : chacune 333.33 ms soit un BPM de 180 / 2 parties = BPM de 90
bras de la platine avec capteur → multiplexeur → arduino -(usb-série)→ ordi avec patch pure data
Le premier montage utilise 8 photorésistances, à chacune d'entre elle est associée une led pour fournir un éclairage homogène.
Problème : les photorésistances sont un peu lentes
Dans cette version, les photorésistances sont remplacées par des phototransistors pour augmenter la vitesse de détection, le circuit électronique est adapté en conséquence. Deux pièces en impression 3D sont utilisées : la première pour maintenir le bras (dont le mécanisme de retour automatique a été désactivé) et la seconde pour fixer les composants.
A l'origine la platine est alimentée en 12V par la chaîne hifi, après modification nous avons installé une alimentation directe par bloc secteur / transfo 12V et un interrupteur de marche-arrêt.
Dans cette version, 6 phototransistors sont utilisés, sans multiplexeur. A chaque phototransistor est associé deux résistances (en reprenant les valeurs définies dans le projet de Yunchi Luo et Mengliang Yu de l'université Cornell, voir sources en bas de page) /!\ dans le montage, le ruban de leds est alimenté séparément pour éviter les parasites
platine_sequenceur_porte_bras.stl
/* Élément pour la platine séquenceur Quimper, La Baleine, 23 septembre 2020 OpenSCAD version 2019.05 @ kirin / Debian 9.5 */ difference() { union() { cylinder(h=6, r=5, center=true, $fn=36); translate([0,0,-3]) cylinder(h=1.5, r=12, center=true, $fn=72); translate([-5,0,1]) cube(size=[10,19,2]); translate([-5,4.7,1]) cube(size=[10,2,7]); translate([-5,17,1]) cube(size=[10,2,7]); } translate([0,0,-0.4]) cylinder(h=7, r=3.9, center=true, $fn=36); }
platine_sequenceur_bras_porte_capteur.stl
/* Élément pour la platine séquenceur bras porte capteur Quimper, La Baleine, 23 septembre 2020 OpenSCAD version 2019.05 @ kirin / Debian 9.5 */ difference() { color("Yellow") { difference() { translate([-10,-7.5,0]) cube(size=[12,15,100]); #union() { translate([0,0,10]) cube(size=[30,30,10], center=true); translate([0,0,25]) cube(size=[30,30,10], center=true); translate([0,0,40]) cube(size=[30,30,10], center=true); translate([0,0,55]) cube(size=[30,30,10], center=true); translate([0,0,70]) cube(size=[30,30,10], center=true); translate([0,0,85]) cube(size=[30,30,10], center=true); } } translate([-12,-7.5,-70]) cube(size=[3,15,170]); color("Lime") translate([-12,-7.5,0]) cube(size=[13.5,3,100]); color("Lime") translate([-12,4.5,0]) cube(size=[13.5,3,100]); } # color("Cyan") { translate([0,0,-1]) cylinder(h=102, r=4.5, center=false, $fn=36); translate([0,-4.5,-1]) cube(size=[9,9,102]); } } color("Blue") translate([-12,-9.49,-56]) cube(size=[12,2,8]); color("Blue") translate([-12,7.49,-56]) cube(size=[12,2,8]); * color("Green") translate([0,4.5,0]) rotate([0, 0, -45]) translate([0, 1, 0]) cube(size=[1,10,80]); * color("Green") translate([0.5,-3.5,0]) rotate([0, 0, -135]) cube(size=[1,13,100]); /* barre sans trou color("Red") translate([3.25,-10.4,50]) rotate([0, 0, 30]) cube(size=[1,13,100],center=true); */ color("Red") translate([6.5,-16.85,0]) rotate([0, 0, 30]) plaque_phototransistor(); color("Red") translate([3.25,10.4,50])rotate([0, 0, 150]) cube(size=[1,13,100],center=true); module plaque_phototransistor() { difference() { cube(size=[1,13,100],center=false); #union() { rotate([0,90,0]) translate([-6,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-6,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-22.5,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-22.5,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-39,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-39,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-55.5,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-55.5,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-72,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-72,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-89,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-89,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); } } }
Le code arduino comprend : une phase de calibration, la mesure des capteurs et l'envoi des données vers l'ordinateur, en série
/* * Platine sequenceur / prototype 002 * http://lesporteslogiques.net/wiki/openatelier/projet/platine_sequenceur * Quimper, La baleine, 24 sept 2020 * Debian 9.5 @ kirin / arduino 1.8.5 * + library Adafruit NeoPixel 1.1.3 https://github.com/adafruit/Adafruit_NeoPixel * * CIRCUIT * - 6 phototransistors reliés aux entrées analogiques * - ruban de 8 leds RGB * * MODES DE FONCTIONNEMENT (à régler dans le code) * Mode de réception des données (les données envoyées ne sont pas formatées de la même manière) * 0 pour le mode de test (traceur serie de l'arduino IDE) * 1 pour le mode de réception dans pure data * * VERSIONS * 001 : (prototype 001, photorésistances) envoi de valeurs brutes en série * 002 : (prototype 001, photorésistances) ajout des leds + calibration * 003 : (prototype 002, phototransistors) * * TODO * ajouter un bouton de calibration * ajouter un switch de mode 0 ou 1 * ajouter une led (clignote = calibration, éteinte mode 0, allumée mode 1) * * RESSOURCES * - traitements de lissage des données : https://www.openprocessing.org/sketch/686436 */ int MODE = 0; // Inclure les bibliothèques de fonction (libraries) nécessaires #include <Adafruit_NeoPixel.h> #ifdef __AVR__ #include <avr/power.h> #endif #define BROCHE_PT1 A1 // Broche reliée au phototransistor 1 #define BROCHE_PT2 A2 // Broche reliée au phototransistor 2 #define BROCHE_PT3 A3 // Broche reliée au phototransistor 3 #define BROCHE_PT4 A4 // Broche reliée au phototransistor 4 #define BROCHE_PT5 A5 // Broche reliée au phototransistor 5 #define BROCHE_PT6 A6 // Broche reliée au phototransistor 6 #define BROCHE_LED 5 // A quelle broche est relié le ruban de LEDs ? #define NUMPIXELS 6 // Combien de LEDs sur le ruban ? // Créer l'objet correspondant au ruban de LEDs Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, BROCHE_LED, NEO_RGB + NEO_KHZ800); int luminosite = 255; int v1b, v2b, v3b, v4b, v5b, v6b; // valeurs brutes int v1l, v2l, v3l, v4l, v5l, v6l; // valeurs lissées int v1c, v2c, v3c, v4c, v5c, v6c; // valeurs calibrées boolean CALIBRATION = true; long v1s, v2s, v3s, v4s, v5s, v6s; // sommes utilisées pour la calibration int v1i, v2i, v3i, v4i, v5i, v6i; // valeurs d'initialisation définies pendant la phase de calibration int calibration_start; // démarrage de la calibration à cette milliseconde! int calibration_compteur = 0; // utlisé pour le calcul réactualisé des moyennes void setup() { pixels.begin(); // Initialiser l'objet du ruban de leds Serial.begin(57600); // Fixer la luminosité pour l'ensemble du ruban pixels.setBrightness(luminosite); // Définir une couleur identique pour chaque LED, la LED 0 est la plus proche des broches for (int i = 0; i < 6; i++) { pixels.setPixelColor(i, pixels.Color( 255, 255, 255 )); } pixels.show(); delay(500); calibration_start = millis(); } void loop () { if (CALIBRATION) { calibration_compteur ++; if (millis() - calibration_start > 3000) { // L'étape de calibration dure 3 secondes CALIBRATION = false; v1i = (int)(v1s / (calibration_compteur - 1) ); v2i = (int)(v2s / (calibration_compteur - 1) ); v3i = (int)(v3s / (calibration_compteur - 1) ); v4i = (int)(v4s / (calibration_compteur - 1) ); v5i = (int)(v5s / (calibration_compteur - 1) ); v6i = (int)(v6s / (calibration_compteur - 1) ); v1l = v1i; v2l = v2i; v3l = v3i; v4l = v4i; v5l = v5i; v6l = v6i; } else { v1s += analogRead(BROCHE_PT1); delayMicroseconds(3); v2s += analogRead(BROCHE_PT2); delayMicroseconds(3); v3s += analogRead(BROCHE_PT3); delayMicroseconds(3); v4s += analogRead(BROCHE_PT4); delayMicroseconds(3); v5s += analogRead(BROCHE_PT5); delayMicroseconds(3); v6s += analogRead(BROCHE_PT6); delayMicroseconds(3); } } if (!CALIBRATION) { // Récupérer les valeurs actuelles v1b = analogRead(BROCHE_PT1); delayMicroseconds(3); v2b = analogRead(BROCHE_PT2); delayMicroseconds(3); v3b = analogRead(BROCHE_PT3); delayMicroseconds(3); v4b = analogRead(BROCHE_PT4); delayMicroseconds(3); v5b = analogRead(BROCHE_PT5); delayMicroseconds(3); v6b = analogRead(BROCHE_PT6); delayMicroseconds(3); v1l = (0.85 * v1l) + (0.15 * v1b) ; v2l = (0.85 * v2l) + (0.15 * v2b) ; v3l = (0.85 * v3l) + (0.15 * v3b) ; v4l = (0.85 * v4l) + (0.15 * v4b) ; v5l = (0.85 * v5l) + (0.15 * v5b) ; v6l = (0.85 * v6l) + (0.15 * v6b) ; v1c = (v1l - v1i) * -1; v2c = (v2l - v2i) * -1; v3c = (v3l - v3i) * -1; v4c = (v4l - v4i) * -1; v5c = (v5l - v5i) * -1; v6c = (v6l - v6i) * -1; if (MODE == 0) { Serial.print(v1c); Serial.print(","); Serial.print(v2c); Serial.print(","); Serial.print(v3c); Serial.print(","); Serial.print(v4c); Serial.print(","); Serial.print(v5c); Serial.print(","); Serial.println(v6c); //Serial.println(""); } if (MODE == 1) { Serial.print("photores "); Serial.print(v1c); Serial.print(" "); Serial.print(v2c); Serial.print(" "); Serial.print(v3c); Serial.print(" "); Serial.print(v4c); Serial.print(" "); Serial.print(v5c); Serial.print(" "); Serial.println(v6c); } delay(5); } }
Le code pure data récupère les données série, et déclenche les sons en conséquence
Un modèle de disque 33T à imprimer en A3, à l'échelle avec les 6 pistes correspondant à la position des capteurs.
Les rythmes sont à dessiner dans le sens inverse des aiguilles d'une montre (lévogyre!), le disque tournant dans le sens des aiguilles (dextrogyre)
Pour mémoire, distances des capteurs avec le centre du disque : 4,7 / 6,4 / 8,1 / 9,7 / 11,3 / 12,9 et les disques font 27,8 cm de diamètre (pour ne pas déborder du plateau, un vinyle format 33t fait 30 cm)
Le signal des phototransistors est très parasité :
→ alimenter séparément les leds : testé, et c'est beaucoup mieux
→ utiliser la source de tension de référence 1.1V incluse dans l'arduino pour la capture analogique (plutôt que VCC) (pas testé)
→ traiter le signal (moyenne, etc) : un lissage 85-15 est appliqué (voir https://www.openprocessing.org/sketch/686436 )
Autres améliorations possibles :
→ envoyer des messages série plus courts
→ mesurer les temps pour trouver un timing précis
→ tous les phototransistors ne réagissent pas de la même manière : réglé en ajoutant des seuils définissables dans le patch pure data
Ajouter quelques composants complémentaires (on verra plus tard)
Datasheet du phototransistor Osram Opto SFH 309 : phototransistor_osram-opto_sfh309.pdf
Utilisation des phototransistors, un bon exemple : https://people.ece.cornell.edu/land/courses/ece4760/FinalProjects/s2010/yl477_my288/yl477_my288/index.html
Utilisation basique des phototransistors avec arduino : https://arduino103.blogspot.com/2017/12/comment-utiliser-un-photo-transistor.html
Groove Pizza : https://apps.musedlab.org/groovepizza/?museid=ucEbu-1J6&
Pocket Operations, a collection of drum patterns (pdf à télécharger sur https://shittyrecording.studio )
rhythm patterns : https://www.ethanhein.com/wp/2013/my-collection-of-transcribed-rhythm-patterns/
Drum machine patterns : http://808.pixll.de/
How to write beats : https://mccormick.cx/news/entries/how-to-write-beats.news