Menetelmät mediatietojen pakkaamiseen/tallennusta WAVE- ja JPEG-muodoissa, osa 1

Hei! Ensimmäinen artikkelisarjani keskittyy tutkimaan kuvan/äänen pakkaus- ja tallennusmenetelmiä, kuten JPEG (kuva) ja WAVE (ääni), ja sisältää myös esimerkkejä ohjelmista, jotka käyttävät näitä formaatteja (.jpg, .wav) käytännössä. Tässä osassa tarkastellaan WAVEa.

Tarina

WAVE (Waveform Audio File Format) on säilötiedostomuoto äänivirran tallennukseen. Tätä säilöä käytetään tyypillisesti pakkaamattoman pulssikoodimoduloidun äänen tallentamiseen. (Otettu Wikipediasta)

Sen keksivät ja julkaisivat vuonna 1991 yhdessä RIFF:n kanssa Microsoft ja IBM (tuohon aikaan johtavat IT-yritykset).

Tiedoston rakenne

Tiedostossa on otsikko-osa, itse tiedot, mutta ei alatunnistetta. Otsikko painaa yhteensä 44 tavua.
Otsikko sisältää asetukset näytteen bittien lukumäärälle, näytetaajuudelle, äänen syvyydelle jne. äänikorttiin tarvittavat tiedot. (Kaikki numeeriset taulukon arvot on kirjoitettava Little-Endian-järjestyksessä)

Estä nimi
Lohkon koko (B)
Kuvaus/tarkoitus
Arvo (joillekin se on kiinteä

chunkId
4
Tiedoston määrittäminen mediasäiliöksi
0x52494646 Big-Endianissa ("RIFF")

chunkSize
4
Koko tiedoston koko ilman chunkId ja chunkSize
FILE_SIZE - 8

muoto
4
Tyyppimäärittely RIFF:stä
0x57415645 Big-endianissa ("WAVE")

subchunk1d
4
Jotta tiedosto vie enemmän tilaa muodon jatkona
0x666d7420 Big-endianissa ("fmt")

osapala1 Koko
4
Jäljellä oleva otsikko (tavuina)
16 oletuksena (tapauksessa ilman äänivirran pakkausta)

äänimuoto
2
Äänimuoto (riippuu pakkausmenetelmästä ja äänidatarakenteesta)
1 (PCM:lle, jota harkitsemme)

numChannels
2
Kanavien lukumäärä
1/2, otamme 1 kanavan (3/4/5/6/7... - tietty ääniraita, esimerkiksi 4 nelikanavaiselle äänelle jne.)

näytteenottotaajuus
4
Äänen näytteenottotaajuus (hertseinä)
Mitä korkeampi, sitä parempi ääni, mutta mitä enemmän muistia tarvitaan samanpituisen ääniraidan luomiseen, suositeltu arvo on 48000 (hyväksyttävin äänenlaatu)

byteRate
4
Tavujen määrä sekunnissa
näytteenottotaajuus numChannels bitsPerSample (lisäksi)

blockAlign
2
Tavujen määrä 1 näytteelle
numChannels * bitsPerSample: 8

bitsPerSample
2
Bittien määrä yhtä näytettä kohti (syvyys)
Mikä tahansa luku, joka on 8:n kerrannainen. Mitä suurempi luku, sitä parempi ja raskaampi ääni on; 32 bitistä ihmisille ei ole eroa

subchunk2d
4
Tietojen viitemerkki (koska ääniformaatista riippuen voi olla muita otsikkoelementtejä)
0x64617461 Big-endianissa ("data")

osapala2 Koko
4
Tietoalueen koko
datan koko int

tiedot
byteRate * äänen kesto
Äänitiedot
?

WAVE esimerkki

Edellinen taulukko voidaan helposti kääntää C:n rakenteeksi, mutta tämän päivän kielemme on Python. Helpoin asia, jonka voit tehdä, on käyttää "aaltoa" - melugeneraattoria. Tätä tehtävää varten emme tarvitse korkeaa tavunopeutta ja pakkausta.
Tuodaan ensin tarvittavat moduulit:

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

Seuraavaksi meidän on luotava kaikki tarvittavat muuttujat taulukosta niiden koon mukaan. Siinä olevat muuttujan arvot riippuvat vain numSamplesista (näytteiden määrästä). Mitä enemmän niitä on, sitä pidempään melumme jatkuu.

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

Jäljelle jää vain kirjoittaa ne muistiin vaaditussa järjestyksessä (kuten taulukossa):

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

Ja niin, valmis. Komentosarjan käyttämiseksi meidän on lisättävä tarvittavat komentoriviargumentit:
python3 WAV.py [num of samples] [output]
näytteiden määrä - count. näytteet
output — polku tulostetiedostoon

Tässä on linkki testiäänitiedostoon, jossa on kohinaa, mutta muistin säästämiseksi laskin BPS:n 1b/s:iin ja kanavien lukumäärän 1:een (32-bittisellä pakkaamattomalla stereoäänivirralla 64kbs:lla se osoittautui 80 miljoonaa puhdasta .wav-tiedostoa ja vain 10): https://instaud.io/3Dcy

Koko koodi (WAV.py) (Koodissa on paljon päällekkäisiä muuttujaarvoja, tämä on vain luonnos):

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

Koko

Joten olet oppinut hieman enemmän digitaalisesta äänestä ja sen tallentamisesta. Tässä viestissä emme käyttäneet pakkausta (audioFormat), mutta jokaisen suositun huomioimiseksi tarvitaan 10 artikkelia. Toivottavasti opit jotain uutta itsellesi ja tämä auttaa sinua tulevassa kehityksessä.
Kiitos!

lähteet

WAV-tiedostorakenne
WAV - Wikipedia

Lähde: will.com

Lisää kommentti