Medijos duomenų glaudinimo / saugojimo WAVE ir JPEG formatais metodai, 1 dalis

Sveiki! Mano pirmoji straipsnių serija bus skirta vaizdų / garso glaudinimo ir saugojimo metodų, tokių kaip JPEG (vaizdas) ir WAVE (garsas), studijoms, taip pat bus pateikti praktikoje šiuos formatus (.jpg, .wav) naudojančių programų pavyzdžiai. Šioje dalyje apžvelgsime WAVE.

Istorija

WAVE (Waveform Audio File Format) yra konteinerio failo formatas, skirtas garso srauto įrašams saugoti. Šis konteineris paprastai naudojamas nesuspausto impulsinio kodo moduliuoto garso saugojimui. (Paimta iš Vikipedijos)

Jį išrado ir 1991 m. kartu su RIFF išleido Microsoft ir IBM (to meto pirmaujančios IT įmonės).

Failo struktūra

Failas turi antraštės dalį, pačius duomenis, bet neturi poraštės. Antraštė iš viso sveria 44 baitus.
Antraštėje yra bitų skaičiaus imtyje, mėginio dažnio, garso gylio ir kt. nustatymai. garso kortelei reikalinga informacija. (Visos skaitinės lentelės reikšmės turi būti parašytos Little-Endian tvarka)

Blokuoti pavadinimą
Bloko dydis (B)
Aprašymas/Paskirtis
Vertė (kai kuriems ji yra fiksuota

chunkId
4
Failo apibrėžimas kaip medijos konteineris
0x52494646 Big-Endian („RIFF“)

gabalo dydis
4
Viso failo dydis be chunkId ir chunkSize
FILE_SIZE – 8

formatas
4
Tipo apibrėžimas iš RIFF
0x57415645 Big-Endian („WAVE“)

subchunk1Id
4
Kad failas užimtų daugiau vietos, tęsiant formatavimą
0x666d7420 Big-Endian („fmt“)

subgabalas1 Dydis
4
Likusi antraštė (baitais)
16 pagal numatytuosius nustatymus (dėklui be garso srauto glaudinimo)

garso formatas
2
Garso formatas (priklauso nuo suspaudimo metodo ir garso duomenų struktūros)
1 (PCM, ką mes svarstome)

kanalų skaičius
2
Kanalų skaičius
1/2, paimsime 1 kanalą (3/4/5/6/7... - konkretų garso takelį, pavyzdžiui, 4 keturkampiui garsui ir pan.)

mėginio rodiklis
4
Garso atrankos dažnis (hercais)
Kuo aukštesnis, tuo geresnis bus garsas, bet tuo daugiau atminties reikės norint sukurti tokio pat ilgio garso takelį, rekomenduojama vertė yra 48000 (priimtiniausia garso kokybė)

byteRate
4
Baitų skaičius per sekundę
mėginio rodiklis kanalų skaičius bitsPerSample (toliau)

blockAlign
2
1 mėginio baitų skaičius
numChannels * bitsPerSample: 8

bitsPerSample
2
Bitų skaičius 1 mėginyje (gylis)
Bet koks skaičius, kuris yra 8 kartotinis. Kuo didesnis skaičius, tuo geresnis ir sunkesnis bus garsas; nuo 32 bitų žmonėms nėra jokio skirtumo

subchunk2Id
4
Duomenų nuorodos ženklas (nes gali būti ir kitų antraštės elementų, priklausomai nuo garso formato)
0x64617461 Big-Endiane („duomenys“)

subgabalas2 Dydis
4
Duomenų srities dydis
duomenų dydis tarpt

duomenys
byteRate * garso trukmė
Garso duomenys
?

WAVE pavyzdys

Ankstesnę lentelę galima lengvai išversti į C struktūrą, tačiau šiandien mūsų kalba yra Python. Lengviausias dalykas, kurį galite padaryti, yra naudoti „bangą“ - triukšmo generatorių. Šiai užduočiai mums nereikia didelio baitų greičio ir glaudinimo.
Pirma, importuokime reikiamus modulius:

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

Toliau iš lentelės turime sukurti visus reikiamus kintamuosius pagal jų dydžius. Jame esančios kintamųjų reikšmės priklauso tik nuo numSamples (mėginių skaičiaus). Kuo daugiau jų bus, tuo ilgiau tęsis mūsų triukšmas.

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

Belieka juos užrašyti reikiama seka (kaip lentelėje):

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

Ir taip, pasiruošę. Norėdami naudoti scenarijų, turime pridėti būtinus komandinės eilutės argumentus:
python3 WAV.py [num of samples] [output]
mėginių skaičius – skaičius. pavyzdžiai
output – kelias į išvesties failą

Čia yra nuoroda į bandomąjį garso failą su triukšmu, bet taupydamas atmintį sumažinau BPS iki 1b/s ir sumažinau kanalų skaičių iki 1 (su 32 bitų nesuspaustu stereo garso srautu 64 kb. 80M gryno .wav failo ir tik 10): https://instaud.io/3Dcy

Visas kodas (WAV.py) (kode yra daug pasikartojančių kintamųjų reikšmių, tai tik eskizas):

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

Visas

Taigi jūs sužinojote šiek tiek daugiau apie skaitmeninį garsą ir jo saugojimą. Šiame įraše mes nenaudojome glaudinimo (audioFormat), tačiau norint apsvarstyti kiekvieną iš populiariausių, reikės 10 straipsnių. Tikiuosi, kad sužinojote ką nors naujo ir tai padės ateityje.
Dėkojame!

Informacijos šaltiniai

WAV failo struktūra
WAV – Vikipedija

Šaltinis: www.habr.com

Добавить комментарий