我的主要目标:通过AVAudioRecorder查找噪音的频率。我跟着这个:
http://www.ehow.com/how_12224909_detect-blow-mic-xcode.html
我已经阅读了很多关于如何检测频率的问题。大多数答案都说“使用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 ......(我将使用accele.h),
结束“频率= 450.3”?
如果有人能告诉我我将使用的实际代码
非常感谢。
提前致谢。
答案 0 :(得分:4)
没有什么"去那里",因为AVRecorder API没有插入Accelerate框架。相反,您必须使用完全不同的API,音频队列或RemoteIO音频单元API来捕获音频输入,完全不同的代码安排,例如等待回调来获取数据,缓冲区大小管理以获取数据数组适当的大小来提供FFT,然后了解足够的DSP来对您正在寻找的特定频率测量的FFT结果进行后处理。
答案 1 :(得分:1)
嗯,事实证明,有些东西可以去那里"。我没有使用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
}
}
为了获得音频,我使用了诺沃卡因:https://github.com/alexbw/novocaine
我建议您阅读有关傅立叶变换的一些内容,但是将Novocaine(麦克风)的数据插入FFT计算机并返回某些频率并不是很困难。
(2是伽玛是realXin的计数。我本来可以计算伽马,所以如果你想改变它,请继续。只需将Novocaine数据转换为CGFloats数组,将其放入realXin,放入在imagXin中输出相同大小的空数组,然后输入正确的伽马值。然后,可以将输出图形化以查看频率。)