Format .wav
Le format RIFF_WAV
Le format Wav
Le format PCM : C'est le format de fichier "standard" pour les samples (les enregistrements de sons), car les données sont brutes, c'est-à-dire qu'elles ne sont ni modifiées, ni compressées. Le fichier possède une en-tête de 44 octets (en tout cas en général, voir ci-dessous), permettant de connaître le type du sample: Son format, sa fréquence, le nombre de voies, etc...
Cet en-tête (« header » en anglais) peut, dans certaines variantes du format PCM, avoir une taille supérieure à 44 octets. Mais voyons d'abord le format le plus standard :
Les 12 premiers octets indiquent de le type de.
• 1 - FORMAT
• On trouve d'abord la mention « RIFF » dans les 4 premiers octets du fichier ($52, $49, $42, $42 en hexadécimal. Ce sont les codes ASCII des lettres R,I,F,F)
• On trouve ensuite la taille TOTALE du fichier codée sous la forme d'un entier long (4 octets, donc)
• On trouve ensuite la mention « WAVE» soit 4 caractères ce qui nous donne en hexadécimal : $57,$41,$56,$45
Cette première partie est suivie du.
• 2- descriptif du son : fréquence d'échantillonage, nombre d'octets par échantillons, etc. Les données qu'il contient ainsi que leurs types et leur ordre correspondent exactement à la structure WAVEFORMAT (cette structure, définie par Microsoft, se retrouve dans pas mal de docs. Elle est aujourd'hui officiellement remplacée par la structure WAVEFORMATEX qui est exactement la même pour les 6 premiers champs, c'est-à-dire tout les champs que l'on retrouve dans l'en-tête du fichier WAVE/PCM).
• Indicateur de zone : « fmt » soit 4 caractères (attention, le dernier caractère est un espace) ce qui nous donne en hexadécimal : $66,$6D,$74,$20. « fmt » est l'abréviation de « format ». Cet indicateur nous prévient que les informations qui vont suivre concernent le format du son (comme vous allez le voir)
• Taille de la structure WAVEFORMAT sous la forme d'un entier long (soit 4 octets). La structure WAVEFORMAT comporte 16 octets. On trouve donc, logiquement, la valeur 16 (ou $10 en hexadécimal) stockée à cet endroit.
• wFormatTag.w (2 octets) : ce champ contient un code correspondant au format exact de codage des données. Pour les fichiers de type PCM, ce champ contiendra la valeur 1
• nChannels.w (2 octets) : nombre de canaux. On aura la valeur 1 pour les sons mono, 2 pour les sons stéréo, et éventuellement plus pour les sons moins standards.
• nSamplesPerSec.l (4 octets) : nombre d'échantillons par seconde (voir plus loin la note concernant l'amplitude)
• nAvgBytesPerSec.l (4 octets) : nombre d'octets par secondes. Cette valeur fait double emploi avec les autres valeurs enregistrées mais vous devez la compléter correctement pour être certains que votre fichier sera compatible avec tous les programmes de son. Le nombre d'octets par seconde dépend :
• du nombre d'échantillons pas seconde
• du nombre d'octets par échantillon
• du nombre de canaux
Il se calcul comme suit :
nAvgBytesPerSec= nSamplesPerSec* nBitsPerSample/8* nChannels
(nBitsPerSample est le nombre de BITS par seconde, un octet comporte 8 bits)
• nBlockAlign.w (2 octets) : contient la taille totale (en octets) d'un échantillon. Cette valeur fait également double emploi avec les autres valeurs enregistrées mais vous devez aussi la compléter correctement pour être certains que votre fichier sera compatible avec tous les programmes de son. Elle dépend :
• du nombre d'octets par échantillon
• du nombre de canaux
Elle se calcul comme suit :
nBlockAlign = nBitsPerSample/8* nChannels*
(nBitsPerSample est le nombre de BITS par seconde, un octet comporte 8 bits)
• nBitsPerSample.w (2 octets) : contient le nombre de bits par échantillon (voir note concernant l'amplitude)
Pour finir, le fichier contient les données proprement dites, que l'on appelle, en anglais, les.
• 3 - DATAS
• Indicateur de zone : «data» soit 4 caractères ce qui nous donne en hexadécimal : $64,$61,$74,$61. Cet indicateur nous prévient que les informations qui vont suivre sont les données proprement dites.
• Taille des datas sous la forme d'un entier long (soit 4 octets). Cette taille est le nombre total d'octets des datas. Elle nous permet, par exemple, de calculer la durée du sample en appliquant la formule :
Durée = Taille des datas/ nAvgBytesPerSec
ATTENTION : la taille des données doit TOUJOURS être un multiple de nBlockAlign. Lorsqu'une modification d'un son amène une modification de la taille des données, on peut « arrondir » la taille à un multiple de nBlockAlign à l'aide des deux opérations suivantes :
NouvelleTaille = NouvelleTaille/ nBlockAlign
NouvelleTaille = NouvelleTaille* nBlockAlign
Cela ne fonctionne bien sur que si NouvelleTaille est un entier, ce qui doit normalement être le cas.
Si par ailleurs, vous avez besoin d'extraire une partie d'un son, les deux extrémités de votre tronçon doivent également être des multiples de nBlockAlign (tous les échantillons extraits doivent être entiers). Vous pouvez « arrondir » vos extrémités avec un calcul identique à celui proposé ci-dessus.
Les plus malins auront sans doute remarqué que le début de la zone 2 ressemble beaucoup au début de la zone 3. Ces zones sont baptisées « chunck ». (tronçon). Certains fichiers WAVE comportent d'autres « chuncks » que ceux décrits ci-dessus afin de stocker plus d'information sur le fichier (nom de l'auteur, par exemple). Le format WAVE comporte en fait la possibilité d'ajouter autant de chuncks que l'on veut, avant ou après le chunck des datas. Dans la pratique, presque tous les fichiers comportent un en-tête de 44 octets qui correspondent exactement à la description ci-dessus et qui ne comportent donc que les 2 chuncks que nous venons de décrire.
SoundEditor utilise le format PCM comme base de travail. C'est-à-dire que les fichiers non PCM (OGG ou MP3, par exemple) doivent être convertis en PCM (on dit aussi « décompressés » ou « décodés » pour pouvoir être affichés. Le format utilisé par SoundEditor doit avoir un en-tête de 44 octets comme décrit ci-dessus. C'est le « Gestionnaire de décodeurs » qui est chargé de délivrer des fichiers conformes à cette description.
Résumé :
Structure générale:
offset (hexa) |
nom |
longueur (oct.) |
description |
|
0 |
00h |
rID |
4 |
contient "RIFF" |
4 |
04h |
rLen |
4 |
longueur du fichier |
8 |
08h |
wID |
4 |
contient "WAVE" |
Le Format Chunk:
offset (hexa) |
nom |
longueur (octet) |
description |
|
12 |
0Ch |
fId |
4 |
contient "fmt " ("fmt espace") |
16 |
10h |
fLen |
4 |
Longueur du Chunck |
20 |
14h |
wFormatTag |
2 |
format (1 = Microsoft Pulse Code Modulation PCM) |
22 |
16h |
nChannels |
2 |
nombre de canaux (1=mono, 2=stéréo) |
24 |
18h |
nSamplesPerSec |
4 |
fréquence d'échantillonage (en Hz) |
28 |
1Ch |
nAvgBytesPerSec |
4 |
= nChannels * nSamplesPerSec * (nBitsPerSample/8) |
32 |
20h |
nBlockAlign |
2 |
= nChannels * (nBitsPerSample / 8) |
34 |
22h |
nBitsPerSample |
2 |
longueur d'un échantillon en bits (8, 16, 24 ou 32) |
Le WAVE Data Chunk:
offset (hexa) |
nom |
longueur (octet) |
description |
|
36 |
24h |
dId |
4 |
contient "data" |
40 |
28h |
dLen |
4 |
longueur du chunck dData (en octets) |
44 et plus |
2Ch |
dData |
dLen |
les données du son échantillonné |
Utilisation
L'amplitude : Un sample est composé d'une courbe
continue ayant une valeur bi-polaire (signée) . Le 1er
élément d'un son est l'amplitude: C'est le point le plus
élevé (et le plus bas) de la courbe. Plus l'amplitude est
élevée, plus le son est fort, bruyant. L'unité de
grandeur de l'amplitude est le décibel (dB). "C'est une mesure
logarithmique donnant le degré d'amplification d'une vibration."
Nous n'irons pas plus loin dans la description du décibel,
puisque ce n'est pas indispensable dans la programmation. L'amplitude
est digitalisée avec l'ADC de la carte son. Par exemple, en 8
bits, l'amplitude possède une résolution de 256 valeurs.
En 16 bits, 65536 valeurs, etc... Il existe aussi le 24 et 32 bits.
Pour le moment, toutefois, SoudEditor ne supporte pas les
données 24 bits qui sont très embétantes à
manipuler et qui sont très rarement utilisées. Plus la
résolution est élevée, plus l'échantillon
est proche du son original. Dans les images ci-dessus, l'amplitude
digitalisée est illustrée en vert. En 8 bits, la valeur
de l'amplitude est non signée, et en 16 bits, l'amplitude est
signée. Cela complique un peu les choses, par exemple, pour
convertir un sample 16 bits en 8 bits, il ne suffit pas de diviser la
valeur de l'amplitude par 256, il faut aussi penser à soustraire
(ou à ajouter) ce décalage. Cette manip est
expliquée un peu plus bas.
La fréquence : En bleu, c'est la fréquence
d'échantillonnage, le nombre de valeurs définissant
l'amplitude pour une seconde d'enregistrement. Ainsi 44100 Hz
signifie 44100 échantillons pour une seconde de son
mémorisé. Plus la fréquence
d'échantillonnage est élevée, meilleure est la
qualité du sample, plus les données digitales sont
proches de l'original.
Le débit : On peut calculer le "débit" (ko/s) d'un sample
avec ces paramètres: L'amplitude (format 8 ou 16 bits), le mode
(mono ou stéréo) et la fréquence. Par exemple, en
8 bits mono 44100Hz, cela nous donne pour une seconde d'enregistrement:
44100 octets (1 octet=8 bits). En stéréo, c'est le
double. En 16 bits stéréo, c'est le quadruple. Ainsi,
avec la qualité du CD audio (16 bits stéréo 44,1
kHz), on obtient 176400 octets par seconde. A partir de la taille du
fichier (donnée par fileSize), et les caractéristiques du
sample, il est facile de calculer le temps total en secondes (ou ms) de
lecture d'un sample...
L'ordre des données : Après les 44
octets de l'en-tête, viennent les données. Les
données ont un ordre bien défini. Dans le cas d'un sample
8 bits mono , c'est 1 seul octet par sample, donc les données se suivent normalement. Pour un sample 8 bits stéréo , ce sont 2
octets par sample, l'octet de la voie de gauche, puis l'octet de la
voie de droite: L,R, L,R, L,R, etc... Dans le cas d'un sample 16 bits mono , ce sont 2
octets par sample, l'octet de poids faible, puis l'octet de poids fort.
Par exemple pour une donnée qui vaudrait 15000, nous
aurions: $98 $3A (les octets sont toujours inversés). Dans le
cas d'un sample 16 bits stéréo , ce sont 4 octets par sample; Deux octets pour la voie de gauche, et deux pour la voie de droite: L,L,R,R, L,L,R,R, L,L,R,R, etc...
Le format des données : Le sample 8 bits
(mono ou stéréo) possède des données
non-signées, c'est-à-dire que le point (l'amplitude) le
plus bas vaut zéro , le point du milieu vaut 127 , et le point le plus haut vaut 255 .
Pour pouvoir travailler sur ces données 8 bits, (par exemple pour modifier le volume du sample, ou le mixer avec un autre, etc...) les données 8 bits doivent subir une petite manipulation afin d'être présentées de la même façon que les données 16 ou 32 bits.
Data = PeekB(*adresse) ; PureBasic lit la donnée et la considère comme une donnée signée. Cela n'arrange pas nos affaires puisqu'il ne s'agit PAS d'une donnée signée. On va donc corriger le tir :
If Data<0 : Data + 256 : EndIf ; Il nous reste à corriger le décalage de 127 octets vers le bas pour avoir un point milieu à 0 : Data - 127
Une fois nos données modifiées par un programme quelconque, nous allons devoir faire l'opération inverse avant de les enregistrer :
If Data>127 : Data = 127 : Endif ; Au cas où nos calculs, généralement faits avec des entiers longs, nous aient donné des valeurs supérieures au maximum toléré par l'enregistrement en 8 bits
Data + 127 ; Pour ramener le point milieu à + 127
PokeB (*adresse,Data)
Les données 16 et 32 bits sont signées et n'ont besoin d'aucun « bricolage » pour pouvoir être exploitées.
Data = PeekW (*adresse) ou PeekL(*adresse)
.
. votre programme ici
.
PokeW(*adresse,Data) ou PokeL(*adresse,Data)
Pour convertir des données 8 bits en 16 bits :
Data = PeekB(*adresseSource)
If Data<0 : Data + 256 : EndIf
Data - 127
Data * 256
PokeW(*adresseDestination,Data)