Intercettare dati Midi grezzi con le funzioni esterne del API di RtMidi
La libreria RtMidi è un insieme di classi, scritte in C++, che fornisce funzionalità per la gestione dei dati Midi in entrata ed in uscita.
E' possibile con alcune funzioni esterne della libreria RtMidi intercettare i dati Midi grezzi provenienti da un dispositivo Midi. Sarà necessario avere installata nel proprio sistema la libreria condivisa: librtmidi.so.7.0.0 ".
Mostriamo di seguito un possibile codice che intercetta i dati Midi grezzi provenienti da un dispositivo esterno e li scrive in console. Poiché la libreria RtMidi, come già accennato, è scritta in C++, non è possibile richiamare direttamente nel modo consueto con il comando Extern le sue necessarie funzioni esterne. Si rende, pertanto, necessario scrivere in C++ in un'apposita libreria condivisa, da noi realizzata, la parte di codice che richiama le predette funzioni esterne della libreria RtMidi, lasciando al codice dell'applicativo Gambas quanto più possibile e in particolare una funzione di coordinamento dell'intero processo. V'è da aggiungere che nell'esempio che segue, poiché non è stato possibile scrivere in autonome routine le varie funzioni esterne della libreria RtMidi, bensì tutte in quella sola principale, si è cercato un escamotage (come si potrà facilmente notare) per individuare e gestire da Gambas ogni singola funzione esterna necessaria.
Tale sorgente, da noi scritto in C++, della libreria dinamica condivisa esterna sarà posto nel codice dell'applicazione Gambas, dal quale anche si provvederà a creare la libreria medesima.
Il codice dell'applicativo Gambas (che tra l'altro prevede anche un Button posto sul Form) sarà dunque il seguente:
Library "/tmp/libadhoc"
' int main(int c, char** s)
' La funzione principale della libreria esterna da noi creata.
Private Extern main(c As Integer, s As Pointer) As Integer
Public Sub Form_Open()
Dim p As Pointer
Dim numPorteIn, numPorteEx As Integer
Dim porta As String
CreaSo()
p = Alloc("PorteEntrata")
numPorteIn = main(0, VarPtr(p))
If numPorteIn = 0 Then Error.Raise("Impossibile trovare porte Midi in Entrata !")
Free(p)
p = Alloc("NomePorteIn")
main(0, VarPtr(p))
TextArea1.Text = "Numero porte Midi di Entrata trovate: " & numPorteIn & Chr(10)
TextArea1.Text &= String@(p)
Free(p + 8)
Me.Show
porta = Val(InputBox("Porte Midi di Entrata trovate: " & numPorteIn & "\nScegli una porta:"))
p = Alloc("openPort()")
main(porta, VarPtr(p))
Free(p)
p = Alloc("ignoreTypes()")
main(0, VarPtr(p))
Free(p)
End
Public Sub Button1_Click()
Me.Close
End
Private Procedure CreaSo()
File.Save("/tmp/libadhoc.cpp", "#include <sstream>\n" &
"#include <cstdlib>\n" &
"#include \"RtMidi.h\"\n" &
"#include <string.h>" &
"\n\n" &
"RtMidiIn * midiIn = 0;\n" &
"unsigned int nPorteIn;\n" &
"\n\n" &
"void callback( double, std::vector< unsigned char > *, void * );" &
"\n\n" &
"int main(int c, char** s){" &
"\n\n" &
" std::string nomePortaIn, a;\n" &
" std::stringstream n;\n" &
" unsigned int i;\n" &
"\n\n" &
" midiIn = new RtMidiIn();\n" &
"\n\n" &
" if (strcmp((char * )s[0], \"PorteEntrata\") == 0){\n"
" nPorteIn = midiIn->getPortCount();\n" &
" return nPorteIn;}" &
"\n\n" &
" if (strcmp((char *)s[0], \"NomePorteIn\") == 0) {\n" &
" for ( i=0; i<nPorteIn; i++ ) {\n" &
" nomePortaIn = midiIn->getPortName(i);\n" &
" n << i;" &
"/* Vengono unite le stringhe di tipo base */\n" &
" a = a + \" \" + n.str() + \" \" + nomePortaIn;\n" &
" n.str(" ");}" &
"\n\n" &
"/* La variabile base stringa \"a\" viene convertita nel tipo 'char*'\n" &
"affinché possa essere restituita al codice Gambas attraverso\n" &
"il parametro \"char** s\" della routine \"main()\" */\n" &
" char* ritornare = strcpy((char*)malloc(a.length()+1), a.c_str());\n" &
" *s = ritornare;}" &
"\n\n" &
" if (strcmp((char *)s[0], \"openPort()\") == 0) {\n" &
" midiIn->openPort( c );\n" &
" midiIn->setCallback( &callback );}" &
"\n\n" &
"/* Imposta i valori booleani, se deve ignorare rispettivamente i messaggi:\n" &
"sysex, timing, active sensing*/\n" &
" if (strcmp((char *)s[0], \"ignoreTypes()\") == 0) {\n" &
" midiIn->ignoreTypes( false, true, true);\n}" &
"\n\n" &
" return (0);\n}" &
"\n\n" &
"void callback( double tempodelta, std::vector< unsigned char > *messaggio, void */*userData*/ ) {" &
"\n\n" &
" unsigned int nByte = messaggio->size();\n" &
" for ( unsigned int j=0; j<nByte; j++ )\n" &
" std::cout << \"Byte \" << j << \" = \" << (int)messaggio->at(j) << \", \";\n" &
" if ( nByte > 0 )\n" &
" std::cout << \"timestamp = \" << tempodelta << std::endl;\n}")
Shell "g++ -o /tmp/libadhoc.so /tmp/libadhoc.cpp -shared -fPIC -lrtmidi" Wait
End