Metoaden foar it komprimearjen / opslaan fan mediagegevens yn WAVE- en JPEG-formaten, diel 1

Hallo! Myn earste rige fan artikels sil rjochtsje op in stúdzje ôfbylding / audio kompresje en opslach metoaden lykas JPEG (ôfbylding) en WAVE (lûd), en sil ek befetsje foarbylden fan programma mei help fan dizze formaten (.jpg, .wav) yn de praktyk. Yn dit diel sille wy sjen nei WAVE.

История

WAVE (Waveform Audio File Format) is in kontenerbestânformaat foar it opslaan fan in opname fan in audiostream. Dizze kontener wurdt typysk brûkt om net-komprimeare pulskoade-moduleare audio op te slaan. (Trochwiisd fan Wikipedia)

It waard útfûn en publisearre yn 1991 tegearre mei RIFF troch Microsoft en IBM (Leading IT-bedriuwen fan dy tiid).

Triemstruktuer

De triem hat in koptekst diel, de gegevens sels, mar gjin foettekst. De koptekst waacht yn totaal 44 bytes.
De koptekst befettet ynstellings foar it oantal bits yn 'e stekproef, samplerate, lûddjipte, ensfh. ynformaasje nedich foar de lûdkaart. (Alle numerike tabelwearden moatte wurde skreaun yn Little-Endian folchoarder)

Blok namme
Blokgrutte (B)
Beskriuwing / Doel
Wearde (foar guon is it fêst

chunkId
4
It definiearjen fan in bestân as in mediacontainer
0x52494646 yn Big-Endian ("RIFF")

chunkSize
4
Grutte fan it hiele bestân sûnder chunkId en chunkSize
FILE_SIZE - 8

opmaak
4
Type definysje fan RIFF
0x57415645 yn Big-Endian ("WAVE")

subchunk1Id
4
Sadat it bestân mear romte nimt as fuortsetting fan it formaat
0x666d7420 yn Big-Endian ("fmt")

subchunk1 Grutte
4
Resterende koptekst (yn bytes)
16 standert (foar it gefal sûnder kompresje fan audiostream)

audioFormat
2
Audioformaat (hinget ôf fan kompresjemetoade en audiogegevensstruktuer)
1 (foar PCM, dat is wat wy beskôgje)

numChannels
2
Oantal kanalen
1/2, sille wy 1 kanaal nimme (3/4/5/6/7 ... - in spesifyk audiospoar, bygelyks 4 foar quad audio, ensfh.)

sampleRate
4
Audio sampling rate (yn Hertz)
Hoe heger, hoe better it lûd sil wêze, mar hoe mear ûnthâld sil nedich wêze om in audiospoar fan deselde lingte te meitsjen, de oanrikkemandearre wearde is 48000 (de meast akseptabele lûdskwaliteit)

byteRate
4
Oantal bytes per sekonde
sampleRate numChannels bitsPerSample (fierder)

blockAlign
2
Oantal bytes foar 1 stekproef
numChannels * bitsPerSample: 8

bitsPerSample
2
Oantal bits per 1 stekproef (djipte)
Elk nûmer dat in mearfâldich is fan 8. Hoe heger it nûmer, hoe better en swierder de audio sil wêze; fan 32 bits is d'r gjin ferskil foar minsken

subchunk2Id
4
Gegevensreferinsjemark (om't d'r oare kopteksteleminten kinne wêze ôfhinklik fan it audioformaat)
0x64617461 yn Big-Endian ("gegevens")

subchunk2 Grutte
4
Data gebiet grutte
data grutte yn int

data
byteRate * audio doer
Audio data
?

Foarbyld fan WAVE

De foarige tabel kin maklik oerset wurde yn in struktuer yn C, mar ús taal foar hjoed is Python. It maklikste ding dat jo kinne dwaan is in "welle" te brûken - in lûdgenerator. Foar dizze taak hawwe wy gjin hege byteRate en kompresje nedich.
Litte wy earst de nedige modules ymportearje:

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

Folgjende, wy moatte meitsje alle nedige fariabelen út de tabel neffens harren maten. De fariabele wearden dêryn binne allinich ôfhinklik fan numSamples (oantal samples). Hoe mear der binne, hoe langer ús lûd trochgiet.

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 oerbliuwt is om se op te skriuwen yn 'e fereaske folchoarder (lykas yn' e tabel):

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

En sa, klear. Om it skript te brûken, moatte wy de nedige kommandorigelarguminten tafoegje:
python3 WAV.py [num of samples] [output]
oantal samples - telle. samples
útfier - paad nei it útfiertriem

Hjir is in keppeling nei in test-audio-bestân mei lûd, mar om ûnthâld te bewarjen haw ik de BPS ferlege nei 1b/s en it oantal kanalen ferlege nei 1 (mei in 32-bit net-komprimeare stereo-audiostream op 64kbs, it die bliken te wêzen 80M fan suver .wav triem, en mar 10): https://instaud.io/3Dcy

De hiele koade (WAV.py) (De koade hat in protte dûbele fariabele wearden, dit is gewoan in skets):

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

It resultaat

Sa hawwe jo wat mear leard oer digitaal lûd en hoe't it bewarre wurdt. Yn dizze post hawwe wy gjin kompresje (audioFormat) brûkt, mar om elk fan 'e populêre te beskôgjen, sille 10 artikels ferplicht wurde. Ik hoopje dat jo wat nijs foar josels leard hawwe en dit sil jo helpe by takomstige ûntjouwings.
Tankewol!

Boarnen

WAV triem struktuer
WAV - Wikipedy

Boarne: www.habr.com

Add a comment