Dulliau ar gyfer cywasgu/storio data cyfryngau mewn fformatau WAVE a JPEG, rhan 1

Helo! Bydd fy nghyfres gyntaf o erthyglau yn canolbwyntio ar astudio dulliau cywasgu delwedd/sain a storio megis JPEG (delwedd) a WAVE (sain), a bydd hefyd yn cynnwys enghreifftiau o raglenni sy'n defnyddio'r fformatau hyn (.jpg, .wav) yn ymarferol. Yn y rhan hon byddwn yn edrych ar WAVE.

Stori

Fformat ffeil cynhwysydd ar gyfer storio recordiad o ffrwd sain yw WAVE (Waveform Audio File Format). Mae'r cynhwysydd hwn yn cael ei ddefnyddio fel arfer i storio sain wedi'i fodiwleiddio â chod pwls heb ei gywasgu. (Cymerwyd o Wikipedia)

Fe'i dyfeisiwyd a'i chyhoeddi ym 1991 ynghyd â RIFF gan Microsoft ac IBM (Cwmnïau TG blaenllaw y cyfnod hwnnw).

Strwythur ffeil

Mae gan y ffeil ran pennawd, y data ei hun, ond dim troedyn. Mae'r pennawd yn pwyso cyfanswm o 44 beit.
Mae'r pennawd yn cynnwys gosodiadau ar gyfer nifer y darnau yn y sampl, cyfradd y sampl, dyfnder sain, ac ati. gwybodaeth sydd ei hangen ar gyfer y cerdyn sain. (Rhaid ysgrifennu holl werthoedd tabl rhifol yn nhrefn Little-Endian)

Enw bloc
Maint bloc (B)
Disgrifiad/Diben
Gwerth (i rai mae'n sefydlog

chunkId
4
Diffinio ffeil fel cynhwysydd cyfryngau
0x52494646 yn Big-Endian (“RIFF”)

Maint talpiau
4
Maint y ffeil gyfan heb chunkId a chunkSize
FILE_SIZE - 8

Fformat
4
Teipiwch ddiffiniad o RIFF
0x57415645 yn Big-Endian (“WAVE”)

isgyfuniad1Id
4
Fel bod y ffeil yn cymryd mwy o le fel parhad o'r fformat
0x666d7420 yn Big-Endian (“fmt”)

subchunk1Size
4
Pennyn sy'n weddill (mewn beit)
16 yn ddiofyn (ar gyfer yr achos heb gywasgu llif sain)

fformat sain
2
Fformat sain (yn dibynnu ar ddull cywasgu a strwythur data sain)
1 (ar gyfer PCM, sef yr hyn yr ydym yn ei ystyried)

numSianeli
2
Nifer y sianeli
1/2, byddwn yn cymryd 1 sianel (3/4/5/6/7... - trac sain penodol, er enghraifft 4 ar gyfer sain cwad, ac ati)

Cyfradd sampl
4
Cyfradd samplu sain (yn Hertz)
Po uchaf, gorau oll fydd y sain, ond po fwyaf o gof fydd ei angen i greu trac sain o'r un hyd, y gwerth a argymhellir yw 48000 (yr ansawdd sain mwyaf derbyniol)

byteRate
4
Nifer y beit yr eiliad
Cyfradd sampl numSianeli bitsPerSample (ymhellach)

blocAlign
2
Nifer y beit ar gyfer 1 sampl
numChannels * bitsPerSample:8

didauPerSample
2
Nifer y darnau fesul 1 sampl (dyfnder)
Unrhyw rif sy'n lluosrif o 8. Po uchaf yw'r rhif, y gorau a'r trymach fydd y sain; o 32 did does dim gwahaniaeth i fodau dynol

isgyfuniad2Id
4
Cyfeirnod data (gan y gall fod elfennau pennawd eraill yn dibynnu ar y fformat sain)
0x64617461 yn Big-Endian ("data")

subchunk2Size
4
Maint ardal data
maint y data yn int

data
byteRate * hyd sain
Data sain
?

TON enghraifft

Mae'n hawdd trosi'r tabl blaenorol yn strwythur yn C, ond Python yw ein hiaith heddiw. Y peth hawsaf y gallwch chi ei wneud yw defnyddio "ton" - generadur sŵn. Ar gyfer y dasg hon nid oes angen byteRate a chywasgu uchel arnom.
Yn gyntaf, gadewch i ni fewnforio'r modiwlau angenrheidiol:

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

Nesaf, mae angen i ni greu'r holl newidynnau angenrheidiol o'r tabl yn ôl eu maint. Mae'r gwerthoedd newidiol ynddo yn dibynnu ar numSamples yn unig (nifer y samplau). Po fwyaf ohonynt sydd, yr hiraf y bydd ein sŵn yn mynd ymlaen.

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

Y cyfan sydd ar ôl yw eu hysgrifennu yn y dilyniant gofynnol (fel yn y tabl):

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

Ac felly, yn barod. I ddefnyddio'r sgript, mae angen i ni ychwanegu'r dadleuon llinell orchymyn angenrheidiol:
python3 WAV.py [num of samples] [output]
nifer o samplau - cyfrif. samplau
allbwn - llwybr i'r ffeil allbwn

Dyma ddolen i ffeil sain prawf gyda sŵn, ond i arbed cof gostyngais y BPS i 1b/s a gostwng nifer y sianeli i 1 (gyda ffrwd sain stereo anghywasgedig 32-did ar 64kbs, trodd allan i fod 80M o ffeil .wav pur, a dim ond 10): https://instaud.io/3Dcy

Y cod cyfan (WAV.py) (Mae gan y cod lawer o werthoedd amrywiol dyblyg, dim ond braslun yw hwn):

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

Cyfanswm

Felly rydych chi wedi dysgu ychydig mwy am sain digidol a sut mae'n cael ei storio. Yn y swydd hon ni wnaethom ddefnyddio cywasgu (audioFormat), ond i ystyried pob un o'r rhai poblogaidd, bydd angen erthyglau 10. Gobeithio ichi ddysgu rhywbeth newydd i chi'ch hun a bydd hyn yn eich helpu mewn datblygiadau yn y dyfodol.
Diolch yn fawr!

Ffynonellau

Strwythur ffeil WAV
WAV - Wicipedia

Ffynhonnell: hab.com

Ychwanegu sylw