我正在写一个乐器调谐器应用程序(现在从吉他开始)。对于基音检测,我使用的是TarsosDSP。它确实正确地检测到了音高,但它是相当不稳定的-例如,我将在我的吉他上敲击(正确调整的)D弦,它正确地将其识别为D,但过了片刻,它很快就会在一堆随机的音符中循环。我不确定如何最好地解决这个问题。下面是我的代码,它负责检测音高:
val dispatcher: AudioDispatcher = AudioDispatcherFactory.fromDefaultMicrophone(44100, 4096, 3072)
val pdh = PitchDetectionHandler { res, _ ->
val pitchInHz: Float = res.pitch
runOnUiThread { processing.closestNote(pitchInHz)}
}
val pitchProcessor: AudioProcessor =
PitchProcessor(PitchProcessor.PitchEstimationAlgorithm.FFT_YIN,
44100F, 4096, pdh)
dispatcher.addAudioProcessor(pitchProcessor)
val audioThread = Thread(dispatcher, "Audio Thread")
audioThread.start() 然后,我编写了一个函数,该函数用于检测与当前音高最接近的音符。此外,我试图通过编写一个函数来获得“不那么不稳定”的结果,该函数应该找到以hz为单位的最接近的音调,然后将该结果用于closestNote函数,我认为这样可能会得到更少的不同结果(即使它应该是相同的,我也没有注意到任何差异)。下面是两个函数:
...
private val allNotes = arrayOf("A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#")
private val concertPitch = 440
...
/** detects closest note in A = 440hz with with equal temperament formula:
* pitch(i) = pitch(0) * 2^(i/12)
* therefore formula to derive interval between two pitches:
* i = 12 * log2 * (pitch(i)/pitch(o))
*/
fun closestNote(pitchInHz: Float) {
(myCallback as MainActivity).noteSize() //adjusts the font size of note
if (pitchInHz != -1F) {
val roundHz = closestPitch(pitchInHz)
val i = (round(log2(roundHz / concertPitch) * 12)).toInt()
val closestNote = allNotes[(i % 12 + 12) % 12]
myCallback?.updateNote(closestNote) // updates note text
}
}
private fun closestPitch(pitchInHz: Float): Float {
val i = (round(log2(pitchInHz / concertPitch) * 12)).toInt()
val closestPitch = concertPitch * 2.toDouble().pow(i.toDouble() / 12)
return closestPitch.toFloat()
}你知道怎样才能得到更一致的结果吗?谢谢!
发布于 2020-11-13 05:17:00
我自己解决了这个问题: TarsosDSP计算每个音符播放的概率。我设置了我的closestNote函数,只在概率大于0.91时更新文本(我发现这个值可以提供“稳定性”,就文本而言,在命中字符串后不会改变,并且仍然可以正确地识别音符,而不会多次命中字符串/太用力,我还用一个未插入插头的、非中空的电吉他进行了测试)
https://stackoverflow.com/questions/64778670
复制相似问题