I am having issues with the MIDI-sniffer sketch found here.
I am a beginner circuit builder and coder and thought this sketch would be a good place to start to learn about the different aspects of MIDI data that I could work with using the Arduino MIDI library.
I am not using the sparkfun MIDI shield but have built a MIDI I/O circuit according to MIDI specs.
The circuit works with no issues when receiving input from a sequencer and the output goes to a software synthesizer sound source.
I have tested this circuit using the Arduino MIDI library (fortyseven effects) basic I/O and callback examples. No issues whatsoever.
The MIDI analyzer circuit uses the same MIDI library but also uses the softwareSerial library and msTimer2 library.
The issue I am having with the MIDI-sniffer.ino sketch is that while the serial monitor seems to be reading all the MIDI data, the output seems to be getting "stuck". Notes will get stuck "on" and after I stop the sequencer, I hear a distinct echo/ feedback noise. I have to reset MIDI output (send note off / panic message) in my DAW to stop the noise from continuing. Is this some kind of loopback?
Why do the basic I/O and callback examples work ok and this one has issues? How can I work to resolve this issue? Any guidance or pointers is greatly appreciated. The MIDI-sniffer code referenced above is here:
#include <softwareserial.h>
#include <mstimer2.h>
#include <midi.h>
#define PIN_RAW_INPUT 2
#define PIN_POT_A0 0
#define PIN_POT_A1 1
static const uint16_t DEBOUNCE_COUNT = 50;
// Need to use soft serial, so we can report what's happening
// via messages on hard serial.
SoftwareSerial SoftSerial(8, 9);
/* Args:
- type of port to use (hard/soft)
- port object name
- name for this midi instance
*/
MIDI_CREATE_INSTANCE(SoftwareSerial, SoftSerial, MIDI);
// This doesn't make much sense to use with hardware serial, as it needs
// hard serial to report what it's seeing...
void setup()
{
// put your setup code here, to run
once:
// LED outputs
Serial.begin(19200);
Serial.println("Setting up");
// do I need to init the soft serial port?
// No - MIDI Lib will do it.
// We want to receive messages on all channels
MIDI.begin(MIDI_CHANNEL_OMNI);
// We also want to echo the input to the output,
// so the sniffer can be dropped inline when things misbehave.
MIDI.turnThruOn();
pinMode(PIN_RAW_INPUT, INPUT_PULLUP);
}
void loop()
{
static uint8_t ticks = 0;
static uint8_t old_ticks = 0;
// put your main code here, to run repeatedly:
if(digitalRead(PIN_RAW_INPUT) == LOW)
{
// If you hold button D2 on the shield, we'll print
// the raw hex values from the MIDI input.
//
// This can be useful if you need to troubleshoot issues with
// running status
byte input;
if(SoftSerial.available() != 0)
{
input = SoftSerial.read();
if(input & 0x80)
{
Serial.println();
}
Serial.print(input, HEX);
Serial.print(' ');
}
}
else
{
// turn the crank...
if ( MIDI.read())
{
switch (MIDI.getType())
{
case midi::NoteOff :
{
Serial.print("NoteOff, chan: ");
Serial.print(MIDI.getChannel());
Serial.print(" Note#: ");
Serial.print(MIDI.getData1());
Serial.print(" Vel#: ");
Serial.println(MIDI.getData2());
}
break;
case midi::NoteOn :
{
uint8_t vel;
Serial.print("NoteOn, chan: ");
Serial.print(MIDI.getChannel());
Serial.print(" Note#: ");
Serial.print(MIDI.getData1());
Serial.print(" Vel#: ");
vel = MIDI.getData2();
Serial.print(vel);
if (vel == 0)
{
Serial.print(" *Implied off*");
}
Serial.println();
}
break;
case midi::AfterTouchPoly :
{
Serial.print("PolyAT, chan: ");
Serial.print(MIDI.getChannel());
Serial.print(" Note#: ");
Serial.print(MIDI.getData1());
Serial.print(" AT: ");
Serial.println(MIDI.getData2());
}
break;
case midi::ControlChange :
{
Serial.print("Controller, chan: ");
Serial.print(MIDI.getChannel());
Serial.print(" Controller#: ");
Serial.print(MIDI.getData1());
Serial.print(" Value: ");
Serial.println(MIDI.getData2());
}
break;
case midi::ProgramChange :
{
Serial.print("PropChange, chan: ");
Serial.print(MIDI.getChannel());
Serial.print(" program: ");
Serial.println(MIDI.getData1());
}
break;
case midi::AfterTouchChannel :
{
Serial.print("ChanAT, chan: ");
Serial.print(MIDI.getChannel());
Serial.print(" program: ");
Serial.println(MIDI.getData1());
}
break;
case midi::PitchBend :
{
uint16_t val;
Serial.print("Bend, chan: ");
Serial.print(MIDI.getChannel());
// concatenate MSB,LSB
// LSB is Data1
val = MIDI.getData2() << 7 | MIDI.getData1();
Serial.print(" value: 0x");
Serial.println(val, HEX);
}
break;
case midi::SystemExclusive :
{
// Sysex is special.
// could contain very long data...
// the data bytes form the length of the message,
// with data contained in array member
uint16_t length;
const uint8_t * data_p;
Serial.print("SysEx, chan: ");
Serial.print(MIDI.getChannel());
length = MIDI.getSysExArrayLength();
Serial.print(" Data: 0x");
data_p = MIDI.getSysExArray();
for (uint16_t idx = 0; idx < length; idx++)
{
Serial.print(data_p[idx], HEX);
Serial.print(" 0x");
}
Serial.println();
}
break;
case midi::TimeCodeQuarterFrame :
{
// MTC is also special...
// 1 byte of data carries 3 bits of field info
// and 4 bits of data (sent as MS and LS nybbles)
// It takes 2 messages to send each TC field,
Serial.print("TC 1/4Frame, type: ");
Serial.print(MIDI.getData1() >> 4);
Serial.print("Data nybble: ");
Serial.println(MIDI.getData1() & 0x0f);
}
break;
case midi::SongPosition :
{
// Data is the number of elapsed sixteenth notes into the song, set as
// 7 seven-bit values, LSB, then MSB.
Serial.print("SongPosition ");
Serial.println(MIDI.getData2() << 7 | MIDI.getData1());
}
break;
case midi::SongSelect :
{
Serial.print("SongSelect ");
Serial.println(MIDI.getData1());
}
break;
case midi::TuneRequest :
{
Serial.println("Tune Request");
}
break;
case midi::Clock :
{
ticks++;
Serial.print("Clock ");
Serial.println(ticks);
}
break;
case midi::Start :
{
ticks = 0;
Serial.println("Starting");
}
break;
case midi::Continue :
{
ticks = old_ticks;
Serial.println("continuing");
}
break;
case midi::Stop :
{
old_ticks = ticks;
Serial.println("Stopping");
}
break;
case midi::ActiveSensing :
{
Serial.println("ActiveSense");
}
break;
case midi::SystemReset :
{
Serial.println("Stopping");
}
break;
case midi::InvalidType :
{
Serial.println("Invalid Type");
}
break;
default:
{
Serial.println();
}
break;
}
}
}
}