Përshëndetje! Seria ime e parë e artikujve do të jetë e orientuar në studimin e metodave të kompresimit dhe ruajtjes së imazheve/zërit, si JPEG (imazh) dhe WAVE (zë), gjithashtu do të përmbajë shembuj programesh që përdorin këto formate (.jpg, .wav) në praktikë. Në këtë pjesë ne do të shqyrtojmë pikërisht WAVE.
Historia
WAVE (Waveform Audio File Format) është një format skedari-konteineri për ruajtjen e regjistrimeve të rrjedhjeve audio. Ky kontejner përdoret zakonisht për ruajtjen e zërit të papërpunuar në modulatorin impulsiv-koduar. (E marrë nga Wikipedia)
Ai u shpik dhe publikua në vitin 1991 së bashku me RIFF nga kompanitë Microsoft dhe IBM (kompanitë kryesore IT të asaj kohe).
Struktura e skedarit
Skedari ka një pjesë titull, të dhënat dhe nuk ka fund. Titulli peshon gjithsej 44 byte.
Në header ndodhen parametrat e numrit të bitëve në mostra, frekuencës së dekodimit, thellësisë së zërit dhe informacione të tjera të nevojshme për kartën e zërit. (Të gjitha vlerat numerike në tabelë duhet të shkruhen në rendin Little-Endian)
Emri i bllokut
Madhësia e bllokut (B)
Përshkrimi/Dedikimi
Vlera (për disa ajo është e fiksur)
chunkId
4
Përcaktimi i skedarit si kontejner mediatik
0x52494646 në Big-Endian («RIFF»)
chunkSize
4
Madhësia e skedarit të plotë pa chunkId dhe chunkSize
FILE_SIZE — 8
format
4
Përcaktimi i tipit nga RIFF
0x57415645 në Big-Endian («WAVE»)
subchunk1Id
4
Që skedari të zërë më shumë vend vazhdimi i formatit
0x666d7420 në Big-Endian («fmt «)
subchunk1Size
4
Headeri i mbetur (në byte)
16 si parazgjedhje (për rastin pa kompresim të rrjedhës audio)
audioFormat
2
Formati audio (varet nga metoda e kompresimit dhe struktura e të dhënave audio)
1 (për PCM, të cilin ne e shqyrtojmë)
numChannels
2
Numri i kanaleve
1/2, ne do të marim 1 kanal (3/4/5/6/7... — rruga specifike audio, për shembull 4 për zë katror etj.)
sampleRate
4
Frekuenca e mostrës së zërit (në Hertz)
Sa më shumë, aq më cilësor do të jetë zëri, por gjithashtu më shumë hapësirë do të nevojitet për të krijuar rrjedhën audio të një te njëjtë gjatësi, vlera e rekomanduar — 48000 (cilësi më e pranueshme e zërit)
byteRate
4
Numri i byte-ve për 1 sekondë
sampleRate numChannels bitsPerSample (më poshtë)
blockAlign
2
Numri i byte-ve për 1 mostrë
numChannels * bitsPerSample: 8
bitsPerSample
2
Numri i bitëve për 1 mostrë (thellësia)
Çdo numër, i shumëzuar me 8. Sa më shumë, aq më mirë dhe më e rëndë do të jetë audio, nga 32 bit nuk ka ndarje për njeriun
subchunk2Id
4
Shenja e gjitha fillimit të të dhënave (pasi mund të ketë elemente të tjera në header në varësi të audioFormat)
0x64617461 në Big-Endian («data»)
subchunk2Size
4
Përmasat e zonës së të dhënave
përmasat e të dhënave në int
data
byteRate * kohëzgjatja e audios
Të dhënat audiovizive
?
Shembulli me WAVE
Tabelën e mëparshme mund ta konvertojmë lehtësisht në një strukturë në C, por gjuha jonë për sot është Python. Gjëja më e lehtë që mund të bëjmë, duke përdorur 'valën' — gjeneratorin e zhurmës. Për këtë detyrë nuk do të na nevojitet një byteRate i lartë dhe kompresimi.
Së pari, importojmë modulet e nevojshme:
# 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)Më pas, nevojitet të krijojmë të gjithë variablat e nevojshëm nga tabela sipas përmasave të tyre. Variablat e paqëndrueshëm në të varen vetëm nga numSamples (numri i mostrave). Sa më shumë mostra të ketë, aq më gjatë do të zgjasë zhurma jonë.
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 kanale do të mjaftonin (stereo)
sampleRate = pack('<L', 1000) # 1000 është e mjaftueshme, por nëse e vendosim më lart, zhurma do të dëgjohet më mirë. Me 1000, ajo tingëllon si era
bitsPerSample = b'x20x00' # 0d32
byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (audio 32 bit)
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) # vetë zhurmaE vetmja gjë që na mbetet është ta shkruajmë ato në rendin e duhur (si në tabelë):
with open(output_path, 'wb') as fh:
fh.write(chunkId + chunkSize + Format + subchunk1ID +
subchunk1Size + audioFormat + numChannels +
sampleRate + byteRate + blockAlign + bitsPerSample +
subchunk2ID + subchunk2Size + data) # shkruajmëDhe kështu, është gati. Për të përdorur skriptin, na nevojiten argumentet e duhura të linjës së komandës:
python3 WAV.py [numri i mostrave] [dalja]
numri i mostrave — numri i mostrave
dalja — rruga për skedarin dalës
Ja një lidhje me një skedar audio testues me zhurmën, por për të kursyer memorie e kam ulur BPS në 1b/s dhe numrin e kanaleve e kam reduktuar në 1 (me një audio 32 bit të pakompresuar stereo me 64kbs kam marrë 80M të pastër .wav skedari, dhe kështu vetëm 10):
I gjithë kodi në tërësi (WAV.py) (Kodi ka shumë kopjime të vlerave të variablave, ky është vetëm një skicë):
from struct import pack # konvertimi i objekteve py në lloje bazë nga C
from os import urandom # funksioni për të lexuar \/dev\/urandom, për windows:
# from random import randint
# urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)]) # lambda për windows, pasi urandom nuk ekziston në windows
from sys import argv, exit # argumente për programin dhe daljen
if len(argv) != 3: # +1 emri i skriptit (-1, nëse do të ngrini)
print('Përdorimi: python3 WAV.py [numri i mostrave] [dalja]')
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 kanale do të mjaftojnë (stereo)
sampleRate = pack('<L', 1000) # 1000 është e mjaftueshme, por mund të jetë edhe më shumë.
bitsPerSample = b'x20x00' # 0d32
byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample \/ 8 (32 bit zëri)
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) # zhurma vetë
with open(output_path, 'wb') as fh:
fh.write(chunkId + chunkSize + Format + subchunk1ID +
subchunk1Size + audioFormat + numChannels +
sampleRate + byteRate + blockAlign + bitsPerSample +
subchunk2ID + subchunk2Size + data) # shkruaj në skedarin rezultatPërfundimi
Tani e dini pak më shumë rreth zërit digjital dhe mënyrës se si ruhet ai. Në këtë post, ne nuk përdorëm kompresim (audioFormat), por për të shqyrtuar secilin nga formatet më të njohura do të nevojiteshin rreth 10 artikuj. Shpresoj të keni mësuar diçka të re për veten dhe kjo do t'ju ndihmojë në zhvillimet e ardhshme.
Faleminderit!
Burimet
Burimi: habr.com
