Implementieren Sie die Echtzeit-Signalverarbeitung in Python - wie wird Audio kontinuierlich aufgezeichnet?

8

Ich habe vor, einen "DSP-ähnlichen" Signalprozessor in Python zu implementieren. Es sollte kleine Fragmente von Audio über ALSA erfassen, sie verarbeiten und dann über ALSA abspielen.

Um etwas anzufangen, schrieb ich den folgenden (sehr einfachen) Code.

%Vor%

Das Problem ist, dass das Audio "stottert" und nicht lückenlos ist. Ich habe versucht, mit dem PCM-Modus zu experimentieren, indem ich ihn entweder auf PCM_ASYNC oder PCM_NONBLOCK setze, aber das Problem bleibt bestehen. Ich denke, das Problem ist, dass Samples zwischen zwei aufeinanderfolgenden Aufrufen von "inp.read ()" verloren gehen.

Gibt es eine Möglichkeit, Audio "kontinuierlich" in Python zu erfassen (vorzugsweise ohne die Notwendigkeit zu "spezifischer" / "Nicht-Standard" -Bibliotheken)? Ich möchte, dass das Signal immer "im Hintergrund" in einen Puffer eingefangen wird, aus dem ich einen "momentanen Zustand" ablesen kann, während der Ton auch während der Zeit, in der ich meine Leseoperationen ausführe, weiter im Puffer gespeichert wird . Wie kann ich das erreichen?

Auch wenn ich einen dedizierten Prozess / Thread verwende, um den Ton aufzunehmen, muss dieser Prozess / Thread immer mindestens (1) Audio von der Quelle lesen, (2) ihn dann in einen Puffer setzen (von dem der " Signalverarbeitung "Prozess / Thread liest dann). Diese beiden Operationen werden daher immer noch sequenziell sein und somit werden Samples verloren gehen. Wie vermeide ich das?

Vielen Dank für Ihren Rat!

BEARBEITEN SIE 2: Jetzt habe ich es laufen.

%Vor%

Wenn ich jedoch sogar die geringste Änderung an den Audiodaten vornimmt (z. B. die Zeile kommentiere), erhalte ich am Ausgang eine Menge Rauschen und extreme Verzerrungen. Es sieht so aus, als würde ich die PCM-Daten nicht korrekt behandeln. Das Seltsame ist, dass die Ausgabe des "Pegelmessers" etc. allesamt sinnvoll erscheint. Die Ausgabe ist jedoch vollständig verzerrt (aber kontinuierlich), wenn ich sie nur leicht versetze.

EDIT 3 : Ich habe gerade herausgefunden, dass meine Algorithmen (die hier nicht enthalten sind) funktionieren, wenn ich sie auf Wave-Dateien anwende. Das Problem scheint also tatsächlich auf die ALSA-API zu reduzieren.

EDIT 4 : Ich habe endlich die Probleme gefunden. Sie waren die folgenden.

1. - ALSA kehrte nach Anforderung von PCM_FORMAT_U32_LE auf PCM_FORMAT_U8_LE zurück und interpretierte die Daten falsch, indem sie annahm, dass jeder Abtastwert 4 Byte breit war. Es funktioniert, wenn ich PCM_FORMAT_S32_LE anfordere.

2. - Die ALSA-Ausgabe scheint die Periodengröße in Bytes zu erwarten, obwohl sie explizit angeben, dass sie in frames in der Spezifikation erwartet wird. Sie müssen also die Periodengröße für die Ausgabe vier Mal so hoch einstellen, wenn Sie die Probentiefe von 32 Bit verwenden.

3. - Sogar in Python (wo es eine "globale Interpretersperre" gibt) sind Prozesse im Vergleich zu Threads langsam. Sie können die Latenzzeit erheblich reduzieren, indem Sie zu Threads wechseln, da die E / A-Threads im Grunde nichts tun, was rechenintensiv ist.

    
no.human.being 05.01.2016, 19:30
quelle

3 Antworten

2

Wenn Sie

  1. lese ein Stück Daten,
  2. schreibe ein Stück Daten,
  3. Warten Sie dann, bis der zweite Datenblock gelesen wurde,

dann wird der Puffer des Ausgabegeräts leer, wenn der zweite Chunk nicht kürzer als der erste Chunk ist.

Sie sollten den Puffer des Ausgabegeräts mit Stille füllen, bevor Sie mit der eigentlichen Verarbeitung beginnen. Dann sind kleine Verzögerungen in der Eingabe- oder Ausgabeverarbeitung egal.

    
CL. 06.01.2016, 08:35
quelle
2

Sie können das alles manuell tun, wie es @CL in seiner Antwort empfiehlt, aber ich würde es nur empfehlen verwenden GNU Radio stattdessen:

Es ist ein Framework, das sich darum kümmert, all das zu tun, "kleine Klumpen von Samples in und aus Ihrem Algorithmus zu bekommen"; es skaliert sehr gut, und Sie können Ihre Signalverarbeitung entweder in Python oder C ++ schreiben.

Tatsächlich kommt es mit einer Audioquelle und einem Audio Sink, die direkt mit ALSA sprechen und nur kontinuierliche Proben geben / nehmen. Ich empfehle das Lesen von GNU Radio Tutorials ; Sie erklären genau, was für eine Signalverarbeitung für eine Audioanwendung erforderlich ist.

Ein wirklich minimaler Flow-Graph würde wie folgt aussehen:

Sie können den Hochpassfilter für Ihren eigenen Signalverarbeitungsblock verwenden oder eine beliebige Kombination der vorhandenen Blöcke verwenden.

Es gibt hilfreiche Dinge wie Datei- und WAV-Dateisenken und Quellen, Filter, Resampler, Verstärker (ok, Multiplikatoren), ...

    
Marcus Müller 06.01.2016 21:43
quelle
0

Ich habe endlich die Probleme gefunden. Sie waren die folgenden.

1. - ALSA kehrte nach Anforderung von PCM_FORMAT_U32_LE auf PCM_FORMAT_U8_LE zurück und interpretierte die Daten falsch, indem sie annahm, dass jeder Abtastwert 4 Byte breit war. Es funktioniert, wenn ich PCM_FORMAT_S32_LE anfordere.

2. - Die ALSA-Ausgabe scheint die Periodengröße in Bytes zu erwarten, obwohl sie explizit angeben, dass sie in Frames in der Spezifikation erwartet wird. Sie müssen also die Periodengröße für die Ausgabe vier Mal so hoch einstellen, wenn Sie eine Probentiefe von 32 Bit verwenden.

3. - Sogar in Python (wo es eine "globale Interpretersperre" gibt) sind Prozesse im Vergleich zu Threads langsam. Sie können die Latenzzeit erheblich reduzieren, indem Sie zu Threads wechseln, da die E / A-Threads im Grunde nichts tun, was rechenintensiv ist.

Audio ist jetzt lückenlos und unverzerrt, aber die Latenz ist viel zu hoch.

    
no.human.being 05.02.2016 20:16
quelle