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):
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
Forrás: will.com