WAVE va JPEG formatlarida media ma'lumotlarini siqish/saqlash usullari, 1-qism

Salom! Mening birinchi maqolalar seriyam JPEG (tasvir) va WAVE (ovoz) kabi tasvir/audio siqish va saqlash usullarini o‘rganishga qaratilgan bo‘lib, amaliyotda ushbu formatlardan (.jpg, .wav) foydalanadigan dasturlar misollarini ham o‘z ichiga oladi. Ushbu qismda biz WAVEni ko'rib chiqamiz.

История

WAVE (Waveform Audio File Format) - audio oqimining yozuvini saqlash uchun konteyner fayl formati. Ushbu konteyner odatda siqilmagan impuls kodini modulyatsiyalangan audioni saqlash uchun ishlatiladi. (Vikipediyadan olingan)

U 1991 yilda RIFF bilan birgalikda Microsoft va IBM (o'sha davrning yetakchi IT kompaniyalari) tomonidan ixtiro qilingan va nashr etilgan.

Fayl tuzilishi

Faylning sarlavha qismi, ma'lumotlarning o'zi bor, lekin pastki qism yo'q. Sarlavha jami 44 baytni tashkil qiladi.
Sarlavhada namunadagi bitlar soni, namuna tezligi, tovush chuqurligi va boshqalar uchun sozlamalar mavjud. ovoz kartasi uchun zarur bo'lgan ma'lumotlar. (Barcha raqamli jadval qiymatlari Little-Endian tartibida yozilishi kerak)

Blok nomi
Blok hajmi (B)
Tavsif/maqsad
Qiymat (ba'zilar uchun u belgilangan

chunkId
4
Faylni media konteyner sifatida belgilash
Big-Endian tilida 0x52494646 (“RIFF”)

chunkSize
4
Butun fayl hajmi chunkId va chunkSizesiz
FILE_SIZE - 8

format
4
RIFF dan tip ta'rifi
0x57415645 Big-Endian ("WAVE")

subchunk1Id
4
Shunday qilib, formatni davom ettirish orqali fayl ko'proq joy egallaydi
Big-Endian tilida 0x666d7420 (“fmt”)

subchunk1Size
4
Qolgan sarlavha (baytlarda)
Sukut bo'yicha 16 (audio oqimi siqilmagan holatda)

audioformat
2
Ovoz formati (siqish usuli va audio ma'lumotlar tuzilishiga bog'liq)
1 (PCM uchun, biz ko'rib chiqayotgan narsamiz)

numChannels
2
Kanallar soni
1/2, biz 1 kanalni olamiz (3/4/5/6/7... - ma'lum bir audio trek, masalan, to'rt ovoz uchun 4 va hokazo)

namuna darajasi
4
Audio namuna olish tezligi (Gertzda)
Qanchalik baland bo'lsa, ovoz shunchalik yaxshi bo'ladi, lekin bir xil uzunlikdagi audio trekni yaratish uchun qancha ko'p xotira talab qilinadi, tavsiya etilgan qiymat 48000 (eng maqbul ovoz sifati)

byteRate
4
Bir soniyadagi baytlar soni
namuna darajasi numChannels bitsPerSample (bundan keyin)

blockAlign
2
1 namuna uchun baytlar soni
numChannels * bitsPerSample: 8

bitsPerSample
2
1 namunadagi bitlar soni (chuqurlik)
8 ga karrali har qanday raqam. Bu raqam qanchalik katta bo'lsa, ovoz shunchalik yaxshi va og'irroq bo'ladi; 32 bitdan odamlar uchun farq yo'q.

subchunk2Id
4
Ma'lumotlarga mos yozuvlar belgisi (chunki audioFormatga qarab boshqa sarlavha elementlari bo'lishi mumkin)
Big-Endian ("ma'lumotlar") da 0x64617461

subchunk2Size
4
Ma'lumotlar maydoni hajmi
ma'lumotlar hajmi int

ma'lumotlar
byteRate * audio davomiyligi
Audio ma'lumotlar
?

WAVE misoli

Oldingi jadvalni C tilidagi strukturaga osongina tarjima qilish mumkin, ammo bizning bugungi tilimiz Python. Siz qila oladigan eng oson narsa bu "to'lqin" - shovqin generatoridan foydalanish. Ushbu vazifani bajarish uchun bizga yuqori bayt tezligi va siqish kerak emas.
Birinchidan, kerakli modullarni import qilaylik:

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

Keyinchalik, jadvaldan barcha kerakli o'zgaruvchilarni ularning o'lchamlari bo'yicha yaratishimiz kerak. Undagi o'zgaruvchan qiymatlar faqat numSamples (namunalar soni) ga bog'liq. Ular qancha ko'p bo'lsa, bizning shovqinimiz shunchalik uzoq davom etadi.

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

Faqat ularni kerakli ketma-ketlikda yozish qoladi (jadvaldagi kabi):

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

Va shuning uchun tayyor. Skriptdan foydalanish uchun biz kerakli buyruq qatori argumentlarini qo'shishimiz kerak:
python3 WAV.py [num of samples] [output]
namunalar soni - hisoblash. namunalar
chiqish - chiqish fayliga yo'l

Bu yerda shovqinli sinov audio fayliga havola, lekin xotirani tejash uchun men BPS ni 1b/s ga tushirdim va kanallar sonini 1 ga tushirdim (32 kb/s tezlikda 64 bitli siqilmagan stereo audio oqimi bilan u shunday bo'lib chiqdi). 80 million sof .wav fayli va faqat 10 tasi): https://instaud.io/3Dcy

Butun kod (WAV.py) (Kodda juda ko'p takrorlanuvchi o'zgaruvchilar qiymatlari mavjud, bu shunchaki eskiz):

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

Xulosa

Shunday qilib, siz raqamli tovush va uning qanday saqlanishi haqida bir oz ko'proq bilib oldingiz. Ushbu postda biz siqishni (audioFormat) ishlatmadik, lekin mashhur bo'lganlarning har birini ko'rib chiqish uchun 10 ta maqola kerak bo'ladi.Umid qilamanki, siz o'zingiz uchun yangi narsalarni o'rgandingiz va bu kelajakdagi ishlanmalarda sizga yordam beradi.
Rahmat!

Axborot manbalari

WAV fayl tuzilishi
WAV - Vikipediya

Manba: www.habr.com

a Izoh qo'shish