PDA

View Full Version : Frequenza suono prodotto nel file wav [c]


djremix
29-05-2014, 17:40
Buonasera a tutti,

sono alle prese con un progetto. Ho recuperato e messo assieme codice per la creazione di un file wav con determinate caratteristiche e per la lettura delle caratteristiche generali di un file wav. Il tutto è in linguaggio C.

Il problema è che utilizzando questo codice:


#include <stdio.h>
#include <stdint.h>


struct T_RIFF {
uint8_t ChunkID[4];
uint32_t ChunkSize;
uint8_t Format[4];
};


struct T_fmt {
uint8_t Subchunk1ID[4];
uint32_t Subchunk1Size;
uint16_t AudioFormat;
uint16_t NumChannels;
uint32_t SampleRate;
uint32_t ByteRate;
uint16_t BlockAlign;
uint16_t BitsPerSample;
};
struct T_data_nosamples {
uint8_t Subchunk2ID[4];
uint32_t Subchunk2Size;
};
struct T_data {
uint8_t Subchunk2ID[4];
uint32_t Subchunk2Size;
};
struct T_WAVE {
struct T_RIFF RIFFheader;
struct T_fmt fmtheader;
struct T_data dataheader;
};


main() {
struct T_WAVE WAVE;
printf("Inserisci il percorso del file: ");
char percorso[50];
scanf("%s",percorso);
FILE* stream = fopen(percorso,"r");
if (stream==NULL)
printf ("Il file non esiste! \n");
else {

fread(&WAVE,1,44,stream);
uint32_t Samplesize, Sample;
printf ("Grandezza blocco: %d byte\n\n",WAVE.RIFFheader.ChunkSize);
printf ("Grandezza blocco fmt: %d byte\n",WAVE.fmtheader.Subchunk1Size);
printf ("Formato audio: %d\n",WAVE.fmtheader.AudioFormat);
printf ("Numero di canali: %d\n",WAVE.fmtheader.NumChannels);
printf ("Frequenza di campionamento: %d Hz\n",WAVE.fmtheader.SampleRate);
printf ("Frequenza di byte: %d byte/s\n",WAVE.fmtheader.ByteRate);
printf ("Allineamento blocco: %d\n",WAVE.fmtheader.BlockAlign);
printf ("Bits per campione: %d\n\n",WAVE.fmtheader.BitsPerSample);
printf ("Grandezza blocco data: %d byte\n\n",WAVE.dataheader.Subchunk2Size);
float durata = (float) WAVE.dataheader.Subchunk2Size/WAVE.fmtheader.ByteRate;
int durataAppr = WAVE.dataheader.Subchunk2Size/WAVE.fmtheader.ByteRate;
printf ("Durata in secondi: %d s\n",durataAppr);
uint32_t SampleSize = WAVE.fmtheader.BitsPerSample / 8;
uint32_t numcampioni = (uint32_t) durata * WAVE.fmtheader.SampleRate;
//processa16bit(WAVE.fmtheader.NumChannels,SampleSize,numcampioni,stream);
fclose(stream);
}

system("pause");
return 0;
}



leggo le caratteristiche generali del file wav ma non la frequenza del suono contenuto (che dovrebbe essere nella parte "dati" del file). Come si potrebbe fare ?

Grazie mille.

tomminno
29-05-2014, 18:29
Parlare di singola frequenza per un file audio non ha molto senso a meno che non sia una sinusoide pura.
Premesso questo, se vuoi capire il contenuto in frequenza della traccia audio devi usare la trasformata di fourier in particolare l'algoritmo FFT, esistono molte librerie per il suo calcolo, io ho sempre usato FFTW.

Daniels118
30-05-2014, 13:22
E' più propriamente una questione di rappresentazione, un suono si può rappresentare in vari modi, i file wave lo rappresentano come l'intensità della pressione sonora in funzione del tempo, quindi bisogna utilizzare una trasformata per passare alla rappresentazione della frequenza, altri formati possono esprimere il suono direttamente in frequenza (come mp3), ma generalmente fanno delle trasformazioni aggiuntive.

djremix
30-05-2014, 13:38
Buonasera e grazie mille per le vostre risposte.

Si, il file audio in oggetto che a me serve deve avere una sinusoide pura. Lo stesso file viene creato da C. Anche in questo caso consigliate l'uso di tali librerie ?

Saluti e grazie :)

Daniels118
30-05-2014, 14:19
Se è come dici risulterebbe molto più economico rilevare i passaggi per lo zero della sinusoide e ricavarne la frequenza.

Daniels118
30-05-2014, 15:11
sarebbe anche sbagliato, perché stai lavorando con un segnale campionato.

E per quale motivo?

Daniels118
30-05-2014, 18:38
se il segnale e' ideale, il campionamento e' ideale (no jitter) e la precisione e' infinita, funziona tutto a meraviglia. ma prova a immaginare il minimo rumore di quantizzazione in presenza di particolari fasi di campionamento (ovvero, quando ti trovi a campionare vicino al passaggio per lo zero)...
Se è questo che ti preoccupa basta definire delle soglie...

Daniels118
30-05-2014, 21:42
è molto più semplice a dirsi che a farsi, dato che dipenderanno dalla fase dell'istante di campionamento...
Non ho capito cosa intendi, puoi spiegarti meglio?

djremix
31-05-2014, 22:38
In sostanza come mi consigliereste di proseguire ?

Daniels118
02-06-2014, 09:47
prova a contare i cambi di segno su questi due segnali (rappresentano la stessa sinusoide campionata con due fasi diverse, stesso tempo di campionamento e stessa durata di osservazione):


-0,309016994374947 0,156434465040231
0,809016994374948 0,987688340595138
0,809016994374948 0,453990499739547
-0,309016994374947 -0,707106781186548
-1 -0,891006524188368
-0,309016994374948 0,156434465040231
0,809016994374947 0,987688340595138
0,809016994374948 0,453990499739546
-0,309016994374947 -0,707106781186548
-1 -0,891006524188368
-0,309016994374948 0,156434465040231
0,809016994374947 0,987688340595138
0,809016994374948 0,453990499739547
-0,309016994374945 -0,707106781186548


sono 6 sul primo segnale e 5 sul secondo. usando il tuo metodo diresti che la frequenza del primo tono è superiore di quella del secondo...
Certo, se vogliamo creare di proposito algoritmi spazzatura possiamo sbagliare senza difficoltà. Il calcolo non deve basarsi su "quanti" cambi di segno avvengono, ma quanto tempo passa tra un cambio di segno e il successivo.
La FFT va sempre bene, se non ci pesa consumare milioni di cicli macchina per analizzare una sinusoide non ho nulla in contrario (ma anche se ci pesa e lo facciamo lo stesso non mi importa più di tanto, ognuno sa il fatto suo).

Daniels118
02-06-2014, 15:21
è la stessa cosa. se vuoi ti creo un altro esempio in cui il "tempo" tra i cambi di segno cambia data una sinusoide con la stessa frequenza ma che viene campionato con due diverse fasi (o meglio, ancora più facilmente, due sinusoidi a frequenza diversa ma che cambiano segno con la stessa cadenza. ma dato che c'avrei anche un lavoro, potresti farlo tu come contro-esempio per capire che anche così l'algoritmo è sbagliato.
Gli algoritmi possono essere progettati anche in base alla conoscenza che si ha dei dati, certo tu puoi creare dei dati appositamente scelti per far fallire un determinato algoritmo, ma in questo caso sei solo tu ad avere il problema, io posso dire di aver utilizzato con soddisfazione l'algoritmo che proposto.

PS. mi sembra scontato che il numero di cicli macchina dipende dalla quantità di dati da elaborare, più ce ne sono più aumenta il divario tra le risorse consumate dai due algoritmi.

Daniels118
02-06-2014, 20:10
ehm, no. un algoritmo deve essere generico. se funziona solamente per un sottoinsieme dei dati e' semplicemente sbagliato. o meglio, e' poco utile.

una FFT viene fatta su un numero fisso di campioni su cui il segnale si presuppone stazionario. e' ragionevole ammettere che con un segnale campionato a 44.1 khz 1024 punti sono piu' che sufficienti. in questo caso non ho idea del numero preciso di cicli richiesto da FFTW, ma su un DSP vettoriale si puo' arrivare a 6000 cicli di clock per fare una FFT a 1024 punti... tenendomi largo quindi FFTW puo' impiegare 60000 cicli di clock... che in genere e' molto di meno del necessario per far girare una printf().
Vorrai dire "generalizzato", e comunque generalizzare non è sempre un vantaggio, quello che tu chiami "sbagliato" altri lo chiamano "ottimizzato".
Il fatto che si scelga di elaborare un blocco di 1024 campioni non significa che bisogna fermarsi al primo blocco, e comunque resta di fatto che la complessità computazionale della FFT è maggiore, indipendentemente dalla quantità di campioni... comunque possiamo stare a discutere in eterno su questi problemi, ma non ne vedo la necessità, come ho già detto a me sta benissimo anche l'uso della FFT.

Daniels118
02-06-2014, 23:16
La mia era una domanda retorica... chiudiamola qui.