Analizzare il valore RMS, il picco e il decay dei dati audio mediante il plugin 'level'usando una linea di pipeline con la funzione 'gst parse launch()'

Da Gambas-it.org - Wikipedia.

Il plug-in Level fornito dalla libreria GStreamer analizza i buffer audio in arrivo e, se la proprietà "message" è vera, esso genera un messaggio denominato "Element", dal quale è possibile estrarre alcuni valori attinente ai dati audio medesimi, come ad esempio il valore RMS, il valore di picco e il valore di decay.
Con la proprietà "intervall " del plug-in "level" è possibile impostare il valore dell'intervallo di tempo riferito ai dati da analizzare. L'impostazione predefinita è 1/10 di secondo. Si suggerisce di non scendere al di sotto di 1 millisecondo, pena la possibilità di un blocco del sistema !

E' necessario avere installata nel proprio sistema e richiamare nel progetto Gambas la libreria dinamica condivisa: "libgstreamer-1.0.so "

Mostriamo di seguito un semplice esempio, nel quale verranno analizzati i dati audio di un file WAV. L'intervallo temporale dei dati da analizzare sarà impostato a 1 millisecondo.

Library "libgstreamer-1.0"

Public Struct GValueArray
  n_values As Integer
  values As Pointer
End Struct

Private Enum GST_STATE_VOID_PENDING = 0, GST_STATE_NULL, GST_STATE_READY, GST_STATE_PAUSED, GST_STATE_PLAYING
Private Const GST_MESSAGE_ERROR As Integer = 2
Private Const GST_MESSAGE_ELEMENT As Integer = 32768

' gst_init (int *argc, char **argv[])
' Initializes the GStreamer library, setting up internal path lists, registering built-in elements, and loading standard plugins.
Private Extern gst_init(argc As Pointer, argv As Pointer)

' GMainLoop * g_main_loop_new (GMainContext *context, gboolean is_running)
' Creates a new GMainLoop structure.
Private Extern g_main_loop_new(context As Pointer, is_running As Boolean) As Pointer

' GstElement * gst_parse_launch (const gchar *pipeline_description, GError **error)
' Create a new pipeline based on command line syntax.
Private Extern gst_parse_launch(description As String, gerror As Pointer) As Pointer

' GstBus * gst_pipeline_get_bus (GstPipeline *pipeline)
' Gets the GstBus of pipeline.
Private Extern gst_pipeline_get_bus(pipeline As Pointer) As Pointer

' guint gst_bus_add_watch (GstBus *bus, GstBusFunc func, gpointer user_data)
' Adds a bus watch to the default main context with the default priority.
Private Extern gst_bus_add_watch(bus As Pointer, func As Pointer, user_data As Pointer) As Integer

' GstStateChangeReturn gst_element_set_state(GstElement *element, GstState state)
' Sets the state of the element.
Private Extern gst_element_set_state(element As Pointer, state As Integer) As Integer

' void g_main_loop_run (GMainLoop *loop)
' Runs a main loop until g_main_loop_quit() is called on the loop.
Private Extern g_main_loop_run(gloop As Pointer)

' const gchar * gst_structure_get_name (const GstStructure *structure)
' Get the name of structure as a string.
Private Extern gst_structure_get_name(gstructure As Pointer) As String

' const GstStructure * gst_message_get_structure (GstMessage *message)
' Access the structure of the message.
Private Extern gst_message_get_structure(message As Pointer) As Pointer

' gpointer g_value_get_boxed (const GValue *value)
' Get the contents of a G_TYPE_BOXED derived GValue.
Private Extern g_value_get_boxed(value As Pointer) As Pointer

' const GValue * gst_structure_get_value (const GstStructure *structure, const gchar *fieldname)
' Get the value of the field with name fieldname.
Private Extern gst_structure_get_value(gstructure As Pointer, fieldname As String) As Pointer

' GValue * g_value_array_get_nth (GValueArray *value_array, guint index_)
' Return a pointer to the value at index_ containd in value_array.
Private Extern g_value_array_get_nth(value_array As GValueArray, index As Integer) As Pointer

' gdouble g_value_get_double (const GValue *value)
' Get the contents of a G_TYPE_DOUBLE GValue.
Private Extern g_value_get_double(value As Pointer) As Float

' gboolean gst_structure_get_clock_time (const GstStructure *structure, const gchar *fieldname, GstClockTime *value)
' Sets the clock time pointed to by value corresponding to the clock time of the given field.
Private Extern gst_structure_get_clock_time(gstructure As Pointer, fieldname As String, value As Pointer) As Boolean

' void gst_object_unref(gpointer object)
' Decrements the reference count on object.
Private Extern gst_object_unref(gobject As Pointer)


Public Sub Main()
 
 Dim lp, lev, bs As Pointer
 Dim fileaudio As String
 
 fileaudio = "/percorso/del/file.wav"
   
 gst_init(0, 0)
  
 lp = g_main_loop_new(0, False)
 If lp == 0 Then Error.Raise("Errore !")
  
' Imposta gli elementi necessari per l'analisi del file audio:
 lev = gst_parse_launch("filesrc location=" & fileaudio & " ! wavparse ! audioconvert ! level interval=1000000 ! audio/x-raw,channels=2 ! fakesink", 0)
 If lev == 0 Then Error.Raise("Errore !")
  
' Poiché l'elemento "level" inserisce i propri risultati nel puntatore "GstBus", è necessario estrapolarlo dalla pipeline:
 bs = gst_pipeline_get_bus(lev)
 If bs == 0 Then Error.Raise("Errore !")
  
' Resta in osservazione se è pronto un messaggio nel bus, nel qual caso invoca la funzione "Gestione_messaggio_bus()":
 Print gst_bus_add_watch(bs, Gestione_messaggio_bus, lp)
  
' Avvia l'analisi del file audio:
 gst_element_set_state(lev, GST_STATE_PLAYING)
  
' Avvia un loop infinito:
 g_main_loop_run(lp)
  
End


Public Function Gestione_messaggio_bus(bus As Pointer, msg As Pointer, data As Pointer) As Boolean
 
 Dim gst, GValue As Pointer
 Dim rms, rms_dB, peak_dB, decay_dB As Float
 Dim rms_arr, peak_arr, decay_arr As GValueArray
 Dim channels, i As Integer
 Dim endtime As Long
  
 Select Case Int@(msg + 64)        ' GstMessage->type
   Case GST_MESSAGE_ELEMENT
     gst = gst_message_get_structure(msg)
     If gst_structure_get_name(gst) = "level" Then
       rms_arr = g_value_get_boxed(gst_structure_get_value(gst, "rms"))
       peak_arr = g_value_get_boxed(gst_structure_get_value(gst, "peak"))
       decay_arr = g_value_get_boxed(gst_structure_get_value(gst, "decay"))
       channels = rms_arr.n_values
        
       Print "\e[1mNumero canali audio: "; channels
      
       For i = 0 To channels - 1
         Print "\e[0m\e[5mCanale: "; i
         GValue = g_value_array_get_nth(rms_arr, i)
         rms_dB = g_value_get_double(GValue)
         
         GValue = g_value_array_get_nth(peak_arr, i)
         peak_dB = g_value_get_double(GValue)
         
         GValue = g_value_array_get_nth(decay_arr, i)
         decay_dB = g_value_get_double(GValue)
         Print "\e[0m    RMS: "; rms_dB; " dB, picco: "; peak_dB; " dB, decay: "; decay_dB; " dB"
         
' Converte da dB a normale dando un valore compreso tra 0,0 e 1,0:
         rms = (10 ^ (rms_dB / 20))
         Print "    Valore rms normalizzato: "; rms
         
         If gst_structure_get_clock_time(gst, "endtime", VarPtr(endtime)) = False Then
           Print "Attenzione: impossibile analizzare 'endtime' !"
         Else
           Print "endtime: "; CStr(Time(0, 0, 0, CInt(endtime / 1000000)))
         Endif
         Wait 0.01
         Print
       Next
     Endif
   Case GST_MESSAGE_ERROR
     Print "Errore durante l'analisi del file audio !"
 End Select
  
 Return True
  
End


Riferimenti