Получить звуковой уровень воспроизведения wav в качестве выходного

Я хочу сделать говорящий рот, который движется или излучает свет или что-то, когда воспроизводимый wav файл испускает звук. Поэтому мне нужно определить, когда говорит wav файл, или когда он находится в тишине между словами. В настоящее время я использую pygame script, который я нашел

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. Но я не знаю, как это достичь.

Любая помощь будет высоко оценена

Ответы

Ответ 1

Вам нужно будет проверить файл WAV, чтобы он работал, когда голос присутствует. Самый простой способ сделать это - искать громкие и спокойные периоды. Поскольку звук работает с волнами, когда он тикает значения в волновом файле, это не изменится очень сильно, и когда он громко, они будут сильно меняться.

Одним из способов оценки громкости является variance. Как вы можете видеть статью, ее можно определить как E[(X - mu)^2], которая может быть записана average((X - average(X))^2). Здесь X - это значение сигнала в данной точке (значения, хранящиеся в WAV файле, называемые sample в коде). Если он меняет много, дисперсия будет большой.

Это позволит вам рассчитать громкость всего файла. Тем не менее, вы хотите отслеживать, насколько громким является файл в любой момент времени, что означает, что вам нужна форма скользящая средняя. Легкий способ получить это с помощью фильтра нижних частот первого порядка.

Я не тестировал код ниже, поэтому он вряд ли сработает, но он должен вас начать. Он загружает 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'