Projet pedalier interface Ableton Live via LiveOSC

Bonjour,
Je débute sur l'arduino et je me suis lancé dans un projet surement un peu sur-dimensionné pour mes humbles compétences.

Le contexte:
J'utilise What’s new in Live 11 | Ableton sur scène depuis pas mal de temps. Sur notre projet actuel je joue de la basse quasiment tout le long de notre set.
Ableton live pour ceux qui ne connaitraient pas est très souple pour les lancement de scènes audio (ou plus). Il est facilement programmable via midi (assignation des scènes et ou fonction à des midi notes). Jusque là je déclenchais donc les séquences avec un pédalier midi qui génère des midi notes. En ayant tjrs un oeil sur l'ordi afin de lancer le bon truc ... .
Un ordinateur sur scène c'est bien mais c'est pas toujours très jolie :(. En fait plusieurs retours de scénographes et du public nous font douté de la présence de l'objet informatique sur scène. (A moins d'être DJ vissé à son écran, c'est vrai que haranguer la foule avec sa basse sur les épaules tout en matant l'écran du portable ça le fait pas).

L'idée:

  • Planquer le portable en font de scène (ça c'est pas dur :wink: ).
  • Avoir sous les yeux (sur un pédalier) via un écran LCD, les noms des 6 scènes correspondants aux 6 switchs.

    (dessiné sur un bout de nappe ce midi au café du coin désolé :-?).
  • les switchs + et - permettent de visualiser les scènes +6 (de 7 à 12 , de 13 à 18, etc) ou de décrémenter.
  • le switch stop ? franchement je sais pas à quoi y peu servir ... hihi.
  • idéalement je voudrait que la scène en court de lecture soit indiqué par un éclairage sur le switch correspondant (led sous plexi autour des switchs).

Des solutions :

Liste du matériel:

Du coup je suis en train de me pencher sur la programmation de l'arduino comme seul interface avec Live. Mais j'ai beaucoup de problèmes à gérer:
1- les commutations (en utilisant le code exempel Button State Change ça marche pour un switch pour 2 c'est pas ça alors pour 6???)
2- la récupération de la syntax OSC et la gestion de la liste des noms de scènes. (cf : http://monome.q3f.org/browser/trunk/LiveOSC/OSCAPI.txt).
3- l'incrémentation à +6 et vis et versa.
4- je pensais gérer l'affichage des leds de switch via i2c soit avec un autre arduino ( dans ce que là j'en profiterait pour gérer et les switch en entrée et l'affichage de leur état), soit avec un remote i2c (PCF8574 ou autre). Et du coup je ne sais pas bien comment ça va se goupier. Quoique j'ai déjà taté du Wire avec l'afficheur LCD.

Je publierais mes scripts et la vidéo de démo avec interfaçage Max/MSP lundi. Mais si déjà vous avez des suggestions, des conseils et/ ou des questions je reste à votre dispositions
Bien sincèrement, très bon WEEK-END.

Du coup je suis en train de me pencher sur la programmation de l'arduino comme seul interface avec Live. Mais j'ai beaucoup de problèmes à gérer:
1- les commutations (en utilisant le code exempel Button State Change ça marche pour un switch pour 2 c'est pas ça alors pour 6???)
2- la récupération de la syntax OSC et la gestion de la liste des noms de scènes. (cf : http://monome.q3f.org/browser/trunk/LiveOSC/OSCAPI.txt).
3- l'incrémentation à +6 et vis et versa.
4- je pensais gérer l'affichage des leds de switch via i2c soit avec un autre arduino ( dans ce que là j'en profiterait pour gérer et les switch en entrée et l'affichage de leur état), soit avec un remote i2c (PCF8574 ou autre). Et du coup je ne sais pas bien comment ça va se goupier. Quoique j'ai déjà taté du Wire avec l'afficheur LCD.

Je pense avoir saisi l'idée du projet !

1-Je ne vois pas bien ton soucis ici : les entrées digitales ne te conviennent pas ?
2-si je comprends bien l'interface avec le logiciel sur PC se fait juste avec des mots-clés ?
3-Pareil que 1 : je ne vois pas bien le soucis. Tu as juste à incrémenter ou décrémenter une variable suivant que tu appuis sur + ou -.
4- tu peux te servir d'un multiplexeur/démultiplexeur comme celui-ci :http://radiospares-fr.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=0308411

il te permet à partir de 3 fils de l'arduino d'allumer par exemple 8 leds (une à la fois sur ce modèle, mais c'est parfait dans ton cas!)

Bonjour B@tto,

Merci de ta réponse.
1-En fait les entrées digitales me conviennent très bien. C'est plutôt la programmation des commutations qui me pose problème.
2-Oui oui c'est quasi exactement ça. En gros on a une adresse /live une commande /tempo et une valeur 120 et c'est ça qu'on envoi au logiciel : /live/tempo 120. Pour les déclenchements de scènes, il me faut envoyer /live/play/scene X . Mais ça pas trop de soucis (à condition de régler le point 1). En revanche pour afficher les titres de scène sur l'écran LCD, le logiciel, lorsque je lui aurais envoyer la requête /live/name/scenes, enverra une liste du genre /live/name/scenes 01 nom1 02 nom2 03 nom3 ... XX nomX . du coup je ne sais pas bien comment récupérer les 6 premiers noms et comment en incrémentant, je pourrais récupérer les 6 suivant etc. parfaite transition pour le point 3 :wink:
3-En effet j'ai vu les fonction x++ / x-- pour incrémenter/décrémenter. Je vais me pencher dessus.
4-ça c'est une très bonne idée. je vais étudier la question, mais c'est vrai que si j'ai pensé à l'I2C c'est que c'est moins gourmand en connections et que je l'utilise déjà sur le LCD. J'avais même imaginé tout faire à partir de l'I2C, entrées (état des switchs) et sortit (état des leds) mais bon ... verrais plus tard.

En tout cas merci de tes bons conseils et de ton soutient. Snif, me sentais un peu seul. :slight_smile:

je pensais gérer l'affichage des leds de switch via i2c soit avec un autre arduino

En même temps tu n'as pas tant d'entrées/sorties que ça, tu peux peut être les gérer directement avec les I/O de l'arduino.

En faisant le compte :
pour les digitales I/O
6 pour les scenes
2 pour +/-
1 stop
1 mode (une option en étude)
les pins 11 12 et 13 sont réservées à l'ethernet shield
reste 1 I/O
pour les analogiques
les 4 et 5 sont utilisées pour l'i2C
reste 4 in
ça pourrais le faire? Les entrées analogiques peuvent elles être des sorties?

Merci

Si t'es pas anglophobe : http://www.earthshineelectronics.com/files/ASKManualRev4.pdf

Il y a notamment un tuto qui te conviendra parfaitement puisqu'il s'agit de découper une chaine de caractère (question 2).

Oui le projet 10. Merci B@tto.

voilà où j'en suis. Cette version est à peu prêt fonctionnelle avec une petite application Max/MSP du coup les commande OSC sont personnalisées

#define VERSION "1.1"
#include <Ethernet.h>
#include <Wire.h>
#include <inttypes.h>
#include <LCDi2cW.h>    
#include <ArdOSC.h>

LCDi2cW lcd = LCDi2cW(2,16,0x4C,0);

uint8_t rows = 4;
uint8_t cols = 20;

//Déclaration des variables 

byte myMac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte myIp[]  = { 192, 168, 0, 255 };
int serverPort = 9003;
//
byte destIp[] =  { 192, 168, 0, 1 };
int  destPort = 9002;
//
char oscAdr[] = "/flourbard/bank";
char oscAdr1[] = "/flourbard/scene";
char oscAdr2[] = "/flourbard/play";
//
int scene1;
int scene2;
int scene0;
int scene3;
int scene4;
int scene5;
int scene6;
int scene7;
//
int bank;
//
int  pin14 = 14 ;
int  pin15 = 15 ;
int  pin9 = 9 ;
int  pin8 = 8 ;
int  pin7 = 7 ;
int  pin6 = 6 ;
int  pin5 = 5 ;
int  pin4 = 4 ;
int  pin3 = 3 ;
int  pin2 = 2 ;
int  pin1 = 1 ;
int  pin0 = 0 ;

volatile int  valplus = HIGH;
volatile int  valmoins = HIGH;
volatile int  play = HIGH;
volatile int  stop = HIGH;
volatile int  fb0 = HIGH;
volatile int  fb1 = HIGH;
volatile int  fb2 = HIGH;
volatile int  fb3 = HIGH;
volatile int  fb4 = HIGH;
volatile int  fb5 = HIGH;
volatile int  fb6 = HIGH;
volatile int  fb7 = HIGH;


OSCClient client;
OSCServer server;
OSCMessage *rcvMes;


//configuration Materiel

void setup(){
  
 lcd.init();   // Init the display, clears the display
 lcd.cursor_off(); // Curseur eteint
 lcd.setCursor(0,0);
 lcd.print("   Flourbard V1.0   ");       //titre
 lcd.setCursor(0,1);
 lcd.print("Mode:");   // titre Mode
 lcd.setCursor(13,1);
 lcd.print("BPM:");   //titre BPM


 
  pinMode(pin14, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin14, HIGH); // Resistance de PullUp interne
  pinMode(pin15, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin15, HIGH); // Resistance de PullUp interne
  pinMode(pin9, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin9, HIGH); // Resistance de PullUp interne
  pinMode(pin8, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin8, HIGH);
  pinMode(pin7, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin7, HIGH); // Resistance de PullUp interne
  pinMode(pin6, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin6, HIGH);
  pinMode(pin5, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin5, HIGH);
  pinMode(pin4, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin4, HIGH); // Resistance de PullUp interne
  pinMode(pin3, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin3, HIGH);
  pinMode(pin2, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin2, HIGH); // Resistance de PullUp interne
  pinMode(pin1, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin1, HIGH);
  pinMode(pin0, INPUT); // configure la broche en entrée et met le resultat dans la variable
  digitalWrite(pin0, HIGH);
  
  Serial.begin(19200);

  Ethernet.begin(myMac ,myIp);  
   
 server.sockOpen(serverPort);
}


//programme

void loop(){
  if(server.available()){
    rcvMes=server.getMessage();
    logMessage();

    
   
 }
 // variables attachées aux entrées pour Bank + et Bank -
  valplus=digitalRead(pin9) ;
  valmoins=digitalRead(pin8);
  // variables attachées aux entrées pour PLAY
  play=digitalRead(pin6); 
  // variables attachées aux entrées les 6 BOUTONS de selection
  fb5=digitalRead(pin5);
  fb4=digitalRead(pin4);
  fb3=digitalRead(pin3);
  fb2=digitalRead(pin2);
  fb1=digitalRead(pin1);
  fb0=digitalRead(pin0);
  
  long int tmp1 =(long int)scene1;
  long int tmp2 =(long int)scene2;
  long int tmp0 =(long int)scene0;
 //
  if (fb0 == LOW){
    long int num = (long int)pin0;
     OSCMessage message; 
     message.setAddress(destIp,destPort);
     message.setOSCMessage(oscAdr1 ,"i",&num);
     client.send(&message);
     delay(750);
  }
  else
  {
  }
  
  
  // état des switch de scène et envois de commandes OSC
   if (fb1 == LOW){
    long int num = (long int)pin1;
     OSCMessage message; 
     message.setAddress(destIp,destPort);
     message.setOSCMessage(oscAdr1 ,"i",&num);
     client.send(&message);
      delay(750);
    
  }
 else
  {
  }
  
  //
   if (fb2 == LOW){
    long int num = (long int)pin2;
     OSCMessage message; 
     message.setAddress(destIp,destPort);
     message.setOSCMessage(oscAdr1 ,"i",&num);
     client.send(&message);
      delay(750);
  }
 else
  {
  }
////
if (fb3 == LOW){
    long int num = (long int)pin3;
     OSCMessage message; 
     message.setAddress(destIp,destPort);
     message.setOSCMessage(oscAdr1 ,"i",&num);
     client.send(&message);
      delay(500);
    
  }
 else
  {
  }
  ///
  if (fb4 == LOW){
    long int num = (long int)pin4;
     OSCMessage message; 
     message.setAddress(destIp,destPort);
     message.setOSCMessage(oscAdr1 ,"i",&num);
     client.send(&message);
      delay(750);
  }
 else
  {
  }
  ///
  if (fb5 == LOW){
    long int num = (long int)pin5;
     OSCMessage message; 
     message.setAddress(destIp,destPort);
     message.setOSCMessage(oscAdr1 ,"i",&num);
     client.send(&message);
      delay(750);
    
  }
 else
  {
  }
  // état des switch +/- et envois de commandes OSC

  if (valplus == LOW){
    long int tmpplus =(long int)bank;
OSCMessage message; 
     message.setAddress(destIp,destPort);
      message.setOSCMessage(oscAdr ,"i", &tmpplus);
     client.send(&message);
    valplus = !valplus;
    bank = 1;
     delay(750);
  }
 else
  {
    
  }
  if (valmoins == LOW){
     long int tmpplus =(long int)bank;
    OSCMessage message; 
     message.setAddress(destIp,destPort);
      message.setOSCMessage(oscAdr ,"i", &tmpplus);
     client.send(&message);
    valplus = !valplus;
    bank = 2;
     delay(750);
  }
 else
  {
     
  }
// état du switch play et envois de commandes OSC

  if (play == LOW){
    
    long int play =1;
    OSCMessage message; 
     message.setAddress(destIp,destPort);
      message.setOSCMessage(oscAdr2 ,"i", &play);
     client.send(&message);
   
    
    delay(750);
    }
 else
  {
   } 
 

     
     
}

    // affichage des noms de scène  

    void logMessage(){
    uint16_t i;
    byte *ip=rcvMes->getIpAddress();
    long int intValue;
    
    float floatValue;
    char *stringValue;
    char *valchar=rcvMes->getOSCAddress();
    char *topAddress[13]={"nom0" , "nom1" , "nom2" , "nom3" , "nom4" , "nom5", "tempo"};
    
    for(i=0 ; i<rcvMes->getArgsNum(); i++){
      
     switch( rcvMes->getTypeTag(i) ){
      case 'i':       
          intValue = rcvMes->getInteger32(i);
         break; 
         
        case 'f':        
          floatValue = rcvMes->getFloat(i);
         break; 
        
        case 's':         
          stringValue = rcvMes->getString(i);
     
         break; 
     }
    
     if( !strcmp( valchar, topAddress[0]) ){
     lcd.setCursor (1,2);
     lcd.print(stringValue);
     }
     if( !strcmp( valchar, topAddress[1]) ){
     lcd.setCursor (8,2);
     lcd.print(stringValue);
     }
     if( !strcmp( valchar, topAddress[2]) ){
     lcd.setCursor (15,2);
     lcd.print(stringValue);
     }
     if( !strcmp( valchar, topAddress[3]) ){
     lcd.setCursor (1,3);
     lcd.print(stringValue);
     }
     if( !strcmp( valchar, topAddress[4]) ){
     lcd.setCursor (8,3);
     lcd.print(stringValue);
     }
     if( !strcmp( valchar, topAddress[5]) ){
     lcd.setCursor (15,3);
     lcd.print(stringValue);
     }
      
     if( !strcmp( valchar, topAddress[6]) ){
     lcd.setCursor (17,1);
     lcd.print(intValue);
     }
     
    
   }  
}

Dans cette version c'est Max/msp qui gère les noms de scènes ainsi que l'incrementation