Мобильная разработка

Как реализовать beat‑детекцию в Android‑приложении

В Android‑приложении можно использовать TarsosDSP, Essentia или FFT‑подход для beat‑детекции, а затем вызывать VibrationEffect и обновлять UI‑элементы.

I want to build an Android app that listens to a music track, detects each beat—say, in a waltz—and then triggers a vibration and a visual cue for every beat to help deaf users. What techniques or libraries can I use for beat detection, and how should I implement the vibration and display logic?

A beat‑tracking app for Android can be built by combining a real‑time audio analysis library (e.g., TarsosDSP, Essentia, or a lightweight FFT‑based approach) with Android’s vibration API (VibrationEffect) and a simple UI callback. The audio stream is analyzed frame‑by‑frame, onsets are detected, and a beat‑estimator produces timestamps that trigger vibrate() and visual updates on the main thread.

Содержание

Выбор подхода к детекции барабана

Beat detection обычно делится на два этапа:

  1. Определение onsets – моменты, когда начинается новый музыкальный сегмент.
  2. Синтез beat‑tracker – интерпретация onsets в ритмическую структуру (бит‑план).

Для простого приложения подойдёт onset‑based подход, потому что он более лёгок в реализации и быстрее. Если нужна более точная синхронизация с музыкой, можно использовать beat‑root‑подобные алгоритмы, которые анализируют временные паттерны.

Либрари для обработки аудио

Библиотека Ключевые возможности Пример использования
TarsosDSP Onset detection, BeatRoot‑style beat tracking, MFCC, Constant‑Q OnsetDetector + BeatTrack
Essentia (Java‑порт) Расширенные алгоритмы аудио‑анализа, включая beat‑tracking BeatTracker
FFmpeg + aubio (JNI) Быстрый DSP, аудио‑фичи, beat‑tracker aubio::tempo
TwelveTone (коробковая реализация) Минимальный набор для onsets TwelveToneOnsetDetector

TarsosDSP считается самым простым для Android, так как не требует нативных библиотек и уже включает PercussionOnsetDetector, который хорошо работает с ритмичными треками.

Согласно GitHub‑репозиторию TarsosDSP, библиотека поддерживает как спектральные, так и временные методы детекции.

Интеграция в Android‑приложение

  1. Получение аудио‑стрима

    • Для записи с микрофона используйте AudioRecord.
    • Для воспроизведения локального файла – MediaPlayer + AudioTrack с передачей PCM‑данных в TarsosDSP.
  2. Создание потока обработки

    kotlin
    val dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(44100, 1024, 512)
    val onsetDetector = PercussionOnsetDetector(44100, 1024) { timestamp ->
        // callback on each detected onset
    }
    dispatcher.addAudioProcessor(onsetDetector)
    Thread(dispatcher, "Audio Dispatcher").start()
    
  3. Beat‑tracker

    kotlin
    val beatTracker = BeatTrack(44100)
    dispatcher.addAudioProcessor(beatTracker)
    beatTracker.setOnBeatListener { beatTime ->
        // UI update + vibration
    }
    
  4. Передача сигнала в UI‑поток

    kotlin
    runOnUiThread {
        triggerVibration()
        updateVisualCue()
    }
    

Вибрация и визуальный отклик

Вибрация

kotlin
private fun triggerVibration() {
    val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator ?: return
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val effect = VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE)
        vibrator.vibrate(effect)
    } else {
        @Suppress("DEPRECATION")
        vibrator.vibrate(50) // deprecated after API 26
    }
}
  • Частота: 50 – 100 мс обычно достаточно для восприятия, но можно подстроить под конкретный ритм.
  • Параметры: VibrationEffect позволяет задавать амплитуду и сложные паттерны (waveform).

Визуальный сигнал

kotlin
private fun updateVisualCue() {
    val pulseView = findViewById<View>(R.id.pulseView)
    pulseView.animate()
        .scaleX(1.5f).scaleY(1.5f)
        .setDuration(100)
        .withEndAction { pulseView.scaleX = 1f; pulseView.scaleY = 1f }
        .start()
}
  • Используйте простую анимацию увеличения/сжатия или меняющийся цвет для мгновенного визуального отклика.
  • Для более сложных эффектов можно подключить Canvas или SurfaceView.

Оптимизация производительности и батареи

Мера Зачем Как реализовать
Использовать AudioRecord с объёмом 1024 Снижает задержку до ~23 мс AudioDispatcherFactory.fromDefaultMicrophone(44100, 1024, 512)
Параллельный поток для DSP Не блокирует UI Thread(dispatcher)
Ограничить частоту обновлений UI Сохраняет ресурсы Handler.postDelayed с 100 мс
Выключать микрофон после завершения Экономит батарею audioRecord.stop()

Примечание

Если приложение будет работать в фоновом режиме, убедитесь, что вы запрашиваете разрешения RECORD_AUDIO и VIBRATE, а также используете ForegroundService для постоянной аудио‑обработки.

Полный пример кода

kotlin
class BeatVibratorActivity : AppCompatActivity() {

    private lateinit var dispatcher: AudioDispatcher
    private val sampleRate = 44100

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_beat_vibrator)

        startBeatDetection()
    }

    private fun startBeatDetection() {
        dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(sampleRate, 1024, 512)

        val beatTracker = BeatTrack(sampleRate).apply {
            setOnBeatListener { beatTime ->
                runOnUiThread {
                    triggerVibration()
                    updateVisualCue()
                }
            }
        }
        dispatcher.addAudioProcessor(beatTracker)

        Thread(dispatcher, "Audio Dispatcher").start()
    }

    private fun triggerVibration() {
        val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator ?: return
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val effect = VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE)
            vibrator.vibrate(effect)
        } else {
            @Suppress("DEPRECATION")
            vibrator.vibrate(50)
        }
    }

    private fun updateVisualCue() {
        val pulse = findViewById<View>(R.id.pulseView)
        pulse.animate()
            .scaleX(1.4f).scaleY(1.4f)
            .setDuration(70)
            .withEndAction { pulse.scaleX = 1f; pulse.scaleY = 1f }
            .start()
    }

    override fun onDestroy() {
        dispatcher.stop()
        super.onDestroy()
    }
}

Итоги:

  • TarsosDSP обеспечивает быстрый и надёжный алгоритм детекции beat‑a.
  • Android VibrationEffect позволяет создавать точные вибрационные сигналы.
  • Синхронизация callback‑ов с UI‑потоком гарантирует мгновенный визуальный отклик.

Дополнительные ресурсы

Эти материалы помогут вам быстро приступить к разработке, настроить параметры под ваш музыкальный материал и предоставить инклюзивный ритмический опыт для глухих пользователей.

Авторы
Проверено модерацией
Модерация