MIDI USB 2 CV
- Войдите на сайт для отправки комментариев
Всем привет! В данный момент пытаюсь перевести данный проект (https://github.com/elkayem/midi2cv) для поддержки USBMIDI. Переводит midi-сигналы в cv\gate сигналы (для аналоговых синтезаторов). Код рабочий, собирал под обычный MIDI.
Для начала решил протестировать выход с пинов Gate, trigger и clock. Clock и Trigger работают идеально, а вот с Gate проблемы. Когда первый раз после запуска нажимаешь какую нибудь ноту, Gate-пин переходит в состояние HIGH (как и должно быть). Но, когда отжимаешь ноту, напряжение на пине остаётся. Должно быть LOW. Иными словами, 5 вольт на Gate-пине должно быть только тогда, когда нота нажата. Если нажать любые ноты 20 раз, то пин переходит в LOW, и отзывается едва заметными скачками напряжения на каждое следующее нажатие. Думаю всё дело в функции CommandLastNote(), потому что там в цикле присутствует i<20. Ну и переход пина Gate в состояние LOW тоже там. От программирования я далёк, поэтому своими силами понять, что там происходит, не могу. Прошу любого совета по теме, буду очень признателен.
Если посмотреть на измененный код, можно заметить, что часть функций я убрал - DAC2, выбор NotePriority (оставил только LastNotePriority). Основные вещи старался вообще не трогать, только то, что касается MidiUSB.
Использую Arduino Pro Micro.
Код пока получается такой:
#include "MIDIUSB.h"
#include <SPI.h>
#define GATE 5
#define TRIG 6
#define CLOCK 4
#define DAC1 8
void setup()
{
pinMode(GATE, OUTPUT);
pinMode(TRIG, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(DAC1, OUTPUT);
digitalWrite(GATE,LOW);
digitalWrite(TRIG,LOW);
digitalWrite(CLOCK,LOW);
digitalWrite(DAC1,HIGH);
SPI.begin();
Serial.begin(115200);
}
bool notes[88] = {0};
int8_t noteOrder[20] = {0}, orderIndx = {0};
unsigned long trigTimer = 0;
void loop()
{
int noteMsg, velocity, channel;
static unsigned long clock_timer=0, clock_timeout=0;
static unsigned int clock_count=0;
if ((trigTimer > 0) && (millis() - trigTimer > 20)) {
digitalWrite(TRIG,LOW); // Set trigger low after 20 msec
trigTimer = 0;
}
if ((clock_timer > 0) && (millis() - clock_timer > 20)) {
digitalWrite(CLOCK,LOW); // Set clock pulse low after 20 msec
clock_timer = 0;
}
//NEW PART#############################################################3
midiEventPacket_t rx = MidiUSB.read(); //listen for new MIDI messages
switch (rx.byte1) {
case 0x90: //Note On message channel 1
noteMsg = rx.byte2 - 21; // A0 = 21, Top Note = 108
if ((noteMsg < 0) || (noteMsg > 87)) break;
velocity = rx.byte3;
if (velocity == 0) {
notes[noteMsg] = false;
}
else {
notes[noteMsg] = true;
// velocity range from 0 to 4095 mV Left shift d2 by 5 to scale from 0 to 4095,
// and choose gain = 2X
setVoltage(DAC1, 1, 1, velocity<<5); // DAC1, channel 1, gain = 2X
}
if (notes[noteMsg]) { // If note is on and using last note priority, add to ordered list
orderIndx = (orderIndx+1) % 20;
noteOrder[orderIndx] = noteMsg;
}
commandLastNote();
case 0xF8: //Clock
if (millis() > clock_timeout + 300) clock_count = 0; // Prevents Clock from starting in between quarter notes after clock is restarted!
clock_timeout = millis();
if (clock_count == 0) {
digitalWrite(CLOCK,HIGH); // Start clock pulse
clock_timer = millis();
}
clock_count++;
if (clock_count == 24) { // MIDI timing clock sends 24 pulses per quarter note. Sent pulse only once every 24 pulses
clock_count = 0;
}
break;
}
}
void commandLastNote()
{
int8_t noteIndx;
for (int i=0; i<20; i++) {
noteIndx = noteOrder[ mod(orderIndx-i, 20) ];
if (notes[noteIndx])
commandNote(noteIndx);
else
return;
}
digitalWrite(GATE,LOW); // All notes are off
}
#define NOTE_SF 47.069f // This value can be tuned if CV output isn't exactly 1V/octave
void commandNote(int noteMsg) {
digitalWrite(GATE,HIGH);
digitalWrite(TRIG,HIGH);
trigTimer = millis();
unsigned int mV = (unsigned int) ((float) noteMsg * NOTE_SF + 0.5);
setVoltage(DAC1, 0, 1, mV); // DAC1, channel 0, gain = 2X
}
void setVoltage(int dacpin, bool channel, bool gain, unsigned int mV)
{
unsigned int command = channel ? 0x9000 : 0x1000;
command |= gain ? 0x0000 : 0x2000;
command |= (mV & 0x0FFF);
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
digitalWrite(dacpin,LOW);
SPI.transfer(command>>8);
SPI.transfer(command&0xFF);
digitalWrite(dacpin,HIGH);
SPI.endTransaction();
}
int mod(int a, int b)
{
int r = a % b;
return r < 0 ? r + b : r;
}