Methoden fir d'Kompressioun / Späicheren vun Mediendaten a WAVE a JPEG Formater, Deel 1

Hallo! Meng éischt Serie vun Artikelen konzentréieren op studéiert Bild / Audio Kompressioun a Stockage Methoden wéi JPEG (Bild) an WAVE (Sound), a wäert och Beispiller vun Programmer déi dëse Formater benotzt (.jpg, .wav) an Praxis enthalen. An dësem Deel wäerte mir WAVE kucken.

Geschicht

WAVE (Waveform Audio File Format) ass e Containerdateiformat fir en Opname vun engem Audiostream ze späicheren. Dëse Container gëtt typesch benotzt fir onkompriméiert Pulscode moduléiert Audio ze späicheren. (vun der Wikipedia geholl)

Et gouf erfonnt an 1991 zesumme mam RIFF vu Microsoft an IBM (Leading IT Firmen vun där Zäit) publizéiert.

Datei Struktur

De Fichier huet en Header Deel, d'Donnéeën selwer, awer kee Fousszeil. Den Header weegt insgesamt 44 Bytes.
Den Header enthält Astellunge fir d'Zuel vun de Bits an der Probe, Probequote, Toundéift, asw. Informatiounen néideg fir d'Soundkaart. (All numeresch Tabellwäerter mussen a Little-Endian Uerdnung geschriwwe ginn)

Numm Block
Block Gréisst (B)
Beschreiwung / Zweck
Wäert (fir e puer ass et fix

chunkId
4
Eng Datei als Mediencontainer definéieren
0x52494646 am Big-Endian ("RIFF")

Stéck Gréisst
4
Gréisst vun der ganzer Datei ouni chunkId a chunkSize
FILE_SIZE - 8

Format
4
Typ Definitioun vun RIFF
0x57415645 am Big-Endian ("WAVE")

subchunk1Id
4
Also datt d'Datei méi Plaz ophëlt andeems Dir de Format weiderféiert
0x666d7420 am Big-Endian ("fmt")

subchunk1 Gréisst
4
Rescht Header (a Bytes)
16 par défaut (fir de Fall ouni Audio Stream Kompressioun)

audioFormat
2
Audioformat (ofhängeg vun der Kompressiounsmethod an der Audiodatenstruktur)
1 (fir PCM, dat ass wat mir berücksichtegen)

numChannels
2
Zuel vu Kanäl
1/2, mir huelen 1 Kanal (3/4/5/6/7 ... - eng spezifesch Audio Streck, zum Beispill 4 fir Quad Audio, etc.)

sampleRate
4
Audio Sampling Taux (an Hertz)
Wat méi héich, dest besser ass den Toun, awer wat méi Erënnerung erfuerderlech ass fir en Audiotrack vun der selwechter Längt ze kreéieren, de recommandéierte Wäert ass 48000 (déi akzeptabelst Tounqualitéit)

byteRate
4
Zuel vun Bytes pro Sekonn
sampleRate numChannels bitsPerSample (weider)

blockAlign
2
Zuel vun Bytes fir 1 Prouf
numChannels * bitsPerSample: 8

bitsPerSample
2
Zuel vu Bits pro 1 Probe (Déift)
All Zuel déi e Multiple vun 8 ass. Wat méi héich d'Zuel ass, dest besser a méi schwéier ass den Audio; vun 32 Bits gëtt et keen Ënnerscheed fir Mënschen

subchunk2Id
4
Donnéeën Referenz Mark (well et kann aner Header Elementer ginn ofhängeg vum AudioFormat)
0x64617461 am Big-Endian ("Daten")

subchunk2 Gréisst
4
Donnéeën Beräich Gréisst
Datengréisst an int

Donnéeën
byteRate * Audio Dauer
Audiodaten
?

WAVE Beispill

Déi viregt Tabell kann einfach an eng Struktur am C iwwersat ginn, awer eis Sprooch fir haut ass Python. Dat einfachst wat Dir maache kënnt ass eng "Welle" ze benotzen - e Geräischer Generator. Fir dës Aufgab brauche mir keen héije ByteRate a Kompressioun.
Als éischt, loosst eis déi néideg Moduler importéieren:

# 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)

Als nächst musse mir all déi néideg Variabelen aus der Tabell no hirer Gréisst erstellen. D'Variabel Wäerter an et hänkt nëmmen op numSamples (Zuel vun Echantillon). Wat méi dovunner sinn, dest méi laang wäert eise Kaméidi weidergoen.

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-х каналов будет достаточно (стерео)
sampleRate = pack('<L', 1000)  # 1000 хватит, но если поставить больше, то шум будет слышен лучше. С 1000-ю он звучит, как ветер
bitsPerSample = b'x20x00'  # 0d32
byteRate = pack('<L', 1000 * 2 * 4)  # sampleRate * numChannels * bitsPerSample / 8  (32 bit sound)
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)  # сам шум

Alles wat bleift ass se an der erfuerderter Sequenz ze schreiwen (wéi an der Tabell):

with open(output_path, 'wb') as fh:
    fh.write(chunkId + chunkSize + Format + subchunk1ID +
            subchunk1Size + audioFormat + numChannels + 
            sampleRate + byteRate + blockAlign + bitsPerSample +
            subchunk2ID + subchunk2Size + data)  # записываем

An esou, prett. Fir de Skript ze benotzen, musse mir déi néideg Kommandozeil Argumenter addéieren:
python3 WAV.py [num of samples] [output]
Zuel vun Echantillon - zielen. Echantillon
Ausgang - Wee fir d'Ausgabdatei

Hei ass e Link op eng Test Audiodatei mat Kaméidi, awer fir Erënnerung ze spueren hunn ech de BPS op 1b/s erofgesat an d'Zuel vun de Kanäl op 1 erofgesat (mat engem 32-Bit onkompriméierten Stereo Audio Stream bei 64kbs, et huet sech erausgestallt 80M reng .wav Datei, an nëmmen 10): https://instaud.io/3Dcy

De ganze Code (WAV.py) (De Code huet vill duplizéiert Variabelwäerter, dëst ass just eng Skizz):

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'x10x00x00x00'  # 0d16
audioFormat = b'x01x00'
numChannels = b'x02x00'  # 2-х каналов будет достаточно (стерео) 
sampleRate = pack('<L', 1000)  # 1000 хватит, но можно и больше.
bitsPerSample = b'x20x00'  # 0d32
byteRate = pack('<L', 1000 * 2 * 4)  # sampleRate * numChannels * bitsPerSample / 8  (32 bit sound)
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)  # сам шум

with open(output_path, 'wb') as fh:
    fh.write(chunkId + chunkSize + Format + subchunk1ID +
            subchunk1Size + audioFormat + numChannels + 
            sampleRate + byteRate + blockAlign + bitsPerSample +
            subchunk2ID + subchunk2Size + data)  # записываем в файл результат

D 'Resultat

Also hutt Dir e bësse méi iwwer den digitale Sound geléiert a wéi et gespäichert gëtt. An dësem Beitrag hu mir keng Kompressioun (AudioFormat) benotzt, awer fir all déi populär ze berücksichtegen, sinn 10 Artikelen erfuerderlech. Ech hoffen Dir hutt eppes Neies fir Iech selwer geléiert an dat hëlleft Iech an zukünfteg Entwécklungen.
Merci!

Quellen vun Informatiounen

WAV Datei Struktur
WAV - Wikipedia

Source: will.com

Setzt e Commentaire