Modificare la frequenza di campionamento di un file audio con l'API di Libresample e Libsndfile
Da Gambas-it.org - Wikipedia.
Versione del 13 gen 2024 alle 17:33 di Vuott (Discussione | contributi)
La libreria Libresample, creata da Dominic Mazzoni, consente di modificare la frequenza di campionamento (Sample Rate) di un file audio.
Per poter fruire in Gambas delle risorse della libreria Libresample, bisognera installare e richiamare la libreria condivisa: "libresample.so.1.0 ".
Nell'esempio che segue si farà uso anche della libreria "libsndfile.so.1.0.37 ".
Library "libresample:1.0" ' void *resample_open(int highQuality, double minFactor, double maxFactor) Private Extern resample_open(highQuality As Integer, minFactor As Float, maxFactor As Float) As Pointer ' int resample_process(void *handle, double factor, float *inBuffer, int inBufferLen, int lastFlag, int *inBufferUsed, float *outBuffer, int outBufferLen) Private Extern resample_process(handleP As Pointer, factor As Float, inBUffer As Single[], inBufferLen As Integer, lastFlag As Integer, inBufferUsed As Pointer, outBuffer As Single[], outBufferLen As Integer) As Integer Library "libsndfile:1.0.37" Public Struct SF_INFO frames As Long samplerate As Integer channels As Integer format_ As Integer sections As Integer seekable As Integer End Struct Public Struct SF_FORMAT_INFO format_ As Integer name As Pointer extension As Pointer End Struct Private Const SFM_READ As Integer = &10 Private Const SFM_WRITE As Integer = &20 Private Enum SFC_GET_FORMAT_MAJOR_COUNT = &1030, SFC_GET_FORMAT_MAJOR Private Const SF_FORMAT_SUBMASK As Integer = &0000FFFF ' 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 Integer) ' 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 srcinfo, dstinfo As New SF_INFO Dim formatinfo As New SF_FORMAT_INFO Dim srcfile, dstfile, p As Pointer Dim dsti, src, dst, srci As Single[] Dim handle As Pointer[] Dim dstrate, srcrate, ratio As Float Dim channels, numformats, i, c, srclen, dstlen As Integer Dim pos, bufferpos, outcount, block, lastFlag As Integer Dim inUsed, inused2, out, out2 As Integer Dim extension As String Dim FileAudioIn As String = "/percorso/del/file/audio/originario" Dim FileAudioOut As String = "/percorso/del/file/audio/finale/modificato" ' Imposta la nuova frequenza di campionamento del file audio: dstrate = 22050.00 If (dstrate < 10.0) Or (dstrate > 100000.0) Then Error.Raise("Valore della frequenza di campionamento non consentita !") srcfile = sf_open(FileAudioIn, SFM_READ, srcinfo) If srcfile == 0 Then Error.Raise("Impossibile aprire il file audio in entrata !") Print "File audio in entrata: "; FileAudioIn Print "Frequenza campionamento: "; srcinfo.samplerate; " Hertz" Print "Canali n. "; srcinfo.channels srcrate = srcinfo.samplerate If dstrate = 0.0 Then dstrate = srcrate * ratio Else ratio = dstrate / srcrate Endif channels = srcinfo.channels ' Estrae il formato del file di destinazione: extension = File.Ext(FileAudioOut) If "." & extension Then sf_command(Null, SFC_GET_FORMAT_MAJOR_COUNT, VarPtr(numformats), SizeOf(gb.Integer)) Print "\nLa libreria 'libresample' supporta "; numformats; " formati audio: " p = Alloc(Object.SizeOf(formatinfo)) For i = 0 To numformats - 1 formatinfo.format_ = i sf_command(Null, SFC_GET_FORMAT_MAJOR, p, Object.SizeOf(formatinfo)) formatinfo = p Print String@(formatinfo.extension); " "; If Not Comp(String@(formatinfo.extension), extension) Then Print "\nSi sta usando "; String@(formatinfo.name); " come formato in uscita." dstinfo.format_ = formatinfo.format_ Or (srcinfo.format_ And SF_FORMAT_SUBMASK) Break Endif Next Free(p) Endif If Not dstinfo.format_ Then If (extension) Then Error.Raise("Attenzione: il formato in uscita " & extension & " non è riconosciuto. Usare lo stesso formato del file originario !") dstinfo.format_ = srcinfo.format_ Endif dstinfo.samplerate = CInt(dstrate + 0.5) dstinfo.channels = channels dstfile = sf_open(FileAudioOut, SFM_WRITE, dstinfo) If dstfile == 0 Then Error.Raise("Impossibile aprire il file audio in uscita !") Print "\n\nFile sorgente: "; FileAudioIn; " ("; srcinfo.frames; " frames, ", srcrate; " Hz)" Print "File destinazione: "; FileAudioOut; " ("; dstrate; " Hz, ratio = "; ratio srclen = 4096 dstlen = (srclen * ratio + 1000) srci = New Single[](srclen * channels * SizeOf(gb.Single)) dsti = New Single[](dstlen * channels * SizeOf(gb.Single)) src = New Single[](srclen * SizeOf(gb.Single)) dst = New Single[](dstlen * SizeOf(gb.Single)) handle = New Pointer[](channels * SizeOf(gb.Pointer)) For c = 0 To channels - 1 handle[c] = resample_open(1, ratio, ratio) Next While pos < srcinfo.frames block = Min(srclen - bufferpos, srcinfo.frames - pos) lastFlag = (pos + block == srcinfo.frames) sf_readf_float(srcfile, srci, block) block += bufferpos For c = 0 To channels - 1 For i = 0 To block - 1 src[i] = srci[i * channels + c] Next inUsed = 0 out = resample_process(handle[c], ratio, src, block, lastFlag, VarPtr(inUsed), dst, dstlen) If c = 0 inUsed2 = inUsed out2 = out Else If (inUsed2 <> inUsed) Or (out2 <> out) Then Error.Raise("Grave errore: canali fuori sincronizzazione !") Endif For i = 0 To out - 1 If dst[i] <= -1 Then dsti[i * channels + c] = -1 Else If dst[i] >= 1 dsti[i * channels + c] = 1 Else dsti[i * channels + c] = dst[i] Endif Next Next sf_writef_float(dstfile, dsti, out) bufferpos = block - inUsed For i = 0 To i < (bufferpos * channels) - 1 srci[i] = srci[i + (inUsed * channels)] pos += inUsed outcount += out Next Wend ' Va in chiusura: sf_close(srcfile) sf_close(dstfile) End