MIDI приставка к синтезатору(TapTempo)

Dorrin
Offline
Зарегистрирован: 06.12.2014
Коллега музыкант попросил сделать ему приставку к синтезатору, чтобы темп задавать не переменным сопротивлением, а кнопкой.
 Синтезатор использует протокол MIDI, в котором описаны- ноты,громкость,темп и еще неожиданно много различной информации. Наша задача с помощью Arduino генерировать нужный темп в синтезатор, преобразовав его из частоты нажатия кнопки.
 
Для реализации был выбран Arduino(Nano), как наиболее доступный(остальные платы уже смонтированы и заняты).
 
Как оказалось, MIDI разъем довольно легко использовать.
 
Покурив основы MIDI выяснил, что за задание темпа отвечает специальный  байт - 0хF8. В стандарте принято 24 таких сообщения в секунду при темпе 1 удар в секунду.
 
Значит надо снимать события нажатия кнопки, брать интервал между ними и выдавать соответствующий сигнал  в MIDI порт(специальный байт) одновременно отобразив его на маленьком экране(ударов в минуту).
 
Звучит хорошо, но на практике выяснилось что выдаваемое на экран с реальным сигналом не сочетается, оказалось что одна из переменных в вычислениях была INT,а не FLOAT и поэтому значение сигнала с платы в MIDI разъем выводился округленный,хотя на экране выдавался до 0.001.
 
Поправив типы переменных получил отличный результат, но подвел человеческий фактор- коллега не мог точно выстучать нужный темп. Поэтому было добавлено уточнение-каждый следующий интервал складывался с предыдущим и делился на 2.
 
Результат стал лучше, но получалась вилка вокруг нужного значения, например нужно 120, а выходило 117 и 124(((
 
В итоге был рожден оптимальный алгоритм:
 
Записываются от 1 до 20 интервалов(произвольно), значения усредняются с каждым нажатие(чтобы была динамика изменения темпа при выводе на экранчик) и если оператор не кликает 1.5 секунды, то он может начать цикл заново.
Вот собственно код с подробным описанием(не нашел как его в спойлер спрятать)
 
//6 вход кнопки

//Tx1-выход миди сигнала

#include <LiquidCrystal.h>/////подключаем библиотеку экрана

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);///задаем для экрана ножки данных

int statButton=0;///статус кнопки
int laststatButton=LOW;
unsigned long int lastinHigh=0;///счетчики
unsigned long int inHigh=0;
unsigned long int clock=0;
unsigned long int lastclock=0;

int durations[19];///массив для хранения периодов нажатия
int count=0;
int duration=0;
float sum=3000;////переменная суммы массива периодов
float bps=2;//удары в секунду
float mps;///тики TapTempo в секунду
float tic;
int count2=0;///счетчики
int count3=0;
int count4=0;

void setup()
{

Serial.begin(31250);///////////////ОБЯЗАТЕЛЬНО ТАКАЯ СКОРОСТЬ
//Serial.begin(9600);
pinMode(6,INPUT);

lcd.begin(16, 2);

}

void loop()
{
mps=bps*24 ;//удары в секунду*сообщений в секунду
tic=1000000/mps;// секунду/сообщений в секунду

clock=micros();///засекаем время для тиков

if(clock-lastclock>tic)///Выдача тиков по таймеру
{

Serial.write(byte(0xF8));///собственно сам тик
lastclock=clock;

}
if(count2==400)///чтение кнопки
{
readbut();
count2=0;
}
count2++;

if(count3==2000)//отображение на дисплей
{
lcd.clear();
//lcd.setCursor(0, 0);

lcd.print(bps*60);
count3=0;
}
count3++;

}

void readbut()///отдельно чтение кнопки
{
statButton=digitalRead(6);
if(statButton==HIGH&&laststatButton==LOW)///если кнопка перешла из LOW в HIGH
{
inHigh=millis();///засекаем время нажатия

duration=inHigh-lastinHigh;//вычисляем разницу между последними нажатиями
// Serial.println(duration);

if(duration<1500&&duration>100)//и если она вписывается
{
if(count<19)///то записываем ее в массив
{
durations[count]=duration;
// Serial.println(durations[count]);
count++;

}

}else{
for(int i=0;i<19;i++)
{
durations[i]=0;
}
count=0;

}

}
lastinHigh=inHigh;
laststatButton=statButton;
for(int i=0;i<19;i++)///перебираем массив
{
if(durations[i]!=0)//ищем не нулевые элементы
{

sum=(sum+durations[i]);
// println(durations[i]);
count4++ ;//и считаем их

bps=1000.0/(sum/count4);///сумма не нулевых/число не нулевых
}
}
count4=0;
sum=0;
}

 

 
В итоге все работает и участвует в выступлениях без нареканий.
Если есть пожелания или замечания прошу высказать.
 
Вам понравилось? В следующей статье могу рассказать про робота удаленного присутствия.
 
Gippopotam
Gippopotam аватар
Offline
Зарегистрирован: 12.09.2014

Я начинал делать (заказчик остановил работы) подобный проект - там у меня быле еще энкодер с экраном, для "подкручивания" темпа. А темп задавался "дерганьем" за реле с нужной частотой.