annotate Source/TouchKeys/PianoKeyboard.h @ 20:dfff66c07936

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