2013-07-23 6 views
1

Я пытаюсь написать приложение для Android, которое будет служить, помимо прочего, метроном. Это требует способности периодически воспроизводить различные звуки с точным временем, но на данный момент я работаю над тем, чтобы заставить их работать. Обученный слушатель легко обнаружил ошибку более 2-3 мс. Вот моя воспроизводящая нить:Воспроизведение периодического звука на Android

protected void onCreate(Bundle savedInstanceState) { 
    // stuff 
    int minBufferSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT); 
    mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM); 
} 

public void startThread(View view){ 
    mThread = new Thread (new Runnable() { 
     public void run(){ 
      Log.d(TAG, "Starting met at tempo: " + mTempo + " Interval: " + (60000/mTempo)); 

      android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); 

      InputStream in = getResources().openRawResource(R.raw.chirp); 
      byte [] output = getBytesFromStream(in); 

      Log.d(TAG, "Output length: " + output.length); 

      mAudioTrack.play(); 
      while (mRunning) { 
       mAudioTrack.write(output, 0, output.length); 

       try { 
        Thread.sleep(60000/mTempo); 
       } catch (InterruptedException e) { 
       } 
      } 

      mAudioTrack.release(); 
     } 
    }); 

    mThread.start(); 
} 

R.raw.chirp - синусоидальная структура, генерируемая в Audacity. 1000 Гц, отобранных на 44100 Гц в течение 100 мс, поэтому это должно быть около 4410 образцов. Тестирование этого на Nexus 4 с темпом, установленным на 200bpm (т. Е. Чирп должен воспроизводиться каждые 300 мс), звук оказался хорошим, но для хорошей оценки я записал вывод в Audacity через линейный вход. Я заметил две странности:

1) Чирп, казалось, играл в периоды между 298-299 мс. Это было по большей части последовательным, но что 1-2 мс изменяет темп до 201bpm, что достаточно, чтобы выбить его из синхронизации с эталонным метрономом.

2) Вторая странность не была последовательно повторяемой, но после кажущегося случайного числа чириков был бы один чирп, задерживаемый полными 20 мс.

Второй вопрос, который я мог бы, по-видимому, объяснить; возможно, проблема с потоком/приоритетом? Однако первый вопрос меня озадачивает. Я бы подумал, что если что-нибудь, чириканье должно опоздать, а не рано. Я считаю, что эти проблемы связаны, и я также начинаю думать, что не понимаю, что происходит, и делаю что-то очень простое (это мой первый раз, когда я работаю со звуковым кодом любого типа.)

помощь будет высоко оценена.

ответ

5

В дополнение к использованию слабого источника синхронизации существует большая проблема, заключающаяся в том, что Android предлагает только сравнительно свободную и существенно изменяющуюся связь между временем, когда воспроизведение запрашивается и когда оно на самом деле происходит.

Чтобы обойти это, воспроизводите звук непрерывно - в основном тишину - и смешивайте желаемые клики в нужное время. Вместо использования каких-либо обычных системных часов, доступных для программного обеспечения, чтобы определить время, используйте количество ранее записанных образцов, так что ваше время будет иметь фиксированное отношение к тактам дискретизации цифроаналогового преобразователя.

+0

Спасибо. Это, в конечном счете, то, что я думал, что мне придется делать, но я хотел посмотреть, что будет с этим делать. Я полагал, что это не сработает, но это особый способ, которым это не работает, что меня смущает. Я предположил, что будет какая-то задержка между записью данных и их прослушиванием, благодаря асинхронному характеру функции.Это не объясняет, почему большая часть ударов выходила последовательно раньше, чем ожидалось. – sigmabeta

0

Таким образом, вы зависите от сна, будучи точным. Это не так. Он не предназначен. Он будет спать за не менее того времени, но может спать больше. ОС не будет переключать задачу обратно в этот поток, как только начнется спящий режим, но как только он станет потоком верхнего приоритета в очереди планирования. Вам нужен гораздо более надежный способ ожидания - что-то, основанное на RTC.

Тревога, основанная на сигнале тревоги RTC возможно сделайте это. Я не уверен, действительно ли это прерывание RTC, которое отправит вам немедленную тревогу, или если это только относительные часы, которые он использует.

+0

Второе предложение вашего ответа - это то, что я ожидал; однако поведение, проявляемое, заключается в том, что нить спала меньше запрошенного времени. – sigmabeta

+0

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