Audioframe manipulieren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Toaster1337
User
Beiträge: 6
Registriert: Mittwoch 25. November 2020, 01:18

Guten Tag,

ich beschäftige mich seit einiger Zeit mit der Manipulation von Audioframes um dessen Qualität steigern zu können um in meinem Fall die Erkennung von Sprache-zu-Text (Vosk) zu verbessern.

Geplant ist:
- Rauschen entfernen
- Stille anhängen um das zerhacken des streams zu vermeiden
- Komressor Funktion um die stimme anheben zu können
- Weitere verbesserungen

Mein Scrit sieht derzeit so aus:

Code: Alles auswählen

from array import array
from io import BytesIO
import json
import os
from pyaudio import PyAudio, paInt16
import time

from pydub import *
from audioop import *

LANG = de-de

DEBUG = True

# Mic Settings
THRESHOLD = 5
RATE = 16000
TIMEOUT_LENGTH = 1

CHUNK = 4000
SHORT_NORMALIZE = (1.0 / 32768.0)
NORMALIZE = 1 / 32768


class AudioDetection:
    def __init__(self):
        p = PyAudio()
        self.stream = p.open(rate=RATE,
                             channels=1,
                             format=paInt16,
                             input=True,
                             output=True,
                             input_device_index=None,  # None use default
                             output_device_index=None,  # None use default
                             frames_per_buffer=8000)
        self.stream.start_stream()
        self.stt = Vosk(LANG)

    @staticmethod
    def rms(frame):
        shorts = array('h', frame)
        sum_squares = sum(
            (sample * NORMALIZE) ** 2
            for sample in shorts
        )
        return (sum_squares / len(shorts)) ** 0.5 * 1000

    def detect(self, frame):
        if DEBUG:
            print("Noise detected")
        rec = [frame]
        current = time.time()
        end = time.time() + TIMEOUT_LENGTH

        while current <= end:
            data = self.stream.read(CHUNK)
            if self.rms(data) >= THRESHOLD:
                end = time.time() + TIMEOUT_LENGTH
            current = time.time()
            rec.append(data)

        # rec = AudioSegment.silent(rec)

        if DEBUG:
            print("Play Stream")
            self.stream.write(b''.join(rec))
        text = self.stt.run(b''.join(rec))
        if DEBUG:
            print("Listened: ", text)
        print('Listening...')

    def run(self):
        print("Listening...")
        while True:
            mic_input = self.stream.read(CHUNK)
            rms_val = self.rms(mic_input)
            if rms_val >= THRESHOLD:
                self.detect(mic_input)


class Vosk:
    def __init__(self, language):
        from vosk import Model, KaldiRecognizer
        if not os.path.exists("models/vosk/" + language):
            print("Please download the model from https://alphacephei.com/vosk/models and unpack as "
                  "'" + language + "' in 'models/vosk'.")
            exit(1)

        model = Model("models/vosk/" + language)
        self.rec = KaldiRecognizer(model, RATE)

    def run(self, audiostream):
        audiostream = BytesIO(audiostream)
        while True:
            data = audiostream.read(4000)
            if len(data) == 0:
                break
            if self.rec.AcceptWaveform(data):
                if DEBUG:
                    res = json.loads(self.rec.Result())
                    print("DEBUG: " + res['text'])

        fres = json.loads(self.rec.FinalResult())
        return fres['text']


if __name__ == '__main__':
    recorder = AudioDetection()
    recorder.run()
Jedoch sobald ich versuche das ganze über audioop, Pydub oder eigenen funktionen zu manipulieren bekomme ich gleich fehler wie "int found need byte like"
Mein Grundgedanke ist das ich ersmal die byteorder berücksichten sollte So das man mit Little Endian arbeitet doch wie gehts weiter?
Mir gehen langsam die Ideen aus und hoffe ihr könnt mir dabei weiterhelfen.

MfG
Toaster1337
Rechtschreibfehler sind spezialeffekte meiner Tastatur. Wer diese findet darf's behalten.
Toaster1337
User
Beiträge: 6
Registriert: Mittwoch 25. November 2020, 01:18

Weis jemand mit welchem Modul(en) ich die raw audiodaten vom stream beabreiten kann um zb. Rauschen zu entfernen?
Rechtschreibfehler sind spezialeffekte meiner Tastatur. Wer diese findet darf's behalten.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du musst den eingehenden Frame eben so wandeln wie du ihn später brauchst. 16bit pcm zu float64 zb.
Toaster1337
User
Beiträge: 6
Registriert: Mittwoch 25. November 2020, 01:18

Was ich brauche ist:
Channels: 1 (mono)
Rate: 16000
Format: 16bit

Dies ist doch bereits in pyaudio festgelegt?
Rechtschreibfehler sind spezialeffekte meiner Tastatur. Wer diese findet darf's behalten.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du hast ja oben eine entsprechende Fehlermeldung angegeben. Die Bibliothek liefert die daten in einem definierten Format, sollte sich in der Dokumentation finden, wie Genau das aussieht. Und du hat’s Algorithmen, die ein anderes brauchen. Du musst also wandeln.
Toaster1337
User
Beiträge: 6
Registriert: Mittwoch 25. November 2020, 01:18

__deets__ hat geschrieben: Mittwoch 30. Dezember 2020, 18:14 Du hast ja oben eine entsprechende Fehlermeldung angegeben. Die Bibliothek liefert die daten in einem definierten Format, sollte sich in der Dokumentation finden, wie Genau das aussieht. Und du hat’s Algorithmen, die ein anderes brauchen. Du musst also wandeln.
Klingt sinnvoll da jeder versuch scheitert...
Könnte mir jemand ein Beispiel geben wie ich das umsetzten könnte?
Bin ziemlich neu was Audiomanipulation angeht und versuche mich da zurecht zu finden.

Erstmal will ich damit beginnen das Grundrauschen/Hintergrund geräusdche zu entfernen.
Da ist natürlich die Frage womit sich dies gut lösen lässt.
Mir schwebt PyDub oder Audioop vor doch vielleicht weis jemand besseren Rat.
Rechtschreibfehler sind spezialeffekte meiner Tastatur. Wer diese findet darf's behalten.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mir fehlt der konkrete Code mit der konkreten (nicht paraphrasierten) Fehlermeldung. Denn dann kann man sehen, welcher Aufruf da gemacht wird. Mir jetzt selbst ein Beispiel aus den Fingern zu saugen fehlt die Zeit.
Toaster1337
User
Beiträge: 6
Registriert: Mittwoch 25. November 2020, 01:18

Würde sich meines Erachtens nach gut mit Audioop umsetzten lassen:

Code Beispiel:

Code: Alles auswählen

def echocancel(outputdata, inputdata):
    pos = audioop.findmax(outputdata, 800)    # one tenth second
    out_test = outputdata[pos*2:]
    in_test = inputdata[pos*2:]
    ipos, factor = audioop.findfit(in_test, out_test)
    # Optional (for better cancellation):
    # factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)],
    #              out_test)
    prefill = '\0'*(pos+ipos)*2
    postfill = '\0'*(len(inputdata)-len(prefill)-len(outputdata))
    outputdata = prefill + audioop.mul(outputdata, 2, -factor) + postfill
    return audioop.add(inputdata, outputdata, 2)
Dazu müsste man ja eigentlich nur eine Stilles audio mit dem Grunrauschen aufnehmen und in dieser funktion rausschneiden lassen.
Rechtschreibfehler sind spezialeffekte meiner Tastatur. Wer diese findet darf's behalten.
Benutzeravatar
__blackjack__
User
Beiträge: 14053
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Bei `prefill`/`postfill` müsste es wohl ``b"\0" * length`` heissen wobei das IMHO weniger leicht zu lesen/verstehen ist als ``bytes(length)``.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist doch kein Code, der einen Audio Frame vom System bekommt. Sondern irgendeine Verarbeitung. Womit der Wunsch nach einem nachvollziehbaren Beispiel nicht erfüllt ist.

Was du da zum grundrauschen mutmaßt, kann ich so nicht beurteilen. DSP ist nicht trivial. Das war ja aber eigentlich auch nicht die Frage.
Antworten