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):
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
Ffynhonnell: hab.com