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