Autore Topic: Extern di Ferragosto: leggere un file wav e scriverne a parte i soli dati audio  (Letto 456 volte)

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.719
  • Ne mors quidem nos iunget
    • Mostra profilo
Poiché oggi, Ferragosto, sono rimasto chiuso in convento in piena adorazione estatica, d'estate, del nostro venerato San Midi:

 sanmidi

ho scritto un semplice e breve codice che, usando esclusivamente le funzioni esterne del linguaggio C, legge un file audio di formato WAV, ne estrapola i soli dati audio grezzi che va in fine a scrivere in un nuovo file.

Per i più interessati il codice è sufficientemente commentato:
Codice: [Seleziona]
Library "libc:6"

Private Const SEEK_SET As Integer = 0
Private Const SEEK_CUR As Integer = 1
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

' 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 strcmp (const char *__s1, const char *__s2)
' Compare S1 and S2.
Private Extern strcmp(str1 As Pointer, str2 As String) 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"


Public Sub Main()

  Dim filewav As String
  Dim ent, ptr, usc As Pointer
  Dim lun, sp As Long
 
  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)
 
  sp = 35
' Legge il file a cominciare dal 37° byte (indice 36), sino a quando non trova i caratteri "data":
  Repeat
    Inc sp
' Sposta il Puntatore "ent" alla posizione indicata dal valore di "sp":
    fseek(ent, sp, SEEK_SET)
' Legge in modalità "binaria" soltanto i primi 4 byte del file "wav", ovviamente partendo dall'indice del byte dopo lo spostamento con "fseek()":
    fread(ptr, 1, 4, ent)
  Until strcmp(ptr, "data") == 0
 
' Sposta il Puntatore "ent" di ulteriori 4 byte, per giungere al primo byte audio:
  fseek(ent, 4, SEEK_CUR)
' Ottiene il valore di spostamento (offset) all'interno del Puntatore "ent":
  sp = ftell(ent)
 
' Legge il file "wav" dalla corrente posizione del Puntatore "ent" (primo byte audio) sino alla fine.
' La sottrazione "lun - sp" esclude i dati del blocco d'intestazione del file wav caricato.
  fread(ptr, 1, lun - sp, ent)
 
' 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, 1, lun - sp, usc)

' Libera la memoria precedentemente allocata:
  fclose(usc)
  free_c(ptr)
  fclose(ent)

End


https://www.gambas-it.org/wiki/index.php?title=Extern:_richiamare_funzioni_esterne_a_Gambas


Sia lodato San Midi !


« Ultima modifica: 16 Agosto 2019, 00:45:55 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline Top Fuel

  • Gran Maestro dei Gamberi
  • *****
  • Post: 959
    • Mostra profilo
Ma per allocare una zona di memoria non esiste già la funzione Alloc di Gambas? Cosa cambia con malloc?
Dear youtube administrators, your search bar is broken. When I type the letter "J" it appears justin bieber when it should appear Jimi Hendrix. Fix this, please.

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.719
  • Ne mors quidem nos iunget
    • Mostra profilo
Ma per allocare una zona di memoria non esiste già la funzione Alloc di Gambas? Cosa cambia con malloc?

Ma per aprire un file, non esiste già la funzione Open di Gambas? Cosa cambia con fopen() ?


« Ultima modifica: 16 Agosto 2019, 00:06:53 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.719
  • Ne mors quidem nos iunget
    • Mostra profilo
Per terminare la giornata, in quest'altro esempio - oltre alle sole funzioni esterne di C utilizzate per salvare i dati audio di un file wav - si utilizzeranno le funzioni esterne del sistema sonoro ALSA per eseguire quei dati grezzi.

Insomma, come nel precedente codice NON ho usato alcuna funzione nativa di Gambas.

Codice: c [Seleziona]
Private Const BUFFER As Long = 512 


Library "libc:6"

Private Const SEEK_SET As Integer = 0
Private Const SEEK_CUR As Integer = 1
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"

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:
    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
« Ultima modifica: 17 Agosto 2019, 16:39:53 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »