"Play it (Once) Sam" Arduino MIDI ER Puzzle Help

I was attempting Alastair's keyboard Arduino puzzle. I just attached the keyboard to a MIDI shield on the Arduino and ran the code. Surprisingly Midi.Read was giving output in the Serial Monitor.

I tried adding some comments to the output and now Midi.Read puts out nothing. I reverted back to the original code. Nothing. I switched boards and ran into all kinds of errors uploading and with ports that aren't relevant but added to my frustration.

Anyway, the code is uploaded again and still I'm getting nothing from Midi.Read. I can put a comment in the loop to show it's at least getting there. Also the comment comes out as backwards question marks. I learned that maybe I need to add Serial.begin (9600) but that didn't work.

Here is an image of my set up. As I explained it's just the Arduino Uno, a MIDI shield a MIDI cable and a Rockband 3 Keyboard

Here is the code but it probably won't help since I can verify it was working (kind of) at one point with the same code.

/**
* "Play it once, Sam" Arduino MIDI-sequence puzzle
* Alastair Aitchison (c) 2018
* 
* This puzzle requires the user to play a melody on a MIDI device.
* Each correct note played will light up an LED on a WS2812B LED strip.
* When the entire melody has been played correctly, a relay will be activated (releasing a maglock etc.)
* Playing an incorrect note means the sequence must be restarted from the beginning
*/

// INCLUDES
// FastLED library used for controlling the pixel strip. Download from http://fastled.io/
#include <FastLED.h>
// For handling MIDI messages. Install from Sketch -> Include Library -> Manage Libraries -> "MIDI Library by Forty Seven Effects"
#include <MIDI.h>
// This library defines a simple list structure to keep track of multiple notes played simultaneously by the player 
#include "noteList.h"
// Lookup table to define tone frequency of musical notes. e.g. Concert A = 440Hz
#include "pitches.h"

// CONSTANTS
// Define the number of steps in the sequence that the player must follow
const byte numSteps = 9;
// The correct melody required to solve the puzzle. 
// Defined using MIDI note numbers - see http://www.inspiredacoustics.com/en/MIDI_note_numbers_and_center_frequencies
const byte melody[numSteps] = {50, 55, 58, 57, 55, 62, 61, 58, 55 };
// The MIDI note of the key which will reset the puzzle when pressed. 70 = Bb4
const byte resetPitch = 70;
// This pin will be driven HIGH to release a lock when puzzle is solved
const byte lockPin = A1;
// This pin will have a piezo buzzer connected to it to produce crude audio output
const byte audioOutPin = 9;
// The maximum number of notes that we'll keep track of being pressed at once
const unsigned int maxHeldNotes = 16;

// GLOBALS
// This macro creates an instance of the MIDI interface using the hardware serial ports (0 and 1)
MIDI_CREATE_INSTANCE(HardwareSerial, Serial,  MIDI);
// Create a list structure to keep track of the notes currently being held
MidiNoteList<maxHeldNotes> midiNotes;
// What step of the melody is the player currently on?
int currentStep = 0;
// Create an array to hold the RGB values of each LED in the strip
CRGB leds[numSteps];
// Track the overall state of the puzzle
enum PuzzleState {Initialising, Running, Solved};
PuzzleState puzzleState = Initialising;

/**
 * Called when the program first starts, or each time it is reset
 */
void setup() {
  // The handleNoteOn callback function will be triggered on receipt of a MIDI NoteOn msg
  MIDI.setHandleNoteOn(handleNoteOn);
  
  // The handleNoteOff callback function will be triggered on receipt of a MIDI NoteOff msg
  MIDI.setHandleNoteOff(handleNoteOff);

  // Initiate MIDI communications - my keyboard input uses MIDI channel 1
  MIDI.begin(1);

  // Initialise the LED strip on pin A0. WS2812B strip uses GRB byte-ordering.
  FastLED.addLeds<WS2812B, A0, GRB>(leds, numSteps);
  FastLED.clear();

  // Initialise the relay pin. Setting to low will make the NO and C connected, securing the lock
  pinMode(lockPin, OUTPUT);
  digitalWrite(lockPin, LOW);

  // Set the puzzle state to running
  puzzleState = Running;  
}

/**
 * Callback function to handle a new note being pressed
 */
void handleNoteOn(byte channel, byte pitch, byte velocity) {
  // Add the note value to our list of notes being played
  midiNotes.add(MidiNote(pitch, velocity));
  // Play the note on the buzzer
  tone(audioOutPin, sNotePitches[pitch]);
  // If the puzzle is in progress..
  if(puzzleState == Running) {
    // Has the correct note been pressed?
    if(pitch == melody[currentStep]) {
      // Move on to the next note in the melody
      currentStep++;
      // Have we reached the last note in the melody?
      if(currentStep == numSteps) {
        // Puzzle has been solved!
        onSolve();
      }
    }
    // Has an incorrect note been pressed?
    else {
      // Flash the LEDs red
      for(int i=currentStep; i<numSteps; i++){
        leds[i] = CRGB::Red;
        FastLED.show();
        FastLED.delay(20);
      }
      // Clear the display
      FastLED.clear();
      // Start from the beginning of the sequence again
      currentStep = 0;
    }
  }
  // If the puzzle is solved, has the reset key being pressed?
  else if(puzzleState == Solved && pitch == resetPitch) {
    onReset();
  }
}

/**
 * Callback function to handle a note being released
 */
void handleNoteOff(byte channel, byte pitch, byte velocity) {
  // Remove this note from the list of notes being held
  midiNotes.remove(pitch);
  // If no other notes are being held
  if (midiNotes.empty()) {
    // Turn off the audio
    noTone(audioOutPin);
  }
  // If there are other notes still being held down
  else {
    // Get the last note to be added (i.e. the most recently played one)
    byte currentNote = 0;
    if (midiNotes.getLast(currentNote)) {
      // And play that note instead
      tone(audioOutPin, sNotePitches[currentNote]);
    }
  }
}

/**
 * Updates the LED strip based on the current game state
 */
void updateDisplay() {
  switch(puzzleState){
    // If the game is in progress
    case Running:
      // Turn on the number of LEDs corresponding to the current step
      for(int i=0; i<numSteps; i++){
        leds[i] = (i < currentStep ? CRGB::Green : CRGB::Black);
      }
      break;
    // If the game has been completed
    case Solved:
      // Show a chase sequence of blue LEDs
      fadeToBlackBy(leds, numSteps, 20);
      int pos = beatsin16(12, 0, numSteps-1);
      leds[pos] = CRGB::Blue;
      FastLED.delay(30);
      break;
  }
  // Update the display
  FastLED.show();
}


/**
 * This function is called when the puzzle is reset 
 */
void onReset(){
  // Stop the audio
  noTone(audioOutPin);
  // Light the LEDs up yellow
    for(int i=0; i<numSteps; i++){
      leds[i] = CRGB::Yellow;
      FastLED.show();
      FastLED.delay(20);
      leds[i] = CRGB::Black;
    }
    // Then clear the LED display
    FastLED.clear();
    // Secure the lock again
    digitalWrite(lockPin, LOW);
    // And update the puzzle state
    puzzleState = Running;
}

/**
 * This function gets called when the puzzle is solved 
 */
void onSolve(){
  // Release the lock
  digitalWrite(lockPin, HIGH);
  // Set the puzzle state
  puzzleState = Solved;
}

/**
 * Main program loop
 */
void loop() {
  // The read() function checks for incoming MIDI messages and automatically calls the assigned NoteOn or NoteOff callback
  // if a matching input has been received - no further action required!
  MIDI.read();

  // Updates the LED strip based on the current state of the puzzle
  updateDisplay();
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.