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

Da Gambas-it.org - Wikipedia.

Premessa

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.

L'accesso ad una porta MIDI richiede tre Interi:

  • un numero che rappresenta la scheda audio;
  • un numero che rappresenta il dispositivo;
  • un numero che rappresenta il sub-dispositivo.

Gli esempi, che seguono, mostrano come accedere appunto a questi tre numeri rappresentativi. Avendo a disposizione tali numeri, è possibile aprire una porta MIDI di Entrata o di Uscita con la funzione snd_rawmidi_open() usando una stringa simile:

hw:x,y,z

laddove x, y, z sono i tre numeri che rappresentano e specificano una particolare porta MIDI di Entrata o di Uscita, come ad esempio:

hw:1,0,0


Mostriamo di seguito tre codici, che dovranno essere lanciati dopo aver collegato, ad esempio, uno o più dispositivi Midi esterni hardware (ad esempio una o più tastiere Midi) al proprio computer.


Primo esempio

Cominciamo con il primo esempio più semplice:

Library "libasound:2"

Private Const SND_RAWMIDI_STREAM_OUTPUT As Byte = 0
  
' 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


  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 memoria 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


Secondo esempio

Mostriamo il secondo esempio più complesso del precedente.

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_card_get_name (int card, char **name)
' Obtain the card name.
Private Extern snd_card_get_name(card As Integer, name As Pointer) As Integer

' int snd_card_get_longname (int card, char **name)
' Obtain the card long name.
Private Extern snd_card_get_longname(card As Integer, name 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

' 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)

' 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

' 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

' 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_close (snd_ctl_t *ctl)
' Closes CTL handle.
Private Extern snd_ctl_close(ctl As Pointer) As Integer
 
' const char * snd_strerror (int errnum)
' Returns the message For an Error code.
Private Extern snd_strerror(errore As Integer) As String


Public Sub Main()

 Dim err, scheda As Integer
 Dim nomecorto, nomeesteso As Pointer


  Print "---- DISPOSITIVI HARDWARE MIDI PRESENTI ----\n"
 
  scheda = -1
 
' Individua le schede audio disponibili nel sistema ALSA, mostrando il loro numero ed il nome di ciascuna:
  err = snd_card_next(VarPtr(scheda))
  If err < 0 Then Error.Raise("Impossibile ottenere il numero della scheda audio: " & snd_strerror(err))
   
  If scheda < 0 Then
    Print "Nessuna scheda audio trovata nel sistema !"
    Quit
  Endif  
 
  While scheda >= 0
   
    Print "Scheda: "; scheda
    err = snd_card_get_name(scheda, VarPtr(nomecorto))
    If err < 0 Then Error.Raise("Impossibile ottenere il nome breve della scheda audio !")
   
    err = snd_card_get_longname(scheda, VarPtr(nomeesteso))
    If err < 0 Then Error.Raise("Impossibile ottenere il nome esteso della scheda audio !")
   
    Print "     NOME INTERO:  "; String@(nomeesteso)
    Print "     NOME ABBREV.: "; String@(nomecorto)
   
    err = snd_card_next(VarPtr(scheda))
    If err < 0 Then Error.Raise("Impossibile ottenere il numero della scheda audio: " & snd_strerror(err))
   
  Wend


Individua i dispositivi ed i subdispositivi Midi e le rispettive porte
in grado di leggere e scrivere dati Midi in Entrata ed in Uscita.
  err = snd_card_next(VarPtr(scheda))
  If err < 0 Then Error.Raise("Impossibile ottenere il numero della scheda audio: " & snd_strerror(err))
   
  If scheda < 0 Then
    Print "Nessuna scheda audio trovata nel sistema !"
    Quit
  Endif
   
  Print "\nDir      Dispositivo    Nome"
  Print "====================================\n"
   
  While scheda >= 0
    lista_dispositivi_midi(scheda)
    err = snd_card_next(VarPtr(scheda))
    If err < 0 Then Error.Raise("Impossibile ottenere il numero della scheda audio: " & snd_strerror(err))
  Wend 
   
   
End
   
   
Ottiene informazioni circa i dispositivi hardware Midi
in grado di gestire i dati Midi in Entrata ed in Uscita.

Private Procedure lista_dispositivi_midi(dispSc As Integer)

 Dim nome As String
 Dim err, disp As Integer
 Dim ctl As Pointer
 
 
  disp = -1
   
  nome = "hw:" & CStr(dispSc)
  err = snd_ctl_open(VarPtr(ctl), nome, 0)
  If err < 0 Then Error.Raise("Impossibile aprire un controllo della scheda audio " & CStr(dispSc) & ": " & snd_strerror(err))
   
  Do
     
    err = snd_ctl_rawmidi_next_device(ctl, VarPtr(disp))
    If err < 0 Then Error.Raise("Impossibile ottenere il numero del dispositivo: " & snd_strerror(err))

    If disp >= 0 Then lista_subdispositivi_midi(ctl, dispSc, disp)

  Loop Until disp < 0
  
  snd_ctl_close(ctl)

End


Ottiene informazioni circa i subdispositivi hardware Midi
in grado di gestire i dati Midi in Entrata ed in Uscita.

Private Procedure lista_subdispositivi_midi(subCtl As Pointer, subSc As Integer, subDi As Integer)
 
 Dim mdInfo As Pointer
 Dim subIn, subEx, subs, su, en, ex, err As Integer
 Dim nome, subnome, io As String
 
  snd_rawmidi_info_malloc(VarPtr(mdInfo))
  snd_rawmidi_info_set_device(mdInfo, subDi)
   
  snd_rawmidi_info_set_stream(mdInfo, SND_RAWMIDI_STREAM_INPUT)
  snd_ctl_rawmidi_info(subCtl, mdInfo)
  subIn = snd_rawmidi_info_get_subdevices_count(mdInfo)
  snd_rawmidi_info_set_stream(mdInfo, SND_RAWMIDI_STREAM_OUTPUT)
  snd_ctl_rawmidi_info(subCtl, mdInfo)
  subEx = snd_rawmidi_info_get_subdevices_count(mdInfo)
  If subIn > subEx Then
    subs = subIn
  Else
    subs = subEx
  Endif
   
  err = emissio(subCtl, subDi, su)
  If err < 0 Then
    Error.Raise("Impossibile ottenere informazioni 'rawmidi': " & CStr(subSc) & ":" & subDi & ": " & snd_strerror(err))
  Else If err Then
    ex = 1
  Endif

  err = immissio(subCtl, subDi, su)
  If err < 0 Then
    Error.Raise("Impossibile ottenere informazioni 'rawmidi': " & CStr(subSc) & ":" & subDi & ": " & snd_strerror(err))
  Else If err Then
    en = 1
  Endif
   
  If err = 0 Then Return
   
  nome = snd_rawmidi_info_get_name(mdInfo)
  subnome = snd_rawmidi_info_get_subdevice_name(mdInfo)
    
  If Left(subnome, 1) = Chr(0) Then
    If subs = 1 Then
      If en Then io = "In "
      If ex Then io &= "Out"
      Print io, " hw:"; subSc; ","; subDi, nome
    Else
      If en Then io = "In "
      If ex Then io &= "Out"
      Print io, " hw:"; subSc; ","; subDi, nome; " ("; subs; "subdispositivi)"
    Endif
  Else
    su = 0
    While True
      
      If en Then io = "In "
      If ex Then io &= "Out"
      Print io, " hw:"; subSc; ","; subDi; ","; su, subnome
      Inc su
      If su >= subs Then Exit
      
      en = immissio(subCtl, subDi, su)
      ex = emissio(subCtl, subDi, su)
      snd_rawmidi_info_set_subdevice(mdInfo, su)
       
      If ex Then
        snd_rawmidi_info_set_stream(mdInfo, SND_RAWMIDI_STREAM_OUTPUT)
        err = snd_ctl_rawmidi_info(subCtl, mdInfo)
          If err < 0 Then
            Error.Raise("Impossibile ottenere informazioni 'rawmidi': " & CStr(subSc) & ":" & subDi & ":" & su & ": " & snd_strerror(err))
            Exit
          Endif
      Else
        snd_rawmidi_info_set_stream(mdInfo, SND_RAWMIDI_STREAM_INPUT)
        err = snd_ctl_rawmidi_info(subCtl, mdInfo)
          If err < 0 Then
            Error.Raise("Impossibile ottenere informazioni 'rawmidi': " & CStr(subSc) & ":" & subDi & ":" & su & ": " & snd_strerror(err))
            Exit
          Endif
      Endif
      
      subnome = snd_rawmidi_info_get_subdevice_name(mdInfo)
       
    Wend
     
  Endif
 
End

   
Private Function emissio(subCtl As Pointer, subDi As Integer, su As Integer) As Integer
 
 Dim eInfo As Pointer
 Dim err As Integer
 
  snd_rawmidi_info_malloc(VarPtr(eInfo))
  snd_rawmidi_info_set_device(eInfo, subDi)
  snd_rawmidi_info_set_subdevice(eInfo, su)
  snd_rawmidi_info_set_stream(eInfo, SND_RAWMIDI_STREAM_OUTPUT)

  err = snd_ctl_rawmidi_info(subCtl, eInfo)

  If (err < 0) And (err <> - ENXIO) Then
    Return err
  Else If err = 0 Then
' Ritorna "1", se gli specificati scheda/device/subdevice hanno la capacità di inviare dati MIDI in uscita:
    Return 1
  Endif
 
End


Private Function immissio(subCtl As Pointer, subDi As Integer, su As Integer) As Integer
 
 Dim iInfo As Pointer
 Dim err As Integer
 
  snd_rawmidi_info_malloc(VarPtr(iInfo))
  snd_rawmidi_info_set_device(iInfo, subDi)
  snd_rawmidi_info_set_subdevice(iInfo, su)
  snd_rawmidi_info_set_stream(iInfo, SND_RAWMIDI_STREAM_INPUT)

  err = snd_ctl_rawmidi_info(subCtl, iInfo)
  If (err < 0) And (err <> - ENXIO) Then
    Return err
  Else If err = 0 Then
' Ritorna "1", se gli specificati scheda/device/subdevice hanno la capacità di inviare dati MIDI in entrata:
    Return 1
  Endif
 
End


Terzo esempio

Mostriamo infine il terzo esempio, che consentirà di 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 "nome = "; 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 "   sottonome = '"; snd_rawmidi_info_get_subdevice_name(rawMidiInfo); "'"
   
     Inc i
 
   Wend
 
End