WAVE ve JPEG formatlarındaki medya verilerini sıkıştırma/depolama yöntemleri, bölüm 1

Merhaba! İlk makale serim, JPEG (görüntü) ve WAVE (ses) gibi görüntü/ses sıkıştırma ve depolama yöntemlerinin incelenmesine odaklanacak ve ayrıca bu formatları (.jpg, .wav) pratikte kullanan program örneklerini de içerecektir. Bu bölümde WAVE'e bakacağız.

Öykü

WAVE (Dalga Formu Ses Dosyası Formatı), bir ses akışının kaydını depolamak için kullanılan bir konteyner dosyası formatıdır. Bu kap genellikle sıkıştırılmamış darbe kodu modülasyonlu sesi depolamak için kullanılır. (Wikipedia'dan alınmıştır)

1991 yılında Microsoft ve IBM (o zamanın önde gelen BT şirketleri) tarafından RIFF ile birlikte icat edildi ve yayınlandı.

Dosya yapısı

Dosyanın bir başlık kısmı ve verinin kendisi var, ancak altbilgi yok. Başlık toplam 44 bayt ağırlığındadır.
Başlık, örnekteki bit sayısı, örnekleme hızı, ses derinliği vb. için ayarları içerir. ses kartı için gerekli bilgiler. (Tüm sayısal tablo değerleri Little-Endian sırasına göre yazılmalıdır)

Blok adı
Blok boyutu (B)
Açıklama/Amaç
Değer (bazıları için sabittir)

parça kimliği
4
Bir dosyayı medya taşıyıcısı olarak tanımlama
Big-Endian'da 0x52494646 (“RIFF”)

Parça boyutu
4
ChunkId ve chunkSize olmadan tüm dosyanın boyutu
FILE_SIZE - 8

biçim
4
RIFF'den tür tanımı
Big-Endian'da 0x57415645 (“WAVE”)

alt parça1Id
4
Böylece dosya formatın devamı olarak daha fazla yer kaplar
Big-Endian dilinde 0x666d7420 (“fmt”)

alt parça1Boyut
4
Kalan başlık (bayt cinsinden)
Varsayılan olarak 16 (ses akışı sıkıştırmasının olmadığı durum için)

ses formatı
2
Ses formatı (sıkıştırma yöntemine ve ses veri yapısına bağlıdır)
1 (bizim düşündüğümüz PCM için)

numChannels
2
Kanal sayısı
1/2, 1 kanal alacağız (3/4/5/6/7... - belirli bir ses parçası, örneğin dörtlü ses için 4, vb.)

aynı oran
4
Ses örnekleme hızı (Hertz cinsinden)
Ne kadar yüksek olursa ses o kadar iyi olur, ancak aynı uzunlukta bir ses parçası oluşturmak için o kadar fazla belleğe ihtiyaç duyulur; önerilen değer 48000'dir (en kabul edilebilir ses kalitesi)

Bayt Oranı
4
Saniye başına bayt sayısı
aynı oran numChannels bitsPerSample (daha fazla)

blok Hizalama
2
1 örnek için bayt sayısı
numChannels * bitsPerSample: 8

örnek başına bit
2
1 örnek başına bit sayısı (derinlik)
8'in katı olan herhangi bir sayı. Sayı ne kadar yüksek olursa ses o kadar iyi ve ağır olur, insanlar için 32 bitten hiçbir farkı yoktur.

alt parça2Id
4
Veri referans işareti (audioFormat'a bağlı olarak başka başlık öğeleri olabileceğinden)
Big-Endian'da 0x64617461 ("veri")

alt parça2Boyut
4
Veri alanı boyutu
int cinsinden veri boyutu

veri
byteRate * ses süresi
Ses verileri
?

DALGA örneği

Önceki tablo C dilinde kolaylıkla bir yapıya çevrilebilir ancak bugünkü dilimiz Python'dur. Yapabileceğiniz en kolay şey bir "dalga" - bir gürültü üreteci kullanmaktır. Bu görev için yüksek byteRate ve sıkıştırmaya ihtiyacımız yok.
Öncelikle gerekli modülleri içe aktaralım:

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

Daha sonra tablodan gerekli tüm değişkenleri boyutlarına göre oluşturmamız gerekiyor. İçindeki değişken değerleri yalnızca numSamples'a (örnek sayısına) bağlıdır. Ne kadar çok olursa gürültümüz o kadar uzun sürecektir.

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

Geriye kalan tek şey bunları gerekli sırayla (tablodaki gibi) yazmaktır:

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

Ve böylece hazır. Komut dosyasını kullanmak için gerekli komut satırı bağımsız değişkenlerini eklememiz gerekir:
python3 WAV.py [num of samples] [output]
örnek sayısı - sayım. örnekler
çıktı — çıktı dosyasının yolu

Burada gürültülü bir test ses dosyası bağlantısı var, ancak bellekten tasarruf etmek için BPS'yi 1b/s'ye düşürdüm ve kanal sayısını 1'e düşürdüm (32kbs'de 64 bit sıkıştırılmamış stereo ses akışıyla, bunun 80 milyon saf .wav dosyası ve yalnızca 10): https://instaud.io/3Dcy

Kodun tamamı (WAV.py) (Kodda çok sayıda yinelenen değişken değeri var, bu yalnızca bir taslak):

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

sonuç

Böylece dijital ses ve nasıl saklandığı hakkında biraz daha bilgi sahibi oldunuz. Bu yazıda sıkıştırma (audioFormat) kullanmadık, ancak popüler olanların her birini dikkate almak için 10 makale gerekecek.Umarım kendiniz için yeni bir şeyler öğrenmişsinizdir ve bu, gelecekteki geliştirmelerde size yardımcı olacaktır.
Teşekkürler!

kaynaklar

WAV dosya yapısı
WAV - Vikipedi

Kaynak: habr.com

Yorum ekle