[Conseil] Problème d'envois de notes MIDI / PROJET CREATION DE CONTROLEUR MIDI

Bonjour à tous,

Je suis nouveau sur forum. Je me présente très rapidement, je suis graphiste spécialisé dans le webdesign & le design IHM. Ayant une grande passion pour la MAO (Musique Assisté par Ordinateur). Je cherche a fabriqué mon propre contrôleur MIDI.

Après mettre pas mal documenté sur le web, tous les tutos, du moins une grande majorité (en anglais pour la plupart à mon grand regret), convergent vers cette solution l'arduino.

J'ai donc acquis mon premier Arduino pas plus tard que cette semaine. Après presque un trimestre d'hésitation.

J'ai profité de ce weekend pluvieux pour "étudier" cette carte et faire mes premiers.
Après quelques heures, j'ai réussi à créer mon premier programme, qui consistait à appuyer un bouton poussoir et me renvoyer une information comme quoi celui ci était fermé et vice-versa, j'ai ensuite approfondi mon code jusqu'à envoyer des notes MIDI et c'est là que je coince.

Mais avant de vous montrer mon code et vous montrez où je coince, je vais juste vous faire une présentation rapide du contrôleur midi que je veux créer. Il est inspiré d'un contrôleur midi existant, le Midi Fighter. Un boitier à 16 boutons (des boutons d'arcades OBSF 24mm) qui envoi des notes MIDI à un logiciel de MAO, dans mon cas il s'agit d'Ableton Live 9. Ce boitier est aussi composé de 16 LEDS qui s'allume lorsque le bouton est "maintenu".
(les guillemets c'est parce que mon problème vient de là, mais j'aborderai ce sujet plus tard)

Voici un modèle de midi fighter :

Cliquez sur ce lien pour voir une vidéo de la bête en action

Je me dispense dans un premier temps des potards et des faders, c'est juste la petit matrice de boutons 4x4 - rétro-éclairé qui m’intéresse vraiment pour le moment.

Etape 1 - premier code bouton enfoncé/relâche :

int boutonPin = 2; //bouton type arcade (sanwa OBSF) sur le port digit 2
int etat = 0;// <--- var qui vérifiera l'état de mon bouton

void setup()
{
  Serial.begin (9600);
  pinMode (boutonPin, INPUT); //bouton en mode INPUT
  digitalWrite(boutonPin, HIGH);
}

void loop()
{
  etat = digitalRead(boutonPin);//ecouteur d'évenement sur le boutonPin
  if (etat == HIGH)
  {
    Serial.println("bouton HAUT");//le bouton n'est pas enfoncé
  }
  else
  {
    Serial.println("bouton BAS");//le bouton est enfoncé
  }
}

Voici ce qui se passe sur mon serial moniteur

Premier constat :
Quand j’appuie et maintiens sur le bouton, j'ai le texte "bouton BAS" qui apparait et quand je le relâche celui ci mon serial moniteur, m'affiche "bouton HAUT" (jusqu'ici tous va bien)

NOTE : il est peut être important que vous sachiez que je ne travaille pas avec aucun composant électrique (pas de breadboard, pas de resistors etc...), je bosse directement sur la carte. Voici mon installation :

Je compte bien évidement investir dans quelques LED, resistor et Breadboard pour l'élaboration de mon projet.

Etape 2 - configurer mon MAC pour pouvoir simuler du MIDI :

Je présenterai sous forme de bullet points cette partie pour évider trop m'attarder, c'est essentiellement de la configuration :

  • installation de Hairless - pont SERIAL <--> MIDI / OK

  • configurer mon MAC / OK
    (c'est normal qu'il est des erreurs, le code présent dans ma carte n'est pas du tout adapté)

  • vérifier qu'Ableton Live 9 reconnaisse les ports MIDI IN/OUT/ OK

Etape 3 - Retravailler mon code pour envoyer une note MIDI :
Je démarre donc cette 3eme partie en installant une librairie Arduino Midi 4.2 à partir d'un tutoriel chopé sur youtube, l’installation ce passe bien et c'est même une réussite (je pense) .

Et voici mon nouveau code (qui foire complétement, une vraie défaite) :

#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

MIDI_CREATE_DEFAULT_INSTANCE();

int boutonPin = 2; //bouton type arcade (sanwa OBSF) sur le port digit 2
int etat = 0;// <--- var qui vérifiera l'état de mon bouton

int noteDO = 48;//<-- 48, c'est la valeur MIDI de la note C3 (DO)

void setup()
{
  MIDI.begin();// commencer la connection MIDI
  Serial.begin (115200); // <-- j'ai appliqué ça sans trop savoir pk
  pinMode (boutonPin, INPUT); //bouton en mode INPUT
  digitalWrite(boutonPin, HIGH);
}

void loop()
{
  etat = digitalRead(boutonPin);//ecouteur d'évenement sur le boutonPin
  if (etat == HIGH)
  {
    Serial.println("bouton HAUT");//le bouton n'est pas enfoncé
    MIDI.sendNoteOff(noteDO,0,1);//je j'éteinds DO, velocité 127, Canal MIDI 1
  }
  else
  {
    Serial.println("bouton BAS");//le bouton est enfoncé
    MIDI.sendNoteOn(noteDO,127,1);//je joue DO, velocité 127, Canal MIDI 1
  }
}

Problème 1 :
Je constate que sur ma fenêtre Hairless MIDI, que des notes MIDI sont envoyer dans tous les sens et ne corresponde pas à ce que j'ai demandé d'envoyer :

Problème 2 :
Sur ableton, même résultat quand j'ouvre un instrument, j'ai des espèces de glitchs quand j’appuie sur mon bouton poussoir.
De manière aléatoire, il va lancer plusieurs notes et celle ci vont rester comme dans un état enfoncé même quand je relâche la pression du bouton.
C'est comme si je demandais à un pianiste de me jouer une note, mais qu'il refusait de jouer une fois sur deux. Et que quand il s'y mettait, il me joue des accords , le temps de ce accords varient aléatoirement aussi, ça peut être des temps court comme elles peuvent être longue voir un "freeze".

Etape 4 - réflexion/conclusion
Donc voilà où j'en suis, j'ai pris une feuille de papiers et j'ai essayé de comprendre ce qui n'allait pas dans mon code et voici ce que j'ai retenu :

  • la note MIDI est tout le temps jouer car, quand je prend mon premier code (cf.étape 1) quand je maintenais la touche enfoncé, j'avais le message "bouton BAS" en mode LOOP. Et ide quand je relâchais la touche, le message "bouton HAUT" apparaissaient en mode LOOP.
    J'en conclu donc, que quand j’appuie sur mon bouton la note MIDI est envoyé plusieurs fois.

Il faut donc que je trouve un moyen pour que quand j’appuie et que je l'a maintiens sur le bouton une fois, qu'une NOTE soit envoyé et ensuite il n'y ai plus de transmission. Ensuite quand je relâche le bouton, même scénario, une note est envoyé pour donner l'instruction de killer la note appeler précédemment.

  • Par contre ça ne m'explique pas pourquoi, j'ai plusieurs notes qui sont envoyé et pas que la note DO de valeur 48 que j'ai demandé d'appeler. Idem pour les propriétés de vélocité, que j'ai fixé à 127, mais qui varient de 0 à 127.

  • Pour ce qui est du canal MIDI, il reste bien à 1. (mais est ce que c'est pas une valeur par defaut)

Bref... voilà donc mon problème, ça a pris un peu de temps pour vous expliquez clairement les choses, mais le but de ce projet n'est pas seulement d'obtenir satisfaction d'avoir monter son propre contrôleur MIDI mais elle a aussi un but "pédagogique", je voudrai si j'arrive au bout de ce projet, en faire un tutoriel sur ce type de projet, car quand je vois le nombre de tutos en anglais sur ce projet, je me dis qu'un tuto en français ça pourrai dépanner plus d'un.

Je remercie d'avance, les personnes qui prendront le temps de lire ce long sujet, et de m'aider dans mon projet.

Je suis impatient de lire vos réponses.

Bon finalement, en fouillant et en remaniant mon code, j'ai réussi à résoudre le problème de l'émission continu de NOTE MIDI.

Voici mon nouveau code :

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

int button1 = 2; //<-- je declare un btn type arcade sur la broche digit 2
int lastState = 0; //déclare un "etat" ancien
int currentState = 0;//déclare un "etat" actuel

int noteC1 = 36; //jouer la note C3

void setup()
{
  MIDI.begin(); // demarage de la connexion MIDI
  Serial.begin(115200); // ne sais pas trop pk on passe 9600 à 115200
  pinMode(button1, INPUT);// je met mon btn en mode INPUT 
  digitalWrite(button1, HIGH);//mon bouton est par defaut HIGH -> pas enfoncé
}

void loop ()
{
  currentState = digitalRead(button1); //écouteur d'événement sur broche 2
  
  if (currentState == HIGH) //si mon Etat Actuel est "PAS ENFONCE"
  {
    if (lastState == LOW)//si mon Ancien Etat était "ENFONCE"
    {
      Serial.println ("HIGH");//donc je suis "PAS ENFONCE"
      MIDI.sendNoteOff(noteC1,0,2);
    }
    lastState = HIGH;//mon nouveau Ancien Etat est "PAS ENFONCE"
  }
  else //par contre
  {
    if(currentState == LOW) //si mon Etat Actuel est "ENFONCE"
    {
      if(lastState == HIGH)//si mon Ancien Etat était "PAS ENFONCE"
      {
        Serial.println("LOW");//donc je suis "ENFONCE"
        MIDI.sendNoteOn(noteC1,127,2);
       
      }
      lastState = LOW;//mon nouveau Ancien Etat est "ENFONCE"
    }  
  }

}

Par contre au niveau des notes midis, je reçois bien la note que j'appelle c-a-d ici la note 36 soit C1 (DO)
Le problème c'est qu'au Release, (au relâchement du bouton), j'ai des notes qui s'allume et reste enfoncé.
Et pour le coup, là ce n'est plus de manière aléatoire, mais bien précise.

Ceux sont les notes : C#-1, C3 et B4

! J'ai fais un teste en lançant une autre note que la note 36, C1. J'ai pris la note 38 qui correspond à la note D1 et les mêmes notes s'allument et restent au release.

Salut, je viens de survoler ton post ! Il m'a l'air bien intéressant comme j'aime bien :slight_smile: Pour moi, tu devrais scruter ce qui sort en midi avec un logiciel pour ça comme MIDI Monitor. Cela te permettra d'y voir plus clair sur ce qui sort de ta prise MIDI vers ton interface midi. En plus je vois au premier abord que le bitrate de ton code est a 115200 ce qui ne correspond pas a la norme MIDI ce qui pourrait expliquer le signaux aléatoire que tu as ! Je ne me souviens plus de la valeur de ce bitrate mais Google sera ton ami ! Au besoin n'hésites pas car j'envisage aussi de me remettre à la réalisation d'un petit contrôleur. J'en avais déjà eu l'idée il y a de cela un temps mais j'avais laisser ça de coté mais j'ai un peu de matériel que je peux utiliser comme des capteurs FSR pour des Pads, des potentiomètres, des boutons tactiles type interrupteurs et un arduino Mega à dispo ... Des faders seraient sympa aussi :slight_smile:

Pour la norme MIDI, je viens de regarder pour le Serial.Begin() il devrait être à 31250 c'est la norme.

Bonjour Yeton,

Nous travaillons sur des projets qui ont beaucoup de points communs :
Gant MIDI 3D

Mes conseils :

1) Travailler avec un LEONARDO et pas un UNO :
Tu auras ainsi 2 ports série, un port "hardware" à 31250 pour ton MIDI et un port série-USB que tu pourras utiliser en mode "DEBUG" avec ton ordi.

2) Eviter d'utiliser des librairies pour faire du MIDI :
Pour initialiser une liaison MIDI avec un Arduino il suffit de de faire un Serial.begin(31250) (comme écrit par ziprexa)
Ensuite le protocole MIDI est assez simple, un Serial.print ou Serial.write en hexadécimal suffira.

J'utilise régulièrement ce site :

3) Travailler avec un soft "bas niveau" :
Avant de te lancer avec Abelton, je te suggère de débugger ton code avec un soft comme MIDI-OX (équivalent MAC ?).
Il te permettra de voir les messages MIDI reçu sur l'ordi sous leur format hexadécimal ET midi, ce qui est un très bon outil de débug.

4) Ton projet
Sur ton projet précisément, il te faut envoyer un NOTE ON à l'appui sur un bouton et un NOTE OFF au relâchement de ce bouton :

Un NOTE ON (90) c'est 3 octets, par exemple un LA (45) avec une vélocité de 127 (7F) :
90 - 45 - 7F

Un NOTE OFF (80) c'est pareil avec une vélocité de 64 par défaut :
80 - 45 - 64

EDIT : pour tes boutons, si tu ne comptes pas mettre de résistance, je te conseille de bien suivre ce tuto : http://arduino.cc/en/Tutorial/InputPullupSerial, et surtout de bien mettre les lignes "pinMode(x, INPUT_PULLUP);" en début de SETUP.

@ziprexa : Salut, merci pour ton retour, ça fait plaisir de voir qu'une autre personne sur ce site veut se lancer dans un projet de contrôleur midi, je me suis senti un peu seul au départ, je te le cache pas. :stuck_out_tongue:
En tout cas j'espère qu'on pourra continuer à échanger. Pour ma part, j'ai un peu mis en stand by la partie "programmation" pour me concentrer sur l'aspect de mon boitier directement inspiré du MIDI Fighter Classic de DJTT.
Je vais poster des photos d'un prototype de boitier un petit peu plus bas.

@UniseV : Un grand merci pour tes précieux conseils, ça va beaucoup m'aider dans mon projet. Concernant ton projet, je suis allé sur ton post, je suis designer pas dans le textile, mais graphiste spécialisé dans le web design et interface mobile. Je pourrai peut être te dégoter quelques "inspirations" (type liens, photos) pour ton gant, parce que j'ai cru comprendre que ton problème se situe au niveau esthétique.

D'ailleurs, ton gant me rappelle vaguement un gant mis en place par une artiste dont je ne me souviens plus le nom mais c'est une nana multi-instrumentiste, qui a fait recourt à des ingés pour créer un gant type MIDI contrôleur.

J'essayerai de mettre la main dessus et je le posterai sur la page de ton projet.

En tous cas un grand merci à tous les 2. Je continuerai à poster l'avancé de mon projet.

yeton:
D'ailleurs, ton gant me rappelle vaguement un gant mis en place par une artiste dont je ne me souviens plus le nom mais c'est une nana multi-instrumentiste, qui a fait recourt à des ingés pour créer un gant type MIDI contrôleur.

Imogen Heap ?

Oui c'est elle, Imogen Heap et son projet Mimu glove. Le blog regorde de pas mal d'astuces pour "customiser" des gants.

http://theglovesproject.com/

Design du boitier
De gauche à droite/de haut en bas :

1/ Design d'un template de boitier sur illustrator CS5

2/ Réception des découpes lasers (voir Ponoko.com) du boitier

3/ J'utilise des boutons OBSF24mm de marque sanwa

4/ Vue de la plaque en acrylic (plaque acryilic de 3mm violet translucide)

5/ Mon principe de montage est basé sur des vis et des entretoises

6/ Cette plaque (blanche) est en carton (1,6mm), elle sera substitué plus tard la plaque PCB*

7/ Vue de face du prototype du boitier

8/ Vue de haut du prototype du boitier

Pas de problèmes je suivrais ton projet de près :wink: Pour la norme MIDI oublie ce que j'ai dit car hairless fonctionne de base à 115200 et n'accepte pas 31250 comme valeur ... Je découvre ce soft qui je l'avoue ouvre bien des portes :smiley: J'ai ce projet en tête depuis quelques années maintenant mais je t'avoue aussi que du coup cela me motive bien ! Je fais actuellement quelques tests avec des capteurs FSR (capteurs de force) pour tenter de reproduire le fonctionnement de pads type MPC. Je te posterai le code pour que tu y jettes un coup d'oeuil ! Notamment pour te passer de la librairie MIDI ! Sinon la plaque violette est vraiment sympa !!

Voici ton code revu par moi même et sans librairie MIDI. En espérant que cela t'aidera !

int button1 = 2; //<-- je declare un btn type arcade sur la broche digit 2
int lastState; //déclare un "etat" ancien
int currentState;//déclare un "etat" actuel

int noteC1 = 0x24; //jouer la note C1 (0x24 en hexadecimal)

void setup()
{
  Serial.begin(115200); 
  pinMode(button1, INPUT);// je met mon btn en mode INPUT 
  }

void loop ()
{
  currentState = digitalRead(button1); //écouteur d'événement sur broche 2
  
  if (currentState == HIGH) //si mon Etat Actuel est "PAS ENFONCE"
  {
    if (lastState == LOW)//si mon Ancien Etat était "ENFONCE"
    {
      sendNote(0x80,noteC1,0);//Correspond à MIDI off canal 1, note C1 , velocité de 0 
    }
    lastState = HIGH;//mon nouveau Ancien Etat est "PAS ENFONCE"
  }
  else //par contre
  {
    if(currentState == LOW) //si mon Etat Actuel est "ENFONCE"
    {
      if(lastState == HIGH)//si mon Ancien Etat était "PAS ENFONCE"
      {
        sendNote(0x90,noteC1,110);//Correspond à MIDI on canal 1, note C1, velocité de 110
       
      }
      lastState = LOW;//mon nouveau Ancien Etat est "ENFONCE"
    }  
  }

}

//Fonction sendNote

void sendNote(int cmd, int note, int velocity){
  Serial.write(cmd);//Ecrit cmd sur le port serie
  Serial.write(note);//Ecrit note sur le port serie
  Serial.write(velocity);//Ecrit velocity sur le port serie
}

Il compile correctement mais je ne l'ai pas tester notamment au niveau des conditions que tu avais écrit, mais à première vue cela me semble bon ! Hairless récupérera sans soucis les messages MIDI de note On et de note Off lors de l'enfoncement ou le relâchement du bouton.

Merci pour l'info à propos des gants d'Imogen Heap, c'est vraiment très similaire à mon projet... en beaucoup plus fournis et aboutit donc grosse source d'inspi... :grinning:

Pour ton contrôleur qui est d'ailleurs très zoli, n'as-tu pas peur qu'il soit un peu flexible au milieu s'il n'est tenu que par les 4 coins ?

Si tu pars sur une solution avec une liaison à 115200 qui passe par "Hairless", ton appareil ne sera pas très universel et il ne pourra être utilisé QUE comme ça... ça ne sera donc pas un contrôleur MIDI standard.

UniseV

Tout à fait d'accord avec ta remarque UniseV ! Le contrôleur ne sera pas Universel de cette manière mais cela permet d'effectuer des premiers tests sans avoir a se casser la tête ^^ Sinon je suis tombé sur un projet qui peut résoudre ce problème : HIDUINO. Il permet de flasher la puce qui gère la communication série (8u2 ou 16u2 selon les modèles) pour transformer l'arduino en un vrai contrôleur MIDI. Je n'ai pas réussi à le tester car je ne possède que deux Mega qui sont tout deux des clones "chinois" et donc non 100% compatibles au niveau matériel ... A mon grand regret :frowning:

Il y a une solution plus simple, et pour l'occasion je m'auto-cite :

UniseV:
1) Travailler avec un LEONARDO et pas un UNO :
Tu auras ainsi 2 ports série, un port "hardware" à 31250 pour ton MIDI et un port série-USB que tu pourras utiliser en mode "DEBUG" avec ton ordi.

Le Leonardo n'a pas de chip dédié à la communication série-USB, il émule lui-même une connexion série-USB indépendante de la liaison série (Rx/Tx)... ce qui est idéal pour faire du MIDI.