Médiaadatok WAVE és JPEG formátumú tömörítési/tárolási módszerei, 1. rész

Helló! Első cikksorozatom a kép/audio tömörítési és tárolási módszerek, mint például a JPEG (kép) és a WAVE (hang) tanulmányozására fókuszál, és példákat is tartalmazok az ilyen formátumokat (.jpg, .wav) a gyakorlatban használó programokra. Ebben a részben a WAVE-t fogjuk megnézni.

Történet

A WAVE (Waveform Audio File Format) egy konténerfájl formátum egy hangfolyam felvételének tárolására. Ezt a tárolót általában tömörítetlen impulzuskóddal modulált hang tárolására használják. (A Wikipédiáról átvéve)

1991-ben találta ki és adta ki a RIFF-fel együtt a Microsoft és az IBM (akkori vezető IT-cégek).

Fájlszerkezet

A fájlnak van fejléc része, maga az adat, de nincs lábléc. A fejléc súlya összesen 44 bájt.
A fejléc a mintában lévő bitek számának, a mintavételezési sebességnek, a hangmélységnek stb. beállításait tartalmazza. a hangkártyához szükséges információkat. (Minden numerikus táblázatértéket Little-Endia sorrendben kell írni)

Blokknév
Blokkméret (B)
Leírás/Cél
Érték (egyeseknél fix

chunkId
4
Fájl meghatározása médiatárolóként
0x52494646 Big-Endian nyelven („RIFF”)

chunkSize
4
A teljes fájl mérete chunkId és chunkSize nélkül
FILE_SIZE – 8

formátum
4
Típusdefiníció a RIFF-ből
0x57415645 Big-Endian nyelven („WAVE”)

subchunk1Id
4
Így a fájl több helyet foglal el a formátum folytatásaként
0x666d7420 Big-endian nyelven („fmt”)

alcsonk1Méret
4
Fennmaradó fejléc (bájtban)
Alapértelmezés szerint 16 (audio stream tömörítés nélküli esethez)

audioFormat
2
Hangformátum (a tömörítési módszertől és a hang adatszerkezetétől függ)
1 (PCM-hez, amit fontolóra veszünk)

numChannels
2
Csatornák száma
1/2, 1 csatornát veszünk (3/4/5/6/7... - egy adott hangsávot, például 4-et a négyes hanghoz stb.)

mintavételi ráta
4
Hang mintavételi frekvencia (hertzben)
Minél magasabb, annál jobb lesz a hang, de annál több memóriára lesz szükség egy azonos hosszúságú hangsáv létrehozásához, az ajánlott érték 48000 (a legelfogadhatóbb hangminőség)

byteRate
4
Bájtok száma másodpercenként
mintavételi ráta numChannels bitsPerSample (tovább)

blockAlign
2
Bájtok száma 1 mintához
numChannels * bitsPerSample: 8

bitsPerSample
2
Bitek száma 1 mintánként (mélység)
Bármilyen szám, amely 8 többszöröse. Minél nagyobb a szám, annál jobb és nehezebb lesz a hang; 32 bittől nincs különbség az ember számára

subchunk2Id
4
Adathivatkozási jel (mivel az audioformátumtól függően más fejlécelemek is lehetnek)
0x64617461 Big-Endianban ("adatok")

alcsonk2Méret
4
Adatterület mérete
adatok mérete int

dátum
byteRate * hang időtartama
Hangadatok
?

WAVE példa

Az előző táblázat könnyen lefordítható C-beli struktúrára, de a mai nyelvünk a Python. A legegyszerűbb dolog, amit megtehetsz, egy „hullám” - egy zajgenerátor használata. Ehhez a feladathoz nincs szükségünk magas byteRate-re és tömörítésre.
Először is importáljuk a szükséges modulokat:

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

Ezután létre kell hoznunk az összes szükséges változót a táblázatból méretüknek megfelelően. A benne lévő változó értékek csak a numSamples-től (minták számától) függenek. Minél többen vannak, annál tovább tart a zajunk.

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

Nem kell mást tenni, mint leírni őket a kívánt sorrendben (mint a táblázatban):

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

És kész. A szkript használatához hozzá kell adnunk a szükséges parancssori argumentumokat:
python3 WAV.py [num of samples] [output]
minták száma – szám. minták
output — a kimeneti fájl elérési útja

Itt van egy link egy zajos teszt hangfájlhoz, de a memória megtakarítása érdekében a BPS-t 1b/s-ra, a csatornák számát pedig 1-re csökkentettem (32 bites tömörítetlen sztereó hangfolyammal 64kbs-nál kiderült, hogy 80 millió tiszta .wav fájl, és csak 10): https://instaud.io/3Dcy

A teljes kód (WAV.py) (A kódban sok ismétlődő változóérték van, ez csak egy vázlat):

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

Teljes

Tehát egy kicsit többet tanult a digitális hangról és annak tárolásáról. Ebben a bejegyzésben nem használtunk tömörítést (audioFormat), de a népszerűek mindegyikének figyelembevételéhez 10 cikkre lesz szükség, remélem tanultál valami újat és ez segít a jövőbeni fejlesztésekben.
Köszönöm!

forrás

WAV fájl szerkezet
WAV – Wikipédia

Forrás: will.com

Hozzászólás