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 */ |