diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index f5f75ce50d..52ec2dcd71 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -55,9 +55,9 @@ using namespace std; GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) : ControlProtocol (s, _("Generic MIDI"), midi_ui_context()) + , _motorised (false) , gui (0) { - _input_port = MIDI::Manager::instance()->midi_input_port (); _output_port = MIDI::Manager::instance()->midi_output_port (); @@ -320,7 +320,7 @@ GenericMidiControlProtocol::start_learning (Controllable* c) } if (!mc) { - mc = new MIDIControllable (*_input_port, *c, false); + mc = new MIDIControllable (this, *_input_port, *c, false); } { @@ -417,7 +417,7 @@ GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, MIDI::byte value = control_number; // Create a MIDIControllable - MIDIControllable* mc = new MIDIControllable (*_input_port, *control, false); + MIDIControllable* mc = new MIDIControllable (this, *_input_port, *control, false); // Remove any old binding for this midi channel/type/value pair // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information @@ -533,7 +533,7 @@ GenericMidiControlProtocol::set_state (const XMLNode& node, int version) cerr << "\tresult = " << c << endl; if (c) { - MIDIControllable* mc = new MIDIControllable (*_input_port, *c, false); + MIDIControllable* mc = new MIDIControllable (this, *_input_port, *c, false); if (mc->set_state (**niter, version) == 0) { controllables.push_back (mc); @@ -622,6 +622,12 @@ GenericMidiControlProtocol::load_bindings (const string& xmlpath) _bank_size = atoi (prop->value()); _current_bank = 0; } + + if ((prop = (*citer)->property ("motorised")) != 0) { + _motorised = string_is_affirmative (prop->value ()); + } else { + _motorised = false; + } } if ((*citer)->name() == "Binding") { @@ -714,7 +720,7 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node) prop = node.property (X_("uri")); uri = prop->value(); - MIDIControllable* mc = new MIDIControllable (*_input_port, momentary); + MIDIControllable* mc = new MIDIControllable (this, *_input_port, momentary); if (mc->init (uri)) { delete mc; diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.h b/libs/surfaces/generic_midi/generic_midi_control_protocol.h index 7ad23d9373..0cdb77567d 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.h +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.h @@ -81,6 +81,10 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { void next_bank (); void prev_bank (); + bool motorised () const { + return _motorised; + } + private: MIDI::Port* _input_port; MIDI::Port* _output_port; @@ -124,6 +128,12 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { std::string _current_binding; uint32_t _bank_size; uint32_t _current_bank; + /** true if this surface is motorised. If it is, we assume + that the surface's controls are never out of sync with + Ardour's state, so we don't have to take steps to avoid + values jumping around when things are not in sync. + */ + bool _motorised; mutable void *gui; void build_gui (); diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc index dd94dfe063..d9cd9425ae 100644 --- a/libs/surfaces/generic_midi/midicontrollable.cc +++ b/libs/surfaces/generic_midi/midicontrollable.cc @@ -33,14 +33,16 @@ #include "ardour/utils.h" #include "midicontrollable.h" +#include "generic_midi_control_protocol.h" using namespace std; using namespace MIDI; using namespace PBD; using namespace ARDOUR; -MIDIControllable::MIDIControllable (Port& p, bool m) - : controllable (0) +MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, bool m) + : _surface (s) + , controllable (0) , _descriptor (0) , _port (p) , _momentary (m) @@ -55,8 +57,9 @@ MIDIControllable::MIDIControllable (Port& p, bool m) feedback = true; // for now } -MIDIControllable::MIDIControllable (Port& p, Controllable& c, bool m) - : controllable (&c) +MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, Controllable& c, bool m) + : _surface (s) + , controllable (&c) , _descriptor (0) , _port (p) , _momentary (m) @@ -134,7 +137,7 @@ MIDIControllable::stop_learning () midi_learn_connection.disconnect (); } -float +int MIDIControllable::control_to_midi (float val) { if (controllable->is_gain_like()) { @@ -149,24 +152,24 @@ MIDIControllable::control_to_midi (float val) } float -MIDIControllable::midi_to_control (float val) +MIDIControllable::midi_to_control (int val) { /* fiddle with MIDI value so that we get an odd number of integer steps and can thus represent "middle" precisely as 0.5. this maps to the range 0..+1.0 */ - val = (val == 0.0f ? 0.0f : (val-1.0f) / (max_value_for_type() - 1)); + float fv = (val == 0 ? 0 : float (val - 1) / (max_value_for_type() - 1)); if (controllable->is_gain_like()) { - return slider_position_to_gain (val); + return slider_position_to_gain (fv); } float control_min = controllable->lower (); float control_max = controllable->upper (); const float control_range = control_max - control_min; - return (val * control_range) + control_min; + return (fv * control_range) + control_min; } void @@ -219,11 +222,19 @@ MIDIControllable::midi_sense_controller (Parser &, EventTwoBytes *msg) float range = max_value - min_value; float threshold = 10; - // prevent jumps when MIDI controller and controllable are "out of sync" - if (range < threshold && - controllable->get_value() <= midi_to_control(max_value) && - controllable->get_value() >= midi_to_control(min_value)) { - controllable->set_value (midi_to_control (new_value) ); + bool const in_sync = ( + range < threshold && + controllable->get_value() <= midi_to_control(max_value) && + controllable->get_value() >= midi_to_control(min_value) + ); + + /* If the surface is not motorised, we try to prevent jumps when + the MIDI controller and controllable are out of sync. + There might be a better way of doing this. + */ + + if (in_sync || _surface->motorised ()) { + controllable->set_value (midi_to_control (new_value)); } last_controllable_value = new_value; @@ -360,7 +371,7 @@ MIDIControllable::write_feedback (MIDI::byte* buf, int32_t& bufsize, bool /*forc return buf; } - float const gm = control_to_midi (controllable->get_value()); + int const gm = control_to_midi (controllable->get_value()); if (gm == last_value) { return buf; diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h index 1c2579069e..bf377b6651 100644 --- a/libs/surfaces/generic_midi/midicontrollable.h +++ b/libs/surfaces/generic_midi/midicontrollable.h @@ -40,11 +40,13 @@ namespace MIDI { class Parser; } +class GenericMidiControlProtocol; + class MIDIControllable : public PBD::Stateful { public: - MIDIControllable (MIDI::Port&, PBD::Controllable&, bool momentary); - MIDIControllable (MIDI::Port&, bool momentary = false); + MIDIControllable (GenericMidiControlProtocol *, MIDI::Port&, PBD::Controllable&, bool momentary); + MIDIControllable (GenericMidiControlProtocol *, MIDI::Port&, bool momentary = false); virtual ~MIDIControllable (); int init (const std::string&); @@ -65,8 +67,8 @@ class MIDIControllable : public PBD::Stateful bool get_midi_feedback () { return feedback; } void set_midi_feedback (bool val) { feedback = val; } - float control_to_midi(float val); - float midi_to_control(float val); + int control_to_midi(float val); + float midi_to_control(int val); bool learned() const { return _learned; } @@ -90,7 +92,8 @@ class MIDIControllable : public PBD::Stateful private: int max_value_for_type () const; - + + GenericMidiControlProtocol* _surface; PBD::Controllable* controllable; PBD::ControllableDescriptor* _descriptor; std::string _current_uri; diff --git a/midi_maps/bcf2000.map b/midi_maps/bcf2000.map index f8da879a4d..79f4206db8 100644 --- a/midi_maps/bcf2000.map +++ b/midi_maps/bcf2000.map @@ -5,7 +5,7 @@ - + diff --git a/midi_maps/bcf2000_mackie.map b/midi_maps/bcf2000_mackie.map index 06f0eeee97..3bcfb41166 100644 --- a/midi_maps/bcf2000_mackie.map +++ b/midi_maps/bcf2000_mackie.map @@ -4,7 +4,7 @@ - +