From fb6895ba8634d86fc57f9638f0e0c61d32eb131f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 7 Mar 2012 01:11:22 +0000 Subject: [PATCH] Add motorised attribute to DeviceInfo for generic MIDI maps so that we can specify if a surface is motorised, and as such will keep its phyiscal controls in sync with Ardour's controllables at all times. If this is not the case, we enable the code to avoid jumps when controls and controllables are out of sync. Mark the BCF2000 as motorised. git-svn-id: svn://localhost/ardour2/branches/3.0@11611 d708f5d6-7413-0410-9779-e7cbd77b26cf --- .../generic_midi_control_protocol.cc | 16 +++++--- .../generic_midi_control_protocol.h | 10 +++++ .../surfaces/generic_midi/midicontrollable.cc | 41 ++++++++++++------- libs/surfaces/generic_midi/midicontrollable.h | 13 +++--- midi_maps/bcf2000.map | 2 +- midi_maps/bcf2000_mackie.map | 2 +- 6 files changed, 57 insertions(+), 27 deletions(-) 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 @@ - +