USBMIDI version
Closed this issue · 2 comments
Hello! I was able to build your MIDI2CV device, thanks for the code! But i also was always hoping to do it with MidiUSB. Few days ago i started to change code in order to make it work with USB.
First of all i decided to test gate, trig and clock outputs. Clock and trigger works fine, but gate.. Can you please take a look and maybe see what's going on with it?
Behaviour: When you press a note for the first time, gate pin goes high. But it won't turn off when note is released. Also, if you press random notes 20 times, gate pin turns off and gives small peaks of voltage every next time you press a note. I think the problem is in "CommandLastNote" function (i only use this one), it has i<20 in for cycle. I am noob in programming, expecially in C++.
Oh, by the way, i am using Arduino Pro Micro.
Here is the code, as you can see i deleted many things (2nd DAC, note priority selection) as i don't need it. I will be greatful for any advice!
#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;
}
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;
}
PS: Ok, i was able to turn gate off by adding
case 0x80:
digitalWrite(GATE,LOW);
But it still goes nuts after 20 notes pressed.