summaryrefslogtreecommitdiff
path: root/libs/surfaces/generic_midi
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2018-06-21 22:28:11 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2018-06-21 22:28:11 -0400
commit8725ed5bd1affa2e43023e9ab99e55a67866ba31 (patch)
tree3f39a0904736d3bac7ad22ffbabf26fd5dd8bcc3 /libs/surfaces/generic_midi
parent870625973e4fff58d3b6b94ef14a7160c3279620 (diff)
add Ctl_Dial to get better behaviour when binding a MIDI controller KNOB/DIAL to a toggled controllable.
No intent to change Ctl_Momentary or Ctl_Toggle behaviour, plus I tried to document what they are intended to support
Diffstat (limited to 'libs/surfaces/generic_midi')
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.cc3
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.cc63
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.h2
3 files changed, 42 insertions, 26 deletions
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
index 560bd43e57..a620998a1c 100644
--- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
+++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
@@ -836,6 +836,9 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node)
} else if ((prop = node.property (X_("ctl-toggle"))) !=0) {
ctltype = MIDIControllable::Ctl_Toggle;
ev = MIDI::controller;
+ } else if ((prop = node.property (X_("ctl-dial"))) !=0) {
+ ctltype = MIDIControllable::Ctl_Dial;
+ ev = MIDI::controller;
} else if ((prop = node.property (X_("note"))) != 0) {
ev = MIDI::on;
} else if ((prop = node.property (X_("pgm"))) != 0) {
diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc
index 13b47a4d7c..cbf525bd1b 100644
--- a/libs/surfaces/generic_midi/midicontrollable.cc
+++ b/libs/surfaces/generic_midi/midicontrollable.cc
@@ -56,6 +56,7 @@ MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, MIDI::Parser&
_encoder = No_enc;
setting = false;
last_value = 0; // got a better idea ?
+ last_incoming = 256; // any out of band value
last_controllable_value = 0.0f;
control_type = none;
control_rpn = -1;
@@ -135,6 +136,8 @@ MIDIControllable::set_controllable (Controllable* c)
last_controllable_value = 0.0f; // is there a better value?
}
+ last_incoming = 256;
+
if (controllable) {
controllable->Destroyed.connect (controllable_death_connection, MISSING_INVALIDATOR,
boost::bind (&MIDIControllable::drop_controllable, this, _1),
@@ -372,32 +375,40 @@ MIDIControllable::midi_sense_controller (Parser &, EventTwoBytes *msg)
}
} else {
- /* toggle control: make the toggle flip only if the
- * incoming control value exceeds 0.5 (0x40), so that
- * the typical button which sends "CC N=0x7f" on press
- * and "CC N=0x0" on release can be used to drive
- * toggles on press.
- *
- * No other arrangement really makes sense for a toggle
- * controllable. Acting on the press+release makes the
- * action momentary, which is almost never
- * desirable. If the physical button only sends a
- * message on press (or release), then it will be
- * expected to send a controller value >= 0.5
- * (0x40). It is hard to imagine why anyone would make
- * a MIDI controller button that sent 0x0 when pressed.
- */
- if (msg->value >= 0x40) {
- controllable->set_value (controllable->get_value() >= 0.5 ? 0.0 : 1.0, Controllable::UseGroup);
- DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Midi CC %1 value 1 %2\n", (int) msg->controller_number, current_uri()));
- } else {
- switch (get_ctltype()) {
- case Ctl_Momentary:
- break;
- case Ctl_Toggle:
- controllable->set_value (0.0, Controllable::NoGroup);
- DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Midi CC %1 value 0 %2\n", (int) msg->controller_number, current_uri()));
- break;
+ switch (get_ctltype()) {
+ case Ctl_Dial:
+ /* toggle value whenever direction of knob motion changes */
+ if (last_incoming > 127) {
+ /* relax ... first incoming message */
+ } else {
+ if (msg->value > last_incoming) {
+ controllable->set_value (1.0, Controllable::UseGroup);
+ } else {
+ controllable->set_value (0.0, Controllable::UseGroup);
+ }
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("dial Midi CC %1 value 1 %2\n", (int) msg->controller_number, current_uri()));
+ }
+ last_incoming = msg->value;
+ break;
+ case Ctl_Momentary:
+ /* toggle it if over 64, otherwise leave it alone. This behaviour that works with buttons which send a value > 64 each
+ * time they are pressed.
+ */
+ if (msg->value >= 0x40) {
+ controllable->set_value (controllable->get_value() >= 0.5 ? 0.0 : 1.0, Controllable::UseGroup);
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("toggle Midi CC %1 value 1 %2\n", (int) msg->controller_number, current_uri()));
+ }
+ break;
+ case Ctl_Toggle:
+ /* toggle if value is over 64, otherwise turn it off. This is behaviour designed for buttons which send a value > 64 when pressed,
+ maintain state (i.e. they know they were pressed) and then send zero the next time.
+ */
+ if (msg->value >= 0x40) {
+ controllable->set_value (controllable->get_value() >= 0.5 ? 0.0 : 1.0, Controllable::UseGroup);
+ } else {
+ controllable->set_value (0.0, Controllable::NoGroup);
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Midi CC %1 value 0 %2\n", (int) msg->controller_number, current_uri()));
+ break;
}
}
}
diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h
index b8c69e036e..b795067a61 100644
--- a/libs/surfaces/generic_midi/midicontrollable.h
+++ b/libs/surfaces/generic_midi/midicontrollable.h
@@ -58,6 +58,7 @@ class MIDIControllable : public PBD::Stateful
enum CtlType {
Ctl_Momentary,
Ctl_Toggle,
+ Ctl_Dial,
};
enum Encoder {
@@ -119,6 +120,7 @@ class MIDIControllable : public PBD::Stateful
MIDI::Parser& _parser;
bool setting;
int last_value;
+ int last_incoming;
float last_controllable_value;
bool _momentary;
bool _is_gain_controller;