summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 -->