Hallo! Mijn eerste reeks artikelen is gericht op het bestuderen van methoden voor compressie en opslag van afbeeldingen/g geluid, zoals JPEG (voor afbeeldingen) en WAVE (voor geluid). In deze artikelen worden ook voorbeelden van programma's met het gebruik van deze formaten (.jpg, .wav) in de praktijk gegeven. In dit deel bekijken we specifiek WAVE.
Geschiedenis
WAVE (Waveform Audio File Format) is een containerbestandsformaat voor het opslaan van audio stream opnames. Deze container wordt meestal gebruikt voor het opslaan van onbewerkte geluiden in pulse-code modulatie. (Bron: Wikipedia)
Het werd uitgevonden en gepubliceerd in 1991 samen met RIFF door de bedrijven Microsoft en IBM (de toonaangevende IT bedrijven van die tijd).
dev.yaml
Een bestand heeft een header, de gegevens zelf, maar geen footer. De header weegt in totaal 44 bytes.
In de header bevinden zich instellingen voor het aantal bits per sample, de samplefrequentie, de diepte van het geluid en dergelijke informatie die nodig is voor de geluidskaarten. (Alle numerieke waarden in de tabel moeten in Little-Endian volgorde worden genoteerd.)
Bloknaam
Blokgrootte (B)
Omschrijving/Doel
Waarde (sommige zijn vast)
chunkId
4
Bepaling van het bestand als media-container
0x52494646 in Big-Endian ("RIFF")
chunkSize
4
Grootte van het bestand zonder chunkId en chunkSize
FILE_SIZE — 8
format
4
Bepaling van het type uit RIFF
0x57415645 in Big-Endian ("WAVE")
subchunk1Id
4
Om het bestand meer ruimte in te laten nemen, vervolg van het format
0x666d7420 in Big-Endian ("fmt ")
subchunk1Size
4
Overblijvende header (in bytes)
16 standaard (voor het geval zonder compressie van de audiostream)
audioFormat
2
Audiocompressieformaat (hangt af van de compressiemethode en de structuur van de audiogegevens)
1 (voor PCM, dat wij hier bespreken)
numChannels
2
Aantal kanalen
1/2, we nemen 1 kanaal (3/4/5/6/7… — specifieke audiotrack, bijvoorbeeld 4 voor quad geluid, enz.)
sampleRate
4
Samplefrequentie van het geluid (in Hertz)
Hoe hoger, hoe beter de geluidskwaliteit, maar hoe meer geheugen nodig is voor het creëren van een audiotrack van dezelfde lengte. De aanbevolen waarde is 48000 (de meest acceptabele geluidskwaliteit).
byteRate
4
Aantal bytes per seconde
sampleRate numChannels bitsPerSample (verder)
blockAlign
2
Aantal bytes voor 1 sample
numChannels * bitsPerSample: 8
bitsPerSample
2
Aantal bits per sample (diepte)
Elk getal dat een veelvoud van 8 is. Hoe hoger, hoe beter en zwaarder het audio zal zijn; boven de 32 bits maakt het voor de mens geen verschil.
subchunk2Id
4
Tag voor het begin van de gegevens (aangezien er andere header-elementen kunnen zijn, afhankelijk van audioFormat)
0x64617461 in Big-Endian ("data")
subchunk2Size
4
Grootte van het gegevensgebied
grootte gegevens in een int
data
byteRate * duur van audio
AUDIOGEGEVENS
?
Voorbeeld met WAVE
De vorige tabel kan gemakkelijk worden omgezet naar een C-structuur, maar onze programmeertaal voor vandaag is Python. Het eenvoudigste dat we met de 'wave' kunnen doen, is een ruisgenerator. Voor deze taak hebben we geen hoge byteRate en compressie nodig.
Laten we beginnen met het importeren van de benodigde modules:
# 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)Vervolgens moeten we alle benodigde variabelen uit de tabel creëren op basis van hun grootte. De variabelen hierin zijn alleen afhankelijk van numSamples (aantal monsters). Hoe meer monsters we hebben, hoe langer onze ruis zal zijn.
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 kanalen is voldoende (stereo)
sampleRate = pack('<L', 1000) # 1000 is genoeg, maar als je meer instelt, zal de ruis beter hoorbaar zijn. Bij 1000 klinkt het als wind
bitsPerSample = b'x20x00' # 0d32
byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32-bit geluid)
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) # de ruisHet enige wat we nog hoeven te doen, is ze in de juiste volgorde (zoals in de tabel) opslaan:
with open(output_path, 'wb') as fh:
fh.write(chunkId + chunkSize + Format + subchunk1ID +
subchunk1Size + audioFormat + numChannels +
sampleRate + byteRate + blockAlign + bitsPerSample +
subchunk2ID + subchunk2Size + data) # schrijvenEn zo, dat is het. Om het script te gebruiken, moeten we de nodige commandoregelargumenten toevoegen:
python3 WAV.py [aantal monsters] [output]
aantal monsters — aantal monsters
output — pad naar het uitvoerbestand
Hier is een link naar een testaudiofragment met ruis, maar om geheugen te besparen heb ik BPS verlaagd tot 1b/s en het aantal kanalen tot 1 (met een 32-bits ongecomprimeerde stereo audiostream van 64kbs kreeg ik 80M pure .wav-bestand, en nu slechts 10):
De volledige code (WAV.py) (de code bevat veel duplicaten van variabelwaarden, dit is slechts een schets):
from struct import pack # vertaling van py-objecten naar basis types uit C
from os import urandom # functie voor het lezen van /dev/urandom, voor windows:
# from random import randint
# urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)]) # lambda voor windows, omdat urandom niet beschikbaar is in windows
from sys import argv, exit # argumenten voor het programma en exit
if len(argv) != 3: # +1 scriptnaam (-1, als u gaat bevriezen)
print('Gebruik: python3 WAV.py [aantal samples] [uitvoer]')
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 kanalen zijn voldoende (stereo)
sampleRate = pack('<L', 1000) # 1000 is voldoende, maar meer is ook mogelijk.
bitsPerSample = b'x20x00' # 0d32
byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit geluid)
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) # de ruis zelf
with open(output_path, 'wb') as fh:
fh.write(chunkId + chunkSize + Format + subchunk1ID +
subchunk1Size + audioFormat + numChannels +
sampleRate + byteRate + blockAlign + bitsPerSample +
subchunk2ID + subchunk2Size + data) # schrijf de resultaten naar het bestandConclusie
Hier heeft u wat meer geleerd over digitale audio en hoe deze wordt opgeslagen. In deze post hebben we geen compressie gebruikt (audioFormat), maar om elk van de populaire te overwegen zijn er ongeveer 10 artikelen nodig. Hopelijk heeft u iets nieuws geleerd dat u zal helpen in toekomstige ontwikkelingen.
Bedankt!
Bronnen
Bron: habr.com
