La gestione dei file MIDI mediante le funzioni esterne del API di WildMidi

Da Gambas-it.org - Wikipedia.

La libreria di WildMidi contiene funzioni e risorse per leggere e gestire file Midi.

In particolare la libreria WildMIDI converte i file MIDI in dati audio che potranno essere inviati ad altra applicazione capace di eseguire i dati audio, come ad esempio Alsa, per farli ascoltare. L'API della libreria è progettata in modo che sia facile inserire WildMIDI in applicazioni che prevedono anche la riproduzione di file Midi.


La libreria da utilizzare in Gambas è attualmente la seguente:

libWildMidi.so.1.0.2

Bisognerà avere installato nel sistema il banco di suoni (soundfont bank): Freepats.


Esempio pratico

Il semplice esempio che segue è sostanzialmente strutturato in due parti:

  • la prima dedicata alle funzionalità di WildMidi che passeranno i dati audio, derivati dalla conversione di un file Midi, ad Alsa;
  • la seconda dedicata ad Alsa, che, ricevuti i dati audio da WildMidi, li eseguirà effettivamente.

I dati audio (ottenuti dalla conversione dei dei dati Midi) saranno passati da WildMidi ad Alsa attraverso una variabile di tipo Puntatore che punta ad un'area allocata riempita dei predetti dati audio dalla funzione WildMidi_GetOutput() di WildMidi.

Library "libWildMidi:1.0.2"

' WildMidi_Init  (const char *config_file, unsigned short int rate, unsigned short int options)
' Intializes "libWildMidi" in preparation for playback.
Private Extern WildMidi_Init(config_file As String, rate As Short, options As Short) As Integer

' int WildMidi_MasterVolume (unsigned char master_volume)
' Sets the overall library volume level to master_volume. The range of master_volume is between 0 And 127 with 100 being the default.
Private Extern WildMidi_MasterVolume(master_volume As Byte) As Integer

' midi *WildMidi_Open (const char *midifile)
' Open  a MIDI file pointed to by midifile for processing. This file must be in standard midi format.
' It returns a handle for the midi file opened. This handle is used by most functions in libWildMidi to identify which midi file we are refering to.
Private Extern WildMidi_Open(midifile As String) As Pointer

' int  WildMidi_GetOutput  (midi *handle, char *buffer, unsigned long insize)
' Places size bytes of audio data from a  handle,  previously  opened  by WildMidi_Open() or WildMidi_OpenBuffer(), into a buffer pointer to by buffer.
' Buffer must be atleast size bytes, with size being a multiple of 4 as the data is stored in 16 bit interleaved stereo format.
Private Extern WildMidi_GetOutput(handle As Pointer, buffer As Pointer, insize As Long) As Integer

' int WildMidi_Close (midi *handle)
' Finish processing MIDI data or file. "handle" the indentifier obtained from opening a midi file with "WildMidi_Open()".
Private Extern WildMidi_Close(handle As Pointer) As Integer

' void WildMidi_Shutdown(void)
' Shuts  down  the wildmidi library, resetting data and freeing up memory used by the library.
' Once this is called, the library is no-longer initiaized and "WildMidi_Init()" will need to be called again.
Private Extern WildMidi_Shutdown()

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''


Library "libasound:2"

' int   snd_pcm_open(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode)  --> Apre il sub-sistema PCM
Private Extern snd_pcm_open(pcmP As Pointer, nome As String, stream As Integer, mode As Integer) As Integer

' const char * snd_strerror (int errnum)  --> Ritorna un messaggio relativo ad un codice di Errore.
Private Extern snd_strerror(errnum As Integer) As String

' int snd_pcm_set_params (snd_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int canali, unsigned int rate, int soft_resample, unsigned int latency)
Private Extern snd_pcm_set_params(pcmP As Pointer, formatB As Byte, accessB As Byte, canali As Integer, rate As Integer, soft_resample As Integer, latency As Integer) As Integer

' snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
Private Extern snd_pcm_writei(pcmP As Pointer, buffP As Pointer, uframes As Long) As Integer

' int snd_pcm_close(snd_pcm_t *pcm)  --> Chiude il sub-sistema PCM
Private Extern snd_pcm_close(pcmP As Pointer) As Integer



Public Sub Button1_Click()

 Dim err As Integer
 Dim midi, buffer, handle as Pointer
 Dim frequenza As Integer = 44100

' Va ad inizializzare l'interfaccia PCM di Alsa:
   handle = inizializzaAlsa(frequenza)

 
' Inizializza la libreria di "WildMidi":
' - il primo parametro richiama il file che contiene la configurazione degli strumenti musicali che sarà utilizzata dalla libreria.
'   Il file di configurazione potrà essere: "/etc/timidity/freepats.cfg" oppure "/etc/wildmidi/wildmidi.cfg".
' - il secondo argomento della funzione deve essere identico al 5° parametro (frequenza) di "snd_pcm_set_params()" ):
   err = WildMidi_Init("/etc/timidity/freepats.cfg", frequenza, 0)
   If err < 0 Then Error.Raise("Errore nell'inizializzazione dell'interfaccia libWildMidi !")
   
' Imposta il volume generale (da 0 a 127):
   err = WildMidi_MasterVolume(100)
   If err < 0 Then Error.Raise("Errore nell'impostazione del Volume Generale !")
   
' Apre il file Midi che dovrà essere eseguito:
   midi = WildMidi_Open("/percorso/del/file.mid")
   If IsNull(midi) Then Error.Raise("Impossibile aprire il file Midi !")

' Alloca un'area di memoria che sarà puntata da una variabile di tipo "Puntatore":
   buffer = Alloc(128)

   Do

' Ad ogni giro viene riempita l'area allocata con un certo numero di dati Midi convertiti in dati audio da passare successivamente ad Alsa.
' (In particolare, ad Alsa sarà passata la variabile di tipo "puntatore" - qui chiamata "buffer" - che ora viene riempita di dati):
     err = WildMidi_GetOutput(midi, buffer, 128)

' Viene passata la variabile di tipo "puntatore" (qui chiamata "buffer") alla seguente funzione, che provvede ad inviare i dati audio ad Alsa'
' (il terzo parametro deve essere uguale ad 1/4 del valore del secondo parametro):
     snd_pcm_writei(handle, buffer, 128 / SizeOf(gb.Integer))

   Loop Until err = 0


' Chiude l'elaborazione dei dati Midi da parte di "WildMidi":
   err = WildMidi_Close(midi)
   If err < 0 Then Error.Raise("Errore nella chiusura del processo dei dati Midi !")

   Free(buffer)
   
' Chiude la libreria di "WildMidi":
   WildMidi_Shutdown()
   
' Chiude infine anche l 'handle della libreria di Alsa:
  snd_pcm_close(handle)

End


Private Function inizializzaAlsa(frequenza As Integer) As Pointer
 
 Dim err As Integer
 Dim handle as Pointer
 Dim nomen As String = "default"
 Dim SND_PCM_STREAM_PLAYBACK As Byte = 0
 Dim SND_PCM_ACCESS_RW_INTERLEAVED As Byte = 3
 Dim canali As Byte = 2
 

' Apre il sub-sistema PCM di Alsa creando un apposito "handle":
   err = snd_pcm_open(VarPtr(handle), nomen, SND_PCM_STREAM_PLAYBACK, 0)
   If err < 0 Then Error.Raise("Playback open error: " & snd_strerror(err))

' Imposta i parametri hardware/software dell'interfaccia PCM di ALsa:
   err = snd_pcm_set_params(handle, 2, SND_PCM_ACCESS_RW_INTERLEAVED, canali, frequenza, 1, 500000)
   If err < 0 Then Error.Raise("Playback open error: " & snd_strerror(err))

   Return handle
   
End


Riferimenti