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