Воспроизводить звук каждые N миллисекунд

Я разрабатываю приложение метронома. Пользователь может выбрать во время выполнения bpm, и мое приложение будет соответственно воспроизводить звук «тика». «Тик» – это один метроном «выстрел» (mp3). Я попытался реализовать его с помощью Handler и MediaPlayer, но метроном не совсем точен. Поэтому я подумал об изменении целого подхода: когда пользователь выбирает новое значение bpm, я синтезирую новый звук, повторяя звук тика X раз в каждые миллисекунды, а затем зацикливая на этот звук, созданный во время исполнения. Является ли это действующей альтернативой? Как это можно реализовать в Android?

Solutions Collecting From Web of "Воспроизводить звук каждые N миллисекунд"

Альтернатива петли через синтезированный звук, кажется, лучший выбор на данный момент. Была отличная сессия об аудио в Google I / O 2013 под названием High Performance Audio, которую я бы, конечно же, советовал, наблюдая за более глубоким пониманием того, как работает система, и с какими проблемами сталкиваются разработчики при работе с латентностью звука. Примерно в 17:00 видео есть график, показывающий дрожание и обратные вызовы. В идеальном мире, который не существует (на самом деле?), Дрожание будет равно нулю для всех запланированных обратных вызовов звука. Но это не так, потому что есть дрожания до 35 миллисекунд или даже больше, поскольку данные на графике были сделаны с использованием неуказанного устройства ICS, и, безусловно, хуже сценариев.

Итак, поскольку метроном – это точный инструмент, и эти неудобства вообще не хороши, подход с плановым воспроизведением должен быть оставлен в стороне. Я даже сделал разумную работу метронома с синтезированным звуком, используя AudioTrack .

Надеюсь, это поможет ^^

Вы можете попытаться использовать TimerTask, запланированную для выполнения фиксированной скорости на таймере .

Таймер и TimerTask являются частью Android SDK (и Java SE). Исполнения не задерживаются из-за времени выполнения предыдущего события.

 Timer timer = new Timer("MetronomeTimer", true); TimerTask tone = new TimerTask(){ @Override public void run(){ //Play sound } }; timer.scheduleAtFixedRate(tone, 500, 500); //120 BPM. Executes every 500 ms. 

Затем вы можете отменить TimerTask, когда вам нужно изменить BPM.

 tone.cancel(); tone = new TimerTask(){...} timer.scheduleAtFixedRate(tone, 1000, 1000); //60 BPM. Executes every 1000 ms. 

Другая возможность, которая может соответствовать вашим требованиям (из ваших комментариев), – это прясть потока и проверка System.nanoTime () и спящий с шагом, но вращение, когда вы приближаетесь к пробуждению.

 long delayNanos = 500000000; long wakeup = System.nanoTime() + delayNanos; //Half second from right now long now; while(!done){ now = System.nanoTime(); //If we are less than 50 milliseconds from wake up. Spin away. if(now <= wakeup - 50000000){ //Sleep in very small increments, so we don't spin unrestricted. Thread.sleep(10); } if(now >= wakeup){ //Play sound wakeup += delayNanos; } } в long delayNanos = 500000000; long wakeup = System.nanoTime() + delayNanos; //Half second from right now long now; while(!done){ now = System.nanoTime(); //If we are less than 50 milliseconds from wake up. Spin away. if(now <= wakeup - 50000000){ //Sleep in very small increments, so we don't spin unrestricted. Thread.sleep(10); } if(now >= wakeup){ //Play sound wakeup += delayNanos; } } 

Когда звучит этот звук

 mSoundManager.playSound(1); 

Android ждет, пока этот вызов не будет завершен, затем вы вызываете

 mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200); 

Однако, если вы отмените эти вызовы, вы можете обнаружить, что время более точное.

 mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200); mSoundManager.playSound(1); 

Вы не можете рассчитывать на то, что ваш звук занимает ровно столько же времени, чтобы играть, поэтому сначала сообщить обработчику о начале записи. Тем не менее, он не идеален.