Eseguire un file MIDI mediante il componente gb.media
Per eseguire ed ascoltare un file Midi, utilizzando un breve codice, è possibile adoperare le funzionalità della multipiattaforma gstreamer, attivando il componente gb.media.
E' necessario aver installato il file banco di suoni di default di Timidity:
/usr/share/sounds/sf2/TimGM6mb.sf2
oppure di FluidSynth:
/usr/share/sounds/sf2/FluidR3_GM.sf2
Indice
- 1 La classe MediaPlayer
- 1.1 Utilizzo in un'applicazione a riga di comando
- 1.2 Uso di applicazione grafica
- 1.3 La proprietà .Duration
- 1.4 La Proprietà ".Position"
- 1.5 Modificare il Volume
- 1.6 Annullare l'audio immediatamente
- 1.7 L'evento _AboutToFinish()
- 1.8 L'evento _End()
- 1.9 Gli effetti video con i plug-in
- 1.10 Interfacciare la Classe MediaPlayer con il plugin "jackaudiosink" di GStreamer per eseguire i file Midi
- 2 La Classe MediaPipeline
- 3 Note
La classe MediaPlayer
Si utilizzeranno i metodi specifici della Classe MediaPlayer del componente gb.media.
Gli elementi essenziali per eseguire un file Midi con la Classe MediaPlayer sono:
- la Proprietà ".Url" per caricare il file (se il file è memorizzato su dispositivo di memoria, allora il suo percorso andrà passato mediante il Metodo ".Url" della Classe statica "Media"; se il file è eseguito da un indirizzo web, allora sarà passato direttamente l'indirizzo web);
- il Metodo ".Play()" per avviare l'esecuzione del file Midi;
- la Proprietà ".Duration" per far eseguire il file Midi per l'intera sua durata;
- il Metodo ".Close()" per chiudere il mediaplayer.
Utilizzo in un'applicazione a riga di comando
Vediamo ora un semplice esempio di uso della Classe MediaPlayer in un'applicazione a riga di comando:
Private bo As Boolean Public Sub Main() Dim mp As MediaPlayer With mp = New MediaPlayer As "MediaPlayer1" .URL = Media.URL("/percorso/del/file.mid") .Play() Print "Durata del file Midi: \e[34m"; Str(Time(0, 0, 0, .Duration * 1000)) Repeat Write "\r\e[0mTempo trascorso: \e[1m\e[31m" & Str(Time(0, 0, 0, .Position * 1000)) Wait 0.01 Until bo .Stop .Close End With Write "\n\e[0mEsecuzione terminata !" ' Avendo utilizzato l'Evento "Application_Read()", è necessario invocare l'istruzione "Quit" per terminare il programma: Quit End Public Sub MediaPlayer1_End() ' Questo Evento viene sollevato, quando l'escuzione è terminata bo = True End Public Sub Application_Read() ' Premendo il tasto "Invio" della tastiera, si arresta il programma bo = True End
Uso di applicazione grafica
Vediamo un semplice codice, con il quale sarà possibile ascoltare, porre in pausa e terminare un file Midi in un'applicazione grafica.
Porremo sul Form del progetto:
- un ToggleButton per avviare ed arrestare l'esecuzione del file Midi;
- un ToggleButton per porre in pausa l'esecuzione del file Midi;
- un Timer che ci consentirà di calcolare il tempo trascorso;
Private mp As New MediaPlayer Public Sub Form_Open() ToggleButton2.Enabled = False ' Carica un file Midi: mp.URL = Media.URL("/percorso/del/file/Midi") End Public Sub ToggleButton1_Click() If ToggleButton1.Value Then ToggleButton2.Enabled = True Esegue() Else ' Chiama la funzione per arrestare l'esecuzione del file Midi: Arresta() ToggleButton2.Value = False ToggleButton2.Enabled = False Endif End Public Sub Timer1_Timer() ' Mostra in console la durata del file Midi e il tempo trascorso: Write "\rDurata: " & Time(0, 0, 0, mp.Duration * 1000) & " - Tempo trascorso: " & Time(0, 0, 0, mp.Position * 1000) ' Se la posizione corrente è uguale o maggiore della durata complessiva del file Midi, allora arresta l'esecuzione del file Midi: If mp.Position >= mp.Duration Then Arresta() End Public Sub Esegue() ' Avvia l'ascolto del file Midi: mp.Play With Timer1 ' Il "Timer" si attiva ogni 70 millesimi di secondo: .Delay = 70 .Start End With End Public Sub Arresta() ' Arresta l'ascolto del file Midi: mp.Stop mp.Close Timer1.Stop ToggleButton1.Value = False End Public Sub ToggleButton2_Click() ' Mette in "pausa" l'ascolto del file Midi. ' (Per continuare l'ascolto del file, si dovrà nuovamente attivare la Proprietà ".Play"): If ToggleButton2.Value Then mp.Pause Else If ToggleButton1.Value Then Esegue() Endif End
In quest'altro esempio, simile al precedente, verrà utilizzato un ciclo al posto del Timer.
Si porrà anche un Controllo Slider per poter modificare il volume.
Private mp As New MediaPlayer Public Sub Form_Open() With Slider1 .MinValue = 0 .MaxValue = 100 .Value = 50 End With ToggleButton2.Enabled = False ' Carica un file Midi: mp.URL = Media.URL("/percorso/del/file/Midi") End Public Sub ToggleButton1_Click() If ToggleButton1.Value Then ToggleButton2.Enabled = True Esegue() Else ' Chiama la funzione per arrestare l'esecuzione del file Midi: Arresta() ToggleButton2.Value = False ToggleButton2.Enabled = False Endif End Public Sub Esegue() ' Avvia l'ascolto del file Midi: mp.Play Repeat ' Una brevissima pausa consente di agire sugli eventuali "Controlli" posti sul Form: Wait 0.01 Write "\rDurata: " & Str(Time(0, 0, 0, mp.Duration * 1000)) & " - Tempo trascorso: " & Str(Time(0, 0, 0, mp.Position * 1000)) Until (mp.Position >= mp.Duration) Arresta() End Public Sub Arresta() ' Arresta l'ascolto del file Midi: mp.Stop mp.Close Timer1.Stop ToggleButton1.Value = False End Public Sub ToggleButton2_Click() ' Mette in "pausa" l'ascolto del file Midi. ' (Per continuare l'ascolto del file, si dovrà nuovamente attivare la Proprietà ".Play"): If ToggleButton2.Value Then mp.Pause Else If ToggleButton1.Value Then Esegue() Endif End Public Sub Slider1_Change() mp.Audio.Volume = Slider1.Value / 100 End
La proprietà .Duration
La Proprietà ".Duration" restituisce un valore di tipo Float che rappresenta la durata del file Midi espresso in secondi.
Poiché detta proprietà ritorna più precisamente la durata dei dati processati, essa potrà essere utilizzabile solo successivamente all'attivazione del Metodo ".Play".
Public Sub Main() Dim mp As MediaPlayer With mp = New MediaPlayer .URL = Media.URL("/percorso/del/file/Midi") .Play Print "Durata: \e[34m"; Time(0, 0, 0, .Duration * 1000) Repeat Wait 0.01 Write "\r \e[31m" & Str(Time(0, 0, 0, .pos * 1000)) Until .Pos >= .Duration .Stop .Close End With End
oppure più semplicemente:
...... .Play Print "Durata: \e[34m"; Time(0, 0, 0, .Duration * 1000) Wait .Duration .Stop .Close End With
La Proprietà ".Position"
La Proprietà ".Position" restituisce un valore di tipo Float che rappresenta la posizione, espressa in secondi all'interno dei dati processati.
Imposta, altresì, la posizione di esecuzione del brano. Pertanto, essa consente di spostare il processo dei dati, e dunque l'esecuzione del brano, ad un particolare punto temporale.
Modificare il Volume
Per modificare il volume dell'ascolto si dovrà utilizzare la Proprietà ".Volume" della Proprietà ".Audio" della Classe MediaPlayer.
Più in particolare la Proprietà ".Volume" ritorna od imposta il volume del corrente flusso audio. Nel primo caso restituisce un valore di tipo Float che rappresenta il volume corrente:
valore_di_tipo_Float = mp.Audio.Volume
nel secondo caso il volume è impostato mediante un valore di tipo Float:
mp.Audio.Volume = valore_di_tipo_Float
Annullare l'audio immediatamente
Per annullare l'audio immediatamente, senza modificare i valori del volume, si ha a disposizione la Proprietà ".Mute" della Proprietà ".Audio" della Classe MediaPlayer. Alla Proprietà ".Mute" dovrà essere assegnato il valore booleano True.
mp.Audio.Mute = True
L'evento _AboutToFinish()
L'evento "_AboutToFinish()" si scatena circa un secondo prima della fine della durata del file che si sta eseguendo.
L'evento _End()
L'evento "_End()" si scatena quando l'esecuzione del file Midi è terminata.
Esempio:
Private bo As Boolean Public Sub Main() Dim mp As MediaPlayer With mp = New MediaPlayer As "MediaPlayer1" .URL = Media.URL("/percorso/del/file/Midi") .Play Print "\rDurata del file Midi: "; Str(Time(0, 0, 0, .Duration * 1000)) Repeat Write "\r\e[0mTempo trascorso: \e[31m" & Str(Time(0, 0, 0, .Position * 1000)) Wait 0.01 Until bo .Stop .Close End With Write "\n\e[0mEsecuzione terminata !" End Public Sub MediaPlayer1_End() ' Questo Evento viene sollevato, quando l'escuzione è terminata bo = True End
Gli effetti video con i plug-in
E' possibile ottenere simpatici effetti video utilizzando i plug-in resi disposibili da GStreamer.
Gli effetti video disponibili sono:
"goom", "monoscope", "spacescope", "spectrascope", "synaescope", "wavescope"
In tal caso si farà uso anche della Classe MediaControl che è serve per gestire appositamente i plug-in di GStreamer.
Mostreremo di seguito il codice esenziale per l'utilizzo degli effetti video con i plug-In (si inserirà anche una DrawingArea sul Form):
Private mp As New MediaPlayer Public Sub Form_Open() Dim da As DrawingArea With da = New DrawingArea(Me) .X = 10 .Y = 10 .W = 300 .H = 300 .Background = Color.Black End With mp.URL = Media.URL("/percorso/del/file.mid") AvviaPlugin(da) End Private Procedure AvviaPlugin(drar As DrawingArea) Dim uscitaVideo, plugVis As MediaControl Dim b As Byte Dim tipoPlug As String[] = ["goom", "monoscope", "spacescope", "spectrascope", "synaescope", "wavescope"] Dim arrplugin As MediaControl[] ' Istanzia il controllo di uscita video da usare. In questo caso sarà "ximagesink", ' un "videosink" basato sullo standard X, e che è esso stesso un plug-in: uscitaVideo = New MediaControl(mp, "ximagesink") ' Si dice al MediaControl di mostrare il proprio output (gli effetti video) ' in uno specifico controllo GUI, solitamente una DrawingArea: uscitaVideo.SetWindow(drar) ' Imposta il controllo di uscita video da usare: mp.Video.Output = uscitaVideo ' Un array di variabili di tipo "MediaControl", ossia di vari PlugIn disponibili: arrplugin = New MediaControl[] For b = 0 To 5 plugVis = New MediaControl(mp, tipoPlug[b]) arrplugin.Push(plugVis) Next ' Imposta il plug-in da utilizzare (ad esempio il 6° fra quelli contenuti dal vettore "arrplugin": mp.Video.Visualisation = arrplugin[5] End Public Sub Form_Activate() ' Esegue il file Midi: mp.Play() End
Interfacciare la Classe MediaPlayer con il plugin "jackaudiosink" di GStreamer per eseguire i file Midi
Per eseguire i file Midi con la Classe MediaPlayer è possibile anche effettuare un interfacciamento tra il programma Gambas e il server audio JACK. Per fare ciò, ci si servirà dell'apposito plugin di GStreamer, chiamato "jackaudiosink". [Nota 1]
Ovviamente bisognerà avere l'accortezza di avviare il server Jack (per esempio avviando il programma qjackctl) prima di lanciare il programma Gambas.
All'avvio del programma viene creata dal server Jack una connessione tra il programma sorgente Gambas e la destinazione (di default il primo canale audio d'uscita disponibile della propria scheda audio).
Mostriamo un semplice ed essenziale esempio di esecuzione di un file Midi in un'applicazione a riga di comando:
Public Sub Main() Dim mp As MediaPlayer With mp = New MediaPlayer .URL = Media.URL("/percorso/del/file.mid") .Audio.Output = New MediaControl(mp, "jackaudiosink") .Play End With Wait mp.Duration mp.Stop End
La Classe MediaPipeline
La Classe MediaPipeline è uno speciale contenitore di Elementi GStreamer (ossia i MediaControl del Componente gb.media), ai quali fornisce un clock globale per la sincronizzazione ed un bus per l'inoltro di messaggi provenienti dai thread dello streaming.
Usare la Classe "MediaPipeline" con il decoder "playbin" di GStreamer
La Classe implementa un funzionale media-player; pertanto è possibile anche mediante tale Classe eseguire in modo semplice un file Midi impostando nei suoi argomenti il plugin Playbin.
Mostriamo un esempio pratico in un'applicazione a riga di comando:
Public Sub Main() Dim pl As MediaPipeline Dim s As String pl = New MediaPipeline(Null, "playbin") pl["uri"] = Media.URL("/percorso/del/file.mid") pl.Play() ' Utilizziamo la funzione "Input" per consentire l'esecuzione del file Midi, evitando così un eccessivo ' aggravio di lavoro per la CPU. Inoltre, premendo il tasto "Invio" viene interrotta l'esecuzione." Input s pl.Stop pl.Close End
Il plugin "playbin" può anche essere inserito all'interno di un oggetto della Classe MediaControl, la quale rappresenta un Elemento ordinario di GStreamer.
Public Sub Main() Dim pl As MediaPipeline Dim mc As MediaControl Dim s As String pl = New MediaPipeline mc = New MediaControl(pl, "playbin") mc["uri"] = Media.URL("/percorso/del/file.mid") pl.Play() ' Utilizziamo la funzione "Input" per consentire l'esecuzione del file Midi, evitando così un eccessivo ' aggravio di lavoro per la CPU. Inoltre, premendo il tasto "Invio viene interrotta l'esecuzione." Input s pl.Stop pl.Close End
Usare i plugin di GStreamer con le Classi MediaControl e MediaPipeline per eseguire i file MIDI
E' possibile eseguire i file MIDI utilizzando specifici plugin di GStreamer con le Classi MediaControl e MediaPipeline. [Nota 2]
Usando il plugin "decodebin"
E' possibile utilizzare il plugin "decodebin" di GStreamer:
Private bo As Boolean Public Sub Main() Dim pl As MediaPipeline Dim src, dcb, con, vol, snk As MediaControl pl = New MediaPipeline As "PLine" src = New MediaControl(pl, "filesrc") src["location"] = "/percorso/del/file/midi" dcb = New MediaControl(pl, "decodebin") con = New MediaControl(pl, "audioconvert") vol = New MediaControl(pl, "volume") ' <1.0 = volume <100% | 1.0 = volume 100% | >1.0 = volume >100% vol["volume"] = 0.5 snk = New MediaControl(pl, "autoaudiosink") src.LinkTo(dcb) dcb.LinkLaterTo(con) con.LinkTo(vol) vol.LinkTo(snk) pl.Play() Repeat Write "\rTempo Trascorso: " & Str(Time(0, 0, 0, pl.Position * 1000)) Wait 0.01 Until bo pl.Close() End Public Sub PLine_End() bo = True End
Usando i plugin specifici di GStreamer per il Midi
I plugin specifici di GStreamer utilizzabili per il MIDI sono:
- midiparse: interpreta i file MIDI e li converte in eventi MIDI;
- fluiddec: effettua il render degli eventi MIDI in campioni audio grezzi.
Mostriamo di seguito un esempio in ambiente grafico per l'esecuzione dei file MIDI, nel quale sarà possibile impostare i valori della frequenza di campionamento (rate) e dei canali, nonché modificare in tempo reale mediante tre Slider la tonalità, il tempo di esecuzione e il volume d'uscita. Le due impostazioni relative alla tonalità e al tempo di esecuzione verranno effettuate con il plugin "pitch", considerando che:
- per impostare la tonalità si userà l'omonima proprietà "pitch": il valore di partenza predefinito è 1.00;
- per impostare la velocità del tempo di esecuzione si userà la proprietà "tempo": il valore di partenza predefinito è 1.00 .
Private pl As MediaPipeline Private pit As MediaControl Private vol As MediaControl Private pitch As Float = 1.00 Private tempo As Float = 1.00 Private volume As Float = 1.00 Private bo As Boolean Public Sub Form_Open() Dim src, par, flu, res, cnv, snk As MediaControl Dim flt As MediaFilter pl = New MediaPipeline src = New MediaControl(pl, "filesrc") src["location"] = "/percorso/del/file.mid" par = New MediaControl(pl, "midiparse") flu = New MediaControl(pl, "fluiddec") cnv = New MediaControl(pl, "audioconvert") pit = New MediaControl(pl, "pitch") res = New MediaControl(pl, "audioresample") flt = New MediaFilter(pl, "audio/x-raw,rate=44100,channels=2") vol = New MediaControl(pl, "volume") snk = New MediaControl(pl, "alsasink") ' Volendo, è possibile utilizzare anche il plugin "autoaudiosink" al posto di "alsasink". ' In tal caso, però, non sarà necessario utilizzare il plugin "audioconvert". src.LinkTo(par) par.LinkTo(flu) flu.LinkTo(cnv) cnv.LinkTo(pit) pit.LinkTo(res) res.LinkTo(flt) flt.LinkTo(vol) vol.LinkTo(snk) ' Imposta alcuni valori dei due "Slider": With Slider1 .MinValue = 0 .MaxValue = 1000 .Value = 100 End With With Slider2 .MinValue = 0 .MaxValue = 1000 .Value = 100 End With With Slider3 .MinValue = 0 .MaxValue = 1000 .Value = 100 End With End Public Sub Button1_Click() pl.Play() ' Consente che, qualora sia stata arrestata l'esecuzione, il conteggio possa ricominciare da zero: bo = False While (pl.Duration > pl.Position) And (bo = False) Write "\rDurata: " & Str(Time(0, 0, 0, pl.Duration * 1000)) & " Tempo trascorso: " & Str(Time(0, 0, 0, pl.Position * 1000)) Wait 0.01 Wend End Public Sub Button2_Click() pl.Stop() pl.Close() bo = True End Public Sub Slider1_Change() pitch = Slider1.Value / 100 pit["pitch"] = pitch ValueBox1.Value = pitch End Public Sub Slider2_Change() tempo = Slider2.Value / 100 pit["tempo"] = tempo ValueBox2.Value = tempo End Public Sub Slider3_Change() volume = Slider3.Value / 100 vol["volume"] = volume ' "volume" è una proprietà dell'omonimo plugin "volume" ValueBox3.Value = volume End
Mostriamo di seguito un semplice esempio con applicazione a riga di comando:
Private bo As Boolean Public Sub Main() Dim pl As MediaPipeline Dim src, par, flu, cnv, vol, snk As MediaControl pl = New MediaPipeline As "PLine" src = New MediaControl(pl, "filesrc") src["location"] = "/percorso/del/file.mid" par = New MediaControl(pl, "midiparse") flu = New MediaControl(pl, "fluiddec") cnv = New MediaControl(pl, "audioconvert") vol = New MediaControl(pl, "volume") ' <1.0 = volume <100% | 1.0 = volume 100% | >1.0 = volume >100% vol["volume"] = 0.5 snk = New MediaControl(pl, "alsasink") src.LinkTo(par) par.LinkTo(flu) flu.LinkTo(cnv) cnv.LinkTo(vol) vol.LinkTo(snk) pl.Play() Print "Durata del file Midi: "; Str(Time(0, 0, 0, pl.Duration * 1000)) While Not bo Write "\r\e[0mTempo trascorso: \e[31m" & Str(Time(0, 0, 0, pl.Position * 1000)) Wait 0.01 Wend pl.Close() Write "\n\e[0mEsecuzione terminata !" End Public Sub PLine_End() bo = True End
Impostare il file soundbank dei suoni per il Midi
E' possibile scegliere il file soundbank che consente l'ascolto dei suoni dal Midi, bisognerà utilizzare la proprietà "soundfont " del plugin "fluiddec" di GStreamer, assegnandole il percorso del file sf2 o sf3 desiderato.
Riprendendo il codice di sopra a riga di comando avremo dunque:
flu = New MediaControl(pl, "fluiddec") flu["soundfont"] = "/percorso/del/file.sf2"
Interfacciare le Classi MediaControl e MediaPipeline con il plugin "jackaudiosink" di GStreamer per eseguire i file Midi
Per eseguire i file Midi con le Classi MediaControl e MediaPipeline è possibile anche effettuare un interfacciamento tra il programma Gambas e il server audio JACK. Per fare ciò, ci si servirà dell'apposito plugin di GStreamer, chiamato "jackaudiosink".
Ovviamente bisognerà avere l'accortezza di avviare il server Jack (per esempio avviando il programma qjackctl) prima di lanciare il programma Gambas.
All'avvio del programma viene creata dal server Jack una connessione tra il programma sorgente Gambas e la destinazione (di default il primo canale audio d'uscita disponibile della propria scheda audio).
Mostriamo un semplice esempio di esecuzione di un file Midi in un'applicazione a riga di comando:
Private bo As Boolean Private pl As MediaPipeline Public Sub Main() Dim src, par, flu, cnv, snk As MediaControl pl = New MediaPipeline As "PLine" src = New MediaControl(pl, "filesrc") src["location"] = "/percorso/del/file.mid" par = New MediaControl(pl, "midiparse") flu = New MediaControl(pl, "fluiddec") snk = New MediaControl(pl, "jackaudiosink") src.LinkTo(prs) prs.LinkTo(flu) flu.LinkTo(snk) pl.Play() Print "Durata del file Midi: "; Str(Time(0, 0, 0, pl.Duration * 1000)) Repeat Write "\r\e[0mTempo trascorso: \e[31m" & Str(Time(0, 0, 0, pl.Position * 1000)) Wait 0.01 Until bo = True pl.Stop() pl.Close() Write "\n\e[0mEsecuzione terminata !" End Public Sub PLine_End() bo = True End
Note
[1] La stesura di paragrafo è stata possibile anche grazie al fondamentale apporto e studio del membro allegfede del forum gambas-it.org .
[2] Si rinvia come riferimento alla seguente pagina web: https://github.com/Xilinx/gstreamer/blob/master/docs/random/uraeus/gstreamer_and_midi.txt