Go Down

Topic: USB MIDI to CV converter (Read 414 times) previous topic - next topic

66hertz

Hello! I am trying to remake this project to MIDIUSB support. First of all i decided to check clock, trigger and gate outputs. Clock and trigger works fine, but gate is not.
Behaviour of Gate pin: 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++ :)
If you compare my version with the original code, you will see that i removed some parts, that i don't need: DAC2, Note priority select (only last note priority left).
I'm using arduino Pro Micro.
I will be greatful for any advice!

Here is code so far:

Code: [Select]
#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;
}

66hertz

PS: Ok, i was able to turn gate off by adding
Code: [Select]
    case 0x80:
      digitalWrite(GATE,LOW);

But it still goes nuts after 20 notes pressed.

Go Up