Conoscere con le funzioni esterne di ALSA i dispositivi Midi presenti nel sistema

Da Gambas-it.org - Wikipedia.

Alcune funzioni esterne del API di Alsa consentono di conoscere i dispositivi Midi dell'hardware audio presenti nel proprio sistema, con i quali poter ricevere ed inviare dati Midi grezzi.


Mostriamo di seguito due codici, che dovranno essere lanciati dopo aver collegato, ad esempio, una tastiera Midi esterna al proprio computer.


Primo esempio:

Library "libasound:2"


' int snd_card_next (int *card)
' Try To determine the Next card.
Private Extern snd_card_next(card As Pointer) As Integer

' int snd_ctl_open (snd_ctl_t **ctl, const char *name, int mode)
' Opens a CTL.
Private Extern snd_ctl_open(card As Pointer, name As String, mode As Integer) As Integer

' int snd_ctl_rawmidi_next_device (snd_ctl_t *ctl, int *device)
' Get Next RawMidi device number.
Private Extern snd_ctl_rawmidi_next_device(ctl As Pointer, device As Pointer) As Integer

' int snd_rawmidi_info_malloc (snd_rawmidi_info_t **ptr)
' Allocate a New Snd_rawmidi_info_t structure.
Private Extern snd_rawmidi_info_malloc(ptr As Pointer) As Integer

' size_t snd_rawmidi_info_sizeof (void)
' Get size Of the 'snd_rawmidi_info_t' structure in bytes.
Private Extern snd_rawmidi_info_sizeof() As Integer

' void snd_rawmidi_info_set_device (snd_rawmidi_info_t *obj, unsigned int val)
' Set rawmidi device number.
Private Extern snd_rawmidi_info_set_device(obj As Pointer, ValInt As Integer)

' void snd_rawmidi_info_set_stream (snd_rawmidi_info_t *obj, snd_rawmidi_stream_t val)
' Set rawmidi stream identifier.
Private Extern snd_rawmidi_info_set_stream(obj As Pointer, ValInt As Integer)

' void snd_rawmidi_info_set_subdevice (snd_rawmidi_info_t *obj, unsigned int val)
' Set rawmidi subdevice number.
Private Extern snd_rawmidi_info_set_subdevice(obj As Pointer, ValInt As Integer)

' int snd_ctl_rawmidi_info (snd_ctl_t *ctl, snd_rawmidi_info_t *info)
' Get info about a RawMidi device.
Private Extern snd_ctl_rawmidi_info(ctl As Pointer, info As Pointer) As Integer

' int snd_ctl_close (snd_ctl_t *ctl)
' Closes CTL handle.
Private Extern snd_ctl_close(ctl As Pointer) As Integer

' int snd_config_update_free_global (void)
' Frees the global configuration tree In snd_config.
Private Extern snd_config_update_free_global() As Integer

' void *memset(void *str, int c, size_t n)
' Copies the character c (an unsigned char) to the first n characters of the string pointed to by the argument str.
Private Extern memset(StrP As Pointer, c As Integer, n As Integer) As Pointer In "libc:6"


Public Sub Main()

 Dim err, cardNum, devNum, subDevCount, i As Integer
 Dim cardHandle, rawMidiInfo As Pointer
 Dim $str As String
 Dim j, k As Byte
 Dim SND_RAWMIDI_STREAM_OUTPUT As Byte = 0
 

  Print "---- DISPOSITIVI HARDWARE MIDI PRESENTI ----\n"
 
  cardNum = -1
 
 
  While True

    err = snd_card_next(VarPtr(cardNum))
    If err < 0 Then Error.Raise("Impossibile ottenere il numero della scheda audio successiva !")
   
' Se non vi sono più schede, Alsa imposta "cardNum" a -1:
    If cardNum < 0 Then Exit
     
    $str = "hw:" & CStr(cardNum)

    err = snd_ctl_open(VarPtr(cardHandle), $Str, 0)
    If err < 0 Then Error.Raise("Impossibile aprire la connessione con la scheda audio !")
       
' Parte con il primo dispositivo Midi sulla scheda individuata:
    devNum = -1

     While True

' Ricava il numero del successivo dispositivo Midi sulla scheda attuale:
       err = snd_ctl_rawmidi_next_device(cardHandle, VarPtr(devNum))
       If err < 0 Then Error.Raise("Impossibile ottenere il numero del successivo dispositivo Midi !")

' Se non ci sono altri dispositivi Midi sulla scheda audio, Alsa imposta "devNum" a -1.
' NOTA: E' possibile che la scheda audio (ad esempio una scheda audio digitale) possa non avere dispositivi Midi:
       If devNum < 0 Then Exit
       
' Per ottenere informazioni sui sub-dispositivi del presente dispositivo Midi (sulla scheda),
' bisogna chiamare la funzione "snd_rawmidi_info_t", previa allocazione di memeoria sullo stack:
       snd_rawmidi_info_malloc(VarPtr(rawMidiInfo))
       memset(rawMidiInfo, 0, snd_rawmidi_info_sizeof())
         
' Si dice ad Alsa di quale numero di dispositivo vogliamo ottenere informazioni:
       snd_rawmidi_info_set_device(rawMidiInfo, devNum)
        
' Si ottengono le informazioni Midi del dispositivo:
       snd_rawmidi_info_set_stream(rawMidiInfo, SND_RAWMIDI_STREAM_OUTPUT)
       
       i = -1
       
       subDevCount = 1
       
       While (i < subDevCount - 1)
         Inc i
' Si dice ad Alsa di riempire la funzione "our snd_rawmidi_info_t" con le informazioni sul presente sub-dispositivo:
         snd_rawmidi_info_set_subdevice(rawMidiInfo, i)
         err = snd_ctl_rawmidi_info(cardHandle, rawMidiInfo)
         If err < 0 Then Error.Raise("Impossibile ottenere informazioni dal subdispositivo Midi output !")
             
' NOTA: Se v'è un solo subdevice, allora il numero del subdispositivo è virtuale,
' e può essere omesso quando viene specificato il nome dell'hardware Midi:
         If subDevCount > 1 Then
           Print "hw:"; cardNum; ","; devNum; ","; i; Chr(10)
         Else
           Print"hw:"; cardNum; ","; devNum; Chr(10)
         Endif
       Wend
       
       
     Wend

    snd_ctl_close(cardHandle)
   
  Wend

  snd_config_update_free_global()

End


Ora mostriamo un esempio per ottenere maggiori e più dettagliate informazioni relativamente all'hardware Midi, al dispositivo ed all'eventuale subdispositivo:

Library "libasound:2"

Private Const SND_RAWMIDI_STREAM_OUTPUT As Integer = 0
Private Const SND_RAWMIDI_STREAM_INPUT As Integer = 1

' int snd_card_next (int *card)
' Try To determine the Next card.
Private Extern snd_card_next(card As Pointer) As Integer

' int snd_ctl_open (snd_ctl_t **ctl, const char *name, int mode)
' Opens a CTL.
Private Extern snd_ctl_open(card As Pointer, name As String, mode As Integer) As Integer

' int snd_ctl_rawmidi_next_device (snd_ctl_t *ctl, int *device)
' Get Next RawMidi device number.
Private Extern snd_ctl_rawmidi_next_device(ctl As Pointer, device As Pointer) As Integer

' int snd_ctl_card_info_malloc (snd_ctl_card_info_t **ptr)
' Allocate an invalid snd_ctl_card_info_t using standard malloc.
Private Extern snd_ctl_card_info_malloc(ptr As Pointer) As Integer

' int snd_ctl_card_info (snd_ctl_t *ctl, snd_ctl_card_info_t *info)
' Get card related information.
Private Extern snd_ctl_card_info(ctl As Pointer, snd_ctl_card_info_t As Pointer) As Integer

' const char * snd_ctl_card_info_get_longname (const snd_ctl_card_info_t *obj)
' Get card long name from a CTL card info.
Private Extern snd_ctl_card_info_get_longname(obj As Pointer) As String

' const char * snd_ctl_card_info_get_id (const snd_ctl_card_info_t *obj)
' Get card identifier from a CTL card info.
Private Extern snd_ctl_card_info_get_id(obj As Pointer) As String

' const char * snd_ctl_card_info_get_name (const snd_ctl_card_info_t *obj)
' Get card name from a CTL card info.
Private Extern snd_ctl_card_info_get_name(obj As Pointer) As String

' const char * snd_ctl_card_info_get_driver (const snd_ctl_card_info_t *obj)
' Get card driver name from a CTL card info.
Private Extern snd_ctl_card_info_get_driver(obj As Pointer) As String

' const char * snd_ctl_card_info_get_mixername (const snd_ctl_card_info_t *obj)
' Get card mixer name from a CTL card info.
Private Extern snd_ctl_card_info_get_mixername(obj As Pointer) As String

' const char * snd_ctl_card_info_get_components (const snd_ctl_card_info_t *obj)
' Get card component list from a CTL card info.
Private Extern snd_ctl_card_info_get_components(obj As Pointer) As String

' int snd_rawmidi_info_malloc (snd_rawmidi_info_t **ptr)
' Allocate a New Snd_rawmidi_info_t structure.
Private Extern snd_rawmidi_info_malloc(ptr As Pointer) As Integer

' size_t snd_rawmidi_info_sizeof (void)
' Get size Of the 'snd_rawmidi_info_t' structure in bytes.
Private Extern snd_rawmidi_info_sizeof() As Integer

' void snd_rawmidi_info_set_device (snd_rawmidi_info_t *obj, unsigned int val)
' Set rawmidi device number.
Private Extern snd_rawmidi_info_set_device(obj As Pointer, ValInt As Integer)

' void snd_rawmidi_info_set_stream (snd_rawmidi_info_t *obj, snd_rawmidi_stream_t val)
' Set rawmidi stream identifier.
Private Extern snd_rawmidi_info_set_stream(obj As Pointer, ValInt As Integer)

' void snd_rawmidi_info_set_subdevice (snd_rawmidi_info_t *obj, unsigned int val)
' Set rawmidi subdevice number.
Private Extern snd_rawmidi_info_set_subdevice(obj As Pointer, ValInt As Integer)

' int snd_ctl_rawmidi_info (snd_ctl_t *ctl, snd_rawmidi_info_t *info)
' Get info about a RawMidi device.
Private Extern snd_ctl_rawmidi_info(ctl As Pointer, info As Pointer) As Integer

' unsigned int snd_rawmidi_info_get_subdevices_count (const snd_rawmidi_info_t *obj)
' Get rawmidi count of subdevices.
Private Extern snd_rawmidi_info_get_subdevices_count(obj As Pointer) As Integer

' unsigned int snd_rawmidi_info_get_subdevices_avail (const snd_rawmidi_info_t *obj)
' Get rawmidi available count of subdevices.
Private Extern snd_rawmidi_info_get_subdevices_avail(obj As Pointer) As Integer

' const char * snd_rawmidi_info_get_id (const snd_rawmidi_info_t *obj)
' Get rawmidi hardware driver identifier.
Private Extern snd_rawmidi_info_get_id(obj As Pointer) As String

' const char * snd_rawmidi_info_get_name (const snd_rawmidi_info_t *obj)
' Get rawmidi hardware driver name.
Private Extern snd_rawmidi_info_get_name(obj As Pointer) As String

' const char * snd_rawmidi_info_get_subdevice_name (const snd_rawmidi_info_t *obj)
' Get rawmidi subdevice name.
Private Extern snd_rawmidi_info_get_subdevice_name(obj As Pointer) As String

' int snd_ctl_close (snd_ctl_t *ctl)
' Closes CTL handle.
Private Extern snd_ctl_close(ctl As Pointer) As Integer

' int snd_config_update_free_global (void)
' Frees the global configuration tree In snd_config.
Private Extern snd_config_update_free_global() As Integer

' const char * snd_strerror (int errnum)
' Returns the message For an Error code.
Private Extern snd_strerror(errore As Integer) As String

' void *memset(void *str, int c, size_t n)
' Copies the character c (an unsigned char) to the first n characters of the string pointed to by the argument str.
Private Extern memset(StrP As Pointer, c As Integer, n As Integer) As Pointer In "libc:6"


Public Sub Main()

 Dim err, cardNum, devNum, unaVolta As Integer
 Dim midiHandle, cardInfo As Pointer
 Dim $str As String


  Print "---- DISPOSITIVI HARDWARE MIDI PRESENTI ----"

  cardNum = -1
 

  While True

    err = snd_card_next(VarPtr(cardNum))
    If err < 0 Then Error.Raise("Impossibile ottenere il numero della scheda audio successiva: " & snd_strerror(err))
  
' Se non vi sono più schede, Alsa imposta "cardNum" a -1:
    If cardNum < 0 Then Exit
    
    $str = "hw:" & CStr(cardNum)

    err = snd_ctl_open(VarPtr(midiHandle), $Str, 0)
    If err < 0 Then Error.Raise("Impossibile aprire la connessione con la scheda audio: " & snd_strerror(err))
      
' Parte con il primo dispositivo Midi sulla scheda individuata:
    devNum = -1

    While True

' Ricava il numero del successivo dispositivo Midi sulla scheda attuale:
      err = snd_ctl_rawmidi_next_device(midiHandle, VarPtr(devNum))
      If err < 0 Then Error.Raise("Impossibile ottenere il numero del successivo dispositivo Midi: " & snd_strerror(err))

' Se non ci sono altri dispositivi Midi sulla scheda audio, Alsa imposta "devNum" a -1.
' NOTA: E' possibile che la scheda audio (ad esempio una scheda audio digitale) possa non avere dispositivi Midi:
      If devNum < 0 Then Exit
             
      If Not unaVolta Then
      
' Esegue il codice qui sotto una sola volta:
        unaVolta = 1       
      
        snd_ctl_card_info_malloc(VarPtr(cardInfo))
     
' Dice ad ALSA di riempire 'snd_ctl_card_info_t' con informazioni sulla corrente scheda:
        err = snd_ctl_card_info(midiHandle, cardInfo)
        If err < 0 Then
          Error.Raise("Impossibile ottenere informazioni sulla scheda audio: " & snd_strerror(err))
        Else
          Print "\n\n================================================================================="
          Print snd_ctl_card_info_get_longname(cardInfo)
          Print "=================================================================================\n"
          Print "id = "; snd_ctl_card_info_get_id(cardInfo)
          Print "\nnome = "; snd_ctl_card_info_get_name(cardInfo)
          Print "\ndriver = "; snd_ctl_card_info_get_driver(cardInfo)
          Print "\nmixername = "; snd_ctl_card_info_get_mixername(cardInfo)
          Print "\ncomponenti = "; snd_ctl_card_info_get_components(cardInfo)
        Endif
     
      Endif
     
' Mostra le informazioni relative ai subdispositivi MIDI Output del corrente dispositivo MIDI:
      lista_subdevice(midiHandle, cardNum, devNum, SND_RAWMIDI_STREAM_OUTPUT)
   
' Mostra le informazioni relative ai subdispositivi MIDI Input del corrente dispositivo MIDI:
      lista_subdevice(midiHandle, cardNum, devNum, SND_RAWMIDI_STREAM_INPUT)

    Wend

    snd_ctl_close(midiHandle)
  
  Wend

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

End



Private Procedure lista_subdevice(midiH As Pointer, cardN As Integer, devN As Integer, tipo As Integer)
 
 Dim rawMidiInfo As Pointer
 Dim subDevCount, i, err As Integer
 Dim stringa As String
 
 
  If tipo = SND_RAWMIDI_STREAM_OUTPUT Then
    stringa = "Output"
  Else
    stringa = "Input"
  Endif
   
  snd_rawmidi_info_malloc(VarPtr(rawMidiInfo))
  memset(rawMidiInfo, 0, snd_rawmidi_info_sizeof())
 
' Dice ad ALSA di quale dispositivo Midi si richiedono le informazioni:
   snd_rawmidi_info_set_device(rawMidiInfo, devN)
   
' Si ottengono informazioni sull'uscita Midi o in sezione del corrente dispositivo:
   snd_rawmidi_info_set_stream(rawMidiInfo, tipo)
    
   i = -1
   subDevCount = 1
   
   Inc i
   While i < subDevCount
 
' Dice ad ALSA di riempire 'snd_rawmidi_info_t' con le informazioni sul corrente subdispositivo:
     snd_rawmidi_info_set_subdevice(rawMidiInfo, i)
 
     err = snd_ctl_rawmidi_info(midiH, rawMidiInfo)
     If err < 0 Then Error.Raise("Impossibile ottenere informazioni sul subdevice " & stringa & " Midi 'hw:" & CStr(cardN) & "," & CStr(devN) & "," & CStr(i) & " : " & snd_strerror(err))
   
' Scrive quanti subdispositivi Midi sono presenti:
     If Not i Then
       subDevCount = snd_rawmidi_info_get_subdevices_count(rawMidiInfo)
       Print "\n ------ "; subDevCount; " "; stringa; " subdevice ("; snd_rawmidi_info_get_subdevices_avail(rawMidiInfo); " disponibili)"
       Print "id = "; snd_rawmidi_info_get_id(rawMidiInfo)
       Print "name = "; snd_rawmidi_info_get_name(rawMidiInfo)
     Endif
   
' NOTA: Se è presente un solo subdispositivo, allora il numero del subdispositivo è immateriale, e può essere omesso:
     If subDevCount > 1 Then
       Print "   MIDI "; stringa; " 'hw:"; cardN; ","; devN; ","; i; "'"
     Else
       Print "   MIDI "; stringa; " 'hw:"; cardN; ","; devN; "'"
     Endif

     Print "   subnome = '"; snd_rawmidi_info_get_subdevice_name(rawMidiInfo); "'"
   
     Inc i
 
   Wend
 
End