Идея: Мы с другом создаем метроном с (Elegoo) Arduino-Mega, который дополнительно может посылать сигнал MIDI-Clock через последовательный порт. Мигающий светодиод синхронно c с установленным значением BPM, BPM-Control над поворотными энкодерами и все остальное работает нормально. Только отправка MIDI-сигнала по последовательному каналу вызывает у нас головную боль.
Проблема: Сигнал MIDI Clock (0xF8) необходимо отправлять 24 раза на каждую долю. Поэтому мы просто рассчитали время между тактами часов и после того, как временной интервал пройден, мы отправляем 0xF8 через Serial. Легко. Но когда мы подключили его к гитарному луперу Ditto X4, мигание светодиодов нашего метронома и лупера не синхронизировалось c. Итак, мы написали небольшой скрипт в C#. NET, чтобы проверить, что отправляется через Serial, и оказывается, что в зависимости от установленного BPM некоторые сообщения не отправляются вообще или задерживаются, что приводит к вычислению петлителем другой BPM, чем мы пытаемся отправить ( Скриншот вывода скрипта ).
Но мы полностью потерялись здесь. Почему некоторые сообщения задерживаются / не отправляются? Даже на "обычных" скоростях передачи вроде 9600 проблема та же. И, похоже, он не масштабируется с использованием процессора Arduino или установленным BPM:
Set BPM: Lost Message every x Messages:
300 24-26
150 10-12
50 4-5
Мы также тестировали Arduino Uno R3 (также от Elegoo), но проблема та же.
Этот пример сценария можно использовать для репликации проблемы:
#include <Arduino.h> //Einbinden der Arduino Bibliothek
//Timer Variables
unsigned long startTimeMIDI = 0;
unsigned long currentTime = 0;
unsigned long intervalLED;
unsigned long intervalMIDI;
short counter_BPM = 300 * 2; // Internally we use BMP*2
void setup()
{
Serial.begin(31250); //Forced by the MIDI standard
while ( !Serial ) /*wait for serial init*/ ;
}
void loop()
{
currentTime = micros();
intervalLED = (120000000/counter_BPM); //60000000*(BPM/2)
intervalMIDI = intervalLED/24; //Midi Clock has to be sent 24 times for each beat
if (currentTime - startTimeMIDI > intervalMIDI){
Serial.write(0xF8); //send MIDI Clock signal
startTimeMIDI = currentTime; //reset timer value
}
}
Это сценарий C#, используемый для отслеживания отправляемой информации:
static void Main(string[] args)
{
serial = new SerialPort("COM4", 31250);
serial.Open();
int cycleSize = 50; //Averaging over 50 Values
long[] latencyList = new long[cycleSize+1];
Stopwatch watch = new Stopwatch();
watch.Start();
int n = 0;
while(true)
{
n++;
watch.Start();
int response = serial.ReadByte();
watch.Stop();
long latency = watch.ElapsedTicks/(Stopwatch.Frequency/(1000L*1000L));
watch.Reset();
if (n <= cycleSize)
{
latencyList[n] = latency;
}
else
{
latencyList[n % cycleSize] = latency;
}
double average = latencyList.Average();
Console.WriteLine("" + n + " " + latency.ToString("000000") + "µs - response:" + response + " - Average: " + average.ToString("##0.00") + " - BPM: " + (int)(60000000/(average * 24)));
}
}
EDIT: (May 9, 2020) Мне нужно прояснить проблему с гитарным лупером: поскольку лупер используется для синхронизации c его эффектов с остальной группой, это самая важная проблема. Мигание светодиода Arduinos BPM (мы нажали и подошли достаточно близко к множеству установленных BPM, чтобы считать его достаточно точным) и мигание светодиода Loopers слишком быстро дрейфуют друг от друга, чтобы быть приемлемым . Мы ставим светодиоды рядом друг с другом, и они go из синхронного c мигают попеременно в течение ~ 30 секунд, так что на живом концерте все развалится. Поскольку мигание светодиода луперов запускается входом MIDI, который он получает, мы проверили согласованность отправленных тактовых сигналов и обнаружили нечетную задержку между сигналами.