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".
La classe MediaPlayer
Si utilizzeranno i metodi specifici della Classe MediaPlayer del componente gb.media.
Utilizzo in un'applicazione grafica
Ecco di seguito un semplicissimo codice per lanciare ed ascoltare uno standard file Midi (.mid) in un'applicazione grafica utilizzando un Timer.
Porremo sul Form del progetto:
- tre Button per avviare, mettere in pausa ed arrestare l'esecuzione del file Midi;
- un Timer che ci consentirà di calcolare il tempo trascorso;
- un RadioButton per far ripetere a volontà il medesimo file Midi:
Private mp As New MediaPlayer Public Sub Form_Open() ' Carica il file Midi .mid: mp.URL = Media.URL("/percorso/del/file.mid") ' Facciamo in modo che il "Timer", alla sua prima attivazione, parta senza alcun ritardo: Timer1.Delay = 1 End Public Sub Button1_Click() suona() End Public Sub suona() ' Avvia l'ascolto del file Midi: mp.Play With Timer1 .Start ' Il "Timer" si attiva ogni 70 millesimi di secondo: .Delay = 70 End With End Public Sub Button2_Click() ' Mette in "pausa" l'ascolto del file Midi. ' (Per continuare l'ascolto del file, si dovrà nuovamente attivare la proprietà ".Play"): mp.Pause End Public Sub Button3_Click() RadioButton1.Value = False ' Chiama la funzione per arrestare l'esecuzione del file Midi: arresta() End Public Sub arresta() ' Arresta l'ascolto del file Midi: mp.Stop Timer1.Stop ' Se è stato cliccato sul "RadioButton", verrà ripetuta l'esecuzione del file Midi: If RadioButton1.Value Then mp.Position = 0 suona() Else ' Arresta l'ascolto del file audio: mp.Stop Endif End Public Sub Timer1_Timer() ' Mostra in console la posizione, espressa in secondi, all'interno dei dati processati: Write #File.Out, "\rDurata del brano: " & CStr(Date(0, 0, 0, 0, 0, 0, mp.Duration * 1000)) & " - Tempo trascorso: " & CStr(Date(0, 0, 0, 0, 0, 0, mp.Position * 1000)) ' Se la posizione corrente è uguale o maggiore della durata complessiva del brano Midi, ' allora arresta l'esecuzione del file Midi (altrimenti non sarà possibile riavviarlo semplicemente ri-clkiccando sul "Button1"): If mp.Position >= mp.Duration Then arresta() End
In quest'altro esempio, simile al precedente, verrà utilizzato un ciclo al posto di un oggetto Timer:
Private mp As New MediaPlayer Public Sub Form_Open() ' Carica un file Midi: mp.URL = Media.URL("/percorso/mio/file.mid") End Public Sub Button1_Click() suona() End Public Sub suona() ' Avvia l'ascolto del file Midi: mp.Play Do ' Una brevissima pausa consente di agire sugli eventuali oggetti posti sul Form: Wait 0.01 Write #File.Out, "\rDurata del brano: " & CStr(Date(0, 0, 0, 0, 0, 0, mp.Duration * 1000)) & " - Tempo trascorso: " & CStr(Date(0, 0, 0, 0, 0, 0, mp.Position * 1000)) Loop Until mp.Position >= mp.Duration arresta() End Public Sub Button2_Click() ' Mette in "pausa" l'ascolto del file Midi. ' (Per continuare l'ascolto del file, si dovrà nuovamente attivare la proprietà ".Play"). mp.Pause End Public Sub Button3_Click() RadioButton1.Value = False mp.Position = mp.Duration + 1 End Public Sub arresta() ' Se è stato cliccato sul "RadioButton", verrà ripetuta l'esecuzione del file Midi: If RadioButton1.Value Then mp.Position = 0 suona() Else ' Altrimenti arresta l'ascolto del file Midi: mp.Stop Endif End
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:
Public Sub Main() Dim mp As MediaPlayer With mp = New MediaPlayer .URL = Media.URL("/percorso/mio/file.mid") .Play End With Do ' Mostra in console la posizione, espressa in secondi, all'interno dei dati processati: Write #File.Out, "\rDurata del brano: " & CStr(Date(0, 0, 0, 0, 0, 0, mp.Duration * 1000)) & " - Tempo trascorso: " & CStr(Date(0, 0, 0, 0, 0, 0, mp.Position * 1000)) Loop Until mp.Position >= mp.Duration mp.Stop End
La proprietà .Duration
La proprietà .Duration restituisce un valore di tipo Float che rappresenta la durata del brano musicale espresso in secondi.
Poiché detta proprietà ritorna più precisamente la durata dei dati processati, essa potrà essere utilizzabile solo successivamente all'attivazione della funzione .Play. Per essere funzionante in modo automatico, potrà essere posta all'interno di una routine di attivazione di un Timer (vedi esempio precedente).
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 la durata del file è terminata.
Gli effetti video con i plug-in
E' possibile ottenere simpatici effetti video utilizzando i plug-in resi disposibili da GStreamer.
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] ' Anche qui viene impostata la "DrawingArea", ove mostrare gli effetti video: uscitaVideo.SetWindow(drar) End Public Sub Form_Activate() ' Esegue il file Midi: mp.Play() 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.
Questa 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 pl = New MediaPipeline(Null, "playbin") pl["uri"] = Media.URL("/percorso/del/file.mid") pl.State = Media.Playing 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 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 pl = New MediaPipeline mc = New MediaControl(pl, "playbin") mc["uri"] = Media.URL("/percorso/del/file.mid") pl.State = Media.Playing 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 End
Utilizzare 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.
I plugin specifici da utilizzare 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 per l'esecuzione dei file MIDI:
Public Sub Main() Dim pl As MediaPipeline Dim src, mprs, fdc, cnv, snk As MediaControl pl = New MediaPipeline src = New MediaControl(pl, "filesrc") src["location"] = "/percorso/del/file.mid" ' "location" è una proprietà del plugin "filesrc" mprs = New MediaControl(pl, "midiparse") fdc = New MediaControl(pl, "fluiddec") cnv = New MediaControl(pl, "audioconvert") snk = New MediaControl(pl, "alsasink") src.LinkTo(mprs) mprs.LinkTo(fdc) fdc.LinkTo(cnv) cnv.LinkTo(snk) pl.Play() Sleep 1 While pl.Duration > pl.Position Write #File.Out, "\rDurata: " & Date(0, 0, 0, 0, 0, 0, pl.Duration * 1000) & " Tempo trascorso: " & Date(0, 0, 0, 0, 0, 0, pl.Position * 1000) Wend End