5 Stimmen

Bearbeitung von WAV-Dateien mit Python

Zwischen den einzelnen Wörtern in der wav-Datei herrscht völlige Stille (ich habe mit dem Hex-Workshop überprüft, dass Stille mit 0 dargestellt wird).

Wie kann ich das nicht-geräuschlose Geräusch abstellen?

Ich programmiere mit Python.

Danke!

21voto

Soviut Punkte 83233

Python hat eine Wav-Modul . Sie können damit eine WAV-Datei zum Lesen öffnen und den Befehl "getframes(1)" verwenden, um die Datei Bild für Bild durchzugehen.

import wave
w = wave.open('beeps.wav', 'r')
for i in range():
frame = w.readframes(1)

Der zurückgegebene Rahmen ist eine Byte-Zeichenkette mit Hex-Werten darin. Wenn es sich um eine Stereodatei handelt, sieht das Ergebnis etwa so aus (4 Bytes):

'\xe2\xff\xe2\xff'

Wenn es sich um Mono handelt, enthält es die Hälfte der Daten (2 Byte):

'\xe2\xff'

Jeder Kanal ist 2 Byte lang, weil das Audio 16 Bit hat. Bei 8 Bit ist jeder Kanal nur ein Byte lang. Sie können die getsampwidth() Methode, um dies zu bestimmen. Auch, getchannels() bestimmt, ob es sich um Mono oder Stereo handelt.

Sie können eine Schleife über diese Bytes ziehen, um zu sehen, ob sie alle gleich Null sind, was bedeutet, dass beide Kanäle stumm sind. Im folgenden Beispiel verwende ich die ord() Funktion zur Konvertierung der '\xe2' Hex-Werte in Ganzzahlen umwandeln.

import wave
w = wave.open('beeps.wav', 'r')
for i in range(w.getnframes()):
    ### read 1 frame and the position will updated ###
    frame = w.readframes(1)

    all_zero = True
    for j in range(len(frame)):
        # check if amplitude is greater than 0
        if ord(frame[j]) > 0:
            all_zero = False
            break

    if all_zero:
        # perform your cut here
        print 'silence found at frame %s' % w.tell()
        print 'silence found at second %s' % (w.tell()/w..getframerate())

Es ist anzumerken, dass ein einzelnes Bild mit Stille nicht unbedingt einen leeren Raum bedeutet, da die Amplitude die 0-Marke bei normalen Frequenzen überschreiten kann. Es wird daher empfohlen, eine bestimmte Anzahl von Frames bei 0 zu beobachten, bevor man entscheidet, ob die Region tatsächlich still ist.

7voto

ffhaddad Punkte 1543

Ich habe für ein Projekt, an dem ich gerade arbeite, einige Nachforschungen zu diesem Thema angestellt und bin dabei auf einige Probleme mit der angebotenen Lösung gestoßen, nämlich dass die Methode zur Bestimmung der Stille falsch ist. Eine "korrektere" Implementierung wäre:

import struct
import wave

wave_file = wave.open("sound_file.wav", "r")

for i in range(wave_file.getnframes()):
    # read a single frame and advance to next frame
    current_frame = wave_file.readframes(1)

    # check for silence
    silent = True
    # wave frame samples are stored in little endian**
    # this example works for a single channel 16-bit per sample encoding
    unpacked_signed_value = struct.unpack("<h", current_frame) # *
    if abs(unpacked_signed_value[0]) > 500:
        silent = False

    if silent:
        print "Frame %s is silent." % wave_file.tell()
    else
        print "Frame %s is not silent." % wave_file.tell()

Referenzen und nützliche Links

* Struct Unpacking wird hier nützlich sein: https://docs.python.org/2/library/struct.html

**Eine gute Referenz, die ich gefunden habe, um das Format von Wavedateien für den Umgang mit unterschiedlich großen Bitkodierungen und mehreren Kanälen zu erklären, ist: http://www.piclist.com/techref/io/serial/midi/wave.html

Die Verwendung der eingebauten ord()-Funktion in Python auf das erste Element des String-Objekts, das von der readframes(x)-Methode zurückgegeben wird, funktioniert nicht korrekt.

Ein weiterer wichtiger Punkt ist, dass Mehrkanal-Audio verschachtelt ist und daher ein wenig zusätzliche Logik für den Umgang mit Kanälen erforderlich ist. Auch hier geht der Link oben ins Detail über diese.

Hoffentlich hilft das jemandem in der Zukunft.

Hier sind einige der wichtigsten Punkte aus dem Link, und was ich hilfreich fand.

Organisation der Daten


Alle Daten werden in 8-Bit-Bytes im Intel 80x86-Format (d. h. Little Endian) gespeichert. Die Bytes von Mehrbyte-Werten werden mit den niederwertigen (d.h. niedrigstwertigen) Bytes zuerst gespeichert. Die Datenbits sind wie folgt angeordnet (d. h. mit den Bitnummern oben):

         7  6  5  4  3  2  1  0
       +-----------------------+
 char: | lsb               msb |
       +-----------------------+

         7  6  5  4  3  2  1  0 15 14 13 12 11 10  9  8
       +-----------------------+-----------------------+
short: | lsb     byte 0        |       byte 1      msb |
       +-----------------------+-----------------------+

         7  6  5  4  3  2  1  0 15 14 13 12 11 10  9  8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
       +-----------------------+-----------------------+-----------------------+-----------------------+
 long: | lsb     byte 0        |       byte 1          |         byte 2        |       byte 3      msb |
       +-----------------------+-----------------------+-----------------------+-----------------------+

Verschachtelung


Bei mehrkanaligen Klängen (z. B. einer Stereowellenform) werden einzelne Abtastpunkte aus jedem Kanal ineinander verschachtelt. Nehmen wir zum Beispiel eine Stereowellenform (d.h. eine 2-Kanal-Wellenform). Anstatt zuerst alle Abtastpunkte des linken Kanals und dann alle Abtastpunkte des rechten Kanals zu speichern, "mischen" Sie die Abtastpunkte der beiden Kanäle zusammen. Sie würden den ersten Abtastpunkt des linken Kanals speichern. Als nächstes speichern Sie den ersten Abtastpunkt des rechten Kanals. Als nächstes speichern Sie den zweiten Abtastpunkt des linken Kanals. Als nächstes speichern Sie den zweiten Abtastpunkt des rechten Kanals und so weiter, wobei Sie abwechselnd den nächsten Abtastpunkt jedes Kanals speichern. Dies ist mit "verschachtelten Daten" gemeint: Sie speichern den nächsten Abtastpunkt jedes Kanals der Reihe nach, so dass die Abtastpunkte, die gleichzeitig "abgespielt" (d. h. an einen DAC gesendet) werden sollen, zusammenhängend gespeichert werden.

2voto

tzot Punkte 86792

1voto

Stephan202 Punkte 57491

Ich habe damit keine Erfahrung, aber sehen Sie sich die Welle Modul, das in der Standardbibliothek enthalten ist. Das könnte das tun, was Sie wollen. Andernfalls müssen Sie die Datei als Bytestrom lesen und Sequenzen von 0-Bytes herausschneiden (aber Sie können nicht einfach alle 0-Bytes herausschneiden, da dies die Datei ungültig machen würde...)

1voto

Paweł Polewicz Punkte 3591

Versuchen Sie es doch mal mit sox ein Kommandozeilen-Tool zur Klangbearbeitung. Es hat viele Modi, einer von ihnen ist silence :

Schweigen: Entfernt Stille am Anfang, in der Mitte oder am Ende einer Tondatei. Stille ist alles, was unter einem bestimmten Schwellenwert liegt.

Es unterstützt mehrere Tonformate und ist recht schnell, so dass das Parsen großer Dateien kein Problem sein sollte.

Um Stille in der Mitte einer Datei zu entfernen, geben Sie eine below_periods die negativ ist. Dieser Wert wird dann wie ein positiver Wert behandelt und wird auch verwendet, um anzuzeigen, dass der Effekt die Verarbeitung neu starten sollte, wie durch den Parameter above_periods Sie eignet sich zum Entfernen von Stillephasen in der Mitte der Tondatei.

Ich habe zwar kein Python-Gebäude für libsox gefunden, aber Sie können es verwenden, wie Sie alle Kommandozeilenprogramme in Python verwenden (oder Sie können es neu schreiben - verwenden Sie dann die sox-Quellen als Anleitung).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X