Convertire un file audio mpeg in .wav con le funzioni esterne del API di mpg123

Da Gambas-it.org - Wikipedia.

Mostriamo un codice per convertire un file mpeg layers 1, 2 e 3 (ad esempio .mp3) in un file .wav mediante le funzioni esterne del API di mpg123 e della libreria libsndfile.

E' necessario avere installato nel sistema le seguenti librerie: libmpg123.so.0.36.6 e libsndfile.so.1.0.25.

Il codice prevede, fra l'altro, anche un oggetto ListBox, nel quale verranno mostrate alcune informazioni inerenti al file .wav creato:

Library "libmpg123:0.38.4"

Private Const MPG123_OK As Byte = 0
Private Const MPG123_ERR As Short = -1
Private Const MPG123_DONE As Short = -12
Private Const MPG123_ADD_FLAGS As Byte = 2
Private Const MPG123_FORCE_FLOAT As Short = 1024
Private Const SF_FORMAT_WAV As Integer = 65536      ' Microsoft WAV format (little endian default)
Private Const MPG123_ENC_SIGNED_16 As Byte = 208
Private Const SF_FORMAT_PCM_16 As Byte = 2          ' Signed 16 bit data
Private Const SF_FORMAT_FLOAT As Byte = 6           ' 32 bit float data
Private Const SFM_WRITE As Byte = 32                ' Modalità di apertura di un file

' int mpg123_init (void)
' Function to initialise the mpg123 library.
Private Extern mpg123_init() As Integer

' const char* mpg123_plain_strerror (int errcode)
' Return a string describing that error errcode means.
Private Extern mpg123_plain_strerror(errcode As Integer) As String

' mpg123_handle *, mpg123_new (const char *decoder, int *error)
' Create a handle with optional choice of decoder (named by a string)
Private Extern mpg123_new(decoder As String, errorI As Integer) As Pointer

' int mpg123_param (mpg123_handle * mh, Enum mpg123_parms type, long value, double fvalue)
' Set a specific parameter, For a specific mpg123_handle, using a parameter type key chosen From the mpg123_parms enumeration, To the specified value.
Private Extern mpg123_param(mhP As Pointer, type As Integer, valueL As Long, fvalue As Float) As Integer

' int mpg123_open (mpg123_handle * mh, const char * path)
' Open and prepare to decode the specified file by filesystem path. This does not open HTTP urls.
Private Extern mpg123_open(mhP As Pointer, pathFile As String) As Integer

' const char* mpg123_strerror (mpg123_handle * mh)
' Give string describing what error has occured in the context of handle mh.
Private Extern mpg123_strerror(mhP As Pointer) As String

' int mpg123_getformat (mpg123_handle * mh, long * rate, Int * channels, Int * encoding)
' Get the current output format written to the addresses given.
Private Extern mpg123_getformat(mhP As Pointer, ratP As Pointer, channP As Pointer, encodP As Pointer) As Integer

' int mpg123_format_none (mpg123_handle * mh)
' Configure a mpg123 handle to accept no output format at all, use before specifying supported formats with mpg123_format.
Private Extern mpg123_format_none(mhP As Pointer) As Integer

' int mpg123_format (mpg123_handle * mh, long rate, int channels, int encodings)
' Set the audio Format support Of a mpg123_handle
Private Extern mpg123_format(mhP As Pointer, ratInt As Integer, canali As Integer, encodInt As Integer) As Integer

' size_t mpg123_outblock (mpg123_handle * mh)
' The max size of one frame's decoded output with current settings.
Private Extern mpg123_outblock(mhP As Pointer) As Integer

' int mpg123_read (mpg123_handle * mh, unsigned char * outmemory, size_t outmemsize, size_t * done)
' Read from stream and decode up to outmemsize bytes.
Private Extern mpg123_read(mhP As Pointer, outmemory As Pointer, outmemsize As Integer, done As Pointer) As Integer

' int mpg123_encsize (int encoding)
' Return the size (in bytes) of one mono sample of the named encoding
Private Extern mpg123_encsize(encodInt As Integer) As Integer

' int mpg123_close (mpg123_handle * mh)
' Closes the source, if libmpg123 opened it
Private Extern mpg123_close(mhP As Pointer) As Integer

' void mpg123_delete (mpg123_handle * mh)
' Delete handle, mh is either a valid mpg123 handle or NULL
Private Extern mpg123_delete(mhP As Pointer)

' void mpg123_exit (void)
' Function to close down the mpg123 library.
Private Extern mpg123_exit()


Library "libsndfile:1.0.25"

Public Struct SF_INFO
  frames As Long
  samplerate As Integer
  channels As Integer
  formatI As Integer
  sections As Integer
  seekable As Integer
End Struct

' SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo)
' Open the specified file for read, write or both.
Private Extern sf_open(path As String, mode As Integer, sfinStru As SF_INFO) As Pointer

' sf_count_t sf_write_short (SNDFILE *sndfile, short *ptr, sf_count_t items)
' Writes the data chunk in terms of items.
Private Extern sf_write_short(sndfile As Pointer, ptr As Pointer, items As Integer) As Integer

' sf_count_t sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t items)
' Writes the data chunk in terms of items.
Private Extern sf_write_float(sndfile As Pointer, ptr As Pointer, items As Integer) As Integer

' int sf_close (SNDFILE *sndfile)
' Close the SNDFILE and clean up all memory allocations associated with this file.
Private Extern sf_close(sndfile As Pointer) As Integer


Public Sub Main()

 Dim mp3 As String
 Dim err, channels, encoding, buffer_size As Integer
 Dim more_samples, samples, done As Integer
 Dim rate As Long
 Dim mh, buffer, sndfile As Pointer
 Dim sfinfo As New SF_INFO
 
  mp3 = "/percorso/del/file.mp3"
 
 err = mpg123_init()
 If err <> MPG123_OK Then Error.Raise("Configurazione di base errata ! " & mpg123_plain_strerror(err))
 
 mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_FORCE_FLOAT, 0)
 
 mh = mpg123_new(Null, 0)

' Apre il file mpeg in lettura:
 err = mpg123_open(mh, mp3)
 If err <> MPG123_OK Then Error.Raise("Attenzione ! Problemi con 'mpg123': " & mpg123_strerror(mh))
 
 mpg123_getformat(mh, VarPtr(rate), VarPtr(channels), VarPtr(encoding))
 
 mpg123_format_none(mh)

 mpg123_format(mh, rate, channels, encoding)
 
 With sfinfo
   .samplerate = rate
   .channels = channels
   If encoding = MPG123_ENC_SIGNED_16 Then
     .formatI = SF_FORMAT_WAV Or SF_FORMAT_PCM_16
   Else
     .formatI = SF_FORMAT_WAV Or SF_FORMAT_FLOAT
   Endif
 End With
 
 With ListBox1
   .Clear
   .Add("  ********   Creazione del file WAV   ********")
   .Add(Null)
   .Add("Nome:  " & File.BaseName(mp3) & ".wav")
   .Add("Canali =  " & channels)
   .Add("Frequenza =  " & rate & " Hz")
 End With

' Apre il file in scrittura:
   sndfile = sf_open(File.Dir(mp3) &/ File.BaseName(mp3) & ".wav", SFM_WRITE, sfinfo)

 buffer_size = mpg123_outblock(mh)

 buffer = Alloc(buffer_size)

 
 Do
   err = mpg123_read(mh, buffer, buffer_size, VarPtr(done))
   If encoding And MPG123_ENC_SIGNED_16 Then
     more_samples = sf_write_short(sndfile, buffer, done / SizeOf(gb.Short))
   Else
     more_samples = sf_write_float(sndfile, buffer, done / SizeOf(gb.Float))
   Endif
     If (more_samples < 0) Or (more_samples * mpg123_encsize(encoding) <> done) Then
       Error.Raise("Attenzione: è stato scritto un numero di campioni che non corrisponde ai byte ottenuti da 'libmpg123': " & more_samples * mpg123_encsize(encoding) & " <> " & done)
     Endif
   samples += more_samples
 Loop While err = MPG123_OK


 If err <> MPG123_DONE Then
   If err = MPG123_ERR
     Error.Raise("Attenzione: decodifica terminata prematuramente ! " & mpg123_strerror(mh))
   Else
     Error.Raise("Attenzione: decodifica terminata prematuramente ! " & mpg123_plain_strerror(err))
   Endif
 Endif

 sf_close(sndfile)

 samples /= channels
 
 ListBox1.Add("Campioni audio scritti:  " & samples)


' Libera la memoria sinora occupata ed esce dalla libreria:
 Free(buffer)
 mpg123_close(mh)
 mpg123_delete(mh)
 mpg123_exit()

End



Riferimenti