Go Down

Topic: MIDI input doesn't work when using Timer2 (Read 3204 times) previous topic - next topic

zipdox

Mar 23, 2020, 08:13 pm Last Edit: Mar 23, 2020, 08:15 pm by zipdox
I'm trying to make a polyphonic synth with an Arduino UNO but I'm having trouble reading midi input. Anyone see any obvious mistakes?

I've tested with another sketch and the hardware works fine so that's not the issue.

The LED on pin 13 should be turning on and off with MIDI input but it doesn't in this sketch.

Code: [Select]

#include <MIDI.h>

#define samplingRate 62500


float midiNotes[] = {8.18, 8.66, 9.18, 9.72, 10.3, 10.91, 11.56, 12.25, 12.98, 13.75, 14.57, 15.43, 16.35, 17.32, 18.35, 19.45, 20.6, 21.83, 23.12, 24.5, 25.96, 27.5, 29.14, 30.87, 32.7, 34.65, 36.71, 38.89, 41.2, 43.65, 46.25, 49, 51.91, 55, 58.27, 61.74, 65.41, 69.3, 73.42, 77.78, 82.41, 87.31, 92.5, 98, 103.83, 110, 116.54, 123.47, 130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220, 233.08, 246.94, 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392, 415.3, 440, 466.16, 493.88, 523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61, 880, 932.33, 987.77, 1046.5, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760, 1864.66, 1975.53, 2093, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520, 3729.31, 3951.07, 4186.01, 4434.92, 4698.64, 4978.03, 5274.04, 5587.65, 5919.91, 6271.93, 6644.88, 7040, 7458.62, 7902.13, 8372.02, 8869.84, 9397.27, 9956.06, 10548.08, 11175.3, 11839.82, 12543.85};

typedef struct Notes {
    int onTime;
    int offTime;
    int hasBeenOn;
} Note;

Note getNoteTimes(float pitch, float dutyCycle){
  float period = samplingRate/pitch;
  Note finalNote = {round(dutyCycle*period), round((1-dutyCycle)*period), 0};
  return finalNote;
}

volatile Note playingNotes[] = {getNoteTimes(261.6, 0.1), getNoteTimes(329.6, 0.1), getNoteTimes(392.0, 0.1)};



MIDI_CREATE_DEFAULT_INSTANCE();

void handleNoteOn(byte channel, byte pitch, byte velocity){
   digitalWrite(13, HIGH);
}

void handleNoteOff(byte channel, byte pitch, byte velocity){
   digitalWrite(13, LOW);
}


void setup(){
    pinMode(9, OUTPUT);
    pinMode(13, OUTPUT);
    MIDI.setHandleNoteOn(handleNoteOn);
    MIDI.setHandleNoteOff(handleNoteOff);
    MIDI.begin(MIDI_CHANNEL_OMNI);

  cli(); //stop interrupts
  TCCR2A = 0; // set Timer/Counter Control Registers (TCCR2A/B) to 0
  TCCR2B = 0;
 
  OCR2A = 0; // = 16000000 / (freq*prescaler) - 1 (must be <256)
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR2B |= (1 << CS20);
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);
  sei(); //allow interrupts
}

void loop(){
    MIDI.read();

}

ISR(TIMER2_COMPA_vect){

  bool shouldPlay = false;
 
  for(int i = 0; i<(sizeof(playingNotes)/sizeof(playingNotes[0])); i++){
    playingNotes[i].hasBeenOn++;
    if(playingNotes[i].hasBeenOn > playingNotes[i].onTime){
      playingNotes[i].hasBeenOn = -playingNotes[i].offTime;
    }
   
    if(playingNotes[i].hasBeenOn >= 0){
        shouldPlay = true;
    }
  }

  if(shouldPlay){
    PORTB |= 1 << 1;
  }else{
    PORTB &= ~(1 << 1);
  }

}

Grumpy_Mike

#1
Mar 24, 2020, 01:07 am Last Edit: Mar 24, 2020, 01:10 am by Grumpy_Mike
Code: [Select]
if(shouldPlay){
    PORTB |= 1 << 1;
  }else{
    PORTB &= ~(1 << 1);
  }


I can't see this working. Why not use the exclusive OR and toggle the bit?
Also I can't see why this is polyphonic.

Could you explain your reasoning with this code please.

zipdox

Code: [Select]
if(shouldPlay){
    PORTB |= 1 << 1;
  }else{
    PORTB &= ~(1 << 1);
  }


I can't see this working. Why not use the exclusive OR and toggle the bit?
Also I can't see why this is polyphonic.

Could you explain your reasoning with this code please.
shouldPlay is a bool that gets set to true if any of the 3 voices are high. Otherwise it is kept false. I it is true, pin 9 get's set HIGH, if it's false, pin 9 get set LOW.

But that's not the issue I'm having. It produces a C-major chord without problems. The issue is I can't get the Arduino to read MIDI or Serial input at all with this sketch no matter what I try.

zipdox

Ok I fixed it. Turns out that TCCR2A = 0; makes serial break; I removed it and in my application it wasn't required so that's good.

Grumpy_Mike

OK, you beat me to it. I have been looking at your code.
Yes I can confirm that removing that makes it work.

MarkT

What's the reason for the conflict - as far as I can see timer2 isn't used in the MIDI library nor is it used
for HardwareSerial...
[ I DO NOT respond to personal messages, I WILL delete them unread, use the forum please ]

PieterP

I haven't verified it, but I think the problem is that he set the timer in CTC (Clear Timer on Compare Match) mode using
  TCCR2A = 0;
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
,
he also set the compare register to zero using
  OCR2A = 0; // = 16000000 / (freq*prescaler) - 1 (must be <256),
and then he enabled the interrupt using
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);


That causes the timer to clear on each cycle (the timer clears on zero, resets to zero, then matches zero, etc.) causing a timer interrupt basically all the time, so there's no time for the UART interrupt to move the received byte into the RAM RX buffer.

By not clearing TCCR2A first, the WGM20 bit might still be set (Arduino initializes it to 1 for PWM mode), resulting in fast PWM mode, not CTC mode.

Pieter

MarkT

Ah, yes, that could explain the interaction...
[ I DO NOT respond to personal messages, I WILL delete them unread, use the forum please ]

Go Up