comparison Source/TouchKeys/PianoKeyboard.h @ 0:3580ffe87dc8

First commit of TouchKeys public pre-release.
author Andrew McPherson <andrewm@eecs.qmul.ac.uk>
date Mon, 11 Nov 2013 18:19:35 +0000
parents
children dfff66c07936
comparison
equal deleted inserted replaced
-1:000000000000 0:3580ffe87dc8
1 /*
2 TouchKeys: multi-touch musical keyboard control software
3 Copyright (c) 2013 Andrew McPherson
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 =====================================================================
19
20 PianoKeyboard.h: main class that keeps track of each key (and pedal)
21 on the keyboard, while also providing hooks for mapping and scheduling
22 of events. One shared instance of this class is used widely throughout
23 the program.
24 */
25
26 #ifndef KEYCONTROL_PIANOKEYBOARD_H
27 #define KEYCONTROL_PIANOKEYBOARD_H
28
29 #include <iostream>
30 #include <fstream>
31 #include <map>
32 #include "../JuceLibraryCode/JuceHeader.h"
33 #include "../Utility/Types.h"
34 #include "../Utility/Node.h"
35 #include "PianoKey.h"
36 #include "PianoPedal.h"
37 #include "../Display/KeyboardDisplay.h"
38 #include "../Display/KeyPositionGraphDisplay.h"
39 #include "Osc.h"
40 #include "../Utility/Scheduler.h"
41
42
43 #define NUM_KEYS 88
44 #define NUM_PEDALS 3
45
46 enum { // Index of each pedal in the buffers
47 kPedalDamper = 0,
48 kPedalSostenuto = 1,
49 kPedalUnaCorda = 2,
50 kNumPedals
51 };
52
53 const int kDefaultKeyHistoryLength = 8192;
54 const int kDefaultPedalHistoryLength = 1024;
55
56 class TouchkeyDevice;
57 class Mapping;
58 class MidiOutputController;
59 class MappingFactory;
60 class MidiKeyboardSegment;
61 class MappingScheduler;
62
63 /*
64 * PianoKeyboard
65 *
66 * Base class that implements all the functionality needed to measure and process
67 * real-time piano key motion. This class is abstract in that it doesn't define a particular
68 * source for the key motion data. The data source depends on the hardware used: PianoBar,
69 * PnoScan II, CEUS, etc.
70 *
71 * PianoKeyboard is a source of OSC messages (generated by various key actions). Hence,
72 * objects can register with it to implement custom behavior for different actions.
73 */
74
75 class PianoKeyboard : public OscMessageSource {
76 public:
77 ofstream testLog_;
78
79 // ***** Constructors *****
80
81 PianoKeyboard();
82
83 // ***** Destructor *****
84
85 ~PianoKeyboard();
86
87 // ***** Control Methods *****
88 //
89 // These methods start and stop the device and all associated processing. The implementation
90 // is specific to the hardware used. Methods return true on success.
91
92 //virtual bool start() = 0;
93 //virtual bool stop() = 0;
94
95 bool isInitialized() { return isInitialized_; }
96 bool isRunning() { return isRunning_; }
97
98 void reset();
99
100 std::pair<int, int> keyboardGUIRange() { return std::pair<int, int>(lowestMidiNote_, highestMidiNote_); }
101 void setKeyboardGUIRange(int lowest, int highest);
102
103 int numberOfPedals() { return numberOfPedals_; }
104 void setNumberOfPedals(int number);
105
106 // ***** Communication Links and Methods *****
107
108 // Set/query the output controller
109 MidiOutputController* midiOutputController() { return midiOutputController_; }
110 void setMidiOutputController(MidiOutputController* ct) { midiOutputController_ = ct; }
111
112 // Set reference to GUI displays
113 KeyboardDisplay* gui() { return gui_; }
114 void setGUI(KeyboardDisplay* gui);
115 KeyPositionGraphDisplay *graphGUI() { return graphGui_; }
116 void setGraphGUI(KeyPositionGraphDisplay* newGui) { graphGui_ = newGui; }
117
118 // OSC transmitter handles the mechanics of sending messages to one or more targets
119 void setOscTransmitter(OscTransmitter* trans) { oscTransmitter_ = trans; }
120
121 // TouchkeyDevice handles communication with the touch-sensor/piano-scanner hardware
122 void setTouchkeyDevice(TouchkeyDevice* device) { touchkeyDevice_ = device; }
123
124 // Send a named message by OSC (and potentially by MIDI or other means if suitable listeners
125 // are enabled)
126 void sendMessage(const char * path, const char * type, ...);
127
128 // ***** Scheduling Methods *****
129
130 // Add or remove events from the scheduler queue
131 void scheduleEvent(void *who, Scheduler::action func, timestamp_type timestamp) {
132 futureEventScheduler_.schedule(who, func, timestamp);
133 }
134 void unscheduleEvent(void *who) {
135 futureEventScheduler_.unschedule(who);
136 }
137 void unscheduleEvent(void *who, timestamp_type timestamp) {
138 futureEventScheduler_.unschedule(who, timestamp);
139 }
140
141 // Return the current timestamp associated with the scheduler
142 timestamp_type schedulerCurrentTimestamp() { return futureEventScheduler_.currentTimestamp(); }
143
144 // ***** Individual Key/Pedal Methods *****
145
146 // Access to individual keys and pedals
147 PianoKey* key(int note) {
148 //if(note < lowestMidiNote_ || note > highestMidiNote_)
149 // return 0;
150 //return keys_[note - lowestMidiNote_];
151 if(note < 0 || note > 127)
152 return 0;
153 return keys_[note];
154 }
155 PianoPedal* pedal(int pedal) {
156 if(pedal < 0 || pedal >= numberOfPedals_)
157 return 0;
158 return pedals_[pedal];
159 }
160
161 // Keys and pedals are enabled by default. If one has been disabled, reenable it so it reads data
162 // and triggers notes, as normal.
163 void enableKey(int key);
164 void enablePedal(int pedal);
165
166 // Disable a key or pedal from causing any activity to occur.
167 void disableKey(int key);
168 void disablePedal(int pedal);
169
170 // Leave a key enabled, but terminate any activity it has initiated and return it to the idle state.
171 // If the key is active because of a hardware problem, this may be a short-term solution at best, requiring
172 // the key to be disabled until the problem can be properly resolved.
173 void forceKeyIdle(int key);
174
175 // Set the color of an RGB LED for the given key, if relevant hardware is present
176 void setKeyLEDColorRGB(const int note, const float red, const float green, const float blue);
177 void setKeyLEDColorHSV(const int note, const float hue, const float saturation, const float value);
178 void setAllKeyLEDsOff();
179
180 // ***** Mapping Methods *****
181 // Mappings are identified by the MIDI note they affect and by
182 // their owner object.
183 void addMapping(int noteNumber, Mapping* mapping); // Add a new mapping to the container
184 void removeMapping(int noteNumber); // Remove a mapping from the container
185 Mapping* mapping(int noteNumber); // Look up a mapping with the given note and owner
186 std::vector<int> activeMappings(); // Return a list of all active note mappings
187 void clearMappings(); // Remove all mappings
188
189 // Managing the mapping factories
190 MappingFactory *mappingFactory(MidiKeyboardSegment* segment) {
191 ScopedReadLock sl(mappingFactoriesMutex_);
192 if(mappingFactories_.count(segment) == 0)
193 return 0;
194 return mappingFactories_[segment];
195 }
196 void setMappingFactory(MidiKeyboardSegment* segment, MappingFactory *factory) {
197 ScopedWriteLock sl(mappingFactoriesMutex_);
198 mappingFactories_[segment] = factory;
199 }
200 void removeMappingFactory(MidiKeyboardSegment* segment) {
201 ScopedWriteLock sl(mappingFactoriesMutex_);
202 if(mappingFactories_.count(segment) > 0)
203 mappingFactories_.erase(segment);
204 }
205
206 // Passing data to all mapping factories; these methods are not specific to a particular
207 // MIDI input segment so we need to check with each factory whether it wants this data.
208 void tellAllMappingFactoriesTouchBegan(int noteNumber, bool midiNoteIsOn, bool keyMotionActive,
209 Node<KeyTouchFrame>* touchBuffer,
210 Node<key_position>* positionBuffer,
211 KeyPositionTracker* positionTracker);
212 void tellAllMappingFactoriesTouchEnded(int noteNumber, bool midiNoteIsOn, bool keyMotionActive,
213 Node<KeyTouchFrame>* touchBuffer,
214 Node<key_position>* positionBuffer,
215 KeyPositionTracker* positionTracker);
216 void tellAllMappingFactoriesKeyMotionActive(int noteNumber, bool midiNoteIsOn, bool touchIsOn,
217 Node<KeyTouchFrame>* touchBuffer,
218 Node<key_position>* positionBuffer,
219 KeyPositionTracker* positionTracker);
220 void tellAllMappingFactoriesKeyMotionIdle(int noteNumber, bool midiNoteIsOn, bool touchIsOn,
221 Node<KeyTouchFrame>* touchBuffer,
222 Node<key_position>* positionBuffer,
223 KeyPositionTracker* positionTracker);
224
225 MappingScheduler& mappingScheduler() { return *mappingScheduler_; }
226
227 // ***** Member Variables *****
228 public:
229 // This mutex is grabbed by any thread which is supplying performance
230 // data (MIDI or touch). By synchronizing access once centrally, we
231 // can avoid many other lock scenarios in individual objects. The object
232 // is declared public so it can be used in ScopedLocks.
233 CriticalSection performanceDataMutex_;
234
235 private:
236 // Individual key and pedal data structures
237 std::vector<PianoKey*> keys_;
238 std::vector<PianoPedal*> pedals_;
239
240 // Reference to GUI display (if present)
241 KeyboardDisplay* gui_;
242 KeyPositionGraphDisplay *graphGui_;
243
244 // Reference to the MIDI output controller
245 MidiOutputController* midiOutputController_;
246
247 // Reference to message transmitter class
248 OscTransmitter* oscTransmitter_;
249
250 // Reference to TouchKey hardware controller class
251 TouchkeyDevice* touchkeyDevice_;
252
253 // Keyboard range, expressed in MIDI note numbers
254 int lowestMidiNote_, highestMidiNote_;
255 int numberOfPedals_;
256
257 bool isInitialized_;
258 bool isRunning_;
259 bool isCalibrated_;
260 bool calibrationInProgress_;
261
262 // Mapping objects associated with particular messages
263 // When a sendMessage() command is received, it checks the message
264 // against this set of possible listeners to see if it matches the
265 // path. If so, the handler function is called.
266 std::multimap<std::string, OscHandler*> messageListeners_;
267
268 // This object can be used to schedule events to be executed at future timestamps,
269 // for example to handle timeouts. This will often be called from within a particular
270 // key, but we should maintain one central repository for these events.
271 Scheduler futureEventScheduler_;
272
273 // Data related to mappings for active notes
274 std::map<int, Mapping*> mappings_; // Mappings from key motion to sound
275
276 // Collection of mapping factories organised by segment of the keyboard. Different
277 // segments may have different mappings
278 std::map<MidiKeyboardSegment*, MappingFactory*> mappingFactories_;
279 ReadWriteLock mappingFactoriesMutex_;
280
281 // Scheduler specifically used for coordinating mappings
282 MappingScheduler *mappingScheduler_;
283
284 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PianoKeyboard)
285 };
286
287 #endif /* KEYCONTROL_PIANOKEYBOARD_H */