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 TouchkeyBaseMapping.cpp: base class from which all TouchKeys-specific
|
andrewm@0
|
21 mappings derive. Like its Mapping parent class, it handles a mapping
|
andrewm@0
|
22 for one specific note.
|
andrewm@0
|
23 */
|
andrewm@0
|
24
|
andrewm@0
|
25 #include "TouchkeyBaseMapping.h"
|
andrewm@0
|
26 #include "MappingFactory.h"
|
andrewm@0
|
27 #include "../TouchKeys/MidiOutputController.h"
|
andrewm@0
|
28
|
andrewm@0
|
29 // Main constructor takes references/pointers from objects which keep track
|
andrewm@0
|
30 // of touch location, continuous key position and the state detected from that
|
andrewm@0
|
31 // position. The PianoKeyboard object is strictly required as it gives access to
|
andrewm@0
|
32 // Scheduler and OSC methods. The others are optional since any given system may
|
andrewm@0
|
33 // contain only one of continuous key position or touch sensitivity
|
andrewm@0
|
34 TouchkeyBaseMapping::TouchkeyBaseMapping(PianoKeyboard &keyboard, MappingFactory *factory, int noteNumber, Node<KeyTouchFrame>* touchBuffer,
|
andrewm@0
|
35 Node<key_position>* positionBuffer, KeyPositionTracker* positionTracker,
|
andrewm@0
|
36 bool finishesAutomatically)
|
andrewm@0
|
37 : Mapping(keyboard, factory, noteNumber, touchBuffer, positionBuffer, positionTracker),
|
andrewm@0
|
38 controlName_(""), noteIsOn_(false), finished_(true), finishRequested_(false), finishesAutomatically_(finishesAutomatically)
|
andrewm@0
|
39 {
|
andrewm@0
|
40 setOscController(&keyboard_);
|
andrewm@0
|
41 }
|
andrewm@0
|
42
|
andrewm@0
|
43 // Copy constructor
|
andrewm@0
|
44 /*TouchkeyBaseMapping::TouchkeyBaseMapping(TouchkeyBaseMapping const& obj)
|
andrewm@0
|
45 : Mapping(obj), noteIsOn_(obj.noteIsOn_), finished_(obj.finished_), finishRequested_(obj.finishRequested_),
|
andrewm@0
|
46 finishesAutomatically_(obj.finishesAutomatically_)
|
andrewm@0
|
47 {
|
andrewm@0
|
48 setOscController(&keyboard_);
|
andrewm@0
|
49 }*/
|
andrewm@0
|
50
|
andrewm@0
|
51 TouchkeyBaseMapping::~TouchkeyBaseMapping() {
|
andrewm@0
|
52 #ifndef NEW_MAPPING_SCHEDULER
|
andrewm@0
|
53 try {
|
andrewm@0
|
54 disengage();
|
andrewm@0
|
55 }
|
andrewm@0
|
56 catch(...) {
|
andrewm@0
|
57 std::cerr << "~TouchkeyBaseMapping(): exception during disengage()\n";
|
andrewm@0
|
58 }
|
andrewm@0
|
59 #endif
|
andrewm@0
|
60 }
|
andrewm@0
|
61
|
andrewm@0
|
62 // Turn on mapping of data.
|
andrewm@0
|
63 void TouchkeyBaseMapping::engage() {
|
andrewm@0
|
64 Mapping::engage();
|
andrewm@0
|
65
|
andrewm@0
|
66 // Register for OSC callbacks on MIDI note on/off
|
andrewm@0
|
67 addOscListener("/midi/noteon");
|
andrewm@0
|
68 addOscListener("/midi/noteoff");
|
andrewm@0
|
69
|
andrewm@0
|
70 //cout << "TouchkeyBaseMapping::engage(): after TS " << keyboard_.schedulerCurrentTimestamp() << std::endl;
|
andrewm@0
|
71 }
|
andrewm@0
|
72
|
andrewm@0
|
73 // Turn off mapping of data. Remove our callback from the scheduler
|
andrewm@0
|
74 void TouchkeyBaseMapping::disengage(bool shouldDelete) {
|
andrewm@0
|
75 // Remove OSC listeners first
|
andrewm@0
|
76 removeOscListener("/midi/noteon");
|
andrewm@0
|
77 removeOscListener("/midi/noteoff");
|
andrewm@0
|
78
|
andrewm@0
|
79 // Don't send any change in bend, let it stay where it is
|
andrewm@0
|
80
|
andrewm@0
|
81 Mapping::disengage(shouldDelete);
|
andrewm@0
|
82
|
andrewm@0
|
83 noteIsOn_ = false;
|
andrewm@0
|
84 }
|
andrewm@0
|
85
|
andrewm@0
|
86 // Reset state back to defaults
|
andrewm@0
|
87 void TouchkeyBaseMapping::reset() {
|
andrewm@0
|
88 Mapping::reset();
|
andrewm@0
|
89 noteIsOn_ = false;
|
andrewm@0
|
90 }
|
andrewm@0
|
91
|
andrewm@0
|
92 // Set the name of the control
|
andrewm@0
|
93 void TouchkeyBaseMapping::setName(const std::string& name) {
|
andrewm@0
|
94 controlName_ = name;
|
andrewm@0
|
95 }
|
andrewm@0
|
96
|
andrewm@0
|
97 // OSC handler method. Called from PianoKeyboard when MIDI data comes in.
|
andrewm@0
|
98 bool TouchkeyBaseMapping::oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data) {
|
andrewm@0
|
99 if(!strcmp(path, "/midi/noteon") && !noteIsOn_ && numValues >= 1) {
|
andrewm@0
|
100 if(types[0] == 'i' && values[0]->i == noteNumber_) {
|
andrewm@0
|
101 // First notify the subclass of this event
|
andrewm@0
|
102 if(numValues >= 3)
|
andrewm@0
|
103 midiNoteOnReceived(values[1]->i, values[2]->i);
|
andrewm@0
|
104
|
andrewm@0
|
105 // When the MIDI note goes on, if the mapping doesn't finish automatically,
|
andrewm@0
|
106 // make sure we indicate we're busy so the factory doesn't delete the mapping when
|
andrewm@0
|
107 // touch and MIDI both stop. In this case, the subclass is responsible for notifying
|
andrewm@0
|
108 // the factory when finished.
|
andrewm@0
|
109 if(!finishesAutomatically_)
|
andrewm@0
|
110 finished_ = false;
|
andrewm@0
|
111 noteIsOn_ = true;
|
andrewm@0
|
112 return false;
|
andrewm@0
|
113 }
|
andrewm@0
|
114 }
|
andrewm@0
|
115 else if(!strcmp(path, "/midi/noteoff") && noteIsOn_ && numValues >= 1) {
|
andrewm@0
|
116 if(types[0] == 'i' && values[0]->i == noteNumber_) {
|
andrewm@0
|
117 // MIDI note goes off.
|
andrewm@0
|
118
|
andrewm@0
|
119 // First notify the subclass of this event
|
andrewm@0
|
120 if(numValues >= 2)
|
andrewm@0
|
121 midiNoteOffReceived(values[1]->i);
|
andrewm@0
|
122
|
andrewm@0
|
123 noteIsOn_ = false;
|
andrewm@0
|
124 return false;
|
andrewm@0
|
125 }
|
andrewm@0
|
126 }
|
andrewm@0
|
127
|
andrewm@0
|
128 return false;
|
andrewm@0
|
129 }
|
andrewm@0
|
130
|
andrewm@0
|
131 // Override the requestFinish method to return whether the object
|
andrewm@0
|
132 // can be deleted now or not. If not, delete it when we've finished the
|
andrewm@0
|
133 // release processing
|
andrewm@0
|
134 bool TouchkeyBaseMapping::requestFinish() {
|
andrewm@0
|
135 finishRequested_ = true;
|
andrewm@0
|
136 return finished_;
|
andrewm@0
|
137 }
|
andrewm@0
|
138
|
andrewm@0
|
139 // Acknowledge that the mapping is finished. Only relevant if the mapping doesn't
|
andrewm@0
|
140 // finish automatically.
|
andrewm@0
|
141 void TouchkeyBaseMapping::acknowledgeFinish() {
|
andrewm@0
|
142 if(!finishRequested_ || finishesAutomatically_)
|
andrewm@0
|
143 return;
|
andrewm@0
|
144 factory_->mappingFinished(noteNumber_);
|
andrewm@0
|
145 }
|