Méthodes de compression / stockage des données multimédias en formats WAVE et JPEG, partie 1

Bonjour ! Ma première série d'articles sera consacrée à l'étude des méthodes de compression et de stockage d'images / de son, telles que JPEG (image) et WAVE (son). Elle contiendra également des exemples de programmes utilisant ces formats (.jpg, .wav) en pratique. Dans cette partie, nous allons examiner spécifiquement le format WAVE.

Historique

WAVE (Waveform Audio File Format) est un format de fichier conteneur pour le stockage d'une enregistrement audio. Ce conteneur est généralement utilisé pour conserver des sons non compressés en modulation par impulsion codée. (Extrait de Wikipédia)

Il a été conçu et publié en 1991 avec RIFF par les entreprises Microsoft et IBM (les principales entreprises de l'IT à l'époque).

Structure du fichier

Un fichier a une partie d'en-tête, les données elles-mêmes, mais pas de pied de page. L'en-tête fait au total 44 octets.
L'en-tête contient des paramètres concernant le nombre de bits par échantillon, la fréquence d'échantillonnage, la profondeur sonore, et d'autres informations nécessaires pour la carte son. (Tous les valeurs numériques du tableau doivent être enregistrées en ordre Little-Endian)

Nom du bloc
Taille du bloc (B)
Description / Utilité
Valeur (pour certains, elle est fixe)

chunkId
4
Définition du fichier en tant que conteneur multimédia
0x52494646 en Big-Endian («RIFF»)

chunkSize
4
Taille de l'ensemble du fichier sans chunkId et chunkSize
FILE_SIZE — 8

format
4
Définition du type dans RIFF
0x57415645 en Big-Endian («WAVE»)

subchunk1Id
4
Pour que le fichier occupe plus d'espace, continuation du format
0x666d7420 en Big-Endian («fmt «)

subchunk1Size
4
En-tête restant (en octets)
16 par défaut (pour le cas sans compression du flux audio)

audioFormat
2
Format audio (dépend de la méthode de compression et de la structure des données audio)
1 (pour PCM, que nous examinons)

numChannels
2
Nombre de canaux
1 / 2, nous prendrons 1 canal (3 / 4 / 5 / 6 / 7… — une piste audio spécifique, par exemple 4 pour le son quadriphonique, etc.)

sampleRate
4
Fréquence d'échantillonnage audio (en Hertz)
Plus elle est élevée, meilleure sera la qualité du son, mais plus de mémoire sera nécessaire pour créer une piste audio de même longueur, la valeur recommandée est de 48000 (qualité sonore la plus acceptable)

byteRate
4
Nombre d'octets par seconde
sampleRate numChannels bitsPerSample (suivant)

blockAlign
2
Nombre d'octets par échantillon
numChannels * bitsPerSample : 8

bitsPerSample
2
Nombre de bits par échantillon (profondeur)
N'importe quel nombre multiple de 8. Plus il est élevé, meilleur sera le son, au-delà de 32 bits, il n'y a pas de différence perceptible pour l'humain.

subchunk2Id
4
Marqueur de début des données (car il peut y avoir d'autres éléments d'en-tête selon audioFormat)
0x64617461 en Big-Endian («data»)

subchunk2Size
4
Taille de la zone de données
taille de data en int

data
byteRate * durée de l'audio
Données audio
?

Exemple avec WAVE

Il est facile de traduire le tableau précédent dans une structure C, mais notre langage aujourd'hui est Python. La chose la plus simple à faire en utilisant «onde» est un générateur de bruit. Pour cette tâche, nous n'aurons pas besoin d'un byteRate élevé ni de compression.
Pour commencer, importons les modules nécessaires :

# WAV.py

from struct import pack  # перевод py-объектов в базовые типы из C
from os import urandom  # функция для чтения /dev/urandom, для windows:
# from random import randint
# urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)])  # лямбда под windows, т.к. urandom'а в винде нет
from sys import argv, exit  # аргументы к проге и выход

if len(argv) != 3:  # +1 имя скрипта (-1, если будете замораживать)
    print('Usage: python3 WAV.py [num of samples] [output]')
    exit(1)

Ensuite, nous devons créer toutes les variables nécessaires à partir du tableau selon leurs tailles. Les grandeurs variables dépendent ici uniquement de numSamples (nombre d'échantillons). Plus il y en aura, plus notre bruit durera.

numSamples = int(argv[1])
output_path = argv[2]

chunkId = b'RIFF'
Format = b'WAVE'
subchunk1ID = b'fmt '
subchunk1Size = b'x10x00x00x00'  # 0d16
audioFormat = b'x01x00'
numChannels = b'x02x00'  # 2 canaux suffisent (stéréo)
sampleRate = pack('<L', 1000)  # 1000 est suffisant, mais si on en met plus, le bruit sera mieux perceptible. À 1000, ça sonne comme du vent
bitsPerSample = b'x20x00'  # 0d32
byteRate = pack('<L', 1000 * 2 * 4)  # sampleRate * numChannels * bitsPerSample / 8  (son 32 bits)
blockAlign = b'x08x00'  # numChannels * BPS / 8
subchunk2ID = b'data'
subchunk2Size = pack('<L', numSamples * 2 * 4)  # * numChannels * BPS / 8
chunkSize = pack('<L', 36 + numSamples * 2 * 4)  # 36 + subchunk2Size

data = urandom(1000 * 2 * 4 * numSamples)  # le bruit lui-même

Il ne reste plus qu'à les enregistrer dans l'ordre nécessaire (comme dans le tableau) :

with open(output_path, 'wb') as fh:
    fh.write(chunkId + chunkSize + Format + subchunk1ID +
            subchunk1Size + audioFormat + numChannels + 
            sampleRate + byteRate + blockAlign + bitsPerSample +
            subchunk2ID + subchunk2Size + data)  # écriture

Voilà, c'est prêt. Pour utiliser le script, nous devons ajouter les arguments de ligne de commande nécessaires :
python3 WAV.py [num d'échantillons] [sortie]
num d'échantillons — nombre d'échantillons
sortie — chemin du fichier de sortie

Voici un lien vers un fichier audio de test avec du bruit, mais pour économiser de la mémoire, j'ai réduit le BPS à 1b/s et le nombre de canaux à 1 (avec un flux audio stéréo non compressé de 32 bits à 64kbs, j'obtenais 80 Mo de fichier .wav pur, alors qu'avec cela, il ne reste que 10) : https://instaud.io/3Dcy

Tout le code dans son intégralité (WAV.py) (Le code a de nombreuses répétitions de valeurs de variables, c'est juste un brouillon) :

from struct import pack  # conversion des objets python en types de base C
from os import urandom  # fonction pour lire /dev/urandom, pour windows:
# from random import randint
# urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)])  # lambda pour windows, car urandom n'existe pas sur windows
from sys import argv, exit  # arguments pour le programme et sortie

if len(argv) != 3:  # +1 nom du script (-1, si vous prévoyez de le geler)
    print('Usage: python3 WAV.py [nombre d’échantillons] [sortie]')
    exit(1)

numSamples = int(argv[1])
output_path = argv[2]

chunkId = b'RIFF'
Format = b'WAVE'
subchunk1ID = b'fmt '
subchunk1Size = b'x10x00x00x00'  # 0d16
audioFormat = b'x01x00'
numChannels = b'x02x00'  # 2 canaux suffisent (stéréo) 
sampleRate = pack('<L', 1000)  # 1000 sera suffisant, mais on peut faire plus.
bitsPerSample = b'x20x00'  # 0d32
byteRate = pack('<L', 1000 * 2 * 4)  # sampleRate * numChannels * bitsPerSample / 8  (son 32 bits)
blockAlign = b'x08x00'  # numChannels * BPS / 8
subchunk2ID = b'data'
subchunk2Size = pack('<L', numSamples * 2 * 4)  # * numChannels * BPS / 8
chunkSize = pack('<L', 36 + numSamples * 2 * 4)  # 36 + subchunk2Size

data = urandom(1000 * 2 * 4 * numSamples)  # le bruit lui-même

with open(output_path, 'wb') as fh:
    fh.write(chunkId + chunkSize + Format + subchunk1ID +
            subchunk1Size + audioFormat + numChannels + 
            sampleRate + byteRate + blockAlign + bitsPerSample +
            subchunk2ID + subchunk2Size + data)  # écriture du résultat dans le fichier

Conclusion

Vous en savez maintenant un peu plus sur le son numérique et comment il est stocké. Dans ce post, nous n'avons pas utilisé de compression (audioFormat), mais il faudrait environ 10 articles pour examiner chacun des formats populaires. J'espère que vous avez appris quelque chose de nouveau et que cela vous aidera dans vos futurs développements.
Merci!

Sources

Structure du fichier WAV
WAV — Wikipédia

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster