MIDI USB 2 CV

Нет ответов
66hertz
Offline
Зарегистрирован: 24.10.2019

Всем привет! В данный момент пытаюсь перевести данный проект (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;
}