diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2015-11-23 12:26:23 -0500 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2015-11-23 12:27:51 -0500 |
commit | 3c9b71b50ebd24376c84d1d9917084b4d780b195 (patch) | |
tree | 3f2de814ad08e098c03763117b497d10b3f13781 /libs/surfaces | |
parent | 3095cbc4f96fc7bf4fe4f4e1ee966738face9206 (diff) |
allow use of (N)RPN messages in generic MIDI binding maps (UNTESTED)
Diffstat (limited to 'libs/surfaces')
-rw-r--r-- | libs/surfaces/generic_midi/generic_midi_control_protocol.cc | 26 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/midicontrollable.cc | 157 | ||||
-rw-r--r-- | libs/surfaces/generic_midi/midicontrollable.h | 13 |
3 files changed, 192 insertions, 4 deletions
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index 4b59151079..54bb65cb90 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -781,6 +781,10 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node) int intval; bool momentary; MIDIControllable::Encoder encoder = MIDIControllable::No_enc; + bool rpn_value = false; + bool nrpn_value = false; + bool rpn_change = false; + bool nrpn_change = false; if ((prop = node.property (X_("ctl"))) != 0) { ev = MIDI::controller; @@ -802,6 +806,14 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node) } else if ((prop = node.property (X_("enc-b"))) != 0) { encoder = MIDIControllable::Enc_B; ev = MIDI::controller; + } else if ((prop = node.property (X_("rpn"))) != 0) { + rpn_value = true; + } else if ((prop = node.property (X_("nrpn"))) != 0) { + nrpn_value = true; + } else if ((prop = node.property (X_("rpn-delta"))) != 0) { + rpn_change = true; + } else if ((prop = node.property (X_("nrpn-delta"))) != 0) { + nrpn_change = true; } else { return 0; } @@ -841,8 +853,18 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node) return 0; } - mc->set_encoder (encoder); - mc->bind_midi (channel, ev, detail); + if (rpn_value) { + mc->bind_rpn_value (channel, detail); + } else if (nrpn_value) { + mc->bind_nrpn_value (channel, detail); + } else if (rpn_change) { + mc->bind_rpn_change (channel, detail); + } else if (nrpn_change) { + mc->bind_nrpn_change (channel, detail); + } else { + mc->set_encoder (encoder); + mc->bind_midi (channel, ev, detail); + } return mc; } diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc index 9dca702e68..29271418a7 100644 --- a/libs/surfaces/generic_midi/midicontrollable.cc +++ b/libs/surfaces/generic_midi/midicontrollable.cc @@ -59,6 +59,8 @@ MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, MIDI::Parser& last_value = 0; // got a better idea ? last_controllable_value = 0.0f; control_type = none; + control_rpn = -1; + control_nrpn = -1; _control_description = "MIDI Control: none"; control_additional = (MIDI::byte) -1; feedback = true; // for now @@ -78,6 +80,8 @@ MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, MIDI::Parser& last_value = 0; // got a better idea ? last_controllable_value = 0.0f; control_type = none; + control_rpn = -1; + control_nrpn = -1; _control_description = "MIDI Control: none"; control_additional = (MIDI::byte) -1; feedback = true; // for now @@ -113,6 +117,8 @@ void MIDIControllable::drop_external_control () { midi_forget (); + control_rpn = -1; + control_nrpn = -1; control_type = none; control_additional = (MIDI::byte) -1; } @@ -445,6 +451,88 @@ MIDIControllable::midi_receiver (Parser &, MIDI::byte *msg, size_t /*len*/) } void +MIDIControllable::rpn_value_change (Parser&, uint16_t rpn, float val) +{ + if (control_rpn == rpn) { + if (controllable) { + controllable->set_value (val); + } + } +} + +void +MIDIControllable::nrpn_value_change (Parser&, uint16_t nrpn, float val) +{ + if (control_nrpn == nrpn) { + if (controllable) { + controllable->set_value (val); + } + } +} + +void +MIDIControllable::rpn_change (Parser&, uint16_t rpn, int dir) +{ + if (control_rpn == rpn) { + if (controllable) { + /* XXX how to increment/decrement ? */ + // controllable->set_value (val); + } + } +} + +void +MIDIControllable::nrpn_change (Parser&, uint16_t nrpn, int dir) +{ + if (control_nrpn == nrpn) { + if (controllable) { + /* XXX how to increment/decrement ? */ + // controllable->set_value (val); + } + } +} + +void +MIDIControllable::bind_rpn_value (channel_t chn, uint16_t rpn) +{ + int chn_i = chn; + drop_external_control (); + control_rpn = rpn; + control_channel = chn; + _parser.channel_rpn[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::rpn_value_change, this, _1, _2, _3)); +} + +void +MIDIControllable::bind_nrpn_value (channel_t chn, uint16_t nrpn) +{ + int chn_i = chn; + drop_external_control (); + control_nrpn = nrpn; + control_channel = chn; + _parser.channel_nrpn[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::rpn_value_change, this, _1, _2, _3)); +} + +void +MIDIControllable::bind_nrpn_change (channel_t chn, uint16_t nrpn) +{ + int chn_i = chn; + drop_external_control (); + control_nrpn = nrpn; + control_channel = chn; + _parser.channel_nrpn_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::rpn_change, this, _1, _2, _3)); +} + +void +MIDIControllable::bind_rpn_change (channel_t chn, uint16_t rpn) +{ + int chn_i = chn; + drop_external_control (); + control_rpn = rpn; + control_channel = chn; + _parser.channel_rpn_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::nrpn_change, this, _1, _2, _3)); +} + +void MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) { char buf[64]; @@ -504,11 +592,76 @@ MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) MIDI::byte* MIDIControllable::write_feedback (MIDI::byte* buf, int32_t& bufsize, bool /*force*/) { - if (!controllable || control_type == none || !feedback || bufsize <= 2) { + if (!controllable || !feedback) { + return buf; + } + + float val = controllable->get_value (); + + /* Note that when sending RPN/NPRN we do two things: + * + * always send MSB first, then LSB + * null/reset the parameter ID after sending. + * + * this follows recommendations found online, eg. http://www.philrees.co.uk/nrpnq.htm + */ + + if (control_rpn >= 0) { + if (bufsize < 13) { + return buf; + } + int rpn_val = (int) lrintf (val * 16384.0); + if (last_value == rpn_val) { + return buf; + } + *buf++ = (0xb0) | control_channel; + *buf++ = 0x62; + *buf++ = (int) ((control_rpn) >> 7); + *buf++ = 0x63; + *buf++ = (int) (control_rpn & 0x7f); + *buf++ = 0x06; + *buf++ = (int) (rpn_val >> 7); + *buf++ = 0x26; + *buf++ = (int) (rpn_val & 0x7f); + *buf++ = 0x62; + *buf++ = 0x7f; + *buf++ = 0x63; + *buf++ = 0x7f; + bufsize -= 13; + last_value = rpn_val; + DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI out: RPN %1 Channel %2 Value %3\n", control_rpn, (int) control_channel, val)); + return buf; + } + + if (control_nrpn >= 0) { + int rpn_val = (int) lrintf (val * 16384.0); + if (last_value == rpn_val) { + return buf; + } + *buf++ = (0xb0) | control_channel; + *buf++ = 0x64; + *buf++ = (int) ((control_rpn) >> 7); + *buf++ = 0x65; + *buf++ = (int) (control_rpn & 0x7f); + *buf++ = 0x06; + *buf++ = (int) (rpn_val >> 7); + *buf++ = 0x26; + *buf++ = (int) (rpn_val & 0x7f); + *buf++ = 0x64; + *buf++ = 0x7f; + *buf++ = 0x65; + *buf++ = 0x7f; + last_value = rpn_val; + bufsize -= 13; + DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI out: NRPN %1 Channel %2 Value %3\n", control_nrpn, (int) control_channel, val)); + return buf; + } + + if (control_type == none || bufsize <= 2) { return buf; } - int const gm = control_to_midi (controllable->get_value()); + int const gm = control_to_midi (val); if (gm == last_value) { return buf; diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h index 2e5d41c5d6..a19e3a1a28 100644 --- a/libs/surfaces/generic_midi/midicontrollable.h +++ b/libs/surfaces/generic_midi/midicontrollable.h @@ -99,6 +99,11 @@ class MIDIControllable : public PBD::Stateful int set_state (const XMLNode&, int version); void bind_midi (MIDI::channel_t, MIDI::eventType, MIDI::byte); + void bind_rpn_value (MIDI::channel_t, uint16_t rpn); + void bind_nrpn_value (MIDI::channel_t, uint16_t rpn); + void bind_rpn_change (MIDI::channel_t, uint16_t rpn); + void bind_nrpn_change (MIDI::channel_t, uint16_t rpn); + MIDI::channel_t get_control_channel () { return control_channel; } MIDI::eventType get_control_type () { return control_type; } MIDI::byte get_control_additional () { return control_additional; } @@ -130,6 +135,8 @@ class MIDIControllable : public PBD::Stateful MIDI::byte control_additional; MIDI::channel_t control_channel; std::string _control_description; + int16_t control_rpn; + int16_t control_nrpn; bool feedback; uint32_t _rid; std::string _what; @@ -144,6 +151,12 @@ class MIDIControllable : public PBD::Stateful void midi_sense_controller (MIDI::Parser &, MIDI::EventTwoBytes *); void midi_sense_program_change (MIDI::Parser &, MIDI::byte); void midi_sense_pitchbend (MIDI::Parser &, MIDI::pitchbend_t); + + void nrpn_value_change (MIDI::Parser&, uint16_t nrpn, float val); + void rpn_value_change (MIDI::Parser&, uint16_t nrpn, float val); + void rpn_change (MIDI::Parser&, uint16_t nrpn, int direction); + void nrpn_change (MIDI::Parser&, uint16_t nrpn, int direction); + }; #endif // __gm_midicontrollable_h__ |