Я пишу приложение для настройки инструментов (на данный момент начиная с гитары). Для определения высоты тона я использую TarsosDSP. Он правильно определяет высоту тона, однако он довольно шаткий - например, я ударяю по (правильно настроенной) струне ре на своей гитаре, она правильно распознает ее как ре, но через короткое время она циклически повторяется. случайные заметки очень быстро. Я не уверен, как лучше всего решить эту проблему. Вот мой код, который отвечает за определение высоты тона:
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()
Затем я написал функцию, которая должна определять ноту, ближайшую к текущей высоте. Кроме того, я попытался сделать результаты менее шаткими, также написав функцию, которая должна находить ближайшую высоту звука в герцах, а затем использовать этот результат для ближайшей функции Note, думая, что таким образом я могу получить меньше разных результатов (хотя это должно быть то же самое, и я также не замечаю никакой разницы). Вот две функции:
...
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()
}
Любые идеи, как я могу получить более последовательные результаты? Спасибо!