andrewm@0: /* andrewm@0: TouchKeys: multi-touch musical keyboard control software andrewm@0: Copyright (c) 2013 Andrew McPherson andrewm@0: andrewm@0: This program is free software: you can redistribute it and/or modify andrewm@0: it under the terms of the GNU General Public License as published by andrewm@0: the Free Software Foundation, either version 3 of the License, or andrewm@0: (at your option) any later version. andrewm@0: andrewm@0: This program is distributed in the hope that it will be useful, andrewm@0: but WITHOUT ANY WARRANTY; without even the implied warranty of andrewm@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrewm@0: GNU General Public License for more details. andrewm@0: andrewm@0: You should have received a copy of the GNU General Public License andrewm@0: along with this program. If not, see . andrewm@0: andrewm@0: ===================================================================== andrewm@0: andrewm@0: KeyboardDisplay.h: displays the keyboard state, including active MIDI andrewm@0: notes and current touch position and size. andrewm@0: */ andrewm@0: andrewm@0: #ifndef KEYBOARD_DISPLAY_H andrewm@0: #define KEYBOARD_DISPLAY_H andrewm@0: andrewm@0: #include andrewm@0: #include andrewm@0: //#include andrewm@0: #include "../JuceLibraryCode/JuceHeader.h" andrewm@0: #include "../TouchKeys/KeyTouchFrame.h" andrewm@0: #include "OpenGLDisplayBase.h" andrewm@0: andrewm@0: andrewm@0: // This class uses OpenGL to implement the actual drawing of the piano keyboard graphics. andrewm@0: // Graphics include the current state of each key and the touches on the surface. andrewm@0: andrewm@0: class KeyboardDisplay : public OpenGLDisplayBase { andrewm@0: // Internal data structures and constants andrewm@17: protected: andrewm@0: // Display dimensions, normalized to the width of one white key andrewm@0: andrewm@0: static const float kWhiteKeyFrontWidth; andrewm@0: static const float kBlackKeyWidth; andrewm@0: static const float kWhiteKeyFrontLength; andrewm@0: static const float kWhiteKeyBackLength; andrewm@0: static const float kBlackKeyLength; andrewm@0: static const float kInterKeySpacing; andrewm@0: static const float kAnalogSliderVerticalSpacing; andrewm@0: static const float kAnalogSliderLength; andrewm@0: static const float kAnalogSliderWidth; andrewm@0: static const float kAnalogSliderMinimumValue; andrewm@0: static const float kAnalogSliderMaximumValue; andrewm@0: static const float kAnalogSliderZeroLocation; andrewm@0: static const float kAnalogSliderOneLocation; andrewm@0: andrewm@0: // Individual geometry for C, D, E, F, G, A, B, c' andrewm@0: andrewm@0: static const float kWhiteKeyBackOffsets[9]; andrewm@0: static const float kWhiteKeyBackWidths[9]; andrewm@0: andrewm@0: // Display margins andrewm@0: andrewm@0: static const float kDisplaySideMargin; andrewm@0: static const float kDisplayBottomMargin; andrewm@0: static const float kDisplayTopMargin; andrewm@0: andrewm@0: // Key shape constants andrewm@0: andrewm@0: static const int kShapeForNote[12]; andrewm@0: static const int kWhiteToChromatic[7]; andrewm@0: static const float kWhiteKeyFrontBackCutoff; andrewm@0: andrewm@0: // Touch constants andrewm@0: static const float kDisplayMinTouchSize; andrewm@0: static const float kDisplayTouchSizeScaler; andrewm@0: andrewm@0: andrewm@0: typedef struct { andrewm@0: bool active; andrewm@0: float locH; andrewm@0: float locV1; andrewm@0: float locV2; andrewm@0: float locV3; andrewm@0: float size1; andrewm@0: float size2; andrewm@0: float size3; andrewm@0: } TouchInfo; andrewm@0: andrewm@0: typedef struct { andrewm@0: float x; andrewm@0: float y; andrewm@0: } Point; andrewm@44: andrewm@44: typedef struct { andrewm@44: int noteLow; andrewm@44: int noteHigh; andrewm@44: int divisions; andrewm@44: } KeyDivision; andrewm@0: andrewm@0: public: andrewm@0: KeyboardDisplay(); andrewm@17: virtual ~KeyboardDisplay() {} andrewm@27: andrewm@27: // Set canvas for triggering rendering; andrewm@27: void setCanvas(OpenGLJuceCanvas *canvas) { canvas_ = canvas; } andrewm@27: void tellCanvasToRepaint(); andrewm@0: andrewm@0: // Setup methods for display size and keyboard range andrewm@0: void setKeyboardRange(int lowest, int highest); andrewm@0: float keyboardAspectRatio() { return totalDisplayWidth_ / totalDisplayHeight_; } andrewm@17: virtual void setDisplaySize(float width, float height); andrewm@0: andrewm@0: // Drawing methods andrewm@17: virtual void render(); andrewm@0: andrewm@0: // Interaction methods andrewm@17: virtual void mouseDown(float x, float y); andrewm@17: virtual void mouseDragged(float x, float y); andrewm@17: virtual void mouseUp(float x, float y); andrewm@17: virtual void rightMouseDown(float x, float y); andrewm@17: virtual void rightMouseDragged(float x, float y); andrewm@17: virtual void rightMouseUp(float x, float y); andrewm@0: andrewm@0: // Take action associated with clicking a key. These are called within the mouse andrewm@0: // methods but may also be called externally. andrewm@17: virtual void keyClicked(int key); andrewm@17: virtual void keyRightClicked(int key); andrewm@0: andrewm@0: // State-change methods andrewm@0: void setTouchForKey(int key, const KeyTouchFrame& touch); andrewm@0: void clearTouchForKey(int key); andrewm@0: void clearAllTouches(); andrewm@0: void setAnalogCalibrationStatusForKey(int key, bool isCalibrated); andrewm@0: void setAnalogValueForKey(int key, float value); andrewm@0: void clearAnalogData(); andrewm@0: void setMidiActive(int key, bool active); andrewm@0: void clearMidiData(); andrewm@0: andrewm@0: void setAnalogSensorsPresent(bool present) { analogSensorsPresent_ = present; } andrewm@0: void setTouchSensorPresentForKey(int key, bool present); andrewm@0: void setTouchSensingEnabled(bool enabled); andrewm@44: andrewm@44: // Key division methods andrewm@44: void addKeyDivision(void *who, int noteLow, int noteHigh, int divisions); andrewm@44: void removeKeyDivision(void *who); andrewm@0: andrewm@17: protected: andrewm@44: void drawWhiteKey(float x, float y, int shape, bool first, bool last, bool highlighted, int divisions); andrewm@44: void drawBlackKey(float x, float y, bool highlighted, int divisions); andrewm@0: andrewm@0: void drawWhiteTouch(float x, float y, int shape, float touchLocH, float touchLocV, float touchSize); andrewm@0: void drawBlackTouch(float x, float y, float touchLocH, float touchLocV, float touchSize); andrewm@0: andrewm@0: void drawAnalogSlider(float x, float y, bool calibrated, bool whiteKey, float value); andrewm@0: andrewm@0: // Indicate the shape of the given MIDI note. 0-6 for white keys C-B, -1 for black keys. andrewm@0: // We handle unusual shaped keys at the top or bottom of the keyboard separately. andrewm@0: andrewm@0: int keyShape(int key) { andrewm@0: if(key < 0) return -1; andrewm@0: return kShapeForNote[key % 12]; andrewm@0: } andrewm@0: andrewm@0: void refreshViewport(); andrewm@0: andrewm@0: // Conversion from internal coordinate space to external pixel values and back andrewm@0: Point screenToInternal(Point& inPoint); andrewm@0: Point internalToScreen(Point& inPoint); andrewm@0: andrewm@0: // Figure out which key (if any) the current point corresponds to andrewm@0: int keyForLocation(Point& internalPoint); andrewm@44: andrewm@44: // Convert key division map into a number of divisions for each key andrewm@44: void recalculateKeyDivisions(); andrewm@0: andrewm@17: protected: andrewm@27: OpenGLJuceCanvas *canvas_; // Reference to object which handles rendering andrewm@27: andrewm@0: int lowestMidiNote_, highestMidiNote_; // Which keys should be displayed (use MIDI note numbers) andrewm@0: float totalDisplayWidth_, totalDisplayHeight_; // Size of the internal view (centered around origin) andrewm@0: float displayPixelWidth_, displayPixelHeight_; // Pixel resolution of the surrounding window andrewm@0: int currentHighlightedKey_; // What key is being clicked on at the moment andrewm@0: bool touchSensingEnabled_; // Whether touch-sensitive keys are being used andrewm@0: bool touchSensingPresentOnKey_[128]; // Whether the key with this MIDI note has a touch sensor andrewm@0: andrewm@0: bool analogSensorsPresent_; // Whether the given device has analog sensors at all andrewm@0: bool analogValueIsCalibratedForKey_[128]; // Whether the analog sensor is calibrated on this key andrewm@0: float analogValueForKey_[128]; // Latest analog sensor value for each key andrewm@0: bool midiActiveForKey_[128]; // Whether the MIDI note is on for each key andrewm@0: andrewm@0: TouchInfo currentTouches_[128]; // Touch data for each key andrewm@0: TouchInfo currentTouchesMirror_[128]; // Mirror of the above, used for active display andrewm@44: std::map keyDivisions_; // Division of keys into more than one segment, for certain mappings andrewm@44: int keyDivisionsForNote_[128]; // Number of key divisions per note andrewm@0: CriticalSection displayMutex_; // Synchronize access between data and display threads andrewm@0: }; andrewm@0: andrewm@0: #endif /* KEYBOARD_DISPLAY_H */