andrewm@17
|
1 /*
|
andrewm@17
|
2 TouchKeys: multi-touch musical keyboard control software
|
andrewm@17
|
3 Copyright (c) 2013 Andrew McPherson
|
andrewm@17
|
4
|
andrewm@17
|
5 This program is free software: you can redistribute it and/or modify
|
andrewm@17
|
6 it under the terms of the GNU General Public License as published by
|
andrewm@17
|
7 the Free Software Foundation, either version 3 of the License, or
|
andrewm@17
|
8 (at your option) any later version.
|
andrewm@17
|
9
|
andrewm@17
|
10 This program is distributed in the hope that it will be useful,
|
andrewm@17
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
andrewm@17
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
andrewm@17
|
13 GNU General Public License for more details.
|
andrewm@17
|
14
|
andrewm@17
|
15 You should have received a copy of the GNU General Public License
|
andrewm@17
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
andrewm@17
|
17
|
andrewm@17
|
18 =====================================================================
|
andrewm@17
|
19
|
andrewm@17
|
20 KeyboardTesterDisplay.cpp: A keyboard display for raw data that can be used
|
andrewm@17
|
21 for testing the functionality of individual TouchKeys sensors
|
andrewm@17
|
22 */
|
andrewm@17
|
23
|
andrewm@17
|
24 #ifdef ENABLE_TOUCHKEYS_SENSOR_TEST
|
andrewm@17
|
25
|
andrewm@17
|
26 #include "KeyboardTesterDisplay.h"
|
andrewm@17
|
27 #include "../MainApplicationController.h"
|
andrewm@17
|
28 #include "../TouchKeys/PianoKeyboard.h"
|
andrewm@17
|
29
|
andrewm@17
|
30 const int KeyboardTesterDisplay::kNumSensorsPerKey = 26;
|
andrewm@17
|
31 const int KeyboardTesterDisplay::kDefaultSensorThreshold = 16;
|
andrewm@17
|
32
|
andrewm@17
|
33 // Constructor
|
andrewm@17
|
34 KeyboardTesterDisplay::KeyboardTesterDisplay(MainApplicationController& controller, PianoKeyboard& keyboard)
|
andrewm@17
|
35 : controller_(controller), keyboard_(keyboard),
|
andrewm@17
|
36 currentlyActiveKey_(-1), sensorThreshold_(kDefaultSensorThreshold) {
|
andrewm@17
|
37 for(int i = 0; i < 128; i++)
|
andrewm@17
|
38 resetSensorState(i);
|
andrewm@17
|
39
|
andrewm@17
|
40 setOscController(&keyboard_);
|
andrewm@17
|
41 addOscListener("/touchkeys/rawbytes");
|
andrewm@17
|
42 }
|
andrewm@17
|
43
|
andrewm@17
|
44 // Render the display starting with the underlying keyboard and
|
andrewm@17
|
45 // then adding our own display info on top
|
andrewm@17
|
46 void KeyboardTesterDisplay::render() {
|
andrewm@17
|
47 if(lowestMidiNote_ == highestMidiNote_)
|
andrewm@17
|
48 return;
|
andrewm@17
|
49
|
andrewm@17
|
50 // Start with a light gray background
|
andrewm@17
|
51 glClearColor(0.8, 0.8, 0.8, 1.0);
|
andrewm@17
|
52 glClear(GL_COLOR_BUFFER_BIT);
|
andrewm@17
|
53 glLoadIdentity();
|
andrewm@17
|
54
|
andrewm@17
|
55 float invAspectRatio = totalDisplayWidth_ / totalDisplayHeight_;
|
andrewm@17
|
56 float scaleValue = 2.0 / totalDisplayWidth_;
|
andrewm@17
|
57
|
andrewm@17
|
58 glScalef(scaleValue, scaleValue * invAspectRatio, scaleValue);
|
andrewm@17
|
59 glTranslatef(-1.0 / scaleValue, -totalDisplayHeight_ / 2.0, 0);
|
andrewm@17
|
60 glTranslatef(kDisplaySideMargin, kDisplayBottomMargin, 0.0);
|
andrewm@17
|
61
|
andrewm@17
|
62 glPushMatrix();
|
andrewm@17
|
63
|
andrewm@17
|
64 // Draw the keys themselves first, with analog values if present, then draw the touches
|
andrewm@17
|
65 for(int key = lowestMidiNote_; key <= highestMidiNote_; key++) {
|
andrewm@17
|
66 if(keyShape(key) >= 0) {
|
andrewm@17
|
67 // White keys: draw and move the frame over for the next key
|
andrewm@17
|
68 drawWhiteKey(0, 0, keyShape(key), key == lowestMidiNote_,
|
andrewm@17
|
69 key == highestMidiNote_, (key == currentlyActiveKey_) || (key == currentHighlightedKey_));
|
andrewm@17
|
70 // Draw sensor state for this key
|
andrewm@17
|
71 drawSensorState(key, kWhiteKeyBackOffsets[keyShape(key)], 0, kWhiteKeyBackWidths[keyShape(key)], kWhiteKeyFrontLength + kWhiteKeyBackLength);
|
andrewm@17
|
72 glTranslatef(kWhiteKeyFrontWidth + kInterKeySpacing, 0, 0);
|
andrewm@17
|
73 }
|
andrewm@17
|
74 else {
|
andrewm@17
|
75 // Black keys: draw and leave the frame in place
|
andrewm@17
|
76 int previousWhiteKeyShape = keyShape(key - 1);
|
andrewm@17
|
77 float offsetH = -1.0 + kWhiteKeyBackOffsets[previousWhiteKeyShape] + kWhiteKeyBackWidths[previousWhiteKeyShape];
|
andrewm@17
|
78 float offsetV = kWhiteKeyFrontLength + kWhiteKeyBackLength - kBlackKeyLength;
|
andrewm@17
|
79
|
andrewm@17
|
80 glTranslatef(offsetH, offsetV, 0.0);
|
andrewm@17
|
81 drawBlackKey(0, 0, (key == currentlyActiveKey_) || (key == currentHighlightedKey_));
|
andrewm@17
|
82 // Draw sensor state for this key
|
andrewm@17
|
83 drawSensorState(key, 0, 0, kBlackKeyWidth, kBlackKeyLength);
|
andrewm@17
|
84 glTranslatef(-offsetH, -offsetV, 0.0);
|
andrewm@17
|
85 }
|
andrewm@17
|
86 }
|
andrewm@17
|
87
|
andrewm@17
|
88 // Restore to the original location we used when drawing the keys
|
andrewm@17
|
89 glPopMatrix();
|
andrewm@17
|
90
|
andrewm@17
|
91 needsUpdate_ = false;
|
andrewm@17
|
92 glFlush();
|
andrewm@17
|
93 }
|
andrewm@17
|
94
|
andrewm@17
|
95 // Set the threshold level at which a sensor is considered active
|
andrewm@17
|
96 void KeyboardTesterDisplay::setSensorThreshold(int threshold) {
|
andrewm@17
|
97 sensorThreshold_ = threshold;
|
andrewm@17
|
98 }
|
andrewm@17
|
99
|
andrewm@17
|
100 // Set the state of a given sensor on a given key to be on or off,
|
andrewm@17
|
101 // based on some externally-computed threshold. Sensors that are on
|
andrewm@17
|
102 // will flip the "good" flag to true, which remains set until cleared
|
andrewm@17
|
103 // externally.
|
andrewm@17
|
104 void KeyboardTesterDisplay::setSensorState(int key, int sensor, bool active) {
|
andrewm@17
|
105 if(key < 0 || key > 127)
|
andrewm@17
|
106 return;
|
andrewm@17
|
107 if(sensor < 0 || sensor >= kNumSensorsPerKey)
|
andrewm@17
|
108 return;
|
andrewm@17
|
109 if(active) {
|
andrewm@17
|
110 keySensorActive_[key] |= (1 << sensor);
|
andrewm@17
|
111 keySensorGood_[key] |= (1 << sensor);
|
andrewm@17
|
112 }
|
andrewm@17
|
113 else
|
andrewm@17
|
114 keySensorActive_[key] &= ~(1 << sensor);
|
andrewm@17
|
115 currentlyActiveKey_ = key;
|
andrewm@17
|
116 needsUpdate_ = true;
|
andrewm@17
|
117
|
andrewm@17
|
118 if(allSensorsGood(currentlyActiveKey_)) {
|
andrewm@17
|
119 controller_.touchkeySensorTestSetKey(key + 1);
|
andrewm@17
|
120 }
|
andrewm@17
|
121 }
|
andrewm@17
|
122
|
andrewm@17
|
123 // Indicate whether all sensors have shown an active value on this key
|
andrewm@17
|
124 bool KeyboardTesterDisplay::allSensorsGood(int key) {
|
andrewm@17
|
125 if(key < 0 || key > 127)
|
andrewm@17
|
126 return false;
|
andrewm@17
|
127 unsigned int mask = (1 << kNumSensorsPerKey) - 1;
|
andrewm@17
|
128
|
andrewm@17
|
129 return ((keySensorGood_[key] & mask) == mask);
|
andrewm@17
|
130 }
|
andrewm@17
|
131
|
andrewm@17
|
132 // Reset the sensor state to all off
|
andrewm@17
|
133 void KeyboardTesterDisplay::resetSensorState(int key) {
|
andrewm@17
|
134 if(key < 0 || key > 127)
|
andrewm@17
|
135 return;
|
andrewm@17
|
136 keySensorGood_[key] = 0;
|
andrewm@17
|
137 keySensorActive_[key] = 0;
|
andrewm@17
|
138 if(currentlyActiveKey_ == key)
|
andrewm@17
|
139 currentlyActiveKey_ = -1;
|
andrewm@17
|
140 }
|
andrewm@17
|
141
|
andrewm@17
|
142 // Draw the given key sensors as being active, good, or inactive
|
andrewm@17
|
143 void KeyboardTesterDisplay::drawSensorState(int key, float x, float y, float width, float height) {
|
andrewm@17
|
144 float heightInset = height / ((float)kNumSensorsPerKey * 10);
|
andrewm@17
|
145
|
andrewm@17
|
146 glPushMatrix();
|
andrewm@17
|
147 glTranslatef(x, y, 0);
|
andrewm@17
|
148
|
andrewm@17
|
149 for(int i = 0; i < kNumSensorsPerKey; i++) {
|
andrewm@17
|
150 // Draw each sensor in sequence: red = never activated; yellow = active; green = previously
|
andrewm@17
|
151 // activated (good)
|
andrewm@17
|
152 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
andrewm@17
|
153 if(keySensorActive_[key] & (1 << i) && key == currentlyActiveKey_)
|
andrewm@17
|
154 glColor3f(1.0, 1.0, 0.0); // Sensor active right now = yellow
|
andrewm@17
|
155 else if(keySensorGood_[key] & (1 << i))
|
andrewm@17
|
156 glColor3f(0.0, 1.0, 0.0); // Sensor has been active (good) = green
|
andrewm@17
|
157 else
|
andrewm@17
|
158 glColor3f(1.0, 0.0, 0.0); // Sensor has not yet been active = red
|
andrewm@17
|
159
|
andrewm@17
|
160 glBegin(GL_POLYGON);
|
andrewm@17
|
161 glVertex2f(width * 0.1, heightInset);
|
andrewm@17
|
162 glVertex2f(width * 0.1, height / (float)kNumSensorsPerKey - heightInset);
|
andrewm@17
|
163 glVertex2f(width * 0.9, height / (float)kNumSensorsPerKey - heightInset);
|
andrewm@17
|
164 glVertex2f(width * 0.9, heightInset);
|
andrewm@17
|
165 glEnd();
|
andrewm@17
|
166
|
andrewm@17
|
167 glTranslatef(0, height / (float)kNumSensorsPerKey, 0);
|
andrewm@17
|
168 }
|
andrewm@17
|
169
|
andrewm@17
|
170 glPopMatrix();
|
andrewm@17
|
171 }
|
andrewm@17
|
172
|
andrewm@17
|
173 // OSC callback method, for when data comes in
|
andrewm@17
|
174 bool KeyboardTesterDisplay::oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data) {
|
andrewm@17
|
175 // Look for a blob in value 0 holding the raw data
|
andrewm@17
|
176 if(numValues < 1)
|
andrewm@17
|
177 return false;
|
andrewm@17
|
178 if(types[0] != 'b')
|
andrewm@17
|
179 return false;
|
andrewm@17
|
180
|
andrewm@17
|
181 // Get OSC blob which holds raw data
|
andrewm@17
|
182 lo_blob blob = values[0];
|
andrewm@17
|
183 int bufferSize = lo_blob_datasize(blob);
|
andrewm@17
|
184 const unsigned char *buffer = (const unsigned char *)lo_blob_dataptr(blob);
|
andrewm@17
|
185
|
andrewm@17
|
186 // buffer[0] holds the key number from which this data came. Make sure it's sane.
|
andrewm@17
|
187 if(bufferSize == 0)
|
andrewm@17
|
188 return false;
|
andrewm@17
|
189 if(buffer[0] > 127)
|
andrewm@17
|
190 return false;
|
andrewm@17
|
191
|
andrewm@17
|
192 // The remainder is raw data, with each single byte corresponding to a sensor.
|
andrewm@17
|
193 for(int i = 1; i < bufferSize; i++) {
|
andrewm@17
|
194 bool active = (buffer[i] >= sensorThreshold_);
|
andrewm@17
|
195 setSensorState(buffer[0], i - 1, active);
|
andrewm@17
|
196 }
|
andrewm@17
|
197
|
andrewm@17
|
198 return true;
|
andrewm@17
|
199 }
|
andrewm@17
|
200
|
andrewm@17
|
201 #endif // ENABLE_TOUCHKEYS_SENSOR_TEST |