java 音高_使用AVAudioEngine实时检测音高是否可行?

我意识到Hellium3确实给了我关于什么音调的信息,以及用Swift做这些事情是个好主意 .

我的问题最初是关于是否点击PCM总线是从麦克风获取输入信号的方法 .

自从提出这个问题以来,我就是这样做的 . 使用通过点击PCM总线获得的数据并分析缓冲区窗口 .

它工作得非常好,而且我对PCM总线,缓冲区和采样频率的理解不足以让我首先提出这个问题 .

知道这三个就更容易看出这是正确的 .

编辑:根据需要,我将粘贴PitchDetector的我(已弃用)实现 .

class PitchDetector {

var samplingFrequency: Float

var harmonicConstant: Float

init(harmonicConstant: Float, samplingFrequency: Float) {

self.harmonicConstant = harmonicConstant

self.samplingFrequency = samplingFrequency

}

//------------------------------------------------------------------------------

// MARK: Signal processing

//------------------------------------------------------------------------------

func detectPitch(_ samples: [Float]) -> Pitch? {

let snac = self.snac(samples)

let (lags, peaks) = self.findKeyMaxima(snac)

let (τBest, clarity) = self.findBestPeak(lags, peaks: peaks)

if τBest > 0 {

let frequency = self.samplingFrequency / τBest

if PitchManager.sharedManager.inManageableRange(frequency) {

return Pitch(measuredFrequency: frequency, clarity: clarity)

}

}

return nil

}

// Returns a Special Normalision of the AutoCorrelation function array for various lags with values between -1 and 1

private func snac(_ samples: [Float]) -> [Float] {

let τMax = Int(self.samplingFrequency / PitchManager.sharedManager.noteFrequencies.first!) + 1

var snac = [Float](repeating: 0.0, count: samples.count)

let acf = self.acf(samples)

let norm = self.m(samples)

for τ in 1 ..< τMax {

snac[τ] = 2 * acf[τ + acf.count / 2] / norm[τ]

}

return snac

}

// Auto correlation function

private func acf(_ x: [Float]) -> [Float] {

let resultSize = 2 * x.count - 1

var result = [Float](repeating: 0, count: resultSize)

let xPad = repeatElement(Float(0.0), count: x.count - 1)

let xPadded = xPad + x + xPad

vDSP_conv(xPadded, 1, x, 1, &result, 1, vDSP_Length(resultSize), vDSP_Length(x.count))

return result

}

private func m(_ samples: [Float]) -> [Float] {

var sum: Float = 0.0

for i in 0 ..< samples.count {

sum += 2.0 * samples[i] * samples[i]

}

var m = [Float](repeating: 0.0, count: samples.count)

m[0] = sum

for i in 1 ..< samples.count {

m[i] = m[i - 1] - samples[i - 1] * samples[i - 1] - samples[samples.count - i - 1] * samples[samples.count - i - 1]

}

return m

}

/**

* Finds the indices of all key maximum points in data

*/

private func findKeyMaxima(_ data: [Float]) -> (lags: [Float], peaks: [Float]) {

var keyMaximaLags: [Float] = []

var keyMaximaPeaks: [Float] = []

var newPeakIncoming = false

var currentBestPeak: Float = 0.0

var currentBestτ = -1

for τ in 0 ..< data.count {

newPeakIncoming = newPeakIncoming || ((data[τ] < 0) && (data[τ + 1] > 0))

if newPeakIncoming {

if data[τ] > currentBestPeak {

currentBestPeak = data[τ]

currentBestτ = τ

}

let zeroCrossing = (data[τ] > 0) && (data[τ + 1] < 0)

if zeroCrossing {

let (τEst, peakEst) = self.approximateTruePeak(currentBestτ, data: data)

keyMaximaLags.append(τEst)

keyMaximaPeaks.append(peakEst)

newPeakIncoming = false

currentBestPeak = 0.0

currentBestτ = -1

}

}

}

if keyMaximaLags.count <= 1 {

let unwantedPeakOfLowPitchTone = (keyMaximaLags.count == 1 && data[Int(keyMaximaLags[0])] < data.max()!)

if unwantedPeakOfLowPitchTone {

keyMaximaLags.removeAll()

keyMaximaPeaks.removeAll()

}

let (τEst, peakEst) = self.approximateTruePeak(data.index(of: data.max()!)!, data: data)

keyMaximaLags.append(τEst)

keyMaximaPeaks.append(peakEst)

}

return (lags: keyMaximaLags, peaks: keyMaximaPeaks)

}

/**

* Approximates the true peak according to https://www.dsprelated.com/freebooks/sasp/Quadratic_Interpolation_Spectral_Peaks.html

*/

private func approximateTruePeak(_ τ: Int, data: [Float]) -> (τEst: Float, peakEst: Float) {

let α = data[τ - 1]

let β = data[τ]

let γ = data[τ + 1]

let p = 0.5 * ((α - γ) / (α - 2.0 * β + γ))

let peakEst = min(1.0, β - 0.25 * (α - γ) * p)

let τEst = Float(τ) + p

return (τEst, peakEst)

}

private func findBestPeak(_ lags: [Float], peaks: [Float]) -> (τBest: Float, clarity: Float) {

let threshold: Float = self.harmonicConstant * peaks.max()!

for i in 0 ..< peaks.count {

if peaks[i] > threshold {

return (τBest: lags[i], clarity: peaks[i])

}

}

return (τBest: lags[0], clarity: peaks[0])

}

}


版权声明:本文为weixin_39751391原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。