Conoscere con le funzioni esterne di TSE3 le porte Midi disponibili nel sistema

Da Gambas-it.org - Wikipedia.

La libreria TSE3 (Trax Sequencer Engine version 3.00) è un motore sequencer open source scritto in C++.

Utilizzando alcune sue funzioni esterne, è possibile conoscere le porte Midi, e loro caratteristiche, appartenenti agli applicativi Client di Alsa disponibili nel sistema.

Mostriamo di seguito un possibile codice che fa uso della Classe MidiScheduler per individuare le porte disponibili ed attive nel sistema. Poiché la libreria TSE3, 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 TSE3, 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 TSE3, bensì tutte in quella sola principale, si è cercato un escamotage (come si potrà facilmente notare) per individuare e gestire ogni singola funzione esterna necessaria.

La libreria esterna, da noi scritta, il cui sorgente in linguaggio C++ chiameremo ad esempio libadhoc.cpp è la seguente:

#include <sstream>
#include "tse3/MidiScheduler.h"


using namespace std;

TSE3::MidiSchedulerFactory factory;
TSE3::MidiScheduler *sch = factory.createScheduler();


int main(int v, char **c, char **s) {

  int r = 0;
 
  std::vector<int> portNums;
  sch->portNumbers(portNums);
     
/* Converte un valore di tipo "char *" in un "Intero" */
  std::stringstream strValue;
  strValue << (char *)s;
  size_t port;
  strValue >> port;

/* Individua la funzione esterna da utilizzare sulla base del valore passato da Gambas alla variabile "v" */
  switch (v) {
    case 0:
      *c = (char *) sch->implementationName();
      break;
    case 1:
      *c = (char *) sch->numPorts();
      break;
    case 2:
      *c = (char *) portNums[port];
      break;
    case 3:
      *c = (char *) sch->portType(portNums[port]);
      break;
    case 4:
      *c = (char *) sch->portName(portNums[port]);
      break;
    case 5:
      *c = (char *) sch->portReadable(portNums[port]);
      break;
    case 6:
      *c = (char *) sch->portWriteable(portNums[port]);
      break;
    case 7:
      *c = (char *) sch->portInternal(portNums[port]);
      break;
    default:
      r = -1;
      break;
  }
  
  return r;

}

Tale sorgente, da noi scritto, della libreria condivisa sarà posto ad esempio nella cartella "Dati" dell'applicativo.


Il codice dell'applicativo Gambas, che tra l'altro prevede anche una ListBox posta sul Form, sarà invece il seguente:

Private numeroPorte As Byte
Private p2 As Pointer

Library "/tmp/libadhoc"

Private Extern main(vI As Integer, po1 As Pointer, po2 As Pointer) As Integer


Public Sub Form_Open()

 Dim p1 As Pointer
 Dim err As Integer
 Dim numPorta As Byte

   
' Compiliamo la libreria esterna condivisa da noi scritta in C++ :
  Shell "g++ -o /tmp/libadhoc.so " & Application.Path &/ "libadhoc.cpp -shared -fPIC -ltse3" Wait
   

  err = main(0, VarPtr(p1), 0)
  If err <> 0 Then Error.Raise("Errore nella chiamata della funzione esterna 'main()' !")
  ListBox1.Add("Nome implementazione:  " & String@(p1))

  err = main(1, VarPtr(p1), 0)
  If err <> 0 Then Error.Raise("Errore nella chiamata della funzione esterna 'main()' !")
  ListBox1.Add("                Numero porte: " & CStr(p1))
  ListBox1.Add(" ")
  numeroPorte = Val(CStr(p1))
 
   
  For numPorta = 0 To numeroPorte - 1

    p2 = Alloc(CStr(numPorta))
   
    err = main(2, VarPtr(p1), p2)
    If err <> 0 Then Error.Raise("Errore nella chiamata della funzione esterna 'main()' !")
    ListBox1.Add("   -------Numero porta: " & Val("&" & CStr(p1)))
   
    err = main(3, VarPtr(p1), p2)
    If err <> 0 Then Error.Raise("Errore nella chiamata della funzione esterna 'main()' !")
    ListBox1.Add("           Tipo porta: " & String@(p1))
   
    err = main(4, VarPtr(p1), p2)
    If err <> 0 Then Error.Raise("Errore nella chiamata della funzione esterna 'main()' !")
    ListBox1.Add("           Nome porta: " & String@(p1))
  
    err = main(5, VarPtr(p1), p2)
    If err <> 0 Then Error.Raise("Errore nella chiamata della funzione esterna 'main()' !")
    If Val("&" & CStr(p1)) Then
      ListBox1.Add("           Leggibile ")
    Else
      ListBox1.Add("           Non leggibile")
    Endif
   
    err = main(6, VarPtr(p1), p2)
    If err <> 0 Then Error.Raise("Errore nella chiamata della funzione esterna 'main()' !")
    If Val("&" & CStr(p1)) Then
      ListBox1.Add("           Scrivibile")
    Else
      ListBox1.Add("           Non scrivibile")
    Endif

    err = main(7, VarPtr(p1), p2)
    If err <> 0 Then Error.Raise("Errore nella chiamata della funzione esterna 'main()' !")
    If Val("&" & CStr(p1)) Then
      ListBox1.Add("           Destinazione: Interna")
    Else
      ListBox1.Add("           Destinazione: Esterna")
    Endif
    ListBox1.Add(" ")
   
  Next


' Va in chiusura liberando la memoria precedentemente allocata:
  Free(p2)

End


Riferimenti

[1] Il sito di TSE3