Pages: [1]   Go Down
Author Topic: Ricezione dati MIDI con Arduino  (Read 779 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Salve, chiedo supporto!!!
Son riuscito (finalmente) a ricevere dati MIDI con Arduino. Tramite un player midi, mando in play una base musicale e su un display lcd mi scrive il canale midi, codice della nota suonata e il suo volume. Il canale midi lo definisco nell'istruzione MIDI.begin() che per default è il canale 1.
La domanda è: come posso ricevere anche il numero della battuta (o misura)? Ho letto in vari forum l'istruzione SongPosition ma non riesco ad usarlo.
Vorrei far scrivere nel display anche il numero della battuta. Di seguito il codice che ho implementato. Attendo con ansia.. Grazie.

#include <MIDI.h>
#include <LiquidCrystal.h>


LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

void setup() {
  MIDI.begin();
  lcd.begin(16, 2);
 
  }

void loop() {
    if (MIDI.read()) {
     
      if (MIDI.getType()==144) {
      lcd.setCursor(0,0);
      lcd.print("Type: ");
      lcd.setCursor(6, 0);
      lcd.print(MIDI.getType());
     
      lcd.setCursor(9, 0);
      lcd.print("Ch: ");
      lcd.setCursor(13, 0);
      lcd.print(MIDI.getChannel());
     
      lcd.setCursor(0, 1);
      lcd.print("D1: ");
      lcd.setCursor(6, 1);
      lcd.print(MIDI.getData1());
     
      lcd.setCursor(9, 1);
      lcd.print("D2: ");
      lcd.setCursor(13, 1);
      lcd.print(MIDI.getData2());
      }
     
     
      }
 
}
Logged

ivrea (to)
Offline Offline
Faraday Member
**
Karma: 57
Posts: 3484
miaaao ^-^
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Non conosco direttamente la risposta, ma guardando la classe MIDI ho visto che definisce un membro public:
   void setHandleSongPosition(void (*fptr)(unsigned int beats));

Dovrebbe essere necessario creare una funzione del tipo richiesto e l'oggetto richiamerà questa tua funzione.
(Ma nel codice che hai postato non manca la creazione della variabile MIDI di tipo MIDI_Class ? )

Cioè
...
MIDI.begin()
MIDI.setHandleSongPosition(MIAFUNZ);
...

void MIAFUNZ(unsigned int beats)
{
}

poi in teoria l'oggetto chiamerà quando necessario la tua MIAFUNZ a cui passa il numero beats.
in quella funzione potrai scrivere sul display

Una cosa simile fa la SimpleTimer:
http://playground.arduino.cc/Code/SimpleTimer
ovvero per funzionare è necessario creare una funzione da passare all'oggetto. L'oggetto chiamerà la funzione, in questo caso in base a dei millisecondi.
Logged

my name is IGOR, not AIGOR

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Grazie per l'interesse, il fatto è che non sono molto forte con la programmazione in C++.
Potresti essere un po' più chiaro, non capisco cosa devo aggiungere nel mio programma..
Ho visto che c'è

"void setHandleSongPosition(void (*fptr)(unsigned int beats));"

ma non so come usarla smiley-roll

potresti aiutarmi?
grazie
Logged

ivrea (to)
Offline Offline
Faraday Member
**
Karma: 57
Posts: 3484
miaaao ^-^
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
#include <MIDI.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

void MIAFUNZ(unsigned int beats)
{ lcd.setCursor(15, 1);   // devi però dare tu una posizione libera sul display
  lcd.print("XX:");
  lcd.setCursor(18, 1);
  lcd.print(beats);
}

void setup() {
  MIDI.begin();
  MIDI.setHandleSongPosition(MIAFUNZ);
  lcd.begin(16, 2);
}

void loop()
{ if (MIDI.read())
  { if (MIDI.getType()==144) {
      lcd.setCursor(0,0);      lcd.print("Type: ");
      lcd.setCursor(6, 0);     lcd.print(MIDI.getType());   
      lcd.setCursor(9, 0);     lcd.print("Ch: ");
      lcd.setCursor(13, 0);    lcd.print(MIDI.getChannel());
      lcd.setCursor(0, 1);     lcd.print("D1: ");
      lcd.setCursor(6, 1);     lcd.print(MIDI.getData1());
      lcd.setCursor(9, 1);     lcd.print("D2: ");
      lcd.setCursor(13, 1);    lcd.print(MIDI.getData2());
    }     
  }
}

Fra l'altro ho dato una occhiata all'interno del codice della libreria ed ho visto che la libreria stessa crea una variabile MIDI di tipo classe midi. Cioè non devi creare tu un oggetto di tipo midi perchè lo fa la libreria.
« Last Edit: February 02, 2013, 09:45:05 am by nid69ita » Logged

my name is IGOR, not AIGOR

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Cavoli non funziona  smiley-cry

però c'è qualcosa che non mi torna:
la stampa del numero di battuta non avviene ciclicamente!!

Ti rispiego la questione: io mando in play una base MIDI e sul display devi uscire il numero della battuta che cambia in continuazione mentre il brano sta andando. Ma nel codice che mi hai postato non mi sembra che ciò sia possibile. Io ho scritto così:

#include <MIDI.h>
#include <LiquidCrystal.h>


LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

void numBattuta (unsigned int beats) {
  lcd.setCursor(10, 0);
  lcd.print(beats);
}
 
void setup() {
  MIDI.begin();
  MIDI.setHandleSongPosition(numBattuta);
  lcd.begin(16, 2);
  pinMode(13, INPUT);
  }

void loop() {
    if (MIDI.read()) {
      lcd.setCursor(0,0);
      lcd.print("Battuta: ");
      }
      if (digitalRead(13) == HIGH) lcd.clear();
}


ecco... ma la funzione numBattuta non dovrebbe essere richiamata nel loop???

La ricezione dei dati MIDI funziona perchè l'ho già provato, quindi l'hardware è ok...

ma poi, non capisco una cosa: nella libreria MIDI.h dove viene implementata la setHandleSongPosition? Nel senso, dove sono le istruzioni che estrapolano questo numero di battuta??

uff, non ne cavo piedi smiley-cry
Logged

ivrea (to)
Offline Offline
Faraday Member
**
Karma: 57
Posts: 3484
miaaao ^-^
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Se tu chiami la MIAFUNZ come numBattuta è lo stesso.

E' l'oggetto MIDI che pensa a chiamare la numBattuta.
Se leggi il file callback.txt dice che è la MIDI.read() a richiamare la tua funzione numBattuta.
La MIDI.read() deve essere chiamata spesso, infatti deve stare nella loop() e nella loop non ci devono essere troppi ritardi.

------- file callback.txt delle libreria
What is a callback?
A callback is a function that you have writen and that is used by the library when a message arrives.
You put your message handling code in this function, and tell the library to call it back when the corresponding message is received.
For example, you can have a function named DoSomeStuffWithNoteOn, that will look like this:
void DoSomeStuffWithNoteOn (byte channel, byte pitch, byte velocity) {
   // Do some stuff with NoteOn here
}

The arguments of this function are the data from the message received.
When the function is called back from within the library, it will be passed the data in the arguments,
so you can access them more easily than calling MIDI.getData1, etc..

How do I use them?

First, you need to set up the correct function arguments. These vary from one type to another
(because all types have different data). These function must also return nothing (void).

Here is what your function parameters should look like for each type:
void HandleTimeCodeQuarterFrame (byte data)
void HandleSongPosition (unsigned int beats)
void HandleSongSelect (byte songnumber)
....

Once you have your function correctly set, you need to tell the library to use it when the corresponding message is received. Let's take back the example of a NoteOn, handled by the DoSomeStuffWithNoteOn function.

void setup() {
   MIDI.begin();
   MIDI.setHandleNoteOn(DoSomeStuffWithNoteOn);
}

void loop() {
   MIDI.read();
}

And that's all! Just put the name of the function, and the library will automatically call it when a NoteOn is received.
If for some reason, you want to disconnect the callback, you can do it like this:
MIDI.disconnectCallbackFromType(NoteOn);
My sketch is very slow, what's going on?
First, you need to call MIDI.read quite fast, to have the lowest latency possible. Raw MIDI data is stored in the Serial buffer, but the library can only extract it when you call MIDI.read.
Make sure that your callbacks are running fast, as they are launched from within MIDI.read (thus in the loop).
« Last Edit: February 02, 2013, 11:48:51 am by nid69ita » Logged

my name is IGOR, not AIGOR

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

si si certo, la funzione la posso chiamare come voglio, sin lì ci sono arrivato..
cmq non va lo stesso, mi sono attenuto (almeno credo) a quello che mi hai detto e a quello che c'è nel callbacks.txt ma non funziona lo stesso.

#include <MIDI.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

void numBattuta (unsigned int b) {
  lcd.setCursor(0,0);
  lcd.print("Battuta: ");
  lcd.setCursor(10, 0);
  lcd.print(b);
}
 
void setup() {
  lcd.begin(16, 2);
  MIDI.begin();
  MIDI.setHandleSongPosition(numBattuta);
}
 
void loop() {
    MIDI.read();
}


ma che cavolo sto sbagliando?!?!?!
Logged

ivrea (to)
Offline Offline
Faraday Member
**
Karma: 57
Posts: 3484
miaaao ^-^
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Da quel che dice la documentazione e il codice che hai scritto secondo me è tutto giusto.
Purtroppo non ho esperienza diretta con questa libreria. Quel che ti ho suggerito è stato guardando il codice interno alla libreria,
che non è proprio semplice.

Spiacente, ma di più non sò aiutarti.   smiley-red
Logged

my name is IGOR, not AIGOR

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Vabè grazie lo stesso, sei stato molto gentile a starmi appresso smiley
Logged

ivrea (to)
Offline Offline
Faraday Member
**
Karma: 57
Posts: 3484
miaaao ^-^
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Una idea. Se piazzi alcune istruzioni Serial.println() nel codice MIDI.CPP potresti verificare se nella libreria passa qualcosa.
Puoi usare la Serial. per mandare al PC via usb msg, o la seriale è occupata?
(ovvero solito Serial.begin(9600); nel setup e poi in giro Serial.println("msg"); e verifichi in Arduino con Ctrl+Maiusc+M)

Se puoi, nel MIDI.cpp ci sono 2 punti in cui potresti mettere un msg per verificare:
1. a circa riga 610 se hai un conta linee (nella funzione parser() ovvero la funzione che analizza i msg MIDI e decide che tipo di msg è.
Code:
case SongPosition:
  mPendingMessageExpectedLenght = 3;
  Serial.println("parser=SongPosition.");     // aggiunta
  break;

2. circa riga 495
Code:
  Serial.println("richiama callback.");     // aggiunta, prima di questa #if, se il msg okay allora prova dentro la #if
#if USE_CALLBACKS
  launchCallback();
#endif
« Last Edit: February 04, 2013, 11:29:06 am by nid69ita » Logged

my name is IGOR, not AIGOR

Pages: [1]   Go Up
Jump to: