2015-02-13 3 views
0

Я получаю периодические сигналы (удары в минуту) от Transmitter и теперь хочу вызывать методы за долю периода, например. отправьте 1/1, 1/2, 1/4, 1/8, 1/16, .. примечания.Синхронизация с битами в минуту/Передача квантованных сообщений

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

Итак, теперь я хочу определить задержку между входящим сигналом и периодическим сигналом потока, и если задержка равна! = 0, остановите текущий поток и запустите новый поток после «bpm-delay» миллисекунд. Как это может быть сделано ?

Иллюстрация:

передатчик сигнала: | ---- | ---- | ---- | ---- |

****** сигнал бегуна: | ---- | ---- | ---- | ---- |

задержка сигнала бегуна на "onePeriod - задержка" миллисекунд: Сигнал

Передатчик: | ---- | ---- | ---- | ---- |

*** "бегун сигнала:. **** | ---- | ---- | ---- | ---- |

Оба сигнала теперь синхронизированы

public class Quantiser implements Receiver{ 
    private int[] bpmsInMillis = new int[4]; 
    private int bpmInMillis=0; 
    private double smallestNote = 1; 
    private long period=0; 

    private long fire=0; 
    private long prevTimeStamp=0; 

    private Runnable runny = new Runnable() { 
     @Override 
     public void run() { 
      while(true){ 
       fire = System.nanoTime() + period; 
       while(System.nanoTime() < fire){} // busy wait 
       // Call some methods here. 
      } 
     } 
    }; 
    private Thread thread = new Thread(runny); 


    @Override 
    public void send(MidiMessage message, long timeStamp) { 

     // Calculate average bpm 
     for(int i=0; i<bpmsInMillis.length-1;i++) 
      bpmsInMillis[i] = bpmsInMillis[i+1]; 

     bpmsInMillis[bpmsInMillis.length-1] = (int) ((timeStamp - prevTimeStamp)/1000); 

     bpmInMillis = arithmeticMean(bpmsInMillis); 
     prevTimeStamp = timeStamp; 

     period = (long) (bpmInMillis * smallestNote * 1000000); 

     if(!thread.isAlive()) { 
      thread.start(); 
     } 
     /* 
     else{ 
      Calculate delay between signal and thread-signal. 
      if(delay != 0){      
       Delay new thread by "bpm - delay" milliseconds. 
       Stop old thread. 
       Start new thread. 
      } 
     */    
    } 

    @Override 
    public void close() { 

    } 
+0

Не могли бы вы объяснить, как помочь начать новую тему? –

+0

Поскольку новый поток будет задерживаться, он должен теперь синхронизироваться с входящим сигналом (компенсация задержки будет компенсирована) – user

+0

Что я понял из вашего кода, ваш исполняемый файл фактически не прослушивает сигнал, он просто использует рассчитанный которое может быть изменено извне в любое время. Поэтому неясно, о какой задержке вы говорите. Задержка между чем и что? В любом случае, если есть задержка, ваш бегун может использовать его для настройки периода (подождите дольше или короче). Нет необходимости в новом потоке. –

ответ

0

В общем, когда я работаю со звуком (обычно сэмплированным, а не с MIDI), я считаю более точным использовать количество кадров, чем прошедшее время. С прошедшим временем слишком много неизвестных (нарезка резьбы, сборка мусора и т. Д.).). Задержки могут различаться, но 44100 кадров (если это формат) всегда 1 сек.

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

Если это что-то такое, когда входящий ASAP/реальное время, но вы хотите передать его через квантованный, можете ли вы разместить информацию о планировании на выходе Midi, даже если входящий не имеет его? Тогда у вас будут твердые опорные точки для позиционирования.

Ссылка на Real-Time. Обработка звука с низкой задержкой в ​​Java: https://diuf.unifr.ch/main/pai/sites/diuf.unifr.ch.main.pai/files/publications/2007_Juillerat_Mueller_Schubiger-Banz_Real_Time.pdf

+0

Это в реальном времени. К сожалению, единственная информация о MIDI-сообщениях, которые у меня есть, это метки времени. – user

+0

Входит, в режиме реального времени, но может ли он выходить как события с отметками времени (с небольшой задержкой). –

1

Одним из вариантов было бы внедрение фазовой блокировки (PLL).

http://en.wikipedia.org/wiki/Phase-locked_loop

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

long time_of_last_beat; 
while (true) { 
    wait_for_next_beat(); 
    time_of_last_beat = System.currentTimeMillis(); 
} 

Другая нить сидит в петле, которая проходит шестнадцать раз быстрее:

long semiquaver_duration = <starting guess>; 
while (true) { 
    notify_whoever_cares_that_its_time_for_the_next_semiquaver(); 
    Thread.sleep(sixteenth_note_duration); 
    long phase_error = System.currentTimeMillis() - time_of_last_beat; 
    semiquaver_duration += estimate_phase_correction(phase_error); 
} 

Я оставлю вас, чтобы написать функцию estimate_phase_correction(). Линейная функция данной ошибки с правым коэффициентом может быть все, что вам нужно.Если вы правильно это понимаете, цикл 16x должен «запираться», чтобы каждый шестнадцатый полупроходчик происходил точно в такт.


Улучшения:

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

Прохладный! Но я думаю, что в конечном итоге вам понадобится использовать вывод, который добавляет информацию о планировании из-за отсутствия гарантий реального времени в Java. Ошибки в синхронизации, вызванные GC, переключение потоков и т. Д., Могут быть вполне слышимыми. Например, в цикле 16x увеличивайте точку расписания на текущий приращение. –

+0

@PhilFreihofner вы можете быть правы. Я никогда не пытался использовать Java в жестком режиме реального времени. Я - старый программист С в глубине души. Я также хорошо знаю, насколько заметны даже самые незначительные сбои в синхронизации звука. –

+0

Это в основном то, что я там сделал. Если вы установите переменную «smallestNote» в 1.0/16, поток будет ждать заметку 1/16. Но я не знаю, как реализовать функцию valu_phase_correction и как правильно измерить фазу. Например. если я измеряю прошедшее время между входящим ритмом и стрельбой бегуна, он не является постоянным. Как сказал Фил Фрейхофнер, это может быть вызвано самой java. – user