Ottenere un file WAV da un file Midi con le funzioni esterne del API di FluidSynth
Da Gambas-it.org - Wikipedia.
Versione del 13 gen 2024 alle 12:56 di Vuott (Discussione | contributi)
Con le risorse della libreria Libfluidsynth è possibile ottenere un file WAV da un file Midi.
E' necessario avere installata e richiamare in Gambas la libreria condivisa: "libfluidsynth.so.3.0.5 ".
Mostriamo di seguito un esempio a riga di comando:
Library "libfluidsynth:3.0.5" ' fluid_settings_t* new_fluid_settings(void) ' Create a new settings object. Private Extern new_fluid_settings() As Pointer ' fluid_synth_t * new_fluid_synth(fluid_settings_t * settings) ' Create new FluidSynth instance. Private Extern new_fluid_synth(settings As Pointer) As Pointer ' int fluid_is_soundfont(const char * filename) ' Check if a file is a SoundFont file. Private Extern fluid_is_soundfont(filename As String) As Integer ' int fluid_synth_sfload(fluid_synth_t * synth, const char * filename, nt reset_presets) ' Load a SoundFont file. Private Extern fluid_synth_sfload(synth As Pointer, filename As String, reset_presets As Integer) As Integer ' int fluid_settings_getnum(fluid_settings_t* settings, const char *name, double* val) ' Get the numeric value of a named setting. Private Extern fluid_settings_getnum(settings As Pointer, name As String, dval As Pointer) As Integer ' void fluid_synth_set_gain(fluid_synth_t *synth, float gain) ' Set synth output gain value. Private Extern fluid_synth_set_gain(synth As Pointer, gain As Single) ' fluid_player_t* new_fluid_player(fluid_synth_t * synth) ' Create a new MIDI player. Private Extern new_fluid_player(synth As Pointer) As Pointer ' int fluid_is_midifile(const char *filename) ' Check if a file is a MIDI file. Private Extern fluid_is_midifile(filename As String) As Integer ' int fluid_player_add(fluid_player_t * player, Const char * midifile) ' Add a MIDI file to a player queue. Private Extern fluid_player_add(player As Pointer, midifile As String) As Integer ' int fluid_player_play(fluid_player_t * player) ' Activates play mode for a MIDI player if not already playing. Private Extern fluid_player_play(player As Pointer) As Integer ' int fluid_synth_write_s16(fluid_synth_t* synth, int len, void* lout, int loff, int lincr, void* rout, int roff, int rincr) ' Synthesize a block of 16 bit audio samples to audio buffers. Private Extern fluid_synth_write_s16(synth As Pointer, ilen As Integer, luot As Short[], loff As Integer, lincr As Integer, rout As Short[], forr As Integer, rincr As Integer) As Integer ' int fluid_player_get_status(fluid_player_t * player) ' Get MIDI player status. Private Extern fluid_player_get_status(player As Pointer) As Integer ' int delete_fluid_player(fluid_player_t * player) ' Delete a MIDI player instance. Private Extern delete_fluid_player(player As Pointer) As Integer ' int delete_fluid_synth(fluid_synth_t * synth) ' Delete a FluidSynth instance. Private Extern delete_fluid_synth(synth As Pointer) As Integer ' void delete_fluid_settings(fluid_settings_t * settings) ' Delete the provided settings object. Private Extern delete_fluid_settings(settings As Pointer) Public Sub Main() Dim sfb, fileMidi, dati_grezzi As String Dim sett, syn, pl As Pointer Dim i As Integer Dim frequenza As Float Dim buffer, dati As Short[] Dim fl As File ' Imposta il file soundfont-bank che sarà utilizzato: sfb = "/usr/share/sounds/sf2/FluidR3_GM.sf2" ' Verifica se il file caricato è effettivamente un soundfont-bank .sf2: i = fluid_is_soundfont(sfb) If i < 0 Then Error.Raise("Errore: il file non è un soundfont-bank !") ' Imposta il file Midi, dal quale si genererà un file audio wav: fileMidi = "/percorso/del/file.mid" ' Verifica se il file è effettivamente uno file Midi standard: i = fluid_is_midifile(fileMidi) If i < 0 Then Error.Raise("Errore: il file non è un file Midi standard !") sett = new_fluid_settings() If sett == 0 Then Error.Raise("Impossibile creare un oggetto 'settings' !") syn = new_fluid_synth(sett) If syn == 0 Then Error.Raise("Impossibile creare un'istanza di FluidSynth !") i = fluid_synth_sfload(syn, sfb, 1) If i < 0 Then Error.Raise("Impossibile caricare il file soundfont-bank !") fluid_settings_getnum(sett, "synth.sample-rate", VarPtr(frequenza)) ' Imposta il volume del file audio wav finale: fluid_synth_set_gain(syn, 0.5) pl = new_fluid_player(syn) If pl == 0 Then Error.Raise("Impossibile creare un esecutore Midi !") i = fluid_player_add(pl, fileMidi) If i < 0 Then Error.Raise("Errore alla funzione 'fluid_player_add()' !") i = fluid_player_play(pl) If i < 0 Then Error.Raise("Errore alla funzione 'fluid_player_play()' !") dati = New Short[frequenza * 2] Repeat buffer = New Short[frequenza * 2] fluid_synth_write_s16(syn, frequenza, buffer, 0, 2, buffer, 1, 2) dati.Insert(buffer) Until fluid_player_get_status(pl) <> 1 dati_grezzi = "/tmp/dati_grezzi" fl = Open dati_grezzi For Create dati.Write(fl, 0, dati.Count) fl.Close ' Va a generare il file audio wav: Genera_File_wav(frequenza, dati_grezzi) ' Va in chiusura: delete_fluid_player(pl) delete_fluid_synth(syn) delete_fluid_settings(sett) Print "\nTermine creazione del file audio wav." End Private Procedure Genera_File_wav(freq As Float, dati_audio As String) Dim s, ini As String Dim fl As File Dim bh, bb As New Byte[] Dim canali, risoluzione, blal As Byte Dim i, i2, frequenza, brps As Integer s = File.Load(dati_audio) frequenza = CInt(freq) ' Vengono definiti gli elementi fondamentali del blocco d'intestazione del file wav: canali = 2 risoluzione = 16 Print "Caratteristiche del futuro file WAV:" Print "- Frequenza: "; frequenza; " hertz" Print "- Canali: "; canali Print "- Risoluzione: "; risoluzione; " bit" fl = Open "/tmp/audio.wav" For Create ini = "RIFF" bb = Byte[].FromString(ini) i = Len(s) i2 = i + 36 ' Imposta il valore dimensionale di 4 byte a partire dal 5° byte del futuro file: bb.Push(i2 And &FF) bb.Push(Shr(i2 And &FF00&, 8)) bb.Push(Shr(i2 And &FF0000&, 16)) bb.Push(Shr(i2 And &FF000000&, 24)) ' Vengono aggiunti: il tipo di formato di file e l'identificativo del formato del blocco dei dati audio: bb.Insert(bh.FromString("WAVEfmt ")) ' Viene aggiunto il valore della lunghezza dei dati del formato (in questo caso il PCM): bh = [&10, &00, &00, &00] bb.Insert(bh) ' Viene aggiunto il valore del formato audio (1 = PCM): bb.Insert(bh.FromString(Chr(&01) & Chr(&00))) ' Viene aggiunto il numero dei canali di uscita: bb.Insert(bh.FromString(Chr(canali) & Chr(&00))) ' Viene aggiunto il valore della frequenza di campionamento: bb.Push(frequenza And &FF) bb.Push(Shr(frequenza And &FF00&, 8)) bb.Push(Shr(frequenza And &FF0000&, 16)) bb.Push(Shr(frequenza And &FF000000&, 24)) ' Viene aggiunto il valore del "Byte rate per secondo": brps = frequenza * canali * (risoluzione / 8) bb.Push(brps And &FF) bb.Push(Shr(brps And &FF00&, 8)) bb.Push(Shr(brps And &FF0000&, 16)) bb.Push(Shr(brps And &FF000000&, 24)) ' Viene aggiunto il valore del "Block Align": blal = canali * risoluzione / 8 bb.Insert(bh.FromString(Chr(blal) & Chr(&00))) ' Viene aggiunto il valore della risoluzione di campionamento: bb.Insert(bh.FromString(Chr(risoluzione) & Chr(&00))) ' Viene aggiunto l'identificativo del Blocco dei dati audio grezzi: bb.Insert(bh.FromString("data")) ' Imposta il valore dimensionale di 4 byte a partire dal 41° byte del futuro file e relativo alla dimensione dei dati audio grezzi: bb.Push(i And &FF) bb.Push(Shr(i And &FF00&, 8)) bb.Push(Shr(i And &FF0000&, 16)) bb.Push(Shr(i And &FF000000&, 24)) bb.Insert(Byte[].FromString(s)) ' Crea il nuovo file wav: bb.Write(fl, 0, bb.Count) fl.Close End