Исправление обнаружения шаткого шага в Kotlin с помощью TarsosDSP

Я пишу приложение для настройки инструментов (на данный момент начиная с гитары). Для определения высоты тона я использую 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()
    }

Любые идеи, как я могу получить более последовательные результаты? Спасибо!


person Brian    schedule 11.11.2020    source источник


Ответы (1)


Решил сам: TarsosDSP вычисляет вероятность каждой сыгранной ноты. Я установил свою функцию closestNote так, чтобы она обновляла текст только в том случае, если вероятность > 0,91 (я обнаружил, что это значение обеспечивает стабильность с точки зрения того, что текст не меняется после нажатия на строку и по-прежнему правильно распознает заметку, не нажимая на строку несколько раз/слишком сильно, также протестировал его с электрогитарой с неполым корпусом, отключенной от сети)

person Brian    schedule 12.11.2020