Conception électronique: MIDI in et micro-contrôleur (arduino)
- 23 réponses
- 6 participants
- 1 417 vues
- 7 followers
Anonyme
1096
Sujet de la discussion Posté le 15/12/2018 à 20:41:25Conception électronique: MIDI in et micro-contrôleur (arduino)
Salut à tous.
Ca fait quelques années que je pratique l'électronique en tant qu'amateur: réalisation de quelques mini synthés analogiques et numériques.
Je bloque néanmoins sur la conception d'un MIDI in.
Je m'explique: j'ai déjà réalisé des circuits qui pouvaient se synchroniser sur une horloge MIDI, ou pouvaient recevoir des notes MIDI. (6n138 + résistances + diode + micro-contrôleur.)
Cependant ça ne fonctionnait pas toujours très bien... il y avait des notes pas toujours jouées par exemple.
Côté micro-contrôleur j'utilise la gamme Arduino, comme la Uno qui tourne à 16Mhz ou la Due qui tourne à 84MHz. En ce qui concerne la programmation j'ai tendance à bien charger la mule et je pousse souvent ces cartes dans leurs retranchements.
Au final ma question est très simple.
Dans un synthétiseur numérique, vous semble t'il judicieux de dédier un micro-contrôleur à la réception et au filtrage des données MIDI ?
Les arduinos sont capables de lire les données MIDI grâce aux commandes "serial" (qui tournent ici à 31250 bauds). Cependant j'ai l'impression que cette tâche peut être polluée par les autres interruptions de mes programmes, provoquant des pertes de données MIDI.
Quelle solution est habituellement utilisée par les fabricants? un uc dédié ou pas?
Après je suis complètement autodidacte, je ne saisis pas toutes les subtilités de la programmation ...
Merci à ceux qui pourront m'éclairer.
Ca fait quelques années que je pratique l'électronique en tant qu'amateur: réalisation de quelques mini synthés analogiques et numériques.
Je bloque néanmoins sur la conception d'un MIDI in.
Je m'explique: j'ai déjà réalisé des circuits qui pouvaient se synchroniser sur une horloge MIDI, ou pouvaient recevoir des notes MIDI. (6n138 + résistances + diode + micro-contrôleur.)
Cependant ça ne fonctionnait pas toujours très bien... il y avait des notes pas toujours jouées par exemple.
Côté micro-contrôleur j'utilise la gamme Arduino, comme la Uno qui tourne à 16Mhz ou la Due qui tourne à 84MHz. En ce qui concerne la programmation j'ai tendance à bien charger la mule et je pousse souvent ces cartes dans leurs retranchements.
Au final ma question est très simple.
Dans un synthétiseur numérique, vous semble t'il judicieux de dédier un micro-contrôleur à la réception et au filtrage des données MIDI ?
Les arduinos sont capables de lire les données MIDI grâce aux commandes "serial" (qui tournent ici à 31250 bauds). Cependant j'ai l'impression que cette tâche peut être polluée par les autres interruptions de mes programmes, provoquant des pertes de données MIDI.
Quelle solution est habituellement utilisée par les fabricants? un uc dédié ou pas?
Après je suis complètement autodidacte, je ne saisis pas toutes les subtilités de la programmation ...
Merci à ceux qui pourront m'éclairer.
[ Dernière édition du message le 15/12/2018 à 20:52:08 ]
Anonyme
1096
21 Posté le 31/01/2019 à 19:38:35
Merci les gars, j'essaye d'assimiler tout ça... Pour la machine à état j'ai encore des doutes pour savoir si on parle bien de la même chose..
Voici une librairie (.cpp) que j'ai pondu il y a quelques semaines, je me demande si ce ne serait pas tout simplement ça une machine à état:
Cette librairie fonctionne ( c'est ma toute première librairie hourra! ), j'utilise des machines à état malgré moi?
En fait je suis super intrigué par ce qu'a écrit Pfeuh:
Hum cela veut dire qu'il me faudrait plutôt une commande qui interroge le port pour savoir si il a reçu oui ou non des datas?
Il faudrait donc plutôt déjà utiliser la commande Serial.available() ?
Voici une librairie (.cpp) que j'ai pondu il y a quelques semaines, je me demande si ce ne serait pas tout simplement ça une machine à état:
Spoiler - Cliquer ici pour lire la suite
#include "my_MIDI_in.h"
static int _MIDI_Status;
static int _MIDI_Switch_Data;
static int _SPP;
static unsigned int _MIDI_Clock_Pulse;
// MIDI note play list (8voice poly)
int _MIDI_Voice_Container[8]= { -1, -1, -1, -1, -1, -1, -1, -1 };
my_MIDI_in::my_MIDI_in() {
//initializeVariables();
}
void my_MIDI_in::begin(int _incoming_MIDI_Byte, int MIDI_Channel_Select)
{
// MIDI Statut ********
if ( _incoming_MIDI_Byte > 127 ) {
_MIDI_Status = _incoming_MIDI_Byte;
_MIDI_Switch_Data = 1;
if ( _MIDI_Status < 160 ) {
_MIDI_Status = _MIDI_Status - MIDI_Channel_Select ;
}
switch ( _MIDI_Status ) {
case 248: // MIDI pulse * 24 / *6
_MIDI_Clock_Pulse = _MIDI_Clock_Pulse + 1;
break;
}
} else {
// MIDI data 1
if (_MIDI_Switch_Data == 1) {
switch ( _MIDI_Status ) {
case 128: // MIDI note off
for (int i = 0; i < 8; i++) {
if ( _MIDI_Voice_Container[ i] == _incoming_MIDI_Byte ) {
_MIDI_Voice_Container[ i] = -1; // ecrit note off
for (int y = i; y < 7; y++) {
_MIDI_Voice_Container[ y ] = _MIDI_Voice_Container[ y + 1 ];
}
_MIDI_Voice_Container[ 7 ] = -1;
}
}
_MIDI_Switch_Data = 2;
break;
case 144: // MIDI note on
for (int i = 0; i < 8; i++) {
//décale le container d'une case à droite
_MIDI_Voice_Container[ 7 - i] = _MIDI_Voice_Container[ 6 - i];
}
// inscrit derniere note entrante à gauche
_MIDI_Voice_Container[0] = _incoming_MIDI_Byte;
_MIDI_Switch_Data = 2;
break;
case 242:
// MIDI Song Position Pointer intervient a chaque fois qu'on lance la lecture
// ou quand on deplace la tete de lecture à l'arret
// ou quand une loop reprend à son début0
_SPP = _incoming_MIDI_Byte;
_MIDI_Switch_Data = 2;
break;
}
}
else if (_MIDI_Switch_Data == 2) {
// MIDI data 2
switch ( _MIDI_Status ) {
case 128: // MIDI note Off
_MIDI_Switch_Data = 1;
break;
case 144: // MIDI note on
_MIDI_Switch_Data = 1;
break;
case 242:
_SPP = _SPP + ( _incoming_MIDI_Byte << 7);
_MIDI_Clock_Pulse = _SPP * 6;
_MIDI_Switch_Data = 0;
break;
}
}
}
}
unsigned int my_MIDI_in::MIDI_Clock()
{
return _MIDI_Clock_Pulse;
}
int my_MIDI_in::MIDI_Note_0()
{
return _MIDI_Voice_Container[ 0];
}
int my_MIDI_in::MIDI_Note_1()
{
return _MIDI_Voice_Container[ 1];
}
int my_MIDI_in::MIDI_Note_2()
{
return _MIDI_Voice_Container[ 2];
}
int my_MIDI_in::MIDI_Note_3()
{
return _MIDI_Voice_Container[ 3];
}
Cette librairie fonctionne ( c'est ma toute première librairie hourra! ), j'utilise des machines à état malgré moi?
En fait je suis super intrigué par ce qu'a écrit Pfeuh:
Citation :
Toi, tu commences ton programme par Serial.read(), ce qui a pour effet... De totalement bloquer le processeur (sauf les interruptions et le DMA jusqu'à ce qu'un caractère arrive... Pas très efficace...
Hum cela veut dire qu'il me faudrait plutôt une commande qui interroge le port pour savoir si il a reçu oui ou non des datas?
Il faudrait donc plutôt déjà utiliser la commande Serial.available() ?
[ Dernière édition du message le 31/01/2019 à 20:09:23 ]
static volatile
1793
AFicionado·a
Membre depuis 7 ans
22 Posté le 31/01/2019 à 20:26:27
Citation de King :
En fait je suis super intrigué par ce qu'a écrit Pfeuh:
Citation :Toi, tu commences ton programme par Serial.read(), ce qui a pour effet... De totalement bloquer le processeur (sauf les interruptions et le DMA jusqu'à ce qu'un caractère arrive... Pas très efficace...
Hum cela veut dire qu'il me faudrait plutôt une commande qui interroge le port pour savoir si il a reçu oui ou non des datas?
Il faudrait donc plutôt déjà utiliser la commande Serial.available() ?
Exactement.
L'appel à read() est bloquant.
C'est à dire que la fonction ne retournera un byte que s'il y en a un à lire dans le buffer d’entrée, si aucun byte n'arrive, parce que le câble MIDI est débranché par exemple, la fonction ne retournera jamais.
Cela introduit un effet de bord assez ennuyeux: tant que la fonction n'a pas retourne de byte, le programme
Bien sur, si une interruption pète, l'ISR correspondante sera exécutée (après un context switch), mais c'est tout.
L'appel à available(), lui, n'est pas bloquant: si le buffer est vide, il retournera 0 et ton programme pourra continuer à travailler à autre chose jusqu'à ce que available() retourne une valeur non nulle.
Spoiler - Cliquer ici pour lire la suite
Alors, pourquoi diantre faire des fonctions bloquantes?
Et bien, si un jour du explores des systèmes multi-taches comme les RTOS, tu verras que dans certains cas, c'est très utile.
Alors, pourquoi diantre faire des fonctions bloquantes?
Et bien, si un jour du explores des systèmes multi-taches comme les RTOS, tu verras que dans certains cas, c'est très utile.
Pour ta lib, déjà bravo! et oui, c'est le principe.
L'automate fini est juste un moyen de formaliser ta réflexion, de documenter ton code, d'avoir une référence à laquelle comparer ton programme s'il ne fonctionne pas comme prévu, etc.
Sans compter qu'il est toujours préférable de mettre ses idées au clair avant de commencer à coder, et un dessin est plus facile a lire qu'un pavé de texte!
Resistance is not futile... it's voltage divided by current
[ Dernière édition du message le 31/01/2019 à 20:32:45 ]
Anonyme
1096
23 Posté le 31/01/2019 à 20:35:37
Ok merci Aab j'ai compris des trucs là ! Merci Pfeuh aussi !
Je laisse murir tout ça.... quelques jours..
Je laisse murir tout ça.... quelques jours..
Anonyme
1096
24 Posté le 05/02/2019 à 20:00:47
Sans m'être encore attaqué au DMA j'ai déjà pu utiliser la commande Serial1.available en conditions.
Je me suis déjà fais un petite frayeur, cette commande étant répertorié uniquement pour la Mega sur cette page:
https://www.arduino.cc/en/serial/available
Heureusement la Due la reconnait aussi.
En pratique c'est le jour et la nuit par rapport aux précédent tests.
A présent la synchro tient comme il faut. C'est un grand bond en avant.
Merci encore les gars.
Je me suis déjà fais un petite frayeur, cette commande étant répertorié uniquement pour la Mega sur cette page:
https://www.arduino.cc/en/serial/available
Heureusement la Due la reconnait aussi.
En pratique c'est le jour et la nuit par rapport aux précédent tests.
A présent la synchro tient comme il faut. C'est un grand bond en avant.
Merci encore les gars.
[ Dernière édition du message le 05/02/2019 à 20:01:35 ]
- < Liste des sujets
- Charte