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'
Dla mnie to pytanie do Raspberry Pi SE ... Nie wiem, dlaczego został przeniesiony. – NULL
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
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