annotate Source/TouchKeys/MidiInputController.h @ 16:61e3c9df4674

Fix bug where TouchKeys standalone mode turns off when mode is changed.
author Andrew McPherson <andrewm@eecs.qmul.ac.uk>
date Mon, 25 Nov 2013 21:36:02 +0000
parents 3580ffe87dc8
children 88287c1c2c92
rev   line source
andrewm@0 1 /*
andrewm@0 2 TouchKeys: multi-touch musical keyboard control software
andrewm@0 3 Copyright (c) 2013 Andrew McPherson
andrewm@0 4
andrewm@0 5 This program is free software: you can redistribute it and/or modify
andrewm@0 6 it under the terms of the GNU General Public License as published by
andrewm@0 7 the Free Software Foundation, either version 3 of the License, or
andrewm@0 8 (at your option) any later version.
andrewm@0 9
andrewm@0 10 This program is distributed in the hope that it will be useful,
andrewm@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
andrewm@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
andrewm@0 13 GNU General Public License for more details.
andrewm@0 14
andrewm@0 15 You should have received a copy of the GNU General Public License
andrewm@0 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
andrewm@0 17
andrewm@0 18 =====================================================================
andrewm@0 19
andrewm@0 20 MidiInputController.h: handles incoming MIDI data and manages input
andrewm@0 21 ports. Detailed processing is broken down by keyboard segment; see
andrewm@0 22 MidiKeyboardSegment.h/cpp for more.
andrewm@0 23 */
andrewm@0 24
andrewm@0 25
andrewm@0 26 #ifndef MIDI_INPUT_CONTROLLER_H
andrewm@0 27 #define MIDI_INPUT_CONTROLLER_H
andrewm@0 28
andrewm@0 29 #include <iostream>
andrewm@0 30 #include <vector>
andrewm@0 31 #include <map>
andrewm@0 32 #include <set>
andrewm@0 33 #include "../JuceLibraryCode/JuceHeader.h"
andrewm@0 34 #include "PianoKeyboard.h"
andrewm@0 35 #include "Osc.h"
andrewm@0 36 #include "MidiKeyboardSegment.h"
andrewm@0 37
andrewm@0 38 using namespace std;
andrewm@0 39
andrewm@0 40 class MidiOutputController;
andrewm@0 41
andrewm@0 42 // MIDI standard messages
andrewm@0 43
andrewm@0 44 enum {
andrewm@0 45 kMidiMessageNoteOff = 0x80,
andrewm@0 46 kMidiMessageNoteOn = 0x90,
andrewm@0 47 kMidiMessageAftertouchPoly = 0xA0,
andrewm@0 48 kMidiMessageControlChange = 0xB0,
andrewm@0 49 kMidiMessageProgramChange = 0xC0,
andrewm@0 50 kMidiMessageAftertouchChannel = 0xD0,
andrewm@0 51 kMidiMessagePitchWheel = 0xE0,
andrewm@0 52 kMidiMessageSysex = 0xF0,
andrewm@0 53 kMidiMessageSysexEnd = 0xF7,
andrewm@0 54 kMidiMessageActiveSense = 0xFE,
andrewm@0 55 kMidiMessageReset = 0xFF
andrewm@0 56 };
andrewm@0 57
andrewm@0 58 enum {
andrewm@0 59 kMidiControlAllSoundOff = 120,
andrewm@0 60 kMidiControlAllControllersOff = 121,
andrewm@0 61 kMidiControlLocalControl = 122,
andrewm@0 62 kMidiControlAllNotesOff = 123
andrewm@0 63 };
andrewm@0 64
andrewm@0 65 class MidiInputController : public MidiInputCallback {
andrewm@0 66 public:
andrewm@0 67 /*
andrewm@0 68 // Operating modes for MIDI input
andrewm@0 69 enum {
andrewm@0 70 ModeOff = 0,
andrewm@0 71 ModePassThrough,
andrewm@0 72 ModeMonophonic,
andrewm@0 73 ModePolyphonic,
andrewm@0 74 ModeChannelSelect,
andrewm@0 75 ModeConstantControllers
andrewm@0 76 };
andrewm@0 77
andrewm@0 78 // Switch types for Channel Select mode
andrewm@0 79 enum {
andrewm@0 80 ChannelSelectSwitchTypeUnknown = 0,
andrewm@0 81 ChannelSelectSwitchTypeLocation,
andrewm@0 82 ChannelSelectSwitchTypeSize,
andrewm@0 83 ChannelSelectSwitchTypeNumTouches,
andrewm@0 84 ChannelSelectSwitchTypeAngle
andrewm@0 85 };
andrewm@0 86 */
andrewm@0 87
andrewm@0 88 public:
andrewm@0 89 // Constructor
andrewm@0 90 MidiInputController(PianoKeyboard& keyboard);
andrewm@0 91
andrewm@0 92
andrewm@0 93 // Query available devices
andrewm@0 94 vector<pair<int, string> > availableMidiDevices();
andrewm@0 95
andrewm@0 96 // Add/Remove MIDI input ports;
andrewm@0 97 // Enable methods return true on success (at least one port enabled)
andrewm@0 98 bool enablePort(int portNumber);
andrewm@0 99 bool enableAllPorts();
andrewm@0 100 void disablePort(int portNumber);
andrewm@0 101 void disableAllPorts();
andrewm@0 102 vector<int> activePorts();
andrewm@0 103
andrewm@0 104 //void touchkeyStandaloneTouchBegan(int noteNumber, Node<KeyTouchFrame>* touchBuffer);
andrewm@0 105 //void touchkeyStandaloneTouchEnded(int noteNumber);
andrewm@0 106
andrewm@0 107 /*
andrewm@0 108 // Set which channels we listen to
andrewm@0 109 bool enableChannel(int channelNumber);
andrewm@0 110 bool enableAllChannels();
andrewm@0 111 void disableChannel(int channelNumber);
andrewm@0 112 void disableAllChanels();
andrewm@0 113 */
andrewm@0 114
andrewm@0 115 // Set/query the output controller
andrewm@0 116 MidiOutputController* midiOutputController() { return midiOutputController_; }
andrewm@0 117 void setMidiOutputController(MidiOutputController* ct);
andrewm@0 118
andrewm@0 119 // All Notes Off: can be sent by MIDI or controlled programmatically
andrewm@0 120 void allNotesOff();
andrewm@0 121
andrewm@0 122 // Return the number of keyboard segments, and a specific segment
andrewm@0 123 int numSegments() {
andrewm@0 124 ScopedLock sl(segmentsMutex_);
andrewm@0 125 return segments_.size();
andrewm@0 126 }
andrewm@0 127 MidiKeyboardSegment* segment(int num) {
andrewm@0 128 ScopedLock sl(segmentsMutex_);
andrewm@0 129 if(num < 0 || num >= segments_.size())
andrewm@0 130 return 0;
andrewm@0 131 return segments_[num];
andrewm@0 132 }
andrewm@0 133 // Return a unique signature which tells us when the MIDI segments have changed,
andrewm@0 134 // allowing any listeners to re-query all the segments.
andrewm@0 135 int segmentUniqueIdentifier() {
andrewm@0 136 return segmentUniqueIdentifier_;
andrewm@0 137 }
andrewm@0 138
andrewm@0 139 // Add a new keyboard segment. Returns a pointer to the newly created segment
andrewm@0 140 MidiKeyboardSegment* addSegment(int outputPortNumber, int noteMin = 0, int noteMax = 127, int channelMask = 0xFFFF);
andrewm@0 141
andrewm@0 142 // Remove a segment by index or by object
andrewm@0 143 void removeSegment(int index);
andrewm@0 144 void removeSegment(MidiKeyboardSegment* segment);
andrewm@0 145 void removeAllSegments();
andrewm@0 146
andrewm@0 147 /*
andrewm@0 148 // Change or query the operating mode of the controller
andrewm@0 149 int mode() { return mode_; }
andrewm@0 150 void setModeOff();
andrewm@0 151 void setModePassThrough();
andrewm@0 152 void setModeMonophonic();
andrewm@0 153 void setModePolyphonic();
andrewm@0 154 void setModeChannelSelect(int switchType, int numDivisions, int defaultChannel);
andrewm@0 155
andrewm@0 156 int polyphony() { return retransmitMaxPolyphony_; }
andrewm@0 157 void setPolyphony(int polyphony);
andrewm@0 158 bool voiceStealingEnabled() { return useVoiceStealing_; }
andrewm@0 159 void setVoiceStealingEnabled(bool enable) { useVoiceStealing_ = enable; }
andrewm@0 160 */
andrewm@0 161
andrewm@0 162 // Juce MIDI callbacks
andrewm@0 163 void handleIncomingMidiMessage(MidiInput* source, const MidiMessage& message);
andrewm@0 164 void handlePartialSysexMessage(MidiInput* source,
andrewm@0 165 const uint8* messageData,
andrewm@0 166 int numBytesSoFar,
andrewm@0 167 double timestamp) {}
andrewm@0 168
andrewm@0 169 // OSC method: used to get touch callback data from the keyboard
andrewm@0 170 // bool oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data);
andrewm@0 171
andrewm@0 172 // for logging
andrewm@0 173 void createLogFile(string midiLog_filename, string path);
andrewm@0 174 void closeLogFile();
andrewm@0 175 void startLogging();
andrewm@0 176 void stopLogging();
andrewm@0 177
andrewm@0 178 bool logFileCreated;
andrewm@0 179 bool loggingActive;
andrewm@0 180
andrewm@0 181 // Destructor
andrewm@0 182 ~MidiInputController();
andrewm@0 183
andrewm@0 184 private:
andrewm@0 185 // Filtering by channel: return whether this message concerns one of the active channels
andrewm@0 186 // we're listening to.
andrewm@0 187 // bool messageIsForActiveChannel(const MidiMessage& message);
andrewm@0 188
andrewm@0 189 /*
andrewm@0 190 // Mode-specific MIDI input handlers
andrewm@0 191 void modePassThroughHandler(MidiInput* source, const MidiMessage& message);
andrewm@0 192 void modeMonophonicHandler(MidiInput* source, const MidiMessage& message);
andrewm@0 193
andrewm@0 194 void modePolyphonicHandler(MidiInput* source, const MidiMessage& message);
andrewm@0 195 void modePolyphonicNoteOn(unsigned char note, unsigned char velocity);
andrewm@0 196 void modePolyphonicNoteOff(unsigned char note);
andrewm@0 197 void modePolyphonicNoteOnCallback(const char *path, const char *types, int numValues, lo_arg **values);
andrewm@0 198
andrewm@0 199 void modeChannelSelectHandler(MidiInput* source, const MidiMessage& message);
andrewm@0 200 void modeChannelSelectNoteOn(unsigned char note, unsigned char velocity);
andrewm@0 201 void modeChannelSelectNoteOff(unsigned char note);
andrewm@0 202 void modeChannelSelectNoteOnCallback(const char *path, const char *types, int numValues, lo_arg **values);
andrewm@0 203
andrewm@0 204 void modeConstantControllersHandler(MidiInput* source, const MidiMessage& message);
andrewm@0 205
andrewm@0 206 // Helper functions for polyphonic mode
andrewm@0 207 void modePolyphonicSetupHelper();
andrewm@0 208 int oldestNote();
andrewm@0 209 int newestNote();
andrewm@0 210 */
andrewm@0 211
andrewm@0 212 // ***** Member Variables *****
andrewm@0 213
andrewm@0 214 PianoKeyboard& keyboard_; // Reference to main keyboard data
andrewm@0 215 MidiOutputController *midiOutputController_; // Destination for MIDI output
andrewm@0 216
andrewm@0 217 map<int, MidiInput*> activePorts_; // Sources of MIDI data
andrewm@0 218
andrewm@0 219 vector<MidiKeyboardSegment*> segments_; // Segments of the keyboard
andrewm@0 220 CriticalSection segmentsMutex_; // Mutex protecting the segments list
andrewm@0 221 int segmentUniqueIdentifier_; // Identifier of when segment structure has changed
andrewm@0 222
andrewm@0 223
andrewm@0 224 /*
andrewm@0 225
andrewm@0 226
andrewm@0 227 // Current operating mode of the controller
andrewm@0 228 int mode_;
andrewm@0 229
andrewm@0 230 // Mapping between input notes and output channels. Depending on the mode of operation,
andrewm@0 231 // each note may be rebroadcast on its own MIDI channel. Need to keep track of what goes where.
andrewm@0 232 // key is MIDI note #, value is output channel (0-15)
andrewm@0 233 map<int, int> retransmitChannelForNote_;
andrewm@0 234 set<int> retransmitChannelsAvailable_;
andrewm@0 235 int retransmitMaxPolyphony_;
andrewm@0 236 bool useVoiceStealing_;
andrewm@0 237 map<int, timestamp_type> noteOnsetTimestamps_; // When each currently active note began, for stealing
andrewm@0 238
andrewm@0 239 // Parameters for Channel Select mode of operation
andrewm@0 240 int channelSelectSwitchType_;
andrewm@0 241 int channelSelectNumberOfDivisions_;
andrewm@0 242 int channelSelectDefaultChannel_;
andrewm@0 243 int channelSelectLastOnsetChannel_;
andrewm@0 244 */
andrewm@0 245
andrewm@0 246 // for logging
andrewm@0 247 ofstream midiLog;
andrewm@0 248
andrewm@0 249 // for generating timestamps
andrewm@0 250 // Scheduler eventScheduler_;
andrewm@0 251 };
andrewm@0 252
andrewm@0 253 #endif /* MIDI_INPUT_CONTROLLER_H */