Une fois la structure du fichier WAVE comprise, on va créer une fonction qui stockera les données du fichier WAVE dans des variables afin qu’on puisse travailler dessus…

Deuxième partie… La lecture d’une fichier WAVE …

Le fonction que nous allons créer prendra deux paramètres : le nom du fichier WAVE qu’il faut ouvrir, et un pointeur sur une structure WAVE (que nous allons remplir).

On crée une variable de type fichier, puis on ouvre notre fichier en lecture de bytes (octets) grâce à rb (read byte). Un « man fopen » en console (sous Linux) vous donnera plus d’information cernant cette fonction.

//création d'un fichier
 FILE *file;

 //ouverture/lecture du fichier wave_file en mode binaire (rb) : lecture en octets
 file = fopen(wave_file, "rb");

On peut alors passer au stockage des données contenues dans notre fichier dans la structure RIFF créé.
Pour cela, on utilise la fonction fread :

size_t fread (void *ptr, size_t size, size_t nmemb, FILE *stream)

Cette fonction lit les nmemb éléments de données, chacun d’eux représentant size octets (bytes) de long, depuis le flux pointé par stream et les stocke à l’emplacement pointé par ptr.
Par exemple,e pour lire le ChunckID de la partie RIFF, on 1 éléments (nmemb) de 4 octets (size) :

	fread(&son->RIFF.ChunkID, 4, 1, file);

On applique se raisonnement à l’ensemble de la structure (excepté pour les données).

	fread(&son->RIFF.ChunkID, 4, 1, file);
	fread(&son->RIFF.ChunkSize, 4, 1, file);
	fread(&son->RIFF.Format, 4, 1, file);
	fread(&son->fmt.Subchunk1ID, 4, 1, file);
	fread(&son->fmt.Subchunk1Size, 4, 1, file);
	fread(&son->fmt.AudioFormat, 2, 1, file);
	fread(&son->fmt.NumChannels, 2, 1, file);
	fread(&son->fmt.SampleRate, 4, 1, file);
	fread(&son->fmt.ByteRate, 4, 1, file);
	fread(&son->fmt.Blockalign, 2, 1, file);
	fread(&son->fmt.BitsPerSample, 2, 1, file);
	fread(&son->data.Subchunk2ID, 4, 1, file);
	fread(&son->data.Subchunk2Size, 4, 1, file);

Pour stocker les données, on procède ne 2 étapes :
1 – Calcul du nombre de samples, et preparer une tableau pour stocker ces données ( je vous donne un bout de code très bien commenté, et très explicatif ) :

	/* allocation de la taille du tableau data[] contenant les échantillons de la structure WAVE
	 *
	 * Blockalign: nombre d'octects pour coder un sample
	 * Subchunk2Size: nombre d'octects que représente tous les échantillons.
	 * on a donc le nombre d'échantillons en faisant l'opération Subchunk2Size/Blockalign
	 * un échantillon est contenable dans un short donc chaque case doit être de la taille d'un short.
	 */
	son->data.data = malloc( (int)(son->data.Subchunk2Size + 1) / (int)son->fmt.Blockalign * sizeof(short) );

2 – Stocker les donnes : Pour cela, on va simplement faire une boucle, à parti du premier samples (échantillons) jusqu’au dernier ( son->data.Subchunk2Size/son->fmt.Blockalign ), qui contient la fonction fread qui lira et stockera ces données.
On lit à chaque fois 1 éléments (nmemb), de BlockAlign octets.

	//remplissage du tableau d'échantillons data[] de la structure WAVE
	for (i=0; i < (int)son->data.Subchunk2Size/son->fmt.Blockalign; i++){
		fread(&son->data.data[i], son->fmt.Blockalign, 1, file);
	}

( Je viens de réaliser : on pourrai PEUT-ÊTRE utliser fread pour lire nmemb ( = son->data.Subchunk2Size/son->fmt.Blockalign ) éléments de size ( = son->fmt.Blockalign ) octets chacun.

nb_samples = son->data.Subchunk2Size/son->fmt.Blockalign;
fread(&son->data.data[i], son->fmt.Blockalign, nb_samples, file);

Cette idée reste à VÉRIFIER ! ).

Puis on ferme le fichier :

	//fermeture du fichier
	fclose(file);

Le code complet de la fonction :

/*!
 * brief module assurant la lecture d'un fichier son .wav et stocke toutes ses données dans une structure WAVE.
 * param char *wave, nom du fichier .wav à lire
 * param WAVE *son, structure WAVE à écrire
 *ingroup wave
 *
 */
int Read_Wav (char *wave_file, WAVE *son) {

	//création d'un fichier
	FILE *file;

	//ouverture/lecture du fichier wave_file en mode binaire (rb) : lecture en octets
	file = fopen(wave_file, "rb");

	/* gestion d'erreurs
	 *
	 * si l'un des fichiers chargés est null, càd introuvable, on envoie une erreur et on arrête le programme.
	 */
	if (file == NULL) {
		printf("nerreur: fichier  %s  introuvablen", wave_file);
		exit(0);
	}

	/* lecture des données du fichier .wav et stockage de celle-ci dans les champs adéquats de la structure WAVE */
	fread(&son->RIFF.ChunkID, 4, 1, file);
	fread(&son->RIFF.ChunkSize, 4, 1, file);
	fread(&son->RIFF.Format, 4, 1, file);
	fread(&son->fmt.Subchunk1ID, 4, 1, file);
	fread(&son->fmt.Subchunk1Size, 4, 1, file);
	fread(&son->fmt.AudioFormat, 2, 1, file);
	fread(&son->fmt.NumChannels, 2, 1, file);
	fread(&son->fmt.SampleRate, 4, 1, file);
	fread(&son->fmt.ByteRate, 4, 1, file);
	fread(&son->fmt.Blockalign, 2, 1, file);
	fread(&son->fmt.BitsPerSample, 2, 1, file);
	fread(&son->data.Subchunk2ID, 4, 1, file);
	fread(&son->data.Subchunk2Size, 4, 1, file);

	/* allocation de la taille du tableau data[] contenant les échantillons de la structure WAVE
	 *
	 * Blockalign: nombre d'octects pour coder un sample
	 * Subchunk2Size: nombre d'octects que représente tous les échantillons.
	 * on a donc le nombre d'échantillons en faisant l'opération Subchunk2Size/Blockalign
	 * un échantillon est contenable dans un short donc chaque case doit être de la taille d'un short.
	 */
	son->data.data = malloc( (int)(son->data.Subchunk2Size + 1) / (int)son->fmt.Blockalign * sizeof(short) );

	int i;

	//remplissage du tableau d'échantillons data[] de la structure WAVE
	for (i=0; i < (int)son->data.Subchunk2Size/son->fmt.Blockalign; i++){
		fread(&son->data.data[i], son->fmt.Blockalign, 1, file);
	}

	//fermeture du fichier
	fclose(file);

	return 0;
}

.

Prochain étape : Effectué un cross-fade sinusoïdale au début, à la fin et entre chaque fichier son lors de la concaténation.

Sur le même sujet :

  1. Manipulation audio (WAVE) en C : La structure RIFF (Partie 1 / 5)
  2. Manipulation audio (WAVE) en C : cross-fade et overlap lors de la concaténation (Partie 3 / 5)