Le but de cette série d’article est de travailler sur les fichiers WAVE lors de la concaténation de plusieurs en un seul, ces articles sont composés de 4 parties :
- Explication de la structure RIFF d’un fichier WAVE :
- Charger/Stocker un fichier WAVE
- Effectuer un cross-fade et overlap lors de la concaténation de plusieurs fichier WAVE
- Générer un fichier WAVE (Pour bientôt… N’hesitez pas a me demander en cas de problème)
Première partie… La structure WAVE …
Un fichier WAVE est composé de 3 blocs distincts : RIFF, fmt et data…
Le bloc RIFF comporte les informations concernant le type d’en-tête, la taille du fichier et le format du fichier.
Le bloc fmt comporte les spécifications audios : le formt audio, le nombre de canaux, la fréquence, le byte rate, le nolbre de bits par échantillons…
Le bloc data contient la taille du bloc de données et les données.
Plus précisément : (informations venant de http://fr.wikipedia.org/wiki/WAVEform_audio_format ) :
[Bloc de déclaration d'un fichier au format WAVE] [Chunk RIFF début] FileTypeBlocID (4 octets) : Constante «RIFF» (0x52,0x49,0x46,0x46) FileSize (4 octets) : Taille du fichier moins 8 octets FileFormatID (4 octets) : Format = «WAVE» (0x57,0x41,0x56,0x45) [Chunk RIFF fin] [Bloc décrivant le format audio] [Chunk fmt début] FormatBlocID (4 octets) : Identifiant «fmt » (0x66,0x6D, 0x74,0x20) BlocSize (4 octets) : Nombre d'octets du bloc - 8 (0x10) AudioFormat (2 octets) : Format du stockage dans le fichier (1: PCM, ...) NbrCanaux (2 octets) : Nombre de canaux (de 1 à 6, cf. ci-dessous) Frequence (4 octets) : Fréquence d'échantillonnage (en Hertz) [Valeurs standardisées : 11025, 22050, 44100 et éventuellement 48000 et 96000] BytePerSec (4 octets) : Nombre d'octets à lire par seconde (i.e., Frequence * BytePerBloc). BytePerBloc (2 octets) : Nombre d'octets par bloc d'échantillonnage (i.e., tous canaux confondus : NbrCanaux * BitsPerSample/8). BitsPerSample (2 octets) : Nombre de bits utilisées pour le codage de chaque échantillon (8, 16, 24). [Chunk fmt fin] [Bloc des données] [Chunk data début] DataBlocID (4 octets) : Constante «data» (0x64,0x61,0x74,0x61) DataSize (4 octets) : Nombre d'octets des données (i.e. "Data[]", i.e. taille_du_fichier - taille_de_l'entête (qui fait 44 octets normalement). DATAS[] : [Octets du Sample 1 du Canal 1] [Octets du Sample 1 du Canal 2] [Octets du Sample 2 du Canal 1] [Octets du Sample 2 du Canal 2] (si on est en stéréo : 2 cannaux) [Chunk data fin]
ATTENTION : L’ensemble du fichier est codé en « little-endian » excepté pour : FileTypeBlocID et FileFormatID qui sont codés en Big-Endian
- Big-Endian : Bit du poids fort en tête
- Little Endian : Bit du poids faible en tête
Maintenant qu’on connait cette structure on peut la retranscrire en C…
Nous allons utiliser des variable word et dword qui sont des unsigned long . (Nous utilisons ces types car ce sont ceux qu’utilisent Microsoft (qui a crée avec IBM le format WAVE) ).
Pour la bloc (chunk) RIFF (l’indentation saute, à vous de le refaire (ctrl + a puis ctrl + i sous Eclipse) ):
struct RIFF {
char ChunkID[4]; // contient les lettres "RIFF" pour indiquer que le fichier est codé selon la norme RIFF
word ChunkSize; // taille du fichier entier en octets (sans compter les 8 octets de ce champ et le champ précédent CunkID
char Format[4]; // correspond au format du fichier donc ici, contient les lettres "WAVE" car fichier est au format wave
} RIFF;
Le bloc fmt qu contient les spécifications audio, dansn otre cas nous travaillons avec du mono, une fréquence de 44100 et un format de stockage PCM :
struct fmt {
char Subchunk1ID[4]; // contient les lettres "fmt " pour indiquer les données à suivre décrivent le format des données audio
dword Subchunk1Size; // taille en octet des données à suivre (qui suivent cette variable) 16 Pour un fichier PCM
short AudioFormat; // format de compression (une valeur autre que 1 indique une compression)
short NumChannels; // nombre de canaux: Mono = 1, Stereo = 2, etc..
dword SampleRate; // fréquence d'échantillonage, ex 44100, 44800 (nombre d'échantillons par secondes)
dword ByteRate; // nombre d'octects par secondes
short Blockalign; // nombre d'octects pour coder un échantillon
short BitsPerSample; // nombre de bits pour coder un échantillon
} fmt;
Pour char Subchunk1ID[4], on declare un tableau de
Et enfin le bloc data :
struct data {
char Subchunk2ID[4]; // contient les lettres "data" pour indiquer que les données à suivre sont les données audio (les échantillons et)
dword Subchunk2Size; // taille des données audio (nombre total d'octets codant les données audio)
short *data; // données audio... les échantillons
} data;
Nous déclarons short *data car c’est un tableau de bytes qui sera alloué ultérieurement par un malloc en fonction de la taille du SubChunk2Size.
Pour récapituler, voici la structure (les commentaires présent sont formatés pour l’utilisation de Doxygen):
/*!
* def unsigned long word
* Variable de 4 octets
*/
typedef unsigned long word;
/*!
* def unsigned long dword
* Variable de 4 octets
*/
typedef unsigned long dword;
// Structure
/**
* struct WAVE
* brief Structure d'un fichier WAVE standart
* Structure codé grace aux structures RIFF, fmt et data d'un fichier audio .wav
*
*
*ingroup wave
*/
typedef struct WAVE {
/**
*struct RIFF
*brief Description principal du fichier
* "RIFF" (chunk descriptor) structure décrivant la nature du fichier.
*/
struct RIFF {
char ChunkID[4]; // contient les lettres "RIFF" pour indiquer que le fichier est codé selon la norme RIFF
word ChunkSize; // taille du fichier entier en octets (sans compter les 8 octets de ce champ (4o) et le champ précédent CunkID (4o)
char Format[4]; // correspond au format du fichier donc ici, contient les lettres "WAVE" car fichier est au format wave
} RIFF;
/**
*struct fmt
*brief Sprécifications du format audio
* "fmt " (sub-chunk) structure décrivant le format des données audio
*/
struct fmt {
char Subchunk1ID[4]; // contient les lettres "fmt " pour indiquer les données à suivre décrivent le format des données audio
dword Subchunk1Size; // taille en octet des données à suivre (qui suivent cette variable) 16 Pour un fichier PCM
short AudioFormat; // format de compression (une valeur autre que 1 indique une compression)
short NumChannels; // nombre de canaux: Mono = 1, Stereo = 2, etc..
dword SampleRate; // fréquence d'échantillonage, ex 44100, 44800 (nombre d'échantillons par secondes)
dword ByteRate; // nombre d'octects par secondes
short Blockalign; // nombre d'octects pour coder un échantillon
short BitsPerSample; // nombre de bits pour coder un échantillon
} fmt;
/**
*
*struct data
*brief Données du fichier audio
* "data" (sub-chunk) contient les données audio, les échantillons et le nombre d'octets qu'ils représentent.
*/
struct data {
char Subchunk2ID[4]; // contient les lettres "data" pour indiquer que les données à suivre sont les données audio (les échantillons et)
dword Subchunk2Size; // taille des données audio (nombre total d'octets codant les données audio)
short *data; // données audio... les échantillons
} data;
} WAVE;
Dans la prochaine partie nous utiliseront cette structure pour lire un fichier WAVE…
Sur le même sujet :