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