Mercurial > hg > touchkeys
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 */ |