Bạn sẽ cần phải kiểm tra tệp WAV để giải quyết khi có tiếng nói. Cách đơn giản nhất để thực hiện điều này là tìm kiếm các khoảng thời gian lớn và yên tĩnh. Bởi vì âm thanh hoạt động với sóng, khi nó yên lặng các giá trị trong tệp sóng sẽ không thay đổi nhiều, và khi nó lớn thì chúng sẽ thay đổi rất nhiều.
Một cách ước lượng độ ồn là variance. Như bạn có thể thấy bài viết, điều này có thể được định nghĩa là E[(X - mu)^2]
, có thể được viết average((X - average(X))^2)
. Ở đây, X là giá trị của tín hiệu tại một điểm nhất định (các giá trị được lưu trữ trong tệp WAV, được gọi là sample
trong mã). Nếu nó thay đổi rất nhiều, phương sai sẽ lớn.
Điều này sẽ cho phép bạn tính toán độ ồn của toàn bộ tệp. Tuy nhiên, bạn muốn theo dõi độ lớn của tệp tại bất kỳ thời điểm nào, có nghĩa là bạn cần một hình thức moving average. Một cách dễ dàng để có được điều này là với một first-order low-pass filter.
Tôi chưa thử nghiệm mã bên dưới nên rất khó có thể hoạt động, nhưng nó sẽ giúp bạn bắt đầu. Nó tải tệp WAV, sử dụng các bộ lọc low-pass để theo dõi giá trị trung bình và phương sai, và hoạt động khi phương sai đi trên và dưới một ngưỡng nhất định. Sau đó, trong khi chơi các tập tin WAV nó theo dõi thời gian kể từ khi nó bắt đầu chơi, và in ra cho dù các tập tin WAV là lớn hoặc yên tĩnh.
Đây là những gì bạn vẫn có thể cần phải làm:
- Fix tất cả các sai lầm cố ý của tôi trong các mã
- Thêm một cái gì đó hữu ích để phản ứng với/thay đổi yên tĩnh lớn
- Thay đổi ngưỡng và reaction_time để nhận được kết quả tốt với âm thanh của bạn
- Thêm một số hysteresis (ngưỡng biến) để dừng ánh sáng nhấp nháy
Tôi hy vọng điều này sẽ hữu ích!
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'
Đối với tôi, điều này có vẻ như một câu hỏi cho Raspberry Pi SE ... Tôi không biết tại sao nó được di chuyển. – NULL
Nếu tôi hiểu mệnh đề "music.get_busy() == True" while, nó sẽ được thực thi khi tệp .wav đang phát. Vì vậy, bạn sẽ đặt lệnh động cơ của bạn trong vòng lặp trong khi ... phải ... hoặc tôi thiếu một cái gì đó? – NULL
Cảm ơn @NULL vì câu trả lời. 'music.get_busy() == True' sẽ là đúng mọi lúc, vì âm thanh bắt đầu cho đến khi kết thúc. Nhưng tôi muốn phát hiện sự im lặng giữa các từ, tôi không muốn là miệng di chuyển tự động tất cả các thời gian. Tôi muốn ngừng di chuyển trong khi câu trong im lặng. – cor