Найдите среднюю частоту голоса/диапазон через микрофон (AVAudioPCMBuffer и FFT)

Я пытаюсь определить среднюю частоту или диапазон голоса человека, когда он говорит в микрофон. Это не обязательно должно быть в реальном времени. До сих пор мой подход заключался в использовании AVAudioEngine и AVAudioPCMBuffer, получении данных буфера и преобразовании их в БПФ.

inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
            self.recognitionRequest?.append(buffer)

        let data =  buffer.floatChannelData?[0]
        let arrayOfData = Array(UnsafeBufferPointer(start: data, count: Int(buffer.frameLength)))
        let fftData = self.performFFT(arrayOfData)
}




func performFFT(_ input: [Float]) -> [Float] {

    var real = [Float](input)
    var imag = [Float](repeating: 0.0, count: input.count)
    var splitComplex = DSPSplitComplex(realp: &real, imagp: &imag)

    let length = vDSP_Length(floor(log2(Float(input.count))))
    let radix = FFTRadix(kFFTRadix2)
    let weights = vDSP_create_fftsetup(length, radix)
    vDSP_fft_zip(weights!, &splitComplex, 1, length, FFTDirection(FFT_FORWARD))


    var magnitudes = [Float](repeating: 0.0, count: input.count)
    vDSP_zvmags(&splitComplex, 1, &magnitudes, 1, vDSP_Length(input.count))

    var normalizedMagnitudes = [Float](repeating: 0.0, count: input.count)

    vDSP_vsmul(sqrt(magnitudes), 1, [2.0 / Float(input.count)], &normalizedMagnitudes, 1, vDSP_Length(input.count))

    vDSP_destroy_fftsetup(weights)    
    return normalizedMagnitudes
}


public func sqrt(_ x: [Float]) -> [Float] {
    var results = [Float](repeating: 0.0, count: x.count)
    vvsqrtf(&results, x, [Int32(x.count)])
    return results
}

Я думаю, что возвращаю правильные данные FFT, печать выглядит так:

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

Однако это не может быть правильным Гц. Это говорил я, а средние мужские голоса имеют диапазон от 85 до 180 Гц. Я просто не знаю, куда идти отсюда.

Цель состоит в том, чтобы найти среднюю частоту или диапазон, когда пользователь говорит через микрофон. Большое спасибо за любую помощь!!!


person robinyapockets    schedule 13.03.2017    source источник
comment
Две основные проблемы: (1) величина, которую вы хотите измерить, — это высота голоса — это (более или менее) основная частота сложного звука (сложного в том смысле, что он содержит компоненты на многих частотах). на разных частотах) и (2) БПФ не дает вам измерений частоты напрямую - в приведенном выше коде вы фактически генерируете оценку спектра мощности - если вы начертите это, вы должны увидеть спектр (величина против частоты).   -  person Paul R    schedule 13.03.2017
comment
См. этот ответ для псевдокода для определения частоты наибольшего пика в спектре - обратите внимание, что это не обязательно шаг , или даже фундаментальное, но это отправная точка...   -  person Paul R    schedule 13.03.2017
comment
Большое спасибо @PaulR!! Я потрачу некоторое время на ваш связанный ответ.   -  person robinyapockets    schedule 13.03.2017


Ответы (1)


Величина БПФ — это оценщик спектральной частоты (который не работает для многих тонов голоса), а не алгоритм обнаружения/оценки основного тона. Вместо этого попробуйте алгоритм оценки высоты тона, который может лучше определять основную высоту тона, даже если последовательность вокальных гармоник/обертонов имеет большую спектральную мощность.

person hotpaw2    schedule 14.03.2017
comment
Спасибо @hotpaw2 !! Я потрачу больше времени на изучение алгоритма оценки высоты тона. - person robinyapockets; 14.03.2017