Méthodes de compression / stockage des supports dans WAVE et JPEG, partie 1

Bonjour Ma première série d'articles visera à étudier les méthodes de compression et de stockage d'images / son, telles que JPEG (image) et WAVE (son), et ils comprendront également des exemples de programmes utilisant ces formats (.jpg, .wav) dans la pratique. Dans cette partie, nous considérerons WAVE.


L'histoire


WAVE (Waveform Audio File Format) est un format de fichier conteneur pour stocker des enregistrements de flux audio. Ce conteneur est généralement utilisé pour stocker le son non compressé en modulation par impulsions codées. (Adapté de Wikipedia)

Il a été inventé et publié en 1991 avec RIFF par Microsoft et IBM (les principales sociétés informatiques de l'époque).


Structure des fichiers


Le fichier a une partie d'en-tête, les données elles-mêmes, mais il n'y a pas de pied de page. L'en-tête pèse un total de 44 octets.
L'en-tête contient des paramètres pour le nombre de bits dans l'échantillon, la fréquence de descritisation, la profondeur sonore, etc. informations nécessaires pour une carte son. (Toutes les valeurs du tableau numérique doivent être écrites dans l'ordre Little-Endian)


Nom du blocTaille de bloc (B)Description / objectifValeur (pour certains, elle est fixe
chunkId4Définition d'un fichier comme conteneur multimédia0x52494646 en Big-Endian ("RIFF")
chunkSize4La taille du fichier entier sans chunkId et chunkSizeFILE_SIZE - 8
format4Définition de type à partir du RIFF0x57415645 en Big-Endian ("WAVE")
subchunk1Id4Pour occuper plus d'espace sur les fichiers format continu0x666d7420 en Big-Endian ("fmt")
subchunk1Size4En-tête restant (en octets)16 par défaut (pour le cas sans compression de flux audio)
audioFormat2Format audio (dépend de la méthode de compression et de la structure des données audio)1 (pour PCM, que nous envisageons)
numChannels2Nombre de canaux1/2, on prend 1 canal (3/4/5/6/7 ... - une piste audio spécifique, par exemple 4 pour un son quad, etc.)
sampleRate4Fréquence d'échantillonnage sonore (en Hertz)Plus le son est grand, meilleur sera le son, mais plus il faudra de mémoire pour créer une piste audio de la même longueur, la valeur recommandée est 48000 (la qualité sonore la plus acceptable)
byteRate4Nombre d'octets en 1 secondesampleRate numChannels bitsPerSample (ci-après)
blockAlign2Nombre d'octets pour 1 échantillonnumChannels * bitsPerSample: 8
bitsPerSample2Le nombre de bits pour 1 échantillon (profondeur)N'importe quel nombre qui est un multiple de 8. Plus l'audio sera grand et meilleur et dur, à partir de 32 bits il n'y a pas de différence pour une personne
subchunk2Id4La marque de référence du début des données (car il peut y avoir d'autres éléments d'en-tête en fonction de l'audioFormat)0x64617461 en Big-Endian ("données")
subchunk2Size4Taille de la zone de donnéestaille des données en int
les donnéesoctetRate * durée audioDonnées audio?

Exemple WAVE


Le tableau précédent peut être facilement traduit en structure C, mais aujourd'hui notre langage est Python. La chose la plus simple à faire en utilisant l'onde est un générateur de bruit. Pour cette tâche, nous n'avons pas besoin d'un taux d'octets et d'une compression élevés.
Pour commencer, nous 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 en fonction de leurs tailles. Les valeurs des variables ne dépendent ici que de numSamples (le nombre d'échantillons). Plus il y en a, plus notre bruit durera longtemps.


 numSamples = int(argv[1]) output_path = argv[2] chunkId = b'RIFF' Format = b'WAVE' subchunk1ID = b'fmt ' subchunk1Size = b'\x10\x00\x00\x00' # 0d16 audioFormat = b'\x01\x00' numChannels = b'\x02\x00' # 2-    () sampleRate = pack('<L', 1000) # 1000 ,    ,     .  1000-  ,   bitsPerSample = b'\x20\x00' # 0d32 byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit sound) blockAlign = b'\x08\x00' # 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) #   

Il ne reste plus qu'à les écrire 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) #  

Et donc, c'est fait. Pour utiliser le script, nous devons ajouter les arguments de ligne de commande nécessaires:
python3 WAV.py [num of samples] [output]
nombre d'échantillons - compter échantillons
sortie - chemin vers le 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 baissé le nombre de canaux à 1 (avec 32k de flux audio stéréo non compressé à 64kbs, il s'est avéré 80M d'un fichier .wav propre, et seulement 10): https: / /instaud.io/3Dcy


Le code entier (WAV.py) (le code a de nombreuses valeurs de variables en double, ce n'est qu'un croquis):


 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) numSamples = int(argv[1]) output_path = argv[2] chunkId = b'RIFF' Format = b'WAVE' subchunk1ID = b'fmt ' subchunk1Size = b'\x10\x00\x00\x00' # 0d16 audioFormat = b'\x01\x00' numChannels = b'\x02\x00' # 2-    () sampleRate = pack('<L', 1000) # 1000 ,    . bitsPerSample = b'\x20\x00' # 0d32 byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit sound) blockAlign = b'\x08\x00' # 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) #   with open(output_path, 'wb') as fh: fh.write(chunkId + chunkSize + Format + subchunk1ID + subchunk1Size + audioFormat + numChannels + sampleRate + byteRate + blockAlign + bitsPerSample + subchunk2ID + subchunk2Size + data) #     

Résumé


Vous avez donc appris un peu plus sur le son numérique et son stockage. Dans cet article, nous n'avons pas utilisé la compression (audioFormat), mais pour revoir chacun des articles populaires, vous aurez besoin des articles 10. J'espère que vous avez appris quelque chose de nouveau par vous-même et cela vous aidera dans les développements futurs.
Je vous remercie!


Les sources

Structure de fichiers WAV
WAV - Wikipedia

Source: https://habr.com/ru/post/fr450774/


All Articles