Differenze tra le versioni di "Modificare la frequenza di campionamento di un file audio con l' API di Libsamplerate e Libsndfile"

Da Gambas-it.org - Wikipedia.
Riga 1: Riga 1:
La libreria '''SampleRate'' consente, fra l'altro, di modificare la frequenza di campionamento (''Sample Rate'') di un file audio.
+
La libreria '''SampleRate''' consente, fra l'altro, di modificare la frequenza di campionamento (''Sample Rate'') di un file audio.
  
 
Per poter fruire in Gambas delle risorse della libreria ''Libsamplerate'', bisognera installare e richiamare la libreria dinamica condivisa: "''libsamplerate.so.0.1.8''"
 
Per poter fruire in Gambas delle risorse della libreria ''Libsamplerate'', bisognera installare e richiamare la libreria dinamica condivisa: "''libsamplerate.so.0.1.8''"

Versione delle 20:47, 8 gen 2015

La libreria SampleRate consente, fra l'altro, di modificare la frequenza di campionamento (Sample Rate) di un file audio.

Per poter fruire in Gambas delle risorse della libreria Libsamplerate, bisognera installare e richiamare la libreria dinamica condivisa: "libsamplerate.so.0.1.8"


Nell'esempio che segue si farà uso anche della libreria SndFile.

Private Enum SEEK_SET = 0, SEEK_CUR, SEEK_END


Library "libsamplerate:0.1.8"

Public Struct SRC_DATA
  data_in As Pointer
  data_out As Pointer
  input_frames As Long
  output_frames As Long
  input_frames_used As Long
  output_frames_gen As Long
  end_of_input As Integer
  src_ratio As Float
End Struct

' Tipo di interpolatore (Medium_Sinc_Interpolator = default)
Private Enum Best_Sinc_Interpolator = 0, Medium_Sinc_Interpolator, Fastest_Sinc_Interpolator, ZOH_Interpolator, Linear_Interpolator

' int src_is_valid_ratio (double ratio)
' Return TRUE if ratio is a valid conversion ratio.
Private Extern src_is_valid_ratio(ratio As Float) As Boolean

' const char *src_get_name (int converter_type)
' Return a string giving either a name or a more full description of each sample rate converter.
Private Extern src_get_name(converter_type As Integer) As String

' SRC_STATE* src_new (int converter_type, int channels, int *error)
' Standard initialisation function.
Private Extern src_new(converter_type As Integer, channels As Integer, errorP As Pointer) As Pointer

' const char* src_strerror (int error)
' Convert the error number into a string.
Private Extern src_strerror(errorI As Integer) As String

' int src_process (SRC_STATE *state, SRC_DATA *data)
' Standard processing function.
Private Extern src_process(state As Pointer, data As SRC_DATA) As Integer

' SRC_STATE* src_delete (SRC_STATE *state)
' Cleanup all internal allocations.
Private Extern src_delete(state As Pointer) As Pointer


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

Private Const SFM_READ As Integer = &10
Private Const SFM_WRITE As Integer = &20
Private Const SFC_SET_ADD_PEAK_CHUNK As Integer = &1050
Private Const SFC_SET_UPDATE_HEADER_AUTO As Integer = &1061
Private Const SFC_SET_CLIPPING As Integer = &10C0

' 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, SFinf As SF_INFO) As Pointer

' int sf_command (SNDFILE *sndfile, int command, void *data, int datasize)
' Return TRUE if fields of the SF_INFO struct are a valid combination of values.
Private Extern sf_command(snd As Pointer, command As Integer, data As Pointer, datasize As Boolean)

' sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence)
' Seek within the waveform data chunk of the SNDFILE.
Private Extern sf_seek(snd As Pointer, frames As Long, whence As Integer) As Long

' sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames)
' Reads the data chunk in terms of frames. Passes data in the native float format.
Private Extern sf_readf_float(snd As Pointer, ptr As Single[], frames As Long) As Long

' sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames)
' Writes the data chunk in terms of frames. Passes data in the native float format.
Private Extern sf_writef_float(snd As Pointer, ptr As Single[], frames As Long) As Long

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


Public Sub Main()

 Dim infile, outfile As Pointer
 Dim sfinfo As New SF_INFO
 Dim count As Long
 Dim new_sample_rate, converter As Integer
 Dim src_ratio, gain As Float
 Dim max_speed As Boolean
 Dim FileAudioIn As String = "/percorso/del/file/audio/originario"
 Dim FileAudioOut As String = "/percorso/del/file/audio/modificato"
 
  src_ratio = -1.0
  gain = 1.0
  converter = Medium_Sinc_Interpolator

' Imposta la nuova frequenza di campionamento da assegnare al file audio:
  new_sample_rate = 11050
   
  infile = sf_open(FileAudioIn, SFM_READ, sfinfo)
  If IsNull(infile) Then Error.Raise("Impossibile aprire il file audio in entrata !")
   
  Print "File audio in entrata: ", Null; FileAudioIn
  Print "Frequenza campio.nto: ", Null; sfinfo.samplerate
  Print "Frame in ingresso: ", Null; CLong(sfinfo.frames)
   
  If new_sample_rate > 0 Then
    src_ratio = (1.0 * new_sample_rate) / sfinfo.samplerate
    sfinfo.samplerate = new_sample_rate
  Else If src_is_valid_ratio(src_ratio)
    sfinfo.samplerate = CInt(Floor(sfinfo.samplerate * src_ratio))
  Else
    Error.Raise("Impossibile determinare la nuova frequenza di campionamento !")
  Endif
   
  Print "\nSRC Ratio: ", Null, src_ratio
  Print "Converter: ", Null, src_get_name(converter)
   
  If src_is_valid_ratio(src_ratio) = 0 Then Error.Raise("Modifica della frequenza di campionamento al di fuori dell'ambito dei valori consentiti !")
   
  Print "\nFile audio in uscita: ", Null; FileAudioOut
  Print "Frequenza campio.nto: ", Null; sfinfo.samplerate
    
  outfile = sf_open(FileAudioOut, SFM_WRITE, sfinfo)
  If IsNull(outfile) Then Error.Raise("Impossibile aprire il file d'uscita !")

  If max_speed Then
    sf_command(outfile, SFC_SET_ADD_PEAK_CHUNK, Null, False)
  Else
' Aggiorna il file header dopo la scrittura dei nuovi dati audio:
    sf_command(outfile, SFC_SET_UPDATE_HEADER_AUTO, Null, True)
  Endif

  sf_command(outfile, SFC_SET_CLIPPING, Null, True)

  count = Conversione_Frequenza(infile, outfile, converter, src_ratio, sfinfo.channels, VarPtr(gain))
   
  Print "Frames d'uscita: ", Null; CLong(count)

  sf_close(infile)
  sf_close(outfile)

End


Private Function Conversione_Frequenza(infile As Pointer, outfile As Pointer, converter As Integer, src_ratio As Float, channels As Integer, gain As Pointer) As Long
 
 Dim inputS, outputS As New Single[4096]
 Dim err As Integer
 Dim maxF, gm As Float
 Dim output_count As Long
 Dim src_state As Pointer
 Dim srcData As New SRC_DATA
 
  sf_seek(infile, 0, SEEK_SET)
  sf_seek(outfile, 0, SEEK_SET)
  
' Inizializza il convertitore di frequenza:
  src_state = src_new(converter, channels, VarPtr(err))
  If IsNull(src_state) Then Error.Raise("Impossibile inizializzare il convertitore di frequenza !")
   
  srcData.data_in = inputS.Data

  srcData.src_ratio = src_ratio

  srcData.data_out = outputS.Data

  srcData.output_frames = 4096 / channels
   
  While True

' Se il buffer d'ingresso è vuoto, viene riempito:
    If srcData.input_frames == 0 Then
      srcData.input_frames = sf_readf_float(infile, inputS, 4096 / channels)
      srcData.data_in = inputS.Data
      If srcData.input_frames < 4096 / channels Then srcData.end_of_input = 1
    Endif
      
    err = src_process(src_state, srcData)
    If err <> 0 Then Error.Raise("Errore: " & src_strerror(err))
     
' Termina il ciclo se ilprocesso è completato:
    If srcData.end_of_input And srcData.output_frames_gen = 0 Then Break
     
    maxF = Applica_Gain(srcData.data_out, srcData.output_frames_gen, channels, maxF, Float@(gain))
     
' Scrive i dati in uscita:
    sf_writef_float(outfile, outputS, srcData.output_frames_gen)
    output_count += srcData.output_frames_gen
     
    srcData.data_in += srcData.input_frames_used * channels
    srcData.input_frames -= srcData.input_frames_used
     
  Wend
   
  src_state = src_delete(src_state)
   
  If maxF > 1.0 Then
    gm = 1.0 / maxF
    gain = VarPtr(gm)
    Error.Raise("Il risultato ha prodotto distorsione della forma d'onda !\nRiavviare la conversione per evitarla.")
  Endif

  Return output_count
 
End


Private Function Applica_Gain(data As Pointer, frames As Long, channels As Integer, maxF As Float, gain As Float) As Float
 
 Dim k As Long
 Dim st As Stream
 Dim f As Float
 
  st = Memory data For Read Write
 
  For k = 0 To (frames * channels) - 1
    Read #st, f
    f *= gain
    Seek #st, Seek(st) - 8
    Write #st, f As Float
    If Abs(f) > maxF Then maxF = Abs(f)
  Next
   
  st.Close

  Return maxF  
 
End



Riferimenti