【问题标题】:AVAudioRecorder through accelerate FFT into frequency - EXECUTIONAVAudioRecorder 通过将 FFT 加速到频率 - 执行
【发布时间】:2012-05-26 22:11:29
【问题描述】:

我的主要目标:找到通过 AVAudioRecorder 引入的噪音的频率。我遵循了这个:

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

我已经阅读了许多关于 SO 的问题,询问如何检测频率。大多数答案说:“使用 FFT!”然后提问者说:“哦,太好了!”。

我的问题是,你如何从这里得到:

- (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?
    }

}

以某种方式神奇地使用 FFT...(我将使用加速.h),

然后以“频率 = 450.3”结束?

如果有人可以告诉我我将使用的实际代码

  1. 将声音从 AVAudioRecorder 插入 Accelerate 和
  2. 如何将结果转化为频率...

那将不胜感激。

提前致谢。

【问题讨论】:

标签: ios fft avaudiorecorder accelerate-framework


【解决方案1】:

没有什么“去那里”,因为 AVRecorder API 没有插入 Accelerate 框架。相反,您必须使用完全不同的 API,Audio Queue 或 RemoteIO Audio Unit API,来捕获音频输入,完全不同的代码安排,例如等待回调获取数据,缓冲区大小管理以获取数据数组合适的大小来馈送 FFT,然后知道足够的 DSP 来对您正在寻找的特定频率测量类型的 FFT 结果进行后处理。

【讨论】:

    【解决方案2】:

    嗯,事实证明有些东西可以“去那里”。我没有使用 Accelerate,而是在亚马逊上买了一本关于傅立叶分析的书,并用它来构建我自己的 FFT。它输出的不是单个频率,而是许多频率中每个频率的电平,这基本上是我想要的。

    这是我的 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
    }
    }
    

    为了获得音频,我使用了 Novocaine:https://github.com/alexbw/novocaine

    我建议阅读一些有关傅立叶变换的内容,但将 Novocaine(麦克风)中的数据插入 FFTComputer 并返回一些频率确实没有那么难。

    (2 到 gamma 是 realXin 的计数。我本来可以计算 gamma,所以如果你想改变它,请继续。只需将 Novocaine 数据转换为 CGFloats 数组,将其放入 realXin,放入imagXin 中相同大小的空数组,然后输入正确的 gamma。然后,可以绘制输出以查看频率。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-14
      • 2020-09-22
      • 2012-11-11
      相关资源
      最近更新 更多