【问题标题】:get playing wav audio level as output播放 wav 音频电平作为输出
【发布时间】:2015-06-01 06:27:09
【问题描述】:

我想制作一个说话的嘴,当播放的 wav 文件发出声音时,它会移动或发光或其他东西。所以我需要检测 wav 文件何时在说话或何时处于沉默状态。目前我正在使用我找到的 pygame 脚本

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

我想我可以在 while 循环中进行一些检查以查看声音输出级别或类似的东西,然后将其发送到其中一个 gpio 输出。但我不知道如何实现。

任何帮助将不胜感激

【问题讨论】:

  • 对我来说,这似乎是 Raspberry Pi SE 的问题...我不知道为什么要迁移它。
  • 如果我理解“music.get_busy() == True”while 子句,它将在播放 .wav 文件时执行。所以你会把你的电机命令放在while循环中......对......或者我错过了什么?
  • 感谢@NULL 的回答。 music.get_busy() == True 将始终为真,因为声音从开始到结束。但是我想检测单词之间的沉默,我不想一直是自动移动的嘴巴。我想在句子沉默的时候停止移动。
  • 我明白了。嗯....我会考虑的。
  • 它可以通过电路轻松完成,而不是解析音频。您只是在寻找软件解决方案吗?

标签: python audio raspberry-pi


【解决方案1】:

您需要检查 WAV 文件才能确定声音何时出现。最简单的方法是寻找吵闹和安静的时期。因为声音与波一起工作,所以当它安静时,wave 文件中的值不会有太大变化,而当它响亮时,它们会发生很大变化。

估计响度的一种方法是variance。正如你在文章中看到的,这可以定义为E[(X - mu)^2],可以写成average((X - average(X))^2)。这里,X 是信号在给定点的值(存储在 WAV 文件中的值,在代码中称为 sample)。如果变化很大,差异会很大。

这可以让您计算整个文件的响度。但是,您想跟踪文件在任何给定时间的响度,这意味着您需要moving average 的形式。一个简单的方法是使用first-order low-pass filter

我没有测试过下面的代码,所以它不太可能工作,但它应该能让你开始。它加载 WAV 文件,使用低通滤波器跟踪均值和方差,并计算出方差何时高于和低于某个阈值。然后,在播放 WAV 文件时,它会记录开始播放以来的时间,并打印出 WAV 文件是响亮还是安静。

以下是您可能仍需要做的事情:

  • 修复我在代码中故意犯的所有错误
  • 添加一些有用的东西来应对响亮/安静的变化
  • 更改阈值和反应时间以获得良好的音频效果
  • 添加一些hysteresis(可变阈值)以停止灯光闪烁

我希望这会有所帮助!

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'

【讨论】:

  • 你的答案看起来很不错,我会在接下来的几天里再次阅读并尝试代码。谢谢! ;)
  • 我已将其设为社区 wiki,因此希望这意味着您可以使用找到的任何修复程序对其进行编辑。祝你好运!
  • sample_rate 未定义,我将样本作为元组获取,不能相乘。有更新的代码吗?
猜你喜欢
  • 2023-03-12
  • 2020-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多