2015-06-01 15 views
14

Chcę zrobić mówiące usta, które porusza się lub emituje światło lub coś, gdy odtwarzany plik WAV emituje dźwięk. Muszę więc wykryć, kiedy mówi plik wav lub kiedy jest w ciszy pomiędzy słowami. Obecnie używam skryptu Pygame że znalazłemOdtwarzanie dźwięku wav jako wyjścia

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

Chyba mogę zrobić kilka sprawdzenie w pętli while wyglądać poziom wyjściowy dźwięków, czy coś takiego, a następnie wysłać go do jednego z Wyjścia gpio. Ale nie wiem, jak to osiągnąć.

Każda pomoc będzie mile widziane

+0

Dla mnie to pytanie do Raspberry Pi SE ... Nie wiem, dlaczego został przeniesiony. – NULL

+0

Jeśli rozumiem klauzulę "music.get_busy() == True", będzie ona wykonywana podczas odtwarzania pliku .wav. Więc umieścisz swoje polecenia motoryczne w pętli while ... w prawo ... czy coś mi brakuje? – NULL

+0

Dzięki @NULL za odpowiedź. 'music.get_busy() == True' będzie prawdziwe przez cały czas, ponieważ dźwięk zaczyna się do końca. Ale chcę wyczuć milczenie między słowami, nie chcę być ustami poruszającymi się automatycznie przez cały czas. Chcę przestać się poruszać, gdy zdanie jest w milczeniu. – cor

Odpowiedz

7

Musisz sprawdzić plik WAV do pracy, gdy głos jest obecna. Najprostszym sposobem na to jest szukanie głośnych i cichych okresów. Ponieważ dźwięk działa z falami, gdy jest cicho, wartości w pliku falowym nie ulegną znacznej zmianie, a kiedy będzie głośno, będą się bardzo zmieniać.

Jednym ze sposobów szacowania głośności jest variance. Jak widać w artykule, można go zdefiniować jako E[(X - mu)^2], który można zapisać average((X - average(X))^2). Tutaj X jest wartością sygnału w danym punkcie (wartości przechowywane w pliku WAV, o nazwie sample w kodzie). Jeśli dużo się zmienia, wariancja będzie duża.

Umożliwia to obliczenie głośności całego pliku. Jednak chcesz śledzić, jak głośno jest plik w danym momencie, co oznacza, że ​​potrzebujesz formularza moving average. Łatwym sposobem na uzyskanie tego jest first-order low-pass filter.

Nie przetestowałem poniższego kodu, więc jest bardzo mało prawdopodobne, aby działał, ale powinien zacząć. Ładuje plik WAV, wykorzystuje filtry dolnoprzepustowe do śledzenia średniej i wariancji i działa, gdy wariancja idzie powyżej i poniżej pewnego progu. Następnie, podczas odtwarzania pliku WAV, śledzi czas od rozpoczęcia odtwarzania i wyświetla, czy plik WAV jest głośny czy cichy.

Oto, co można jeszcze zrobić:

  • naprawić wszystkie moje świadome błędy w kodzie
  • Dodaj coś pożytecznego do reagowania na głośne/ciche zmiany
  • zmienić próg i reaction_time do uzyskać dobre wyniki z dźwiękiem
  • Dodać trochę hysteresis (próg zmiennej), aby zatrzymać migoczącym świetle

Mam nadzieję, że to pomoże!

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

Twoja odpowiedź wygląda bardzo dobrze. Przeczytam ją jeszcze raz i wypróbuję kod w kolejnych dniach. Dzięki! ;) – cor

+0

Zrobiłem to wiki społeczności, więc mam nadzieję, że oznacza to, że możesz go edytować z dowolnymi znalezionymi poprawkami. Powodzenia! –