MIDI приставка к синтезатору(TapTempo)
- Войдите на сайт для отправки комментариев
Вс, 07/12/2014 - 15:52

Коллега музыкант попросил сделать ему приставку к синтезатору, чтобы темп задавать не переменным сопротивлением, а кнопкой.
Синтезатор использует протокол 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;
}
В итоге все работает и участвует в выступлениях без нареканий.
Если есть пожелания или замечания прошу высказать.
Вам понравилось? В следующей статье могу рассказать про робота удаленного присутствия.
Я начинал делать (заказчик остановил работы) подобный проект - там у меня быле еще энкодер с экраном, для "подкручивания" темпа. А темп задавался "дерганьем" за реле с нужной частотой.