annotate Source/Display/KeyPositionGraphDisplay.cpp @ 56:b4a2d2ae43cf tip

merge
author Andrew McPherson <andrewm@eecs.qmul.ac.uk>
date Fri, 23 Nov 2018 15:48:14 +0000
parents eef567a60146
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 KeyPositionGraphDisplay.cpp: implements a graph of key position over time
andrewm@0 21 for a specific key press, which is useful for analysis of continuous key
andrewm@0 22 position.
andrewm@0 23 */
andrewm@0 24
andrewm@0 25 #include "KeyPositionGraphDisplay.h"
andrewm@27 26 #include "OpenGLJuceCanvas.h"
andrewm@0 27 #include <iostream>
andrewm@0 28 #include <cmath>
andrewm@0 29
andrewm@0 30 // Class constants
andrewm@0 31 // Display margins
andrewm@0 32 const float KeyPositionGraphDisplay::kDisplaySideMargin = 0.5;
andrewm@0 33 const float KeyPositionGraphDisplay::kDisplayBottomMargin = 0.5;
andrewm@0 34 const float KeyPositionGraphDisplay::kDisplayTopMargin = 0.5;
andrewm@0 35
andrewm@0 36 // Size of the graph area
andrewm@0 37 const float KeyPositionGraphDisplay::kDisplayGraphWidth = 20.0;
andrewm@0 38 const float KeyPositionGraphDisplay::kDisplayGraphHeight = 10.0;
andrewm@0 39
andrewm@27 40 KeyPositionGraphDisplay::KeyPositionGraphDisplay() : canvas_(0),
andrewm@0 41 displayPixelWidth_(1.0), displayPixelHeight_(1.0), totalDisplayWidth_(1.0), totalDisplayHeight_(1.0),
andrewm@27 42 xMin_(0.0), xMax_(1.0), yMin_(-0.2), yMax_(1.2)
andrewm@0 43 {
andrewm@0 44 // Initialize OpenGL settings: 2D only
andrewm@0 45
andrewm@0 46 //glMatrixMode(GL_PROJECTION);
andrewm@0 47 //glDisable(GL_DEPTH_TEST);
andrewm@0 48
andrewm@0 49 pressStartTimestamp_ = pressFinishTimestamp_ = releaseStartTimestamp_ = releaseFinishTimestamp_ = missing_value<timestamp_type>::missing();
andrewm@0 50 pressStartPosition_ = pressFinishPosition_ = releaseStartPosition_ = releaseFinishPosition_ = missing_value<key_position>::missing();
andrewm@0 51
andrewm@0 52 totalDisplayWidth_ = kDisplaySideMargin*2 + kDisplayGraphWidth;
andrewm@0 53 totalDisplayHeight_ = kDisplayTopMargin + kDisplayBottomMargin + kDisplayGraphHeight;
andrewm@0 54 }
andrewm@0 55
andrewm@27 56 // Tell the underlying canvas to repaint itself
andrewm@27 57 void KeyPositionGraphDisplay::tellCanvasToRepaint() {
andrewm@27 58 if(canvas_ != 0)
andrewm@27 59 canvas_->triggerRepaint();
andrewm@27 60 }
andrewm@27 61
andrewm@0 62 void KeyPositionGraphDisplay::setDisplaySize(float width, float height) {
andrewm@0 63 ScopedLock sl(displayMutex_);
andrewm@0 64 displayPixelWidth_ = width;
andrewm@0 65 displayPixelHeight_ = height;
andrewm@0 66 refreshViewport();
andrewm@0 67 }
andrewm@0 68
andrewm@0 69
andrewm@0 70 // Render the keyboard display
andrewm@0 71
andrewm@0 72 void KeyPositionGraphDisplay::render() {
andrewm@0 73 // Start with a light gray background
andrewm@0 74 glClearColor(0.8, 0.8, 0.8, 1.0);
andrewm@0 75 glClear(GL_COLOR_BUFFER_BIT);
andrewm@0 76 glLoadIdentity();
andrewm@0 77
andrewm@0 78 float invAspectRatio = totalDisplayWidth_ / totalDisplayHeight_;
andrewm@0 79 float scaleValue = 2.0 / totalDisplayWidth_;
andrewm@0 80
andrewm@0 81 glScalef(scaleValue, scaleValue * invAspectRatio, scaleValue);
andrewm@0 82 glTranslatef(-1.0 / scaleValue, -totalDisplayHeight_ / 2.0, 0);
andrewm@0 83 glTranslatef(kDisplaySideMargin, kDisplayBottomMargin, 0.0);
andrewm@0 84
andrewm@0 85 ScopedLock sl(displayMutex_);
andrewm@0 86
andrewm@0 87 // Draw the region where the graph will be plotted (white with black outline)
andrewm@0 88 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
andrewm@0 89 glColor3f(1.0, 1.0, 1.0);
andrewm@0 90
andrewm@0 91 glBegin(GL_POLYGON);
andrewm@0 92 glVertex2f(0, 0);
andrewm@0 93 glVertex2f(0, kDisplayGraphHeight);
andrewm@0 94 glVertex2f(kDisplayGraphWidth, kDisplayGraphHeight);
andrewm@0 95 glVertex2f(kDisplayGraphWidth, 0);
andrewm@0 96 glEnd();
andrewm@0 97
andrewm@0 98 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
andrewm@0 99 glColor3f(0.0, 0.0, 0.0);
andrewm@0 100 glLineWidth(1.0);
andrewm@0 101
andrewm@0 102 glBegin(GL_POLYGON);
andrewm@0 103 glVertex2f(0, 0);
andrewm@0 104 glVertex2f(0, kDisplayGraphHeight);
andrewm@0 105 glVertex2f(kDisplayGraphWidth, kDisplayGraphHeight);
andrewm@0 106 glVertex2f(kDisplayGraphWidth, 0);
andrewm@0 107 glEnd();
andrewm@0 108
andrewm@0 109 // Draw gray lines for the 0.0 and 1.0 key positions
andrewm@0 110 glColor3f(0.5, 0.5, 0.5);
andrewm@0 111 glBegin(GL_LINES);
andrewm@0 112 glVertex2f(0, graphToDisplayY(0.0));
andrewm@0 113 glVertex2f(kDisplayGraphWidth, graphToDisplayY(0.0));
andrewm@0 114 glEnd();
andrewm@0 115 glBegin(GL_LINES);
andrewm@0 116 glVertex2f(0, graphToDisplayY(1.0));
andrewm@0 117 glVertex2f(kDisplayGraphWidth, graphToDisplayY(1.0));
andrewm@0 118 glEnd();
andrewm@0 119
andrewm@0 120 // Draw the graph of position over time (if data exists)
andrewm@0 121 if(!keyPositions_.empty() && !keyTimestamps_.empty()) {
andrewm@0 122 glColor3f(0.0, 0.0, 0.0);
andrewm@0 123 glBegin(GL_LINE_STRIP);
andrewm@0 124 for(int index = 0; index < keyPositions_.size() && index < keyTimestamps_.size(); index++) {
andrewm@0 125 glVertex2f(graphToDisplayX(keyTimestamps_[index]), graphToDisplayY(keyPositions_[index]));
andrewm@0 126 }
andrewm@0 127 glEnd();
andrewm@0 128 }
andrewm@0 129
andrewm@0 130 // Draw the important features, if they exist
andrewm@0 131 if(!missing_value<timestamp_type>::isMissing(pressStartTimestamp_)) {
andrewm@0 132 glColor3f(0.0, 0.0, 1.0);
andrewm@0 133 glBegin(GL_LINES);
andrewm@0 134 glVertex2f(graphToDisplayX(pressStartTimestamp_), 0);
andrewm@0 135 glVertex2f(graphToDisplayX(pressStartTimestamp_), kDisplayGraphHeight);
andrewm@0 136 glEnd();
andrewm@0 137 }
andrewm@0 138 if(!missing_value<timestamp_type>::isMissing(pressFinishTimestamp_)) {
andrewm@0 139 glColor3f(1.0, 0.0, 0.0);
andrewm@0 140 glBegin(GL_LINES);
andrewm@0 141 glVertex2f(graphToDisplayX(pressFinishTimestamp_), 0);
andrewm@0 142 glVertex2f(graphToDisplayX(pressFinishTimestamp_), kDisplayGraphHeight);
andrewm@0 143 glEnd();
andrewm@0 144 }
andrewm@0 145 if(!missing_value<timestamp_type>::isMissing(releaseStartTimestamp_)) {
andrewm@0 146 glColor3f(0.0, 0.0, 1.0);
andrewm@0 147 glBegin(GL_LINES);
andrewm@0 148 glVertex2f(graphToDisplayX(releaseStartTimestamp_), 0);
andrewm@0 149 glVertex2f(graphToDisplayX(releaseStartTimestamp_), kDisplayGraphHeight);
andrewm@0 150 glEnd();
andrewm@0 151 }
andrewm@0 152 if(!missing_value<timestamp_type>::isMissing(releaseFinishTimestamp_)) {
andrewm@0 153 glColor3f(1.0, 0.0, 0.0);
andrewm@0 154 glBegin(GL_LINES);
andrewm@0 155 glVertex2f(graphToDisplayX(releaseFinishTimestamp_), 0);
andrewm@0 156 glVertex2f(graphToDisplayX(releaseFinishTimestamp_), kDisplayGraphHeight);
andrewm@0 157 glEnd();
andrewm@0 158 }
andrewm@0 159
andrewm@0 160 glFlush();
andrewm@0 161 }
andrewm@0 162
andrewm@0 163 // Mouse interaction methods
andrewm@0 164
andrewm@0 165 void KeyPositionGraphDisplay::mouseDown(float x, float y) {
andrewm@0 166 //Point mousePoint = {x, y};
andrewm@0 167 //Point scaledPoint = screenToInternal(mousePoint);
andrewm@0 168 }
andrewm@0 169
andrewm@0 170 void KeyPositionGraphDisplay::mouseDragged(float x, float y) {
andrewm@0 171 //Point mousePoint = {x, y};
andrewm@0 172 //Point scaledPoint = screenToInternal(mousePoint);
andrewm@0 173 }
andrewm@0 174
andrewm@0 175 void KeyPositionGraphDisplay::mouseUp(float x, float y) {
andrewm@0 176 //Point mousePoint = {x, y};
andrewm@0 177 //Point scaledPoint = screenToInternal(mousePoint);
andrewm@0 178 }
andrewm@0 179
andrewm@0 180 void KeyPositionGraphDisplay::rightMouseDown(float x, float y) {
andrewm@0 181 //Point mousePoint = {x, y};
andrewm@0 182 //Point scaledPoint = screenToInternal(mousePoint);
andrewm@0 183 }
andrewm@0 184
andrewm@0 185 void KeyPositionGraphDisplay::rightMouseDragged(float x, float y) {
andrewm@0 186 //Point mousePoint = {x, y};
andrewm@0 187 //Point scaledPoint = screenToInternal(mousePoint);
andrewm@0 188 }
andrewm@0 189
andrewm@0 190 void KeyPositionGraphDisplay::rightMouseUp(float x, float y) {
andrewm@0 191 //Point mousePoint = {x, y};
andrewm@0 192 //Point scaledPoint = screenToInternal(mousePoint);
andrewm@0 193 }
andrewm@0 194
andrewm@0 195 float KeyPositionGraphDisplay::graphToDisplayX(float x) {
andrewm@0 196 return kDisplayGraphWidth*(x - xMin_)/(xMax_ - xMin_);
andrewm@0 197 }
andrewm@0 198
andrewm@0 199 float KeyPositionGraphDisplay::graphToDisplayY(float y) {
andrewm@0 200 return kDisplayGraphHeight*(y - yMin_)/(yMax_ - yMin_);
andrewm@0 201 }
andrewm@0 202
andrewm@0 203 void KeyPositionGraphDisplay::refreshViewport() {
andrewm@0 204 glViewport(0, 0, displayPixelWidth_, displayPixelHeight_);
andrewm@0 205 }
andrewm@0 206
andrewm@0 207 // Copy data from the circular buffer to our internal buffer for
andrewm@0 208 void KeyPositionGraphDisplay::copyKeyDataFromBuffer(Node<key_position>& keyBuffer,
andrewm@0 209 const Node<key_position>::size_type startIndex,
andrewm@0 210 const Node<key_position>::size_type endIndex) {
andrewm@0 211 // Clear existing information
andrewm@0 212 keyPositions_.clear();
andrewm@0 213 keyTimestamps_.clear();
andrewm@0 214
andrewm@0 215 Node<key_position>::size_type index = startIndex;
andrewm@0 216 if(index < keyBuffer.beginIndex())
andrewm@0 217 index = keyBuffer.beginIndex();
andrewm@0 218
andrewm@0 219 // Iterate through the buffer, copying positions and timestamps
andrewm@0 220 while(index < endIndex && index < keyBuffer.endIndex()) {
andrewm@0 221 keyPositions_.push_back(keyBuffer[index]);
andrewm@0 222 keyTimestamps_.push_back(keyBuffer.timestampAt(index));
andrewm@0 223 index++;
andrewm@0 224 }
andrewm@0 225
andrewm@0 226 // Scale the axes according to what's being displayed. The Y axis should stay
andrewm@0 227 // more or less constant (for now), but X will change depending on timestamps
andrewm@0 228 xMin_ = keyTimestamps_.front();
andrewm@0 229 xMax_ = keyTimestamps_.back();
andrewm@0 230 yMin_ = -0.2;
andrewm@0 231 yMax_ = 1.2;
andrewm@27 232 tellCanvasToRepaint();
andrewm@0 233 }
andrewm@0 234
andrewm@0 235 // Conversion from internal coordinate space to external pixel values and back
andrewm@0 236
andrewm@0 237 // Pixel values go from 0,0 (lower left) to displayPixelWidth_, displayPixelHeight_ (upper right)
andrewm@0 238 // Internal values go from -totalDisplayWidth_/2, -totalDisplayHeight_/2 (lower left)
andrewm@0 239 // to totalDisplayWidth_/2, totalDisplayHeight_/2 (upper right)
andrewm@0 240
andrewm@0 241 // Pixel value in --> OpenGL value out
andrewm@0 242 KeyPositionGraphDisplay::Point KeyPositionGraphDisplay::screenToInternal(Point& inPoint) {
andrewm@0 243 Point out;
andrewm@0 244
andrewm@0 245 out.x = -totalDisplayWidth_*0.5 + (inPoint.x/displayPixelWidth_) * totalDisplayWidth_;
andrewm@0 246 out.y = -totalDisplayHeight_*0.5 + (inPoint.y/displayPixelHeight_) * totalDisplayHeight_;
andrewm@0 247
andrewm@0 248 return out;
andrewm@0 249 }
andrewm@0 250
andrewm@0 251 // OpenGL value in --> Pixel value out
andrewm@0 252 KeyPositionGraphDisplay::Point KeyPositionGraphDisplay::internalToScreen(Point& inPoint) {
andrewm@0 253 Point out;
andrewm@0 254
andrewm@0 255 out.x = ((inPoint.x + totalDisplayWidth_*0.5)/totalDisplayWidth_) * displayPixelWidth_;
andrewm@0 256 out.y = ((inPoint.y + totalDisplayHeight_*0.5)/totalDisplayHeight_) * displayPixelHeight_;
andrewm@0 257
andrewm@0 258 return out;
andrewm@0 259 }