Newbie here. Building a Midi control surface which allows me to scroll through tracks with a knob, and then work on tracks like mute, solo, volume and pan, ONE track at a time. (instead of having 8 channels of hardware control I will have only 1)
Code is working great for mute, solo, and record arm by having the code keep track of the current track's position in the virtual 8-fader bank. The DAW sends midi output which signifies where current track is in this 1-8 position. And then for instance, if the current track is imagining itself as 'track 3 of 8' then the code knows to apply 'MUTE_3' on Mute button press.
Where I hit a snag is when trying to apply this approach to the Pan knob encoder. It seems the encoder's midi command is sort of hard coded as a global, and I'm trying to figure out - Is it possible and good practice to dynamically change the encoderPan's midi command during runtime like I'm doing with the buttons?
The Code:
#include <Encoder.h>
#include <Control_Surface.h> // Include the Control Surface library
#include <Pushbutton.h>
USBMIDI_Interface midi; // Instantiate Control Surface connection in the DAW.
// Mackie visualizes 8 tracks at a time. the current track's bank slot (1-8). set the track buttons such as mute and solo to work with the selected track
static int positionInBank = 1;
// PARSE MIDI data from DAW, and keep positionInBank updated
struct MyMIDI_Callbacks : FineGrainedMIDI_Callbacks<MyMIDI_Callbacks> {
// Function that is called whenever a MIDI Note Off message is received.
void onNoteOff(Channel channel, uint8_t note, uint8_t velocity, Cable cable) {
Serial << "Note Off: " << channel << ", note " << note << ", velocity "
<< velocity << ", " << cable << endl;
}
// Function that is called whenever a MIDI Note On message is received.
void onNoteOn(Channel channel, uint8_t note, uint8_t velocity, Cable cable) {
Serial << "Note On: " << channel << ", note " << note << ", velocity "
<< velocity << ", " << cable << endl;
//keep positionInBank updated. These are the note numbers that the DAW outputs indicating which 1-8 bank slot the current track belongs
if (note == 24 && velocity == 127) { positionInBank = 1; }
if (note == 25 && velocity == 127) { positionInBank = 2; }
if (note == 26 && velocity == 127) { positionInBank = 3; }
if (note == 27 && velocity == 127) { positionInBank = 4; }
if (note == 28 && velocity == 127) { positionInBank = 5; }
if (note == 29 && velocity == 127) { positionInBank = 6; }
if (note == 30 && velocity == 127) { positionInBank = 7; }
if (note == 31 && velocity == 127) { positionInBank = 8; }
}
} callback; // Instantiate a callback
// Send MIDI commands to DAW
class CustomNoteSender {
public:
CustomNoteSender(uint8_t onVelocity, uint8_t offVelocity)
: onVelocity(onVelocity), offVelocity(offVelocity) {}
void sendOn(MIDIAddress address) {
Control_Surface.sendNoteOn(address, onVelocity);
}
void sendOff(MIDIAddress address) {
Control_Surface.sendNoteOff(address, offVelocity);
}
private:
uint8_t onVelocity, offVelocity;
};
struct CustomNoteButton : MIDIButton<CustomNoteSender> {
// Constructor
CustomNoteButton(pin_t pin, MIDIAddress address, uint8_t onVelocity,
uint8_t offVelocity)
: MIDIButton(pin, address, { onVelocity, offVelocity }) {}
// ^~~~~~~~~~ Initialization of the base class MIDIButton
};
Encoder encoderTracks(4, 5); // scrool through tracks
Pushbutton buttonTrackMute(8); // track mute button
Pushbutton buttonTrackSolo(9); // track solo button
Pushbutton buttonTrackRecordArm(6); // track record arm button
// Pan knob - needs to be dynamic though
CCRotaryEncoder encoderPan{
{ 11, 12 }, // pins
MIDI_CC::General_Purpose_Controller_1, // need to make the '1' a dynamic number between 1-8 like the mute and solo buttons
1, // optional multiplier if the control isn't fast enough
};
void setup() {
Serial.begin(9600);
midi.begin();
midi.setCallbacks(callback); // Attach the custom callback
Control_Surface.begin(); // Initialize Control Surface
}
long oldPositionTracks = -999;
void loop() {
if (buttonTrackMute.getSingleDebouncedPress()) {
if (positionInBank == 1) { midi.sendNoteOn(0x10, 0x7f); }
if (positionInBank == 2) { midi.sendNoteOn(0x11, 0x7f); }
if (positionInBank == 3) { midi.sendNoteOn(0x12, 0x7f); }
if (positionInBank == 4) { midi.sendNoteOn(0x13, 0x7f); }
if (positionInBank == 5) { midi.sendNoteOn(0x14, 0x7f); }
if (positionInBank == 6) { midi.sendNoteOn(0x15, 0x7f); }
if (positionInBank == 7) { midi.sendNoteOn(0x16, 0x7f); }
if (positionInBank == 8) { midi.sendNoteOn(0x17, 0x7f); }
}
if (buttonTrackSolo.getSingleDebouncedPress()) {
if (positionInBank == 1) { midi.sendNoteOn(0x08, 0x7f); }
if (positionInBank == 2) { midi.sendNoteOn(0x09, 0x7f); }
if (positionInBank == 3) { midi.sendNoteOn(0x0A, 0x7f); }
if (positionInBank == 4) { midi.sendNoteOn(0x0B, 0x7f); }
if (positionInBank == 5) { midi.sendNoteOn(0x0C, 0x7f); }
if (positionInBank == 6) { midi.sendNoteOn(0x0D, 0x7f); }
if (positionInBank == 7) { midi.sendNoteOn(0x0E, 0x7f); }
if (positionInBank == 8) { midi.sendNoteOn(0x0F, 0x7f); }
}
if (buttonTrackRecordArm.getSingleDebouncedPress()) {
if (positionInBank == 1) { midi.sendNoteOn(0x00, 0x7f); }
if (positionInBank == 2) { midi.sendNoteOn(0x01, 0x7f); }
if (positionInBank == 3) { midi.sendNoteOn(0x02, 0x7f); }
if (positionInBank == 4) { midi.sendNoteOn(0x03, 0x7f); }
if (positionInBank == 5) { midi.sendNoteOn(0x04, 0x7f); }
if (positionInBank == 6) { midi.sendNoteOn(0x05, 0x7f); }
if (positionInBank == 7) { midi.sendNoteOn(0x06, 0x7f); }
if (positionInBank == 8) { midi.sendNoteOn(0x07, 0x7f); }
}
long newPositionTracks = encoderTracks.read();
if (newPositionTracks != oldPositionTracks && newPositionTracks % 2 == 0) {
if (newPositionTracks < oldPositionTracks) {
midi.sendNoteOn(0x60, 0x7f); // UP - goto previous track
} else {
midi.sendNoteOn(0x61, 0x7f); // DOWN - goto next track
}
oldPositionTracks = newPositionTracks;
}
Control_Surface.loop();
midi.update();
MIDI_Interface::updateAll();
}