2015-06-01 5 views
14

Ich möchte einen sprechenden Mund, der sich bewegt oder Licht oder etwas emittiert, wenn eine WAV-Datei spielt Sound. Also muss ich erkennen, wenn eine WAV-Datei spricht oder wenn es in einer Stille zwischen Wörtern ist. Derzeit verwende ich ein pygame Skript, das ichbekommen wav Audio-Level als Ausgabe

import pygame 
pygame.mixer.init() 
pygame.mixer.music.load("my_sentence.wav") 
pygame.mixer.music.play() 
while pygame.mixer.music.get_busy() == True: 
    continue 

gefunden habe, ich denke, ich einige Kontrolle bei der while-Schleife machen könnte die Klänge Ausgangspegel, oder so ähnlich aussehen, und es dann zu einem der schicken GPIO-Ausgaben. Aber ich weiß nicht, wie ich das erreichen soll.

Jede Hilfe wäre viel

+0

Für mich scheint dies eine Frage für die Raspberry Pi SE ... Ich weiß nicht, warum es migriert wurde. – NULL

+0

Wenn ich die while-Klausel "music.get_busy() == True" verstehe, wird sie bei der Wiedergabe der .wav-Datei ausgeführt. Also würden Sie Ihre Motorbefehle in die While-Schleife legen ... richtig ... oder fehle ich etwas? – NULL

+0

Danke @NULL für die Antwort. 'music.get_busy() == True' wird die ganze Zeit wahr sein, da der Sound bis zum Ende beginnt. Aber ich möchte Stille zwischen Wörtern entdecken, ich möchte nicht der Mund sein, der sich die ganze Zeit authomatisch bewegt. Ich möchte aufhören, mich zu bewegen, während der Satz still ist. – cor

Antwort

7

geschätzt werden Sie benötigen, um die WAV-Datei überprüfen heraus zu arbeiten, wenn die Stimme vorhanden ist. Der einfachste Weg dies zu tun, ist laute und ruhige Perioden zu suchen. Da Sound mit Wellen arbeitet, ändern sich die Werte in der Wave-Datei nicht sehr, wenn sie leise sind, und wenn sie laut sind, werden sie sich sehr verändern.

Eine Möglichkeit, die Lautheit zu schätzen, ist die variance. Wie Sie den Artikel sehen können, kann dies als E[(X - mu)^2] definiert werden, die average((X - average(X))^2) geschrieben werden könnte. Hier ist X der Wert des Signals an einem bestimmten Punkt (die Werte, die in der WAV-Datei gespeichert sind, im Code sample genannt). Wenn es sich stark ändert, wird die Varianz groß sein.

Damit können Sie die Lautstärke einer ganzen Datei berechnen. Sie möchten jedoch verfolgen, wie laut die Datei zu einem bestimmten Zeitpunkt ist, dh Sie benötigen eine Form von moving average. Eine einfache Möglichkeit, dies zu erreichen, ist eine first-order low-pass filter.

Ich habe den Code unten nicht getestet, so dass es sehr unwahrscheinlich ist, dass es funktioniert, aber es sollte Ihnen den Anfang machen. Es lädt die WAV-Datei, verwendet Tiefpassfilter, um den Mittelwert und die Varianz zu verfolgen, und ermittelt, wann die Varianz über und unter einen bestimmten Schwellenwert fällt. Während der Wiedergabe der WAV-Datei wird die Zeit seit dem Beginn der Wiedergabe verfolgt und ausgegeben, ob die WAV-Datei laut oder leise ist.

Hier ist, was Sie noch tun müssen, könnten:

  • Fix alle meine absichtlich Fehler im Code
  • nützlich etwas hinzufügen zu den laut/leise Änderungen
  • Ändern der Schwelle und reaction_time zu reagieren erhalten gute Ergebnisse mit Ihrem Audio-
  • einige hysteresis (eine variable Schwelle) hinzufügen, das Licht zu stoppen flackernden

Ich hoffe, das hilft!

import wave 
import struct 
import time 

def get_loud_times(wav_path, threshold=10000, time_constant=0.1): 
    '''Work out which parts of a WAV file are loud. 
     - threshold: the variance threshold that is considered loud 
     - time_constant: the approximate reaction time in seconds''' 

    wav = wave.open(wav_path, 'r') 
    length = wav.getnframes() 
    samplerate = wav.getframerate() 

    assert wav.getnchannels() == 1, 'wav must be mono' 
    assert wav.getsampwidth() == 2, 'wav must be 16-bit' 

    # Our result will be a list of (time, is_loud) giving the times when 
    # when the audio switches from loud to quiet and back. 
    is_loud = False 
    result = [(0., is_loud)] 

    # The following values track the mean and variance of the signal. 
    # When the variance is large, the audio is loud. 
    mean = 0 
    variance = 0 

    # If alpha is small, mean and variance change slower but are less noisy. 
    alpha = 1/(time_constant * float(sample_rate)) 

    for i in range(length): 
     sample_time = float(i)/samplerate 
     sample = struct.unpack('<h', wav.readframes(1)) 

     # mean is the average value of sample 
     mean = (1-alpha) * mean + alpha * sample 

     # variance is the average value of (sample - mean) ** 2 
     variance = (1-alpha) * variance + alpha * (sample - mean) ** 2 

     # check if we're loud, and record the time if this changes 
     new_is_loud = variance > threshold 
     if is_loud != new_is_loud: 
      result.append((sample_time, new_is_loud)) 
     is_loud = new_is_loud 

    return result 

def play_sentence(wav_path): 
    loud_times = get_loud_times(wav_path) 
    pygame.mixer.music.load(wav_path) 

    start_time = time.time() 
    pygame.mixer.music.play() 

    for (t, is_loud) in loud_times: 
     # wait until the time described by this entry 
     sleep_time = start_time + t - time.time() 
     if sleep_time > 0: 
      time.sleep(sleep_time) 

     # do whatever 
     print 'loud' if is_loud else 'quiet' 
+0

Ihre Antwort sieht sehr gut aus, ich werde es wieder lesen und den Code an den folgenden Tagen versuchen. Vielen Dank! ;) – cor

+0

Ich habe es Community-Wiki so hoffentlich gemacht, dass du es mit allen Fixes bearbeiten kannst, die du findest. Viel Glück! –