Differenze tra le versioni di "Ottenere un file WAV da un file Midi con le funzioni esterne del API di FluidSynth"
Da Gambas-it.org - Wikipedia.
Riga 26: | Riga 26: | ||
' ''Get the numeric value of a named setting.''</font> | ' ''Get the numeric value of a named setting.''</font> | ||
Private Extern fluid_settings_getnum(settings As Pointer, name As String, dval As Pointer) As Integer | Private Extern fluid_settings_getnum(settings As Pointer, name As String, dval As Pointer) As Integer | ||
+ | |||
+ | <FONT Color=gray>' ''void fluid_synth_set_gain(fluid_synth_t *synth, float gain)'' | ||
+ | ' ''Set synth output gain value.''</font> | ||
+ | Private Extern fluid_synth_set_gain(synth As Pointer, gain As Single) | ||
<FONT Color=gray>' ''fluid_player_t* new_fluid_player(fluid_synth_t * synth)'' | <FONT Color=gray>' ''fluid_player_t* new_fluid_player(fluid_synth_t * synth)'' | ||
Riga 66: | Riga 70: | ||
'''Public''' Sub Main() | '''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 | ||
+ | |||
+ | <FONT Color=gray>' ''Imposta il file soundfont-bank che sarà utilizzato:''</font> | ||
+ | sfb = "/usr/share/sounds/sf2/FluidR3_GM.sf2" | ||
+ | |||
+ | <FONT Color=gray>' ''Verifica se il file caricato è effettivamente un soundfont-bank .sf2:''</font> | ||
+ | i = fluid_is_soundfont(sfb) | ||
+ | If i < 0 Then Error.Raise("Errore: il file non è un soundfont-bank !") | ||
+ | |||
+ | <FONT Color=gray>' ''Imposta il file Midi, dal quale si genererà un file audio wav:''</font> | ||
+ | fileMidi = "<FONT Color=gray>''/percorso/del/file.mid''</font>" | ||
+ | |||
+ | <FONT Color=gray>' ''Verifica se il file è effettivamente uno file Midi standard:''</font> | ||
+ | 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)) | ||
+ | Print "Frequenza del futuro file audio wav: "; frequenza; " hertz" | ||
+ | |||
+ | <FONT Color=gray>' ''Imposta il volume del file audio wav finale:''</font> | ||
+ | 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] | ||
+ | |||
+ | Do | ||
+ | buffer = New Short[frequenza * 2] | ||
+ | fluid_synth_write_s16(syn, frequenza, buffer, 0, 2, buffer, 1, 2) | ||
+ | dati.Insert(buffer) | ||
+ | Loop 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 | ||
+ | |||
+ | <FONT Color=gray>' ''Va a generare il file audio wav:''</font> | ||
+ | Genera_File_wav(dati_grezzi) | ||
+ | |||
+ | |||
+ | <FONT Color=gray>' ''Va in chiusura:''</font> | ||
+ | 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(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) | ||
+ | |||
+ | <FONT Color=gray>' ''Vengono definiti gli elementi fondamentali del blocco d'intestazione del file wav: ''</font> | ||
+ | canali = 2 | ||
+ | frequenza = 44100 | ||
+ | risoluzione = 16 | ||
+ | |||
+ | fl = Open "/tmp/audio.wav" For Create | ||
+ | |||
+ | ini = "RIFF" | ||
+ | |||
+ | bb = Byte[].FromString(ini) | ||
+ | |||
+ | i = Len(s) | ||
+ | |||
+ | i2 = i + 36 | ||
+ | |||
+ | <FONT Color=gray>' ''Imposta il valore dimensionale di 4 byte a partire dal 5° byte del futuro file:''</font> | ||
+ | bb.Add(i2 And &FF) | ||
+ | bb.Add(Shr(i2 And &FF00&, 8)) | ||
+ | bb.Add(Shr(i2 And &FF0000&, 16)) | ||
+ | bb.Add(Shr(i2 And &FF000000&, 24)) | ||
+ | |||
+ | <FONT Color=gray>' ''Vengono aggiunti: il tipo di formato di file e l'identificativo del formato del blocco dei dati audio:''</font> | ||
+ | bb.Insert(bh.FromString("WAVEfmt ")) | ||
+ | |||
+ | <FONT Color=gray>' ''Viene aggiunto il valore della lunghezza dei dati del formato (in questo caso il PCM):''</font> | ||
+ | bh = [&10, &00, &00, &00] | ||
+ | bb.Insert(bh) | ||
+ | |||
+ | <FONT Color=gray>' ''Viene aggiunto il valore del formato audio (1 = PCM):''</font> | ||
+ | bb.Insert(bh.FromString(Chr(&01) & Chr(&00))) | ||
+ | |||
+ | <FONT Color=gray>' ''Viene aggiunto il numero dei canali di uscita:''</font> | ||
+ | bb.Insert(bh.FromString(Chr(canali) & Chr(&00))) | ||
+ | |||
+ | <FONT Color=gray>' ''Viene aggiunto il valore della frequenza di campionamento:''</font> | ||
+ | bb.Add(frequenza And &FF) | ||
+ | bb.Add(Shr(frequenza And &FF00&, 8)) | ||
+ | bb.Add(Shr(frequenza And &FF0000&, 16)) | ||
+ | bb.Add(Shr(frequenza And &FF000000&, 24)) | ||
+ | |||
+ | <FONT Color=gray>' ''Viene aggiunto il valore del "Byte rate per secondo":''</font> | ||
+ | brps = frequenza * canali * (risoluzione / 8) | ||
+ | bb.Add(brps And &FF) | ||
+ | bb.Add(Shr(brps And &FF00&, 8)) | ||
+ | bb.Add(Shr(brps And &FF0000&, 16)) | ||
+ | bb.Add(Shr(brps And &FF000000&, 24)) | ||
+ | |||
+ | <FONT Color=gray>' ''Viene aggiunto il valore del "Block Align":''</font> | ||
+ | blal = canali * risoluzione / 8 | ||
+ | bb.Insert(bh.FromString(Chr(blal) & Chr(&00))) | ||
+ | |||
+ | <FONT Color=gray>' ''Viene aggiunto il valore della risoluzione di campionamento:''</font> | ||
+ | bb.Insert(bh.FromString(Chr(risoluzione) & Chr(&00))) | ||
+ | |||
+ | <FONT Color=gray>' ''Viene aggiunto l'identificativo del Blocco dei dati audio grezzi:''</font> | ||
+ | bb.Insert(bh.FromString("data")) | ||
+ | |||
+ | <FONT Color=gray>' ''Imposta il valore dimensionale di 4 byte a partire dal 41° byte del futuro file'' | ||
+ | ' ''e relativo alla dimensione dei dati audio grezzi:''</font> | ||
+ | bb.Add(i And &FF) | ||
+ | bb.Add(Shr(i And &FF00&, 8)) | ||
+ | bb.Add(Shr(i And &FF0000&, 16)) | ||
+ | bb.Add(Shr(i And &FF000000&, 24)) | ||
+ | |||
+ | bb.Insert(Byte[].FromString(s)) | ||
+ | |||
+ | <FONT Color=gray>' ''Crea il nuovo file wav:''</font> | ||
+ | bb.Write(fl, 0, bb.Count) | ||
+ | |||
+ | fl.Close | ||
'''End''' | '''End''' | ||
Riga 75: | Riga 230: | ||
=Riferimenti= | =Riferimenti= | ||
* http://fluidsynth.sourceforge.net/api/ | * http://fluidsynth.sourceforge.net/api/ | ||
− | |||
− | |||
− | |||
− |
Versione delle 17:24, 4 mag 2016
Con le risorse della libreria Libfluidsynth è possibile ottenere un file WAV da un file Midi.
E' necessario avere istallata e richiamare in Gambas la libreria dinamica condivisa: "libfluidsynth:1.5.2"
Mostriamo di seguito un esempio a riga di comando:
Library "libfluidsynth:1.5.2" ' 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)) Print "Frequenza del futuro file audio wav: "; frequenza; " hertz" ' 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] Do buffer = New Short[frequenza * 2] fluid_synth_write_s16(syn, frequenza, buffer, 0, 2, buffer, 1, 2) dati.Insert(buffer) Loop 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(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(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) ' Vengono definiti gli elementi fondamentali del blocco d'intestazione del file wav: canali = 2 frequenza = 44100 risoluzione = 16 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.Add(i2 And &FF) bb.Add(Shr(i2 And &FF00&, 8)) bb.Add(Shr(i2 And &FF0000&, 16)) bb.Add(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.Add(frequenza And &FF) bb.Add(Shr(frequenza And &FF00&, 8)) bb.Add(Shr(frequenza And &FF0000&, 16)) bb.Add(Shr(frequenza And &FF000000&, 24)) ' Viene aggiunto il valore del "Byte rate per secondo": brps = frequenza * canali * (risoluzione / 8) bb.Add(brps And &FF) bb.Add(Shr(brps And &FF00&, 8)) bb.Add(Shr(brps And &FF0000&, 16)) bb.Add(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.Add(i And &FF) bb.Add(Shr(i And &FF00&, 8)) bb.Add(Shr(i And &FF0000&, 16)) bb.Add(Shr(i And &FF000000&, 24)) bb.Insert(Byte[].FromString(s)) ' Crea il nuovo file wav: bb.Write(fl, 0, bb.Count) fl.Close End