2016-08-14 4 views
12

Я разрабатываю music programming language и используя JVM (через Clojure) для воспроизведения музыкальных партитур, написанных на этом языке. До сих пор мы просто используем javax.sound.midi MidiSynthesizer для воспроизведения баллов.Звук Java MIDI задерживается после выхода ноутбука из спящего режима

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

Все это отлично работает по большей части, однако есть странная проблема, что мы видим, где, если вы запустите сервер, затем закройте свой ноутбук * и позвольте ему спящий режим, затем откройте его снова и сервер играет оценку, звук не происходит сразу, но задерживается на несколько секунд. Запустив сервер с протоколом отладки, я действительно вижу, что события MIDI-события вкл/выкл происходят немедленно (и правильно настроены), но звук задерживается.

* Это может быть или не быть специфичным для платформы. Я вижу проблему на своем MacBook Pro 2014 под управлением OS X 10.9.5 Mavericks.

Чтобы сузить это, я соединял этот простой пример (с использованием Java, не Clojure), демонстрирующую проблему:

https://github.com/daveyarwood/java-midi-delayed-audio-example

Я почесал голову над этим некоторое время теперь , Почему звук задерживается, и есть ли что-нибудь, что мы можем с этим поделать?

ответ

4

Это похоже на ошибку в реализации Sun Synthesizer.

Я не исследовал это глубоко, но я обнаружил, что проблема, по-видимому, в Jitter Corrector, которая обертывает AudioInputStream. Поток корректора джиттера зависит от System.nanoTime(). Однако nanoTime может перескакивать, когда компьютер просыпается из режима ожидания или спящего режима.

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

synth = MidiSystem.getSynthesizer(); 

    if (synth instanceof com.sun.media.sound.SoftSynthesizer) { 
     Map<String, Object> params = Collections.singletonMap("jitter correction", false); 
     ((com.sun.media.sound.SoftSynthesizer) synth).open(null, params); 
    } else { 
     synth.open(); 
    } 
+0

Я пробовал это и могу проверить, что он работает как обходной путь! Потрясающие! –

+0

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

+1

Поскольку это единственный ответ, который я получил, и он хотя бы объясняет проблему и один из способов ее решения, я буду считать ее принятым ответом. Я сделал файл [ошибка] (http://bugs.java.com/bugdatabase/view_bug.do?bug_id = JDK-8164300) с Java, поэтому пальцы скрещены, что в какой-то момент он может быть исправлен. –

0

В дополнении к @ apangin, решению которого, я нашел две других путей решения проблемы:

  • Перед каждое воспроизведение, закрыть и повторно открыть тот же синтезатор пример.

  • Используйте новый экземпляр синтезатора для каждого воспроизведения.

Ни один из них идеальны, потому что это занимает несколько секунд, чтобы открыть экземпляр синтезатора (даже если это существующий, который ранее был открыт), но эти обходные пути может быть достаточно для некоторых случаев применения.