2013-06-14 3 views
0

Я пишу простое приложение NDK OpenSL ES, которое записывает, что пользователи касаются виртуальной клавиатуры пианино, а затем воспроизводят их навсегда в заданном цикле. После долгих экспериментов и чтения я решил использовать отдельный цикл POSIX для достижения этого. Как вы можете видеть в коде вычитает любое время обработки, взятое из времени сна, чтобы сделать интервал каждого цикла, как близко к желаемому интервалу сна, насколько это возможно (в данном случае это 5000000 наносекунд.Точная синхронизация потоков POSIX с использованием NDK

void init_timing_loop() { 
    pthread_t fade_in; 
    pthread_create(&fade_in, NULL, timing_loop, (void*)NULL); 
} 

void* timing_loop(void* args) { 

    while (1) { 

     clock_gettime(CLOCK_MONOTONIC, &timing.start_time_s); 

     tic_counter(); // simple logic gates that cycle the current tic 
     play_all_parts(); // for-loops through all parts and plays any notes (From an OpenSL buffer) that fall on the current tic 

     clock_gettime(CLOCK_MONOTONIC, &timing.finish_time_s); 

     timing.diff_time_s.tv_nsec = (5000000 - (timing.finish_time_s.tv_nsec - timing.start_time_s.tv_nsec)); 

     nanosleep(&timing.diff_time_s, NULL); 
    } 

    return NULL; 
} 

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

Есть ли лучший способ приблизиться к этому? Я запустил следующий код:

gettimeofday(&timing.curr_time, &timing.tzp); 
__android_log_print(ANDROID_LOG_DEBUG, "timing_loop", "gettimeofday: %d %d", 
    timing.curr_time.tv_sec, timing.curr_time.tv_usec); 

Который дает довольно последовательное считывание - это не отражает неточности воспроизведения. Существуют ли другие силы для работы с Android, предотвращающие точное время? Или OpenSL ES - потенциальная проблема? Все данные буфера загружаются в память - могут ли быть узкие места?

Удалось опубликовать больше кода OpenSL, если это необходимо ... но на этом этапе я пытаюсь выяснить, является ли этот цикл потока точным или если есть лучший способ сделать это.

+0

одна мысль: держать аудио буфер полон во все времена. Заполните молчание, «играя» соответствующее количество образцов молчания. Таким образом, все синхронизируется через звуковые часы, и переменные задержки не будут влиять на вас (пока вы не будете заполнять буферы). – fadden

+0

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

+0

[This] (http://stackoverflow.com/questions/4485072/accurate-timing-in-ios?lq=1) поток затрагивает аналогичную проблему, но с iOS, если кому-то это интересно. –

ответ

0

Вы также должны учитывать секунды при использовании clock_gettime, вы можете получить больше timing.start_time_s.tv_nsec, чем timing.finish_time_s.tv_nsec. tv_nsec начинается с нуля, когда tv_sec увеличен.

timing.diff_time_s.tv_nsec = 
(5000000 - (timing.finish_time_s.tv_nsec - timing.start_time_s.tv_nsec)); 

попробовать что-то вроде

#define NS_IN_SEC 1000000000 
(timing.finish_time_s.tv_sec * NS_IN_SEC + timing.finish_time_s.tv_nsec) - 
(timing.start_time_s.tv_nsec * NS_IN_SEC + timing.start_time_s.tv_nsec) 
+0

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

Смежные вопросы