Eseguire un file audio WAV con le sole funzioni esterne di C e di ALSA
Da Gambas-it.org - Wikipedia.
Di seguito mostreremo un interessante esempio, con il quale sarà possibile eseguire un file audio WAV con le sole funzioni esterne di C e di ALSA, senza dunque utilizzare le funzioni native di Gambas.
Private Const BUFFER As Long = 512 Library "libc:6" Private Const SEEK_SET As Integer = 0 Private Const SEEK_END As Integer = 2 Private Const SIGKILL As Integer = 9 ' FILE *fopen (const char *__restrict __filename, const char *__restrict __modes) ' Open a file and create a new stream for it. Private Extern fopen(__filename As String, __modes As String) As Pointer ' int printf (const char *__restrict __format, ...) ' Write formatted output to stdout. Private Extern printf(__format As String) As Integer Private Extern printf_2(__format As String, param1 As Integer, param2 As Integer, param3 As Float) As Integer Exec "printf" ' int kill (__pid_t __pid, int __sig) ' Send signal SIG to process number PID. Private Extern kill_c(__pid As Integer, __sig As Integer) As Integer Exec "kill" ' int fseek (FILE *__stream, long int __off, int __whence) ' Seek to a certain position on STREAM. Private Extern fseek(__stream As Pointer, __off As Long, __whence As Integer) As Integer ' long int ftell (FILE *__stream) ' Return the current position of STREAM. Private Extern ftell(__stream As Pointer) As Long ' void *malloc (size_t __size) ' Allocate SIZE bytes of memory. Private Extern malloc(__size As Long) As Pointer ' size_t fread (void *__restrict __ptr, size_t __size, size_t __n, FILE *__restrict __stream) ' Read chunks of generic data from STREAM. Private Extern fread(__ptr As Pointer, __size As Long, __n As Long, __stream As Pointer) As Long ' int sprintf (char *__restrict __s, const char *__restrict __format, ...) ' Write formatted output to S. Private Extern sprintf(__str As Pointer, __format As String, param1 As Pointer) As Integer ' int strncmp (const char *__s1, const char *__s2, size_t __n) ' Compare N characters of S1 and S2. Private Extern strncmp(__s1 As Pointer, __s2 As String, __n As Long) As Integer ' size_t fwrite (const void *__restrict __ptr, size_t __size, size_t __n, FILE *__restrict __s) ' Write chunks of generic data to STREAM. Private Extern fwrite(__ptr As Pointer, __size As Long, __n As Long, __stream As Pointer) As Long ' int fclose (FILE *__stream) ' Close STREAM. Private Extern fclose(__stream As Pointer) As Integer ' void free (void *__ptr) ' Free a block allocated by `malloc'. Private Extern free_c(__ptr As Pointer) Exec "free" '''''''''''''''''''''''''''''''''''''''''''''' Library "libasound:2.0.0" Private Const SND_PCM_STREAM_PLAYBACK As Integer = 0 Private Const SND_PCM_FORMAT_S16_LE As Integer = 2 Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Integer = 3 ' int snd_pcm_open (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode) ' Opens a PCM. Private Extern snd_pcm_open(pcm As Pointer, nome As String, stream As Integer, mode As Integer) As Integer ' const char * snd_strerror (int errnum) ' Returns the message for an Error code. Private Extern snd_strerror(errnum As Integer) As String ' int snd_pcm_set_params (snd_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int canali, unsigned int rate, int soft_resample, unsigned int latency) ' Set the hardware and software parameters in a simple way. Private Extern snd_pcm_set_params(pcm As Pointer, formatI As Integer, accessI As Integer, channels As Integer, rate As Integer, soft_resample As Integer, latency As Integer) As Integer ' snd_pcm_sframes_t snd_pcm_writei (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) ' Write interleaved frames to a PCM. Private Extern snd_pcm_writei(pcm As Pointer, buffer As Pointer, uframes As Long) As Integer ' int snd_pcm_drain (snd_pcm_t *pcm) ' Stop a PCM preserving pending frames. Private Extern snd_pcm_drain(pcm As Pointer) As Integer ' int snd_pcm_close (snd_pcm_t *pcm) ' Close PCM handle. Private Extern snd_pcm_close(pcm As Pointer) As Integer Public Sub Main() Dim filewav As String Dim ent, ptr, usc, pcm As Pointer Dim lun, sp, off As Long Dim ii As New Integer[1] Dim err, tot As Integer Dim cc As New Short[1] Dim h, m As Short Dim sec As Float filewav = "/percorso/del/file.wav" ' Apre il file "wav" in sola "lettura" binaria: ent = fopen(filewav, "r") If ent == 0 Then printf("ERRORE in lettura del file wav!") kill_c(0, SIGKILL) Endif ' Posiziona il puntatore nell'area di memoria, puntata dalla variabile "ent", alla fine del flusso: fseek(ent, 0, SEEK_END) ' Ritorna la quantità di dati contenuti nell'area di memoria, puntata dalla variabile "ent": lun = ftell(ent) ' Alloca un'area di memoria di lunghezza pari al valore contenuto dalla varibile "lun": ptr = malloc(lun) ' Riposiziona il Puntatore all'inizio del file, per poter leggere tutti i suoi dati: fseek(ent, 0, SEEK_SET) ' Legge l'intera quantità di dati del file wav: fread(ptr, 1, lun, ent) ' Assegna un numero di byte, presenti nell'area puntata dal Puntatore "ptr", pari alla quantità di byte occupata da un "Intero Corto". ' L'assegnazione comincia dal byte di indice 22 per estrarre il numero dei canali del file wav. sprintf(cc.Data, "%s", ptr + 22) ' Assegna un numero di byte, presenti nell'area puntata dal Puntatore "ptr", pari alla quantità di byte occupata da un "Intero". ' L'assegnazione comincia dal byte di indice 24 per estrarre il valore della frequenza di campionamento del file wav. sprintf(ii.Data, "%s", ptr + 24) sp = 35 Repeat ' Legge il file a cominciare dal 37° byte (indice 36), sino a quando non trova i caratteri "data": Inc sp Until strncmp(ptr + sp, "data", 4) == 0 ' Incrementa di otto unità la variabile "sp", per raggiungere l'indice del byte di inizio dei dati audio grezzi: sp += 8 ' Apre il file dei dati grezzi wav in sola "scrittura" binaria: usc = fopen("/tmp/datigrezzi", "w") If ent == 0 Then printf("ERRORE in scrittura del file wav!") kill_c(0, SIGKILL) Endif ' Scrive i dati, precedentemente letti, in un nuovo file contenente i soli dati audio wav: fwrite(ptr + sp, 1, lun - sp, usc) ' Chiude il flusso di dati in uscita per consentire la scrittura tottale dei dati grezzi nel file: fclose(usc) ' ALSA ' ' Apre il sub-sistema "PCM" di ALSA: err = snd_pcm_open(VarPtr(pcm), "default", SND_PCM_STREAM_PLAYBACK, 0) If err < 0 Then printf("Errore nell'apertura del subsistema PCM: " & snd_strerror(err)) kill_c(0, SIGKILL) Endif ' Imposta gli opportuni parametri: err = snd_pcm_set_params(pcm, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, cc[0], ii[0], 1, 500000) If err < 0 Then printf("Errore nell'impostazione dei parametri audio: " & snd_strerror(err)) kill_c(0, SIGKILL) Endif Repeat ' Scrive i dati letti nel sub-sistema "PCM" di ALSA. ' Ad ogni giro il Puntatore avanza di BUFFER byte in avanti nell'area di memoria puntata. err = snd_pcm_writei(pcm, ptr + sp + off, BUFFER / 4) tot += err sec = tot \ ii[0] h = (sec / 3600) m = (sec - (3600 * h)) / 60 ' Mostra il tempo trascorso. ' A destra del carattere di formato ".3lf" è posto uno spazio, per impedire che dopo il 59° secondo, ' ritornando la stampa dei secondi alle unità, resti visibile l'ultimo millesimo di secondo del precedente minuto. printf_2("\rTempo trascorso: %d:%d:%.3lf ", h, m, (sec - (3600 * h) - (m * 60))) off += BUFFER Until tot >= lun / 4 ' Impedisce che avvenga un troncamento inaspettato del processo dei dati audio finali: snd_pcm_drain(pcm) ' Libera la memoria precedentemente allocata: snd_pcm_close(pcm) free_c(ptr) fclose(ent) End