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