Hello!
First post here...thanks for a wonderful platform! Really, too much fun.
I am also trying to bring a sequencer into a simple synth sketch written with Audio Tools.
But first, I'm looking at the Fifteenstep library, basic example. I should probably get this working before bringing Fifteenstep into my synth.
I have the MIDI Library and hardware set up example working from here:
https://www.pjrc.com/teensy/td_libs_MIDI.html
(what satisfaction to see those midi notes firing off)
So i know my serial Midi output is working and wired correctly , on Serial1.
Here's the basic example as-is:
Code:
// ---------------------------------------------------------------------------
//
// basic.ino
//
// A MIDI sequencer example using a standard MIDI cable and a push button
// attached to pin 4.
//
// Author: Todd Treece <todd@uniontownlabs.org>
// Copyright: (c) 2015 Adafruit Industries
// License: GNU GPLv3
//
// ---------------------------------------------------------------------------
#include "FifteenStep.h"
// sequencer init
FifteenStep seq = FifteenStep();
// save button state
int button_last = 0;
void setup() {
// set MIDI baud
Serial.begin(31250);
// initialize digital pin 13 as an output
pinMode(13, OUTPUT);
// initialize digital pin 4 as an input for a button
pinMode(4, INPUT);
// start sequencer and set callbacks
seq.begin();
seq.setMidiHandler(midi);
seq.setStepHandler(step);
}
void loop() {
// read the state of the button
int button = digitalRead(4);
// check for button press or release and
// send note on or off to seqencer if needed
if(button == HIGH && button_last == LOW) {
// button pressed. play middle C preview now
midi(0x0, 0x9, 0x3C, 0x40);
// store note in sequence
seq.setNote(0x0, 0x3C, 0x40);
} else if(button == LOW && button_last == HIGH) {
// button released. send middle C note off preview now
midi(0x0, 0x8, 0x3C, 0x0);
// store note off in sequence
seq.setNote(0x0, 0x3C, 0x0);
}
// save button state
button_last = button;
// this is needed to keep the sequencer
// running. there are other methods for
// start, stop, and pausing the steps
seq.run();
}
///////////////////////////////////////////////////////////////////////////////
// //
// SEQUENCER CALLBACKS //
// //
///////////////////////////////////////////////////////////////////////////////
// called when the step position changes. both the current
// position and last are passed to the callback
void step(int current, int last) {
// blink on even steps
if(current % 2 == 0)
digitalWrite(13, HIGH);
else
digitalWrite(13, LOW);
}
// the callback that will be called by the sequencer when it needs
// to send midi commands. this specific callback is designed to be
// used with a standard midi cable.
//
// the following image will show you how your MIDI cable should
// be wired to the Arduino:
// http://arduino.cc/en/uploads/Tutorial/MIDI_bb.png
void midi(byte channel, byte command, byte arg1, byte arg2) {
if(command < 128) {
// shift over command
command <<= 4;
// add channel to the command
command |= channel;
}
// send MIDI data
Serial.write(command);
Serial.write(arg1);
Serial.write(arg2);
}
Here's what I've done to bring the MIDI hardware example in, adding those bits in. I also reversed the button states, as we're not using Bounce:
Code:
// ---------------------------------------------------------------------------
//
// basic.ino
//
// A MIDI sequencer example using a standard MIDI cable and a push button
// attached to pin 4- *changed to 5
//
// Author: Todd Treece <todd@uniontownlabs.org>
// Copyright: (c) 2015 Adafruit Industries
// License: GNU GPLv3
//
// ---------------------------------------------------------------------------
#include "FifteenStep.h"
#include <MIDI.h>
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
//const int channel = 1;
// sequencer init
FifteenStep seq = FifteenStep();
// save button state
int button_last = 0;
void setup() {
// set MIDI baud
//Serial1.begin(31250);
MIDI1.begin();
// initialize digital pin 2 as an LED output
pinMode(2, OUTPUT);
// initialize digital pin 5 as an input for a button
pinMode(5, INPUT);
// start sequencer and set callbacks
seq.begin();
seq.setMidiHandler(midi);
seq.setStepHandler(step);
}
void loop() {
// read the state of the button
int button = digitalRead(5);
// check for button press or release and
// send note on or off to seqencer if needed
if(button == LOW && button_last == HIGH) {
// button pressed. play middle C preview now
midipipe(0x0, 0x9, 0x3C, 0x40);
//(channel, noteon, pitch, velocity)??
// store note in sequence
seq.setNote(0x0, 0x3C, 0x40);
} else if(button == HIGH && button_last == LOW) {
// button released. send middle C note off preview now
midipipe(0x0, 0x8, 0x3C, 0x0);
// store note off in sequence
seq.setNote(0x0, 0x3C, 0x0);
}
// save button state
button_last = button;
// this is needed to keep the sequencer
// running. there are other methods for
// start, stop, and pausing the steps
seq.run();
}
///////////////////////////////////////////////////////////////////////////////
// //
// SEQUENCER CALLBACKS //
// //
///////////////////////////////////////////////////////////////////////////////
// called when the step position changes. both the current
// position and last are passed to the callback
void step(int current, int last) {
// blink on even steps
if(current % 2 == 0)
digitalWrite(2, HIGH);
else
digitalWrite(2, LOW);
}
// the callback that will be called by the sequencer when it needs
// to send midi commands. this specific callback is designed to be
// used with a standard midi cable.
//
// the following image will show you how your MIDI cable should
// be wired to the Arduino:
// http://arduino.cc/en/uploads/Tutorial/MIDI_bb.png
// MIDIcallback *comments from Fifteenstep.h*
//
// This defines the MIDI callback function format that is required by the
// sequencer.
//
// Most of the time these arguments will represent the following:
//
// channel: midi channel
// command: note on or off (0x9 or 0x8)
// arg1: pitch value
// arg1: velocity value
//
// It's possible that there will be other types of MIDI messages sent
// to this callback in the future, so please check the command sent if
// you are doing something other than passing on the MIDI messages to
// a MIDI library.
//
void midi(byte channel, byte command, byte arg1, byte arg2) {
if(command < 128) {
// shift over command
command <<= 4;
// add channel to the command
command |= channel;
}
// send MIDI data
Serial1.write(command);
Serial1.write(arg1);
Serial1.write(arg2);
}
The first issue is it won't compile, seems to be a conflict between the midi callback used in the sketch and MIDI.h ?
Code:
Arduino: 1.8.13 (Mac OS X), TD: 1.53, Board: "Teensy 4.1, Serial + MIDI, 600 MHz, Faster, US English"
15BASIC_AGAIN:126: error: 'void midi(byte, byte, byte, byte)' redeclared as different kind of symbol
void midi(byte channel, byte command, byte arg1, byte arg2) {
^
In file included from /Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/MIDI/src/midi_Defs.h:30:0,
from /Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/MIDI/src/MIDI.h:30,
from /Users/IIIIIo/Documents/TEENSY/15BASIC_AGAIN/15BASIC_AGAIN.ino:14:
/Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/MIDI/src/midi_Namespace.h:31:66: note: previous declaration 'namespace midi { }'
#define BEGIN_MIDI_NAMESPACE namespace MIDI_NAMESPACE {
^
/Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/MIDI/src/midi_Namespace.h:36:1: note: in expansion of macro 'BEGIN_MIDI_NAMESPACE'
BEGIN_MIDI_NAMESPACE
^
15BASIC_AGAIN: In function 'void setup()':
15BASIC_AGAIN:41: error: expected primary-expression before ')' token
seq.setMidiHandler(midi);
^
15BASIC_AGAIN: In function 'void loop()':
15BASIC_AGAIN:56: error: expected primary-expression before '(' token
midi(0x0, 0x9, 0x3C, 0x40);
^
15BASIC_AGAIN:65: error: expected primary-expression before '(' token
midi(0x0, 0x8, 0x3C, 0x0);
^
15BASIC_AGAIN: In function 'void midi(byte, byte, byte, byte)':
15BASIC_AGAIN:126: error: 'void midi(byte, byte, byte, byte)' redeclared as different kind of symbol
void midi(byte channel, byte command, byte arg1, byte arg2) {
^
In file included from /Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/MIDI/src/midi_Defs.h:30:0,
from /Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/MIDI/src/MIDI.h:30,
from /Users/IIIIIo/Documents/TEENSY/15BASIC_AGAIN/15BASIC_AGAIN.ino:14:
/Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/MIDI/src/midi_Namespace.h:31:66: note: previous declaration 'namespace midi { }'
#define BEGIN_MIDI_NAMESPACE namespace MIDI_NAMESPACE {
^
/Applications/Teensyduino.app/Contents/Java/hardware/teensy/avr/libraries/MIDI/src/midi_Namespace.h:36:1: note: in expansion of macro 'BEGIN_MIDI_NAMESPACE'
BEGIN_MIDI_NAMESPACE
^
'void midi(byte, byte, byte, byte)' redeclared as different kind of symbol
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
So, wild guess, let's rename 'midi' to something else. I used 'midipipe' :
Code:
// ---------------------------------------------------------------------------
//
// basic.ino
//
// A MIDI sequencer example using a standard MIDI cable and a push button
// attached to pin 4.
//
// Author: Todd Treece <todd@uniontownlabs.org>
// Copyright: (c) 2015 Adafruit Industries
// License: GNU GPLv3
//
// ---------------------------------------------------------------------------
#include "FifteenStep.h"
#include <MIDI.h>
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
//const int channel = 1;
// sequencer init
FifteenStep seq = FifteenStep();
// save button state
int button_last = 0;
void setup() {
// set MIDI baud
//Serial1.begin(31250);
MIDI1.begin();
// initialize digital pin 2 as an LED output
pinMode(2, OUTPUT);
// initialize digital pin 5 as an input for a button
pinMode(5, INPUT);
// start sequencer and set callbacks
seq.begin();
seq.setMidiHandler(midipipe); //changed midi to midipipe
seq.setStepHandler(step);
}
void loop() {
// read the state of the button
int button = digitalRead(5);
// check for button press or release and
// send note on or off to seqencer if needed
if(button == LOW && button_last == HIGH) {
// button pressed. play middle C preview now
midipipe(0x0, 0x9, 0x3C, 0x40);
//(channel, noteon, pitch, velocity)??
// store note in sequence
seq.setNote(0x0, 0x3C, 0x40);
} else if(button == HIGH && button_last == LOW) {
// button released. send middle C note off preview now
midipipe(0x0, 0x8, 0x3C, 0x0);
// store note off in sequence
seq.setNote(0x0, 0x3C, 0x0);
}
// save button state
button_last = button;
// this is needed to keep the sequencer
// running. there are other methods for
// start, stop, and pausing the steps
seq.run();
}
///////////////////////////////////////////////////////////////////////////////
// //
// SEQUENCER CALLBACKS //
// //
///////////////////////////////////////////////////////////////////////////////
// called when the step position changes. both the current
// position and last are passed to the callback
void step(int current, int last) {
// blink on even steps
if(current % 2 == 0)
digitalWrite(2, HIGH);
else
digitalWrite(2, LOW);
}
// the callback that will be called by the sequencer when it needs
// to send midi commands. this specific callback is designed to be
// used with a standard midi cable.
//
// the following image will show you how your MIDI cable should
// be wired to the Arduino:
// http://arduino.cc/en/uploads/Tutorial/MIDI_bb.png
// MIDIcallback *comments copied from Fifteenstep.h*
//
// This defines the MIDI callback function format that is required by the
// sequencer.
//
// Most of the time these arguments will represent the following:
//
// channel: midi channel
// command: note on or off (0x9 or 0x8)
// arg1: pitch value
// arg1: velocity value
//
// It's possible that there will be other types of MIDI messages sent
// to this callback in the future, so please check the command sent if
// you are doing something other than passing on the MIDI messages to
// a MIDI library.
//
void midipipe(byte channel, byte command, byte arg1, byte arg2) {
if(command < 128) {
// shift over command
command <<= 4;
// add channel to the command
command |= channel;
}
// send MIDI data
Serial1.write(command);
Serial1.write(arg1);
Serial1.write(arg2);
}
Successfully compiles, a bit of progress! But the sketch isn't working as expected.
The LED is blinking, seems like a sequence is running somewhere, neat.
My midi monitor on my laptop is showing I'm getting clock (at 125bpm), and an endless string of note off messages for a C-2, at velocity 0.
Pressing my button doesn't send anything over Serial1.
Two theories:
My new friend midipipe is collecting bytes (note on or off, note value, velocity, and channel) meant to forward to the MIDI library I'm using to transmit actual MIDI data to Serial1. Maybe there's something amiss in the order expected and how its being printed to Serial1?
By changing 'midi' to 'midipipe', I've broken something inside Fifteenstep that's looking for 'midi', so nothing is getting out of the sequencer besides clock.
Can anyone help sort this out? I'm not opposed to using usbMIDI to see this example working, as long as I understand *why* it works
All the Best!