Metoder til komprimering/lagring af mediedata i WAVE- og JPEG-formater, del 1

Hej! Min første serie af artikler vil fokusere på at studere billed-/lydkomprimering og lagringsmetoder som JPEG (billede) og WAVE (lyd), og vil også indeholde eksempler på programmer, der bruger disse formater (.jpg, .wav) i praksis. I denne del vil vi se på WAVE.

Story

WAVE (Waveform Audio File Format) er et containerfilformat til lagring af en optagelse af en lydstrøm. Denne beholder bruges typisk til at lagre ukomprimeret pulskodemoduleret lyd. (Tattet fra Wikipedia)

Den blev opfundet og udgivet i 1991 sammen med RIFF af Microsoft og IBM (den tids førende it-virksomheder).

Filstruktur

Filen har en sidehoveddel, selve dataene, men ingen sidefod. Headeren vejer i alt 44 bytes.
Headeren indeholder indstillinger for antallet af bits i samplet, sample rate, lyddybde osv. nødvendige oplysninger til lydkortet. (Alle numeriske tabelværdier skal skrives i Little-Endian rækkefølge)

Bloknavn
Blokstørrelse (B)
Beskrivelse/Formål
Værdi (for nogle er den fast

chunkId
4
Definere en fil som en mediebeholder
0x52494646 i Big-Endian ("RIFF")

chunkStørrelse
4
Størrelsen på hele filen uden chunkId og chunkSize
FILE_SIZE - 8

format
4
Typedefinition fra RIFF
0x57415645 i Big-Endian ("WAVE")

subchunk1Id
4
Så filen fylder mere ved at fortsætte formateringen
0x666d7420 i Big-Endian ("fmt")

subchunk1 størrelse
4
Resterende overskrift (i bytes)
16 som standard (for tilfældet uden lydstream-komprimering)

lydformat
2
Lydformat (afhænger af komprimeringsmetode og lyddatastruktur)
1 (for PCM, hvilket er det, vi overvejer)

antal kanaler
2
Antal kanaler
1/2, vil vi tage 1 kanal (3/4/5/6/7... - et specifikt lydspor, for eksempel 4 til quad-lyd osv.)

sampleRate
4
Lydsamplinghastighed (i Hertz)
Jo højere, jo bedre bliver lyden, men jo mere hukommelse der kræves for at skabe et lydspor af samme længde, er den anbefalede værdi 48000 (den mest acceptable lydkvalitet)

byteRate
4
Antal bytes pr. sekund
sampleRate antal kanaler bitsPerSample (yderligere)

blokAlign
2
Antal bytes for 1 prøve
antal kanaler * bitsPerSample: 8

bitsPerSample
2
Antal bits pr. 1 sample (dybde)
Ethvert tal, der er et multiplum af 8. Jo højere tal, jo bedre og tungere vil lyden være; fra 32 bit er der ingen forskel for mennesker

subchunk2Id
4
Datareferencemærke (da der kan være andre overskriftselementer afhængigt af lydformatet)
0x64617461 i Big-Endian ("data")

subchunk2 størrelse
4
Dataområdets størrelse
datastørrelse i int

data
byteRate * lydvarighed
Lyddata
?

WAVE eksempel

Den foregående tabel kan nemt oversættes til en struktur i C, men vores sprog for i dag er Python. Det nemmeste du kan gøre er at bruge en "bølge" - en støjgenerator. Til denne opgave har vi ikke brug for høj byteRate og komprimering.
Lad os først importere de nødvendige moduler:

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

Dernæst skal vi oprette alle de nødvendige variabler fra tabellen i henhold til deres størrelser. Variableværdierne i den afhænger kun af numSamples (antal prøver). Jo flere af dem der er, jo længere vil vores støj fortsætte.

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)  # сам шум

Det eneste, der er tilbage, er at skrive dem ned i den påkrævede rækkefølge (som i tabellen):

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

Og så klar. For at bruge scriptet skal vi tilføje de nødvendige kommandolinjeargumenter:
python3 WAV.py [num of samples] [output]
antal prøver - antal. prøver
output — sti til outputfilen

Her er et link til en test lydfil med støj, men for at spare hukommelse sænkede jeg BPS til 1b/s og sænkede antallet af kanaler til 1 (med en 32-bit ukomprimeret stereo lydstream på 64kbs viste det sig at være 80M ren .wav-fil og kun 10): https://instaud.io/3Dcy

Hele koden (WAV.py) (Koden har en masse duplikerede variabelværdier, dette er kun en skitse):

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)  # записываем в файл результат

Total

Så du har lært lidt mere om digital lyd og hvordan den opbevares. I dette indlæg brugte vi ikke komprimering (audioFormat), men for at overveje hver af de populære, kræves der 10 artikler. Jeg håber, du har lært noget nyt for dig selv, og dette vil hjælpe dig i fremtidige udviklinger.
Tak!

kilder

WAV-filstruktur
WAV - Wikipedia

Kilde: www.habr.com

Tilføj en kommentar