Go Down

Topic: MIDI input works but not for all MIDI signals (Read 15957 times) previous topic - next topic

nickgammon


Then I decided to go back to my roots and use my Atari and the damn thing doesn't work with it, every fourth or fifth MIDI note seems to get through but the rest don't. I'm guessing this is something to do with the way I wired the MIDI input ...


It would be funny if this was a coding bug, after all the work we put into the electrical side (work not wasted mind you).

Maybe the Atari pumps out data faster, perhaps we should see the code.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

crx091081gb

The scope is a really old analogue one and it can't seem to trigger off the input making reading bit lengths pretty much impossible, I'm not much of a scope wizard so any tips are welcome on that front. I'm guessing I'd need to make it trigger off a falling voltage then I'd be able to get a stable reading. Hmmm

The code
http://registeringdomainnamesismorefunthandoingrealwork.com/blogs/wp-content/uploads/2009/01/midi_dac_v11.pde

crx091081gb

Thinking about it I should check if the Atari is sending any extra gumph (running status etc) down the line byte wise that my code isn't handling....

nickgammon

That's what I was getting at. My gadget sends a "timing" byte quite often. Maybe you aren't allowing for it, or it overflows your buffer or something.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

crx091081gb

I've checked and there are no status bytes or other gumph coming through. I've also stripped any redundant code in an effort to make sure that it doesn't complete it's main loop fast enough to pick up bytes. No joy.

Is it concievable that the baud rates on the Atari/Arduino are sufficiently different that it could be a bit length/timing issue?

nickgammon

I doubt that personally. Post your code and then we can see.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

crx091081gb

Code: [Select]
#include <avr/pgmspace.h>
#include "LUT.h"

//PIN DEFINITIONS

#define DATAOUT 3 //MOSI, DIN Pin 15 on AD5668
#define SPICLK 4 //Serial Clock In, SCLK Pin 16
#define SLAVESELECT 5//SYNC Active Low Control Input, Pin 2
#define LDAC 6//LDAC, Pin 1, Pulse this pin low to update DAC registers, can be tied permanently low.
#define CLR 7
#define PWRLED 8
#define RXLED 9

//OUTLET DEFINITIONS FOR MIDI X0X
#define GATE 0
#define CV 1
#define ACC 2
#define SLD 3
#define FILT 4

//AD5668 Command definitions
#define WRITE 0
#define UPDATE 1
#define WRITE_UPDATE_ALL 2
#define WRITE_UPDATE_N 3
#define POWER 4
#define LOAD_CC_REG 5
#define LOAD_LDAC_REG 6
#define RESET 7
#define SETUP_INTERNAL_REGISTER 8

//MIDI VARIABLES
byte incomingByte;
int action = 0; //0 not implemented/do nothing, 1 note on, 2 note off, 3 cc, 4 sysex
int note = -1;  //use -1 to indicate the value has not yet been set, this should be changed
int velocity = -1;  //in future versions to save memory (i.e. use a char or a byte)
int extra1 = -1;
int extra2 = -1;

int RX = LOW;                // previous value of the LED
unsigned long interval = 100;           // interval to blink (milliseconds)

boolean noteOn = false;
boolean sysex = false;
unsigned int voltage1 = 13400;
unsigned int voltage2 = 26500;
unsigned int voltage3 = 39550;
unsigned int voltage4 = 52625;
long voltage5 = 65735;

void setup() {
 //set pin modes

 pinMode(DATAOUT, OUTPUT);
 pinMode(SPICLK, OUTPUT);
 pinMode(SLAVESELECT, OUTPUT);
 pinMode(LDAC, OUTPUT);
 pinMode(CLR, OUTPUT);
 pinMode(PWRLED, OUTPUT);
 pinMode(RXLED, OUTPUT);
 //disable DAC to start with
 digitalWrite(DATAOUT,LOW);
 digitalWrite(SPICLK, LOW);
 digitalWrite(SLAVESELECT, LOW);
 digitalWrite(LDAC, HIGH);
 digitalWrite(PWRLED, HIGH);
 digitalWrite(RXLED, HIGH);
 digitalWrite(CLR, LOW);
 delay(500);
 digitalWrite(CLR, HIGH);
 delay(500);
 delay(1000);
 write_dac(SETUP_INTERNAL_REGISTER, 0, 1); //set up internal register on DAC
 delay(1000);
 write_dac(POWER, 0, 0);
 delay(1000);
 write_dac(RESET, 0, 0);
 delay(1000);
 digitalWrite(RXLED, LOW);
 Serial.begin(31250); //change this when you want to graduate from usb midi to real midi
}


void write_dac(byte command, byte address, unsigned int data) {
 switch (command) {
 case WRITE_UPDATE_N:
   {
     byte b1 = B11110000|command; //padding at beginning of byte
     ////Serial.print("b1 ");
     ////Serial.println(b1, BIN);
     byte b2 = address << 4 | data >> 12; //4 address bits and 4 MSBs of data
     ////Serial.print("b2 ");
     ////Serial.println(b2, BIN);
     byte b3 = (data << 4) >> 8; // middle 8 bits of data
     ////Serial.print("b3 ");
     ////Serial.println(b3, BIN);
     byte b4 = (data << 12) >> 8 | B00001111;
     ////Serial.print("b4 ");
     ////Serial.println(b4, BIN);
     ////Serial.println();
     digitalWrite(SLAVESELECT, LOW);
     delayMicroseconds(1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b2);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b3);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b4);
     delayMicroseconds(1);
     digitalWrite(LDAC, LOW);
     delayMicroseconds(1);
     digitalWrite(LDAC, HIGH);
     delayMicroseconds(1);
     digitalWrite(SLAVESELECT, HIGH);
     break;
   }
 case SETUP_INTERNAL_REGISTER:
   {
     byte b1 = B11111000; //padding at beginning of byte
     ////Serial.print("b1 ");
     ////Serial.println(b1, BIN);
     byte b2 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b2, BIN);
     byte b3 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b3, BIN);
     byte b4 = B00000000|data;
     ////Serial.print("b4 ");
     ////Serial.println(b4, BIN);
     ////Serial.println();
     digitalWrite(SLAVESELECT, LOW);
     delayMicroseconds(1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b2);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b3);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b4);
     delayMicroseconds(1);
     digitalWrite(SLAVESELECT, HIGH);
     break;
   }
 case RESET:
   {
     byte b1 = B11110111; //padding at beginning of byte
     ////Serial.print("b1 ");
     ////Serial.println(b1, BIN);
     byte b2 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b2, BIN);
     byte b3 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b3, BIN);
     byte b4 = B00000000|data;
     ////Serial.print("b4 ");
     ////Serial.println(b4, BIN);
     ////Serial.println();
     digitalWrite(SLAVESELECT, LOW);
     delayMicroseconds(1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b2);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b3);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b4);
     delayMicroseconds(1);
     digitalWrite(SLAVESELECT, HIGH);
     break;
   }
 case POWER:
   {
     byte b1 = B11110100; //padding at beginning of byte
     ////Serial.print("b1 ");
     ////Serial.println(b1, BIN);
     byte b2 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b2, BIN);
     byte b3 = B00000000;
     ////Serial.print("b2 ");
     ////Serial.println(b3, BIN);
     byte b4 = B11111111;
     ////Serial.print("b4 ");
     ////Serial.println(b4, BIN);
     ////Serial.println();
     digitalWrite(SLAVESELECT, LOW);
     delayMicroseconds(1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b1);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b2);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b3);
     shiftOut(DATAOUT, SPICLK, MSBFIRST, b4);
     delayMicroseconds(1);
     digitalWrite(SLAVESELECT, HIGH);
     break;
   }
 }
}

crx091081gb

Code: [Select]

void playNote(int note_, int velocity) {
  unsigned int note = note_;
  unsigned int voltage = 0;
  if ((note >= 12) && (note < 24)) {
    ////Serial.println("note >= 12 && note < 24");
    voltage = (voltage1)*((note - 12)/12.0);
  }
  else if ((note >= 24) && (note < 36)) {
    ////Serial.println("note >= 24 && note < 36");
    voltage = (voltage2 - voltage1)*((note - 24)/12.0) + voltage1;
  }
  else if ((note >= 36) && (note < 48)) {
    ////Serial.println("note >= 36 && note < 48");
    voltage = (voltage3 - voltage2)*((note - 36)/12.0) + voltage2;
  }
  else if ((note >= 48) && (note < 60)) {
    ////Serial.println("note >= 48 && note < 60");
    voltage = (voltage4 - voltage3)*((note - 48)/12.0) + voltage3;
  }
  else if ((note >= 60) && (note < 72)) {
    ////Serial.println("note >= 60 && note < 72");
    voltage = (voltage5 - voltage4)*((note - 60)/12.0) + voltage4;
  }
  noteOn = true;
  /*
  if ((velocity >= 1) && (velocity < 64)) { //normal note
    write_dac(WRITE_UPDATE_N, ACC, 0);
    write_dac(WRITE_UPDATE_N, CV, voltage);
    write_dac(WRITE_UPDATE_N, GATE, 65535);
    //Serial.print("cv = ");
    //Serial.print(voltage);
    //Serial.println(", accent = OFF");
  }
  else if (velocity >= 64) { //accent
    write_dac(WRITE_UPDATE_N, ACC, 65535);
    write_dac(WRITE_UPDATE_N, CV, voltage);
    write_dac(WRITE_UPDATE_N, GATE, 65535);
    //Serial.print("cv = ");
    //Serial.print(voltage);
    //Serial.println(", accent = ON");
  }
  */
  write_dac(WRITE_UPDATE_N, CV, voltage);
  write_dac(WRITE_UPDATE_N, GATE, 65535);
}

void stopNote(int note, int velocity) {
  //Serial.println("Note off, GATE = 0");
  write_dac(WRITE_UPDATE_N, GATE, 0);
  noteOn = false;
}

void cc(int note_, int velocity_) {
  write_dac(SETUP_INTERNAL_REGISTER, 0, 1);
  unsigned int note = note_;
  unsigned int velocity = velocity_; //you wouldn't have to convert the ints if you used
                                     //something other than -1 to indicate they were empty,
                                     //just keep them as bytes through out and use 128 as
                                     //empty for MSB and LSB data byte
  if (note == 1) {
    if (velocity >= 64) {
      write_dac(SETUP_INTERNAL_REGISTER, 0, 1);
      //Serial.println("INTERNAL REGISTER ON");
    }
    else {
      write_dac(SETUP_INTERNAL_REGISTER, 0, 0);
      //Serial.println("INTERNAL REGISTER OFF");
    }
  } else if (note == 12) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 2, voltage);
  }
  else if (note == 13) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 3, voltage);
    //Serial.print("OUTPUT 3 = ");
    //Serial.println(voltage);
  }
  else if (note == 14) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 4, voltage);
    //Serial.print("OUTPUT 4 = ");
    //Serial.println(voltage);
  }
  else if (note == 20) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 5, voltage);
    //Serial.print("OUTPUT 5 = ");
    //Serial.println(voltage);
  }
  else if (note == 21) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 6, voltage);
    //Serial.print("OUTPUT 6 = ");
    //Serial.println(voltage);
  }
  else if (note == 22) {
    unsigned int voltage = 65535*velocity/127.0;
    write_dac(WRITE_UPDATE_N, 7, voltage);
    //Serial.print("OUTPUT 7 = ");
    //Serial.println(voltage);
  }
}

void loop() {
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();
    if ((incomingByte == 144) &! sysex) {
      //incoming note on
      action = 1;
    }
    else if ((incomingByte == 128) &! sysex) {
      //incoming note off
      action = 2;
    }
    else if ((incomingByte == 176) &! sysex) {
      action = 3;
    }
    else if ((incomingByte == 240) &! sysex) {
      action = 4;
      sysex = true;
      //Serial.println("incoming sysex");
    }
    else if ((incomingByte == 247) && sysex) {
      sysex = false;
      //Serial.println("sysex finished");
    }
    else if ((action == 1) && (note == -1)) {
      note = incomingByte;
    }
    else if ((action == 1) && (note != -1)) {
      velocity = incomingByte;
      //Serial.print("note on 144 ");
      //Serial.print(note, DEC);
      //Serial.print(" ");
      //Serial.println(velocity, DEC);
      if (velocity == 0) {
        stopNote(note,velocity);
      }
      else {
        playNote(note,velocity);
      }
      action = 0;
      note = -1;
      velocity = -1;
    }
    else if ((action == 2) && (note == -1)) {
      note = incomingByte;
    }
    else if ((action == 2) && (note != -1)) {
      velocity = incomingByte;
      //Serial.print("note off 128 ");
      //Serial.print(note, DEC);
      //Serial.print(" ");
      //Serial.println(velocity, DEC);
      stopNote(note,velocity);
      action = 0;
      note = -1;
      velocity = -1;
    }
    else if ((action == 3) && (note == -1)) {
      note = incomingByte;
    }
    else if ((action == 3) && (note != -1)) {
      velocity = incomingByte;
      //Serial.print("cc ");
      //Serial.print(note, DEC);
      //Serial.print(" ");
      //Serial.println(velocity, DEC);
      cc(note,velocity);
      action = 0;
      note = -1;
      velocity = -1;
    }
    else if ((action == 4) && (note == -1)) {
      note = incomingByte;
    }
    else if ((action == 4) && (note != -1) && (velocity == -1)) {
      velocity = incomingByte;
    }
    else if ((action == 4) && (note != -1) && (velocity != -1) && (extra1 == -1)) {
      extra1 = incomingByte;
    }
    else if ((action == 4) && (note != -1) && (velocity != -1) && (extra1 != -1) && (extra2 == -1)) {
      extra2 = incomingByte;
      //Serial.print("sysex: ");
      //Serial.print(note);
      //Serial.print(" ");
      //Serial.print(velocity);
      //Serial.print(" ");
      //Serial.print(extra1);
      //Serial.print(" ");
      //Serial.println(extra2);
      switch (note) {
      case 1:
        voltage1 = velocity*512 + extra1*4 + extra2;
        //Serial.print("voltage1 = ");
        //Serial.println(voltage1);
        break;
      case 2:
        voltage2 = velocity*512 + extra1*4 + extra2;
        //Serial.print("voltage2 = ");
        //Serial.println(voltage2);
        break;
      case 3:
        voltage3 = velocity*512 + extra1*4 + extra2;
        //Serial.print("voltage3 = ");
        //Serial.println(voltage3);
        break;
      case 4:
        voltage4 = velocity*512 + extra1*4 + extra2;
        //Serial.print("voltage4 = ");
        //Serial.println(voltage4);
        break;
      case 5:
        voltage5 = 65535 + velocity*512 + extra1*4 + extra2;
        //Serial.print("voltage5 = ");
        //Serial.println(voltage5);
        break;
      }
      action = 0;
      note = -1;
      velocity = -1;
      extra1 = -1;
      extra2 = -1;
    }
  }
  if (noteOn) {
    RX = HIGH;
  }
  else {
    RX = LOW;
  }
  digitalWrite(RXLED, RX);
}

nickgammon

Code: [Select]

      digitalWrite(SLAVESELECT, LOW);
      delayMicroseconds(1);
      shiftOut(DATAOUT, SPICLK, MSBFIRST, b1);
      shiftOut(DATAOUT, SPICLK, MSBFIRST, b2);
      shiftOut(DATAOUT, SPICLK, MSBFIRST, b3);
      shiftOut(DATAOUT, SPICLK, MSBFIRST, b4);
      delayMicroseconds(1);
      digitalWrite(LDAC, LOW);
      delayMicroseconds(1);
      digitalWrite(LDAC, HIGH);
      delayMicroseconds(1);
      digitalWrite(SLAVESELECT, HIGH);


Why not use SPI.transfer() rather than all these shifts and delays?

Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

nickgammon


I made this MIDI to CV box and for years it worked just fine receiving MIDI from my computer's M4UXL USB controlled 4 in / 4 out MIDI box. Then I decided to go back to my roots and use my Atari and the damn thing doesn't work with it, every fourth or fifth MIDI note seems to get through but the rest don't.


Now here's a funny thing. I was playing with a sketch that reads MIDI messages, here:

http://arduino.cc/forum/index.php/topic,100382.0.html

And it worked absolutely fine on one device (a Korg synth) but quite badly on another one (a Roland keyboard). Pretty much the same symptoms - some notes got through, a lot didn't.

I'm going to order the improved optocoupler chip in the next couple of days to see if that fixes it.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

crx091081gb

It was written along time ago and either the SPI library wasn't there or more likely I didn't know about it, that part of the code has worked solidly these last years so I never saw any need to fiddle with it. Let us know if the better class of opto fixes matters for you. I have to wait till my list of desired components grows to the right amount to get free shipping from Farnell.  :0

nickgammon


Yes. Here are the suggested schematics from the MIDI Manufacturer's Association (which suggests 280 ohms):


I got some 4N35 today (100% CTR). Still with 330 ohms the results aren't very good:



I got better results with a 1K resistor, but I don't totally like the rounded edges:



Anyway, it turns out that the problems I had with the other device were software more than hardware. :)

Despite all the documentation about MIDI, it still leaves a bit to be desired when you want to interpret the protocol at the low level.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

RuggedCircuits

I am really surprised the 100% CTR devices didn't get the output down lower. Can you confirm the current coming in on the input (LED) side? Is it at least 5mA?

--
The Aussie Shield: breakout all 28 pins to quick-connect terminals

nickgammon

I also got a few SFH618A-4X. With 330 ohms:



They claim to have 160 to 320% CTR at 1 mA.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

nickgammon

#29
Apr 11, 2012, 06:54 am Last Edit: Apr 11, 2012, 06:56 am by Nick Gammon Reason: 1

I am really surprised the 100% CTR devices didn't get the output down lower. Can you confirm the current coming in on the input (LED) side? Is it at least 5mA?


With my meter in circuit with the wire from the MIDI, I am measuring an average of 0.12 mA DC.

(edit) Maximum of about 0.48 mA
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Go Up