Kaedah untuk memampatkan/menyimpan data media dalam format WAVE dan JPEG, bahagian 1

helo! Siri pertama artikel saya akan menumpukan pada mengkaji kaedah pemampatan dan storan imej/audio seperti JPEG (gambar) dan WAVE (bunyi), dan juga akan menyertakan contoh program yang menggunakan format ini (.jpg, .wav) dalam amalan. Dalam bahagian ini kita akan melihat WAVE.

Kisah

WAVE (Format Fail Audio Bentuk Gelombang) ialah format fail bekas untuk menyimpan rakaman strim audio. Bekas ini biasanya digunakan untuk menyimpan audio termodulat kod nadi yang tidak dimampatkan. (Diambil dari Wikipedia)

Ia telah dicipta dan diterbitkan pada tahun 1991 bersama-sama dengan RIFF oleh Microsoft dan IBM (syarikat IT terkemuka pada masa itu).

Struktur fail

Fail mempunyai bahagian pengepala, data itu sendiri, tetapi tiada pengaki. Pengepala mempunyai berat sebanyak 44 bait.
Pengepala mengandungi tetapan untuk bilangan bit dalam sampel, kadar sampel, kedalaman bunyi, dsb. maklumat yang diperlukan untuk kad bunyi. (Semua nilai jadual angka mesti ditulis dalam susunan Little-Endian)

Nama blok
Saiz blok (B)
Penerangan/Tujuan
Nilai (untuk sesetengahnya ia tetap

chunkId
4
Mentakrifkan fail sebagai bekas media
0x52494646 dalam Big-Endian (“RIFF”)

Saiz ketul
4
Saiz keseluruhan fail tanpa chunkId dan chunkSize
FILE_SIZE - 8

format
4
Taip definisi daripada RIFF
0x57415645 dalam Big-Endian (“GELOMBANG”)

subchunk1Id
4
Supaya fail mengambil lebih banyak ruang sebagai kesinambungan format
0x666d7420 dalam Big-Endian (“fmt”)

subchunk1Saiz
4
Pengepala yang tinggal (dalam bait)
16 secara lalai (untuk kes tanpa pemampatan strim audio)

AudioFormat
2
Format audio (bergantung pada kaedah mampatan dan struktur data audio)
1 (untuk PCM, yang kami sedang pertimbangkan)

numChannels
2
Bilangan saluran
1/2, kami akan mengambil 1 saluran (3/4/5/6/7... - trek audio tertentu, contohnya 4 untuk bunyi quad, dsb.)

kadar sampel
4
Kadar pensampelan audio (dalam Hertz)
Lebih tinggi, lebih baik bunyinya, tetapi lebih banyak memori diperlukan untuk mencipta trek audio dengan panjang yang sama, nilai yang disyorkan ialah 48000 (kualiti bunyi yang paling boleh diterima)

byteRate
4
Bilangan bait sesaat
kadar sampel numChannels bitsPerSample (selanjutnya)

blockAlign
2
Bilangan bait untuk 1 sampel
numChannels * bitsPerSample: 8

bitsPerSample
2
Bilangan bit setiap 1 sampel (kedalaman)
Mana-mana nombor gandaan 8. Lebih tinggi nombor, lebih baik dan lebih berat audionya; daripada 32 bit tiada perbezaan untuk manusia

subchunk2Id
4
Tanda rujukan data (kerana mungkin terdapat elemen pengepala lain bergantung pada AudioFormat)
0x64617461 dalam Big-Endian("data")

subchunk2Saiz
4
Saiz kawasan data
saiz data dalam int

data
byteRate * tempoh audio
Data audio
?

Contoh GELOMBANG

Jadual sebelumnya boleh diterjemahkan dengan mudah ke dalam struktur dalam C, tetapi bahasa kami untuk hari ini ialah Python. Perkara paling mudah yang boleh anda lakukan ialah menggunakan "gelombang" - penjana bunyi. Untuk tugas ini kami tidak memerlukan byteRate dan mampatan tinggi.
Pertama, mari kita import modul yang diperlukan:

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

Seterusnya, kita perlu mencipta semua pembolehubah yang diperlukan dari jadual mengikut saiznya. Nilai pembolehubah di dalamnya hanya bergantung pada numSamples (bilangan sampel). Semakin ramai mereka, semakin lama bunyi bising kita akan berlarutan.

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

Apa yang tinggal ialah menulisnya dalam urutan yang diperlukan (seperti dalam jadual):

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

Jadi, bersedia. Untuk menggunakan skrip, kita perlu menambah argumen baris arahan yang diperlukan:
python3 WAV.py [num of samples] [output]
bilangan sampel - kiraan. sampel
output — laluan ke fail output

Berikut ialah pautan ke fail audio ujian dengan bunyi bising, tetapi untuk menjimatkan memori saya menurunkan BPS kepada 1b/s dan menurunkan bilangan saluran kepada 1 (dengan aliran audio stereo tidak dimampatkan 32-bit pada 64kbs, ternyata menjadi 80M fail .wav tulen, dan hanya 10): https://instaud.io/3Dcy

Keseluruhan kod (WAV.py) (Kod ini mempunyai banyak nilai pembolehubah pendua, ini hanyalah lakaran):

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

Jumlah

Oleh itu, anda telah mempelajari sedikit lagi tentang bunyi digital dan cara ia disimpan. Dalam siaran ini kami tidak menggunakan pemampatan (AudioFormat), tetapi untuk mempertimbangkan setiap satu daripada yang popular, 10 artikel akan diperlukan. Saya harap anda mempelajari sesuatu yang baru untuk diri sendiri dan ini akan membantu anda dalam perkembangan masa depan.
Thank you!

sumber

Struktur fail WAV
WAV - Wikipedia

Sumber: www.habr.com

Tambah komen