Как начать запись сэмплов при обнаружении определенной частоты тона?

#python

#python

Вопрос:

Я реализовал аналогичный метод, который можно увидеть в этом репозитории https://github.com/rraval/pied-piper/blob/master/decode.py

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

введите описание изображения здесь

Это сигнал, который я сгенерировал программно, а затем добавил немного шума с помощью audacity. Этот аудиосигнал начинается с НАЧАЛЬНОГО сигнала с частотой 400 Гц и заканчивается тоном 500 Гц, между ними находятся тоны (в данном случае 8) с частотами от 10 кГц до 20 кГц, что довольно далеко от частот ЗАПУСКА / остановки.

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

Итак, как именно мне интерпретировать точный момент записи сигнала НАЧАЛЬНОЙ частоты, продолжать запись до тех пор, пока не будет записан стоп-сигнал, а затем получить массив nump или даже wav-файл, с которым я могу работать?

Некоторые значения, которые известны получателю:

 Sampling Rate: 44100 Hz
Tone length: 0.1s (can be changed)
Silence (noise) length: 0.1s (can be changed)
START and END tone frequencies: i.e. 400 and 500 Hz
  

Эти значения указывают на размер окна в 4410 сэмплов, см. Расчет frame_rate ниже, где я пытался уменьшить окно до половины во время записи.

Перед началом и после завершения я добавил 0,5 секунды тишины (шума), чтобы audacity не отключал некоторые звуковые сэмплы

Я немного отладил, чтобы увидеть, когда и если я когда-нибудь введу фрагмент, в котором указана НАЧАЛЬНАЯ / конечная частота, но это очень ненадежно. Я думаю, что это просто чистая удача, поскольку вычисляется dominant_frequency .

Функция сопоставления имеет отклонение около 50 Гц, на всякий случай. Я записываю с помощью sounddevice.

 stop_sync_freq = 500
start_sync_freq = 400
fs = 44100
tone_len = 0.1
silence_len = 0.1

def get_dominant_frequency(data_chunk):
    w = np.fft.fft(data_chunk)
    frequencies = np.fft.fftfreq(len(data_chunk))

    peak_coeff = np.argmax(np.abs(w))
    peak_freq = frequencies[peak_coeff]
    return abs(peak_freq * fs


def record_audio():
    # devices = sd.query_devices()
    frame_rate = int(round(tone_len / 2 * fs))

    in_window = False
    audio_packet = []

    while True:
        data_input = sd.rec(frames=frame_rate, samplerate=fs, channels=1)
        sd.wait()

        if not data_input.size > 0:
            continue

        dominant_frequency = get_dominant_frequency(data_input)
        print(dominant_frequency)

        if in_window and match(dominant_frequency, stop_sync_freq):
            # End - Stop freq
            in_window = False
            break
        elif in_window:
            audio_packet.append(dominant_frequency)
        elif match(dominant_frequency, start_sync_freq):
            # Start - Start freq
            in_window = True


record_audio()
  

Комментарии:

1. Если волна всегда такая, как в вашем примере, проблема кажется «как начать запись, когда амплитуда больше нуля», что проще. В любом случае, использование записи для этой цели кажется немного сложным: то, что вы хотите сделать, это просто обрезать существующий файл. Почему бы не загрузить его в буфер и тихо изменить его размер оттуда?

2. @dspr Волна может быть длиннее, короче, но начало и конец всегда одинаковы. Амплитуда важных частей всегда около «1». Так что, я думаю, это может быть вариант проверить, когда это так, а затем отключить любую информацию до этого сценария, а затем то же самое в конце? Но тогда я не вижу смысла в синхронизации, если только я не хочу убедиться, что это действительно отправляемое сообщение, а не какой-то случайный окружающий звук, который вызвал запуск.

3. В конце, поскольку между звуками есть некоторые паузы, выполнение того, что для начала, невозможно. Если вы будете работать с буфером вместо своего рода потока, я бы предложил сделать то же самое, но в обратном направлении и начать с конца.

4. @dspr И просто для пояснения, я хочу явно отправить его по звуку и записать его с помощью микрофона, а не обрезать сам исходный файл, потому что это могут быть разные клиенты, которые это делают.

5. Ну, это намного сложнее, поскольку вы вынуждены работать в режиме реального времени. Теоретически для этого вам нужен обратный вызов из звуковой системы. В рамках этого обратного вызова вы должны проанализировать сигнал, начать захватывать все сэмплы в массиве, как только вы столкнулись с начальным сигналом, и пока не дойдете до конечного сигнала. После этого вы можете делать с захваченными данными все, что хотите.