Обнаружение звука с GoLang - PullRequest
       3

Обнаружение звука с GoLang

1 голос
/ 18 февраля 2020

Я работаю над созданием очень простого и легкого решения для того, что в принципе было бы Golang звуковым детектором. Мне нужно прочитать аудиопоток MP3 / MP4 (на данный момент работающий с файлом) и выполнить функцию, которая есть у меня, когда обнаружен более громкий, чем обычно, звук. Я относительно новичок в Golang и не имею опыта работы с цифровым аудио. У меня есть код ниже, который обнаруживает звуковой сигнал, но я не знаю, как go об обнаружении только более громких шумов, а не просто звукового сигнала. Любая помощь будет оценена !!

package main

import (
    "encoding/binary"
    "fmt"
    "log"
    "math"
    "math/cmplx"
    "net/http"

    "os"

    "github.com/hajimehoshi/go-mp3"
    "github.com/hajimehoshi/oto"

    "github.com/mjibson/go-dsp/fft"

    "github.com/mjibson/go-dsp/window"
)

// const sampleRate = 44100
const toneFrequency = 440
const mp3file = "C:/Users/mmekaiel/Music/audio-samples/440Hz.mp3"

func serveHome(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/html")
    fmt.Fprint(w, "<h1>Hello world site!!</h1>")
}

func serveAudio(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("<h1>The <a href='https://github.com/rwarford/simple-tone-detect'>tone-detect</a> audio page!!</h1>"))

    if err := process(toneFrequency); err != nil {
        log.Fatal(err)
    }
}

func process(toneFreq int) error {
    f, err := os.Open(mp3file)
    if err != nil {
        return err
    }
    defer f.Close()

    d, err := mp3.NewDecoder(f)

    if err != nil {
        return err
    }

    p, err := oto.NewPlayer(d.SampleRate(), 2, 2, 8192)

    if err != nil {
        return err
    }

    defer p.Close()

    windowSize := 40 // window size in milliseconds
    windowSamples := int(float32(d.SampleRate()) * float32(windowSize) / 1000.0)

    // fftSize is the smallest power of 2 greater than or equal to windowSamples
    fftSize := int(math.Pow(2, math.Ceil(math.Log2(float64(windowSamples)))))

    spectralWidth := float64(d.SampleRate()) / float64(fftSize)
    targetIndex := int(float64(toneFreq) / spectralWidth)

    fmt.Printf("Sample Rate: %d\n", d.SampleRate())
    fmt.Printf("Length: %d[bytes]\n", d.Length())
    fmt.Printf("Window size: %d[samples]\n", windowSamples)
    fmt.Printf("FFT size: %d\n", fftSize)
    fmt.Printf("Spectral Line width: %v[hertz]\n", spectralWidth)
    fmt.Printf("Tone index: %d\n", targetIndex)

    b := make([]byte, windowSamples*4) // 2 bytes per sample, 2 channels
    w := make([]float64, fftSize)
    t := 0
    toneStart := -1

outerloop:
    for {
        // Read a window of samples
        bytesRead := 0
        for bytesRead < len(b) {
            n, err := d.Read(b[bytesRead:])
            if err != nil {
                break outerloop
            }
            bytesRead += n
        }

        // Convert to float (ignore second channel)
        for i := 0; i < len(b); i += 4 {
            w[i/4] = float64(int16(binary.LittleEndian.Uint16(b[i+0:i+2]))) / 32768.0
        }

        // Apply window function
        window.Apply(w, window.Hamming)

        // Perform FFT
        c := fft.FFTReal(w)

        // Compute the normalized magnitude
        r, _ := cmplx.Polar(c[targetIndex])
        r = r / float64(fftSize)

        // Look for tone
        toneDetected := r > 0.05 // Apply arbitrary threshold
        if toneDetected && toneStart < 0 {
            toneStart = t
        } else if !toneDetected && (toneStart >= 0) {
            fmt.Printf("Tone from %dms to %dms.\n", toneStart, t)
            toneStart = -1
        }

        t += windowSize
    }

    return nil
}

func main() {
    mux := &http.ServeMux{}

    mux.HandleFunc("/", serveHome)

    mux.HandleFunc("/audio", serveAudio)

    http.ListenAndServe(":8080", mux)
}

1 Ответ

0 голосов
/ 26 марта 2020

Используемая вами библиотека mp3 декодирует mp3 в "Raw" аудио, обычно PCM . В документации для NewDecoder также упоминается

Поток всегда форматируется как 16-битные (с прямым порядком байтов) 2 канала, даже если источником является одноканальный MP3. Таким образом, сэмпл всегда состоит из 4 байтов.

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

Чтобы искать громкость, вам нужно искать большое значение или, возможно, большое изменение значения со времени последнего кадра. Вам не нужны вещи FTT. Это операция, известная как « быстрое преобразование Фурье ». Это позволяет вам видеть, какие частоты в настоящее время в звуке. Это полезно для определения высоты тона, но совсем не полезно для определения громкости. Я бы удалил практически все после декодера и попытался бы просто прочитать с него несколько байтов.

РЕДАКТИРОВАТЬ: После дальнейших размышлений громкий звук длится гораздо дольше, чем один образец (цифровой звук не это мое поле). - это то, как вы на самом деле это делаете -

Также обратите внимание: 16 битов могут быть подписаны или не подписаны (s16le или u16le). Похоже, что подписанный является «стандартным» и вероятным.

РЕДАКТИРОВАТЬ 2: Если вы не разрабатываете библиотеку обработки звука, я бы порекомендовал найти ее самостоятельно. Я лично использую GStreamer для такого рода вещей, но это то, что вам нужно (я просто рекомендую , а не ).

Может быть, что-то вроде библиотека типов данных PCM . Похоже, что они имеют некоторое усиление и масштабирование в здесь . Похоже, хорошее место, чтобы копать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...