Përshëndetje! Seria ime e parë e artikujve do të jetë e përqendruar në studimin e metodave të kompresimit dhe ruajtjes së imazheve/zërit, si JPEG (imazhi) dhe WAVE (zëri), gjithashtu do të përmbajë shembuj programesh që përdorin këto formate (.jpg, .wav) në praktikë. Në këtë pjesë do të shqyrtojmë pikërisht WAVE.
Historia
WAVE (Waveform Audio File Format) është format skedari-kontejner për ruajtjen e regjistrimit të fluxit audio. Ky konteiner përdoret zakonisht për të ruajtur zë të papërpunuar në modulacionin impulso-kodik. (Marrë nga Wikipedia)
Ai u shpik dhe publikua në vitin 1991 së bashku me RIFF nga kompanitë Microsoft dhe IBM (Kompani kryesore IT të asaj kohe).
Struktura e skedarit
Skedari ka një pjesë titulli, të dhënat vetë, por nuk ka një fund. Titulli peshohet gjithsej 44 byte.
Në header ndodhen specifikimet e numrit të bitëve në mostrë, frekuencës së mostrës, thellësisë së zërit dhe informacione të tjera të nevojshme për kartën audio. (Të gjitha vlerat numerike të tabelës duhet të jenë në rendin Little-Endian)
Emri i bllokut
Pesha e bllokut (B)
Përshkrimi/Përdorimi
Vlera (për disa është e fiksur)
chunkId
4
Përcaktimi i skedarit si konteiner mediatik
0x52494646 në Big-Endian («RIFF»)
chunkSize
4
Pesha e gjithë skedarit pa chunkId dhe chunkSize
FILE_SIZE — 8
format
4
Përcaktimi i llojit nga RIFF
0x57415645 në Big-Endian («WAVE»)
subchunk1Id
4
Për të zgjatur hapësirën e skedarit pa e bërë më të madhe formatin
0x666d7420 në Big-Endian («fmt «)
subchunk1Size
4
Headeri i mbetur (në byte)
16 me default (për rastin pa kompresim të fluxit audio)
audioFormat
2
Formati audio (varet nga metoda e kompresimit dhe struktura e të dhënave audio)
1 (për PCM, të cilin po shqyrtojmë)
numChannels
2
Numri i kanaleve
1/2, ne do të marrim 1 kanal (3/4/5/6/7… — një rrugë audio specifike, për shembull 4 për zë quad dhe të tjerë)
sampleRate
4
Frekenca e mostrës së zërit (në Hertz)
Sa më e lartë, aq më e mirë do të jetë zëri, por aq më shumë hapësirë do të nevojitet për të krijuar një rrugë audio të njëjte, vlera e rekomanduar — 48000 (cilësia më e pranueshme e zërit)
byteRate
4
Numri i bytes për 1 sekondë
sampleRate numChannels bitsPerSample (më poshtë)
blockAlign
2
Numri i bytes për 1 mostrë
numChannels * bitsPerSample: 8
bitsPerSample
2
Numri i bitëve për 1 mostrë (thellësia)
Çdo numër, i shumëfishueshëm me 8. Sa më e madhe, aq më mirë dhe më e rëndë do të jetë audio, nga 32 bit nuk ka ndryshim për njeriun
subchunk2Id
4
Shenja e fillimit të të dhënave (sepse mund të ketë elemente të tjera në header në varësi të audioFormat)
0x64617461 në Big-Endian («data»)
subchunk2Size
4
Pesha e zonës së të dhënave
peshën e të dhënave në int
data
byteRate * kohëzgjatja e audios
Të dhënat audio
?
Shembulli me WAVE
Tabelën e mëparshme mund ta përkthejmë lehtësisht në një strukturë në C, por gjuha jonë sot është — Python. Gjëja më e lehtë që mund të bëjmë duke përdorur ‘valin’ — është gjenerimi i zhurmës. Për këtë detyrë nuk do të na nevojiten byteRate të larta dhe kompresim.
Fillimisht importojmë modulat 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, na nevojitet të krijojmë të gjitha variablat e nevojshme nga tabela sipas madhësive të tyre. Vlerat e papërcaktuara në të varen vetëm nga numSamples (numri i mostrave). Sa më shumë të jenë, aq më gjatë do vazhdojë 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ë mjaftojnë (stereo)
sampleRate = pack('<L', 1000) # 1000 është mjaftueshëm, por nëse e vendosim më shumë, zhurma do dëgjohet më mirë. Me 1000, tingëllon si era
bitsPerSample = b'x20x00' # 0d32
byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (zë 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) # zhurma e vetëNa mbetet vetëm të shkruajmë ato në rendin e nevojshëm (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 nevojshme të linjës së komandës:
python3 WAV.py [num i mostrave] [dalja]
num i mostrave — numri i mostrave
dalja — rruga e skedarit të daljes
Ja një lidhje për një skedar teste audio me zhurmë, por për të kursyer hapësirë unë e kam ulur BPS në 1b/s dhe numrin e kanaleve në 1 (me një fluide audio të pakompresuar 32 bit në 64kbs, u krijua një skedar .wav 80M, kurse kështu vetëm 10):
I gjithë kodi i plotë (WAV.py) (Kodi ka shumë përsëritje të vlerave të variableve, ky është vetëm një skicë):
from struct import pack # konvertimi i objekteve py në tipe bazike 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'it nuk i gjendet në windows
from sys import argv, exit # argumentet për programin dhe dalja
if len(argv) != 3: # +1 emri i skriptit (-1, nëse do të ftohni)
print('Përdorimi: python3 WAV.py [numri i mostrave] [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 kanale do të mjaftonin (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 (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) # 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 keni mësuar diçka më shumë rreth zërit digjital dhe si ruhet ai. Në këtë post, ne nuk e kemi përdorur kompresimin (audioFormat), por për të shqyrtuar secilin nga formatet më të njohura do të nevojiten 10 artikuj. Shpresoj që 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
