andrewm@0: /*
andrewm@0: TouchKeys: multi-touch musical keyboard control software
andrewm@0: Copyright (c) 2013 Andrew McPherson
andrewm@0:
andrewm@0: This program is free software: you can redistribute it and/or modify
andrewm@0: it under the terms of the GNU General Public License as published by
andrewm@0: the Free Software Foundation, either version 3 of the License, or
andrewm@0: (at your option) any later version.
andrewm@0:
andrewm@0: This program is distributed in the hope that it will be useful,
andrewm@0: but WITHOUT ANY WARRANTY; without even the implied warranty of
andrewm@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
andrewm@0: GNU General Public License for more details.
andrewm@0:
andrewm@0: You should have received a copy of the GNU General Public License
andrewm@0: along with this program. If not, see .
andrewm@0:
andrewm@0: =====================================================================
andrewm@0:
andrewm@0: TouchkeyBaseMapping.cpp: base class from which all TouchKeys-specific
andrewm@0: mappings derive. Like its Mapping parent class, it handles a mapping
andrewm@0: for one specific note.
andrewm@0: */
andrewm@0:
andrewm@0: #include "TouchkeyBaseMapping.h"
andrewm@0: #include "MappingFactory.h"
andrewm@0: #include "../TouchKeys/MidiOutputController.h"
andrewm@0:
andrewm@0: // Main constructor takes references/pointers from objects which keep track
andrewm@0: // of touch location, continuous key position and the state detected from that
andrewm@0: // position. The PianoKeyboard object is strictly required as it gives access to
andrewm@0: // Scheduler and OSC methods. The others are optional since any given system may
andrewm@0: // contain only one of continuous key position or touch sensitivity
andrewm@0: TouchkeyBaseMapping::TouchkeyBaseMapping(PianoKeyboard &keyboard, MappingFactory *factory, int noteNumber, Node* touchBuffer,
andrewm@0: Node* positionBuffer, KeyPositionTracker* positionTracker,
andrewm@0: bool finishesAutomatically)
andrewm@0: : Mapping(keyboard, factory, noteNumber, touchBuffer, positionBuffer, positionTracker),
andrewm@0: controlName_(""), noteIsOn_(false), finished_(true), finishRequested_(false), finishesAutomatically_(finishesAutomatically)
andrewm@0: {
andrewm@0: setOscController(&keyboard_);
andrewm@0: }
andrewm@0:
andrewm@0: // Copy constructor
andrewm@0: /*TouchkeyBaseMapping::TouchkeyBaseMapping(TouchkeyBaseMapping const& obj)
andrewm@0: : Mapping(obj), noteIsOn_(obj.noteIsOn_), finished_(obj.finished_), finishRequested_(obj.finishRequested_),
andrewm@0: finishesAutomatically_(obj.finishesAutomatically_)
andrewm@0: {
andrewm@0: setOscController(&keyboard_);
andrewm@0: }*/
andrewm@0:
andrewm@0: TouchkeyBaseMapping::~TouchkeyBaseMapping() {
andrewm@0: #ifndef NEW_MAPPING_SCHEDULER
andrewm@0: try {
andrewm@0: disengage();
andrewm@0: }
andrewm@0: catch(...) {
andrewm@0: std::cerr << "~TouchkeyBaseMapping(): exception during disengage()\n";
andrewm@0: }
andrewm@0: #endif
andrewm@0: }
andrewm@0:
andrewm@0: // Turn on mapping of data.
andrewm@0: void TouchkeyBaseMapping::engage() {
andrewm@0: Mapping::engage();
andrewm@0:
andrewm@0: // Register for OSC callbacks on MIDI note on/off
andrewm@0: addOscListener("/midi/noteon");
andrewm@0: addOscListener("/midi/noteoff");
andrewm@0:
andrewm@0: //cout << "TouchkeyBaseMapping::engage(): after TS " << keyboard_.schedulerCurrentTimestamp() << std::endl;
andrewm@0: }
andrewm@0:
andrewm@0: // Turn off mapping of data. Remove our callback from the scheduler
andrewm@0: void TouchkeyBaseMapping::disengage(bool shouldDelete) {
andrewm@0: // Remove OSC listeners first
andrewm@0: removeOscListener("/midi/noteon");
andrewm@0: removeOscListener("/midi/noteoff");
andrewm@0:
andrewm@0: // Don't send any change in bend, let it stay where it is
andrewm@0:
andrewm@0: Mapping::disengage(shouldDelete);
andrewm@0:
andrewm@0: noteIsOn_ = false;
andrewm@0: }
andrewm@0:
andrewm@0: // Reset state back to defaults
andrewm@0: void TouchkeyBaseMapping::reset() {
andrewm@0: Mapping::reset();
andrewm@0: noteIsOn_ = false;
andrewm@0: }
andrewm@0:
andrewm@0: // Set the name of the control
andrewm@0: void TouchkeyBaseMapping::setName(const std::string& name) {
andrewm@0: controlName_ = name;
andrewm@0: }
andrewm@0:
andrewm@0: // OSC handler method. Called from PianoKeyboard when MIDI data comes in.
andrewm@0: bool TouchkeyBaseMapping::oscHandlerMethod(const char *path, const char *types, int numValues, lo_arg **values, void *data) {
andrewm@0: if(!strcmp(path, "/midi/noteon") && !noteIsOn_ && numValues >= 1) {
andrewm@0: if(types[0] == 'i' && values[0]->i == noteNumber_) {
andrewm@0: // First notify the subclass of this event
andrewm@0: if(numValues >= 3)
andrewm@0: midiNoteOnReceived(values[1]->i, values[2]->i);
andrewm@0:
andrewm@0: // When the MIDI note goes on, if the mapping doesn't finish automatically,
andrewm@0: // make sure we indicate we're busy so the factory doesn't delete the mapping when
andrewm@0: // touch and MIDI both stop. In this case, the subclass is responsible for notifying
andrewm@0: // the factory when finished.
andrewm@0: if(!finishesAutomatically_)
andrewm@0: finished_ = false;
andrewm@0: noteIsOn_ = true;
andrewm@0: return false;
andrewm@0: }
andrewm@0: }
andrewm@0: else if(!strcmp(path, "/midi/noteoff") && noteIsOn_ && numValues >= 1) {
andrewm@0: if(types[0] == 'i' && values[0]->i == noteNumber_) {
andrewm@0: // MIDI note goes off.
andrewm@0:
andrewm@0: // First notify the subclass of this event
andrewm@0: if(numValues >= 2)
andrewm@0: midiNoteOffReceived(values[1]->i);
andrewm@0:
andrewm@0: noteIsOn_ = false;
andrewm@0: return false;
andrewm@0: }
andrewm@0: }
andrewm@0:
andrewm@0: return false;
andrewm@0: }
andrewm@0:
andrewm@0: // Override the requestFinish method to return whether the object
andrewm@0: // can be deleted now or not. If not, delete it when we've finished the
andrewm@0: // release processing
andrewm@0: bool TouchkeyBaseMapping::requestFinish() {
andrewm@0: finishRequested_ = true;
andrewm@0: return finished_;
andrewm@0: }
andrewm@0:
andrewm@0: // Acknowledge that the mapping is finished. Only relevant if the mapping doesn't
andrewm@0: // finish automatically.
andrewm@0: void TouchkeyBaseMapping::acknowledgeFinish() {
andrewm@0: if(!finishRequested_ || finishesAutomatically_)
andrewm@0: return;
andrewm@0: factory_->mappingFinished(noteNumber_);
andrewm@0: }