Methoden zur Komprimierung / Speicherung von Medien in WAVE und JPEG, Teil 1

Hallo! Meine erste Artikelserie befasst sich mit Methoden zum Komprimieren und Speichern von Bildern / Ton wie JPEG (Bild) und WAVE (Ton) und enthält Beispiele für Programme, die diese Formate (.jpg, .wav) in der Praxis verwenden. In diesem Teil werden wir WAVE betrachten.


Die Geschichte


WAVE (Waveform Audio File Format) ist ein Container-Dateiformat zum Speichern von Audio-Stream-Aufzeichnungen. Dieser Container wird normalerweise verwendet, um unkomprimierten Ton bei der Pulscodemodulation zu speichern. (Nach Wikipedia)

Es wurde 1991 zusammen mit RIFF von Microsoft und IBM (damals führende IT-Unternehmen) erfunden und veröffentlicht.


Dateistruktur


Die Datei hat einen Header-Teil, die Daten selbst, aber es gibt keine Fußzeile. Der Header wiegt insgesamt 44 Bytes.
Der Header enthält Einstellungen für die Anzahl der Bits im Sample, die Häufigkeit der Beschreibung, die Schalltiefe usw. Informationen, die für eine Soundkarte benötigt werden. (Alle numerischen Tabellenwerte müssen in Little-Endian-Reihenfolge geschrieben werden.)


BlocknameBlockgröße (B)Beschreibung / ZweckWert (für einige ist es fest
chunkId4Definieren einer Datei als Mediencontainer0x52494646 in Big-Endian ("RIFF")
chunkSize4Die Größe der gesamten Datei ohne chunkId und chunkSizeFILE_SIZE - 8
Format4Typdefinition aus RIFF0x57415645 in Big-Endian ("WAVE")
subchunk1Id4So nehmen Sie mehr Speicherplatz ein Fortsetzung Format0x666d7420 in Big-Endian ("fmt")
subchunk1Size4Verbleibender Header (in Bytes)16 standardmäßig (für den Fall ohne Audiostream-Komprimierung)
audioFormat2Audioformat (abhängig von Komprimierungsmethode und Audiodatenstruktur)1 (für PCM, das wir in Betracht ziehen)
numChannels2Anzahl der Kanäle1/2 nehmen wir 1 Kanal (3/4/5/6/7 ... - eine bestimmte Audiospur, zum Beispiel 4 für einen Quad-Sound usw.)
sampleRate4Tonabtastfrequenz (in Hertz)Je größer, desto besser der Klang, aber je mehr Speicher erforderlich ist, um eine Audiospur gleicher Länge zu erstellen, desto empfohlener ist 48000 (die akzeptabelste Klangqualität).
byteRate4Anzahl der Bytes in 1 SekundesampleRate numChannels bitsPerSample (im Folgenden)
blockAlign2Anzahl der Bytes für 1 ProbenumChannels * bitsPerSample: 8
bitsPerSample2Die Anzahl der Bits pro 1 Abtastung (Tiefe)Jede Zahl, die ein Vielfaches von 8 ist. Je größer, desto besser und härter wird das Audio. Ab 32 Bit gibt es für eine Person keinen Unterschied
subchunk2Id4Die Referenzmarke am Anfang der Daten (da es je nach AudioFormat möglicherweise andere Header-Elemente gibt)0x64617461 in Big-Endian ("Daten")
subchunk2Size4DatenbereichsgrößeDatengröße in int
DatenByteRate * AudiodauerAudiodaten?

WAVE Beispiel


Die vorherige Tabelle kann leicht in eine C-Struktur übersetzt werden, aber heute ist unsere Sprache Python. Mit der Welle ist es am einfachsten, einen Rauschgenerator zu verwenden. Für diese Aufgabe benötigen wir keine hohe Byte-Rate und Komprimierung.
Zunächst importieren wir die erforderlichen Module:


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

Als nächstes müssen wir alle erforderlichen Variablen aus der Tabelle entsprechend ihrer Größe erstellen. Die darin enthaltenen Variablenwerte hängen hier nur von numSamples (der Anzahl der Samples) ab. Je mehr es gibt, desto länger wird unser Lärm dauern.


 numSamples = int(argv[1]) output_path = argv[2] chunkId = b'RIFF' Format = b'WAVE' subchunk1ID = b'fmt ' subchunk1Size = b'\x10\x00\x00\x00' # 0d16 audioFormat = b'\x01\x00' numChannels = b'\x02\x00' # 2-    () sampleRate = pack('<L', 1000) # 1000 ,    ,     .  1000-  ,   bitsPerSample = b'\x20\x00' # 0d32 byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit sound) blockAlign = b'\x08\x00' # 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) #   

Es bleibt nur, sie in der erforderlichen Reihenfolge (wie in der Tabelle) zu schreiben:


 with open(output_path, 'wb') as fh: fh.write(chunkId + chunkSize + Format + subchunk1ID + subchunk1Size + audioFormat + numChannels + sampleRate + byteRate + blockAlign + bitsPerSample + subchunk2ID + subchunk2Size + data) #  

Und so gemacht. Um das Skript zu verwenden, müssen wir die erforderlichen Befehlszeilenargumente hinzufügen:
python3 WAV.py [num of samples] [output]
Anzahl der Proben - Anzahl Proben
Ausgabe - Pfad zur Ausgabedatei


Hier ist ein Link zu einer Test-Audiodatei mit Rauschen, aber um Speicherplatz zu sparen, habe ich BPS auf 1b / s gesenkt und die Anzahl der Kanäle auf 1 gesenkt (mit einem unkomprimierten 32-Bit-Stereo-Audio-Stream mit 64 KBit / s haben wir 80 MB einer sauberen WAV-Datei und nur 10): https: / /instaud.io/3Dcy


Der gesamte Code (WAV.py) (der Code enthält viele doppelte Variablenwerte, dies ist nur eine Skizze):


 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'\x10\x00\x00\x00' # 0d16 audioFormat = b'\x01\x00' numChannels = b'\x02\x00' # 2-    () sampleRate = pack('<L', 1000) # 1000 ,    . bitsPerSample = b'\x20\x00' # 0d32 byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit sound) blockAlign = b'\x08\x00' # 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) #     

Zusammenfassung


Sie haben also etwas mehr über digitalen Sound und dessen Speicherung gelernt. In diesem Beitrag haben wir keine Komprimierung (audioFormat) verwendet, aber um jeden der beliebten Artikel zu überprüfen, benötigen Sie Artikel 10. Ich hoffe, Sie haben etwas Neues für sich gelernt und dies wird Ihnen bei zukünftigen Entwicklungen helfen.
Vielen Dank!


Quellen

WAV-Dateistruktur
WAV - Wikipedia

Source: https://habr.com/ru/post/de450774/


All Articles