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 PianoKeyCalibrator.h: handles calibration of continuous key position data
|
andrewm@0
|
21 */
|
andrewm@0
|
22
|
andrewm@0
|
23
|
andrewm@0
|
24 #ifndef KEYCONTROL_PIANO_KEY_CALIBRATOR_H
|
andrewm@0
|
25 #define KEYCONTROL_PIANO_KEY_CALIBRATOR_H
|
andrewm@0
|
26
|
andrewm@0
|
27 #include <iostream>
|
andrewm@0
|
28 #include <boost/circular_buffer.hpp>
|
andrewm@0
|
29 #include "../JuceLibraryCode/JuceHeader.h"
|
andrewm@0
|
30 #include "../Utility/Types.h"
|
andrewm@0
|
31 #include "PianoKeyboard.h"
|
andrewm@0
|
32
|
andrewm@0
|
33 // Calibration status of the Piano Bar. This compensates for variations in mechanical position, light level, etc.
|
andrewm@0
|
34 enum {
|
andrewm@0
|
35 kPianoKeyNotCalibrated = 0,
|
andrewm@0
|
36 kPianoKeyCalibrated,
|
andrewm@0
|
37 kPianoKeyInCalibration
|
andrewm@0
|
38 };
|
andrewm@0
|
39
|
andrewm@0
|
40 // Size of the calibration history we keep
|
andrewm@0
|
41 const size_t kPianoKeyCalibrationBufferSize = 32; // 32
|
andrewm@0
|
42 const size_t kPianoKeyCalibrationPressLength = 10; // 10
|
andrewm@0
|
43
|
andrewm@0
|
44 // Minimum amount of range between quiescent and press for a note to be calibrated
|
andrewm@0
|
45 const int kPianoKeyCalibrationMinimumRange = 64;
|
andrewm@0
|
46
|
andrewm@0
|
47 /*
|
andrewm@0
|
48 * PianoKeyboardCalibrator
|
andrewm@0
|
49 *
|
andrewm@0
|
50 * This class defines a calibration from raw value to normalized value, generically for
|
andrewm@0
|
51 * any sensor which outputs a continuous value for key position. It allows the calibration
|
andrewm@0
|
52 * to be learned and applied. It allows a direction to be set where pressed keys are either
|
andrewm@0
|
53 * greater or lower in value than unpressed keys, to accommodate different sensor topologies.
|
andrewm@0
|
54 */
|
andrewm@0
|
55
|
andrewm@0
|
56 class PianoKeyCalibrator {
|
andrewm@0
|
57 public:
|
andrewm@0
|
58 // ***** Constructor *****
|
andrewm@0
|
59
|
andrewm@0
|
60 PianoKeyCalibrator(bool pressValueGoesDown, key_position* warpTable);
|
andrewm@0
|
61
|
andrewm@0
|
62 // ***** Destructor *****
|
andrewm@0
|
63
|
andrewm@0
|
64 ~PianoKeyCalibrator();
|
andrewm@0
|
65
|
andrewm@0
|
66 // ***** Evaluator *****
|
andrewm@0
|
67 //
|
andrewm@0
|
68 // In normal (operational) mode, evaluate() returns the calibrated value for the raw input.
|
andrewm@0
|
69 // In other modes, it returns a "missing" value. Specifically in calibration mode, it updates
|
andrewm@0
|
70 // the settings for calibration.
|
andrewm@0
|
71
|
andrewm@0
|
72 key_position evaluate(int rawValue);
|
andrewm@0
|
73
|
andrewm@0
|
74 // ***** Calibration Methods *****
|
andrewm@0
|
75 //
|
andrewm@0
|
76 // Return the current status
|
andrewm@0
|
77 int calibrationStatus() { return status_; }
|
andrewm@0
|
78
|
andrewm@0
|
79 // Manage the calibration state
|
andrewm@0
|
80
|
andrewm@0
|
81 void calibrationStart();
|
andrewm@0
|
82 bool calibrationFinish(); // Returns true on successful calibration
|
andrewm@0
|
83 void calibrationAbort();
|
andrewm@0
|
84 void calibrationClear();
|
andrewm@0
|
85
|
andrewm@0
|
86 // Learn new quiescent values only. This needs to be called from a thread other than the data source
|
andrewm@0
|
87 // (audio or serial callback) thread, since it waits for the buffer to fill up before calculating the values.
|
andrewm@0
|
88
|
andrewm@0
|
89 void calibrationUpdateQuiescent();
|
andrewm@0
|
90
|
andrewm@0
|
91 // ***** XML I/O Methods *****
|
andrewm@0
|
92 //
|
andrewm@0
|
93 // These methods load and save calibration data from an XML string. The PianoKeyCalibrator object handles
|
andrewm@0
|
94 // the relevant file I/O.
|
andrewm@0
|
95
|
andrewm@0
|
96 void loadFromXml(const XmlElement& baseElement);
|
andrewm@0
|
97 bool saveToXml(XmlElement& baseElement);
|
andrewm@0
|
98
|
andrewm@0
|
99 private:
|
andrewm@0
|
100 // ***** Helper Methods *****
|
andrewm@0
|
101
|
andrewm@0
|
102 void changeStatus(int newStatus) {
|
andrewm@0
|
103 prevStatus_ = status_;
|
andrewm@0
|
104 status_ = newStatus;
|
andrewm@0
|
105 }
|
andrewm@0
|
106
|
andrewm@0
|
107 // Update quiescent values
|
andrewm@0
|
108 bool internalUpdateQuiescent();
|
andrewm@0
|
109
|
andrewm@0
|
110 // Average position over the history buffer, for finding minima and maxima
|
andrewm@0
|
111 int averagePosition(int length);
|
andrewm@0
|
112
|
andrewm@0
|
113 // Clean up after a calibration; called by finish() and abort()
|
andrewm@0
|
114 void cleanup();
|
andrewm@0
|
115
|
andrewm@0
|
116 // ***** Member Variables *****
|
andrewm@0
|
117
|
andrewm@0
|
118 int status_, prevStatus_; // Status of calibration (see enum above), and its previous value
|
andrewm@0
|
119 bool pressValueGoesDown_; // If true, the pressed key value is expected to be lower than the quiescent
|
andrewm@0
|
120 int quiescent_; // Resting value for the sensor
|
andrewm@0
|
121 int press_; // Fully pressed value for the sensor
|
andrewm@0
|
122 int newPress_; // Value-in-training for press
|
andrewm@0
|
123
|
andrewm@0
|
124 boost::circular_buffer<int>* history_; // Buffer holds history of raw values for calibrating
|
andrewm@0
|
125
|
andrewm@0
|
126 // Table of warping values to correct for sensor non-linearity
|
andrewm@0
|
127 key_position* warpTable_;
|
andrewm@0
|
128
|
andrewm@0
|
129 CriticalSection calibrationMutex_; // This mutex protects access to the entire calibration structure
|
andrewm@0
|
130 CriticalSection historyMutex_; // This mutex is specifically tied to the history_ buffers
|
andrewm@0
|
131 };
|
andrewm@0
|
132
|
andrewm@0
|
133 #endif /* KEYCONTROL_PIANO_KEY_CALIBRATOR_H */
|
andrewm@0
|
134
|