2015-06-01 13 views
14

Voglio fare una bocca parlante che si muova o emetta luce o qualcosa quando un file wav riproduce il suono. Quindi ho bisogno di rilevare quando un file wav sta parlando o quando si trova in un silenzio tra le parole. Attualmente sto usando uno script pygame che ho trovatoriproduce il livello audio wav come output

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

Credo che avrei potuto fare un po 'il controllo al ciclo while a guardare il livello di uscita i suoni, o qualcosa del genere, e poi inviarlo a uno dei uscite gpio. Ma non so come riuscirci.

Qualsiasi aiuto sarebbe molto apprezzato

+0

Per me questa sembra una domanda per il Raspberry Pi SE ... Non so perché è stata migrata. – NULL

+0

Se comprendo la clausola "music.get_busy() == True" while, verrà eseguita quando viene riprodotto il file .wav. Quindi inseriresti i tuoi comandi motore nel ciclo while ... giusto ... o mi manchi qualcosa? – NULL

+0

Grazie a @NULL per la risposta. 'music.get_busy() == True' sarà vero tutto il tempo, dal momento che il suono inizia fino alla fine. Ma voglio rilevare i silenzi tra le parole, non voglio essere la bocca che si muove automaticamente tutto il tempo. Voglio smettere di muovermi mentre la frase è in silenzio. – cor

risposta

7

Avrai bisogno di ispezionare il file WAV di capire quando la voce è presente. Il modo più semplice per farlo è cercare periodi rumorosi e silenziosi. Poiché il suono funziona con le onde, quando è silenzioso i valori nel file wave non cambieranno molto e quando sarà forte cambieranno molto.

Un modo per stimare il volume è variance. Come puoi vedere nell'articolo, questo può essere definito come E[(X - mu)^2], che potrebbe essere scritto average((X - average(X))^2). Qui, X è il valore del segnale in un dato punto (i valori memorizzati nel file WAV, chiamato sample nel codice). Se sta cambiando molto, la varianza sarà grande.

Ciò consente di calcolare il volume di un intero file. Tuttavia, si desidera tenere traccia di quanto è alto il file in un dato momento, il che significa che è necessario un modulo di moving average. Un modo semplice per ottenere questo è con un first-order low-pass filter.

Non ho testato il codice qui sotto, quindi è estremamente improbabile che funzioni, ma dovrebbe iniziare. Carica il file WAV, utilizza filtri passa-basso per tracciare la media e la varianza, e funziona quando la varianza va sopra e sotto una certa soglia. Quindi, durante la riproduzione del file WAV, tiene traccia del tempo trascorso dall'inizio della riproduzione e stampa se il file WAV è rumoroso o silenzioso.

Ecco cosa si potrebbe ancora bisogno di fare:

  • correggere tutti i miei errori intenzionali nel codice
  • Aggiungere qualcosa di utile per reagire alle forti/modifiche tranquille
  • modificare la soglia e reaction_time a ottengono buoni risultati con l'audio
  • Aggiungere un po 'di hysteresis (una soglia variabile) per fermare la luce tremolante

Spero che questo aiuti!

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

la tua risposta sembra molto buona, leggerò di nuovo e provare il codice nei giorni successivi. Grazie! ;) – cor

+0

Ho reso wiki della comunità quindi spero che questo significhi che puoi modificarlo con qualsiasi correzione che trovi. In bocca al lupo! –

Problemi correlati