summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2012-03-07 01:11:22 +0000
committerCarl Hetherington <carl@carlh.net>2012-03-07 01:11:22 +0000
commitfb6895ba8634d86fc57f9638f0e0c61d32eb131f (patch)
tree1d2fc5fd692a3f4e8d1d29c50ee332d767cc438e
parent208703da535752a33f439e19afe2bd8493b79d0e (diff)
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
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.cc16
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.h10
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.cc41
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.h13
-rw-r--r--midi_maps/bcf2000.map2
-rw-r--r--midi_maps/bcf2000_mackie.map2
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 @@
<!-- Set the BCF2000 to factory preset number 2, and this will bind -->
<!-- the controllers intuitively to the DAW controllers. -->
<!-- -->
-<DeviceInfo bank-size="8"/>
+<DeviceInfo bank-size="8" motorised="yes"/>
<!-- Channel controls: -->
<!-- - the rotary encoder, when pushed, will -->
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 @@
<!-- Adapted by Carl Hetherington -->
<!-- Map for the Behringer BCF2000 in Mackie Control emulation mode -->
-<DeviceInfo bank-size="8"/>
+<DeviceInfo bank-size="8" motorised="yes"/>
<!-- Channel controls: -->
<!-- - the rotary encoder, when pushed, will -->