AVAudioRecorder через ускорение БПФ в частоту - ВЫПОЛНЕНИЕ

Моя основная цель: найти частоту шумов, подтягиваемых через AVAudioRecorder. Я следовал этому:

http://www.ehow.com/how_12224909_detect-blow-mic-xcode.html

Я прочитал много вопросов о SO, спрашивающих, как определить частоту. В большинстве этих ответов говорится: «Используйте БПФ!» а затем задающие вопросы говорят: «О, здорово!».

Мой вопрос в том, как вы получаете отсюда:

- (void)levelTimerCallback {
    [recorder updateMeters];

    const double ALPHA = 0.05;
    double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
    lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;  

    if (lowPassResults > sensitivitySlider.value) {
        NSLog(@"Sound detected");

        //What goes here so I can spit out a frequency?
    }

}

Каким-то волшебным образом используйте БПФ... (я буду использовать ускорение.h),

И получить "Частота = 450,3"?

Если бы кто-нибудь мог показать мне фактический код, который я бы использовал для

  1. Подключите звук из AVAudioRecorder к Accelerate и
  2. Как превратить результат в частоту...

Это было бы очень признательно.

Заранее спасибо.


person Theme    schedule 26.05.2012    source источник
comment
Много дубликатов, например. Обнаружение шага FFT для iOS с использованием Accelerate Framework?   -  person Paul R    schedule 27.05.2012


Ответы (2)


Там ничего не происходит, поскольку API AVRecorder не подключается к среде Accelerate. Вместо этого вы должны использовать совершенно другой API, Audio Queue или RemoteIO Audio Unit API, для захвата аудиовхода, совершенно другую структуру кода, такую ​​как ожидание обратных вызовов для получения ваших данных, управление размером буфера для получения массивов данных соответствующего размера для подачи БПФ, а затем знать достаточно DSP для пост-обработки результатов БПФ для конкретного вида меры частоты, которую вы ищете.

person hotpaw2    schedule 27.05.2012

Что ж, получается, что что-то МОЖЕТ туда "пойти". Вместо использования Accelerate я купил книгу по анализу Фурье на Amazon и использовал ее для построения собственного БПФ. Который выдает не одну частоту, а уровни каждой из многих частот, чего я и хотел.

Вот мой класс вычислений FFT:

class FFTComputer: NSObject {

class func integerBitReverse(_ input:Int,binaryDigits:Int) -> Int {

    return integerForReversedBooleans(booleansForInt(input, binaryDigits: binaryDigits))
}

class func integerForReversedBooleans(_ booleans:[Bool]) -> Int {

    var integer = 0

    var digit = booleans.count - 1
    while digit >= 0 {
        if booleans[digit] == true {
            integer += Int(pow(Double(2), Double(digit)))
        }
        digit -= 1
    }

    return integer
}

class func Pnumber(_ k:Int,placesToMove:Int, gamma:Int) -> Int {

    var booleans = booleansForInt(k, binaryDigits: gamma)

    for _ in 0 ..< placesToMove {
        booleans.removeLast()
        booleans.insert(false, at: 0)
    }

    return integerForReversedBooleans(booleans)
}

class func booleansForInt(_ input:Int,binaryDigits:Int) -> [Bool] {

    var booleans = [Bool]()
    var remainingInput = input

    var digit = binaryDigits - 1
    while digit >= 0 {
        let potential = Int(pow(Double(2), Double(digit)))
        if potential > remainingInput {
            booleans.append(false)
        } else {
            booleans.append(true)
            remainingInput -= potential
        }
        digit += -1
    }

    return booleans
}

class func fftOfTwoRealFunctions(_ realX1:[CGFloat], realX2:[CGFloat], gamma:Int) -> (([CGFloat],[CGFloat]),([CGFloat],[CGFloat])) {

    let theFFT = fft(realX1, imaginaryXin: realX2, gamma: gamma)
    var R = theFFT.0
    var I = theFFT.1
    let N = Int(pow(2.0, Double(gamma)))

    var realOut1 = [CGFloat]()
    var imagOut1 = [CGFloat]()
    var realOut2 = [CGFloat]()
    var imagOut2 = [CGFloat]()

    for n in 0..<N {

        var Rback:CGFloat
        var Iback:CGFloat
        if n == 0 {
            Rback = R[0]
            Iback = I[0]
        } else {
            Rback = R[N-n]
            Iback = I[N-n]
        }

        realOut1.append(CGFloat(R[n]/2 + Rback/2))
        realOut2.append(CGFloat(I[n]/2 + Iback/2))
        imagOut1.append(CGFloat(I[n]/2 - Iback/2))
        imagOut2.append(-CGFloat(R[n]/2 - Rback/2))
    }

    return ((realOut1,imagOut1),(realOut2,imagOut2))
}

class func fft(_ realXin:[CGFloat], imaginaryXin:[CGFloat], gamma:Int) -> ([CGFloat],[CGFloat]) {

    var realX = realXin
    var imaginaryX = imaginaryXin

    let N = Int(pow(2.0, Double(gamma)))
    var N2 = N/2
    var NU1 = gamma - 1 // Always equals (gamma - l)

    var realWP:Double = 1
    var imaginaryWP:Double = 0
    var redoPCounter = 0

    func redoP(_ k:Int, places:Int) {

        let P = Pnumber(k, placesToMove:places, gamma: gamma)
        let inside = (-2*Double.pi*Double(P))/Double(N)
        realWP = cos(inside)
        imaginaryWP = sin(inside)
    }

    var l = 1
    while l <= gamma {
        var k = 0
        var I = 1
        while k < N - 1 {

            if redoPCounter == N2 {
                redoP(k,places: NU1)
                redoPCounter = 0
            }
            redoPCounter += 1
//                Swift.print(realX.count,imaginaryX.count,k+N2)
            let realT1 = (realWP*Double(realX[k + N2]))-(imaginaryWP*Double(imaginaryX[k + N2]))
            let imaginaryT1 = (realWP*Double(imaginaryX[k + N2]))+(imaginaryWP*Double(realX[k + N2]))

            realX[k+N2] = realX[k] - CGFloat(realT1)
            imaginaryX[k+N2] = imaginaryX[k] - CGFloat(imaginaryT1)

            realX[k] = realX[k] + CGFloat(realT1)
            imaginaryX[k] = imaginaryX[k] + CGFloat(imaginaryT1)

            k += 1
            if I == N2 {
                k += N2
                I = 1
            } else {
                I += 1
            }
        }
        N2 = N2/2
        NU1 = NU1 - 1
        redoPCounter = 0
        realWP = 1
        imaginaryWP = 0
        l += 1
    }
    for k in 0 ..< N - 1 {
        let i = integerBitReverse(k, binaryDigits:gamma)
        if i > k {

            let placeholderReal = realX[k]
            let placeholderImaginary = imaginaryX[k]

            realX[k] = realX[i]
            imaginaryX[k] = imaginaryX[i]

            realX[i] = placeholderReal
            imaginaryX[i] = placeholderImaginary
        }
    }

    return (realX,imaginaryX)
}

class func magnitudeAndPhasePresentations(_ realX:[CGFloat], imaginaryX:[CGFloat]) -> ([CGFloat],[CGFloat]) {

    var magnitudes = [CGFloat]()
    var phases = [CGFloat]()

    var lastMagnitude:CGFloat = 0
    var lastPhase:CGFloat = 0

    for n in 0 ..< realX.count {
        let real = realX[n]
        let imaginary = imaginaryX[n]

        if real != 0 {
            lastMagnitude = sqrt(pow(real, 2)+pow(imaginary, 2))
            lastPhase = atan(imaginary/real)
        }
        magnitudes.append(lastMagnitude)
        phases.append(lastPhase)
    }
    return (magnitudes,phases)
}

class func magnitudePresentation(_ realX:[CGFloat], imaginaryX:[CGFloat]) -> [CGFloat] {

    var magnitudes = [CGFloat]()

    var lastMagnitude:CGFloat = 0

    for n in 0 ..< realX.count {
        let real = realX[n]
        let imaginary = imaginaryX[n]

        if real != 0 {
            lastMagnitude = sqrt(pow(real, 2)+pow(imaginary, 2))
        }
        magnitudes.append(lastMagnitude)
    }
    return magnitudes
}
}

А чтобы получить звук, я использовал новокаин: https://github.com/alexbw/novocaine

Я бы порекомендовал немного прочитать о преобразовании Фурье, но на самом деле не так уж сложно подключить данные с новокаина (микрофона) к FFTComputer и получить обратно некоторые частоты.

(2 к гамме — это количество realXin. Я мог бы просто вычислить гамму, поэтому, если вы хотите это изменить, продолжайте. Просто превратите данные новокаина в массив CGFloats, поместите это в realXin, поместите пустой массив того же размера в imagXin и введите правильную гамму. Затем, возможно, нарисуйте график вывода, чтобы увидеть частоты.)

person Theme    schedule 16.04.2018