Modificare la frequenza di campionamento di un file audio con l' API di Libsamplerate e Libsndfile
Da Gambas-it.org - Wikipedia.
Versione del 16 dic 2014 alle 19:44 di Vuott (Discussione | contributi) (Creata pagina con '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 d...')
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