summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.cc24
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.cc95
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.h7
3 files changed, 61 insertions, 65 deletions
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
index 05a3ef0505..f5f75ce50d 100644
--- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
+++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
@@ -259,17 +259,18 @@ GenericMidiControlProtocol::_send_feedback ()
const int32_t bufsize = 16 * 1024; /* XXX too big */
MIDI::byte buf[bufsize];
int32_t bsize = bufsize;
- MIDI::byte* end = buf;
-
+
+ /* XXX: due to bugs in some ALSA / JACK MIDI bridges, we have to do separate
+ writes for each controllable here; if we send more than one MIDI message
+ in a single jack_midi_event_write then some bridges will only pass the
+ first on to ALSA.
+ */
for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
- end = (*r)->write_feedback (end, bsize);
+ MIDI::byte* end = (*r)->write_feedback (buf, bsize);
+ if (end != buf) {
+ _output_port->write (buf, (int32_t) (end - buf), 0);
+ }
}
-
- if (end == buf) {
- return;
- }
-
- _output_port->write (buf, (int32_t) (end - buf), 0);
}
bool
@@ -574,9 +575,6 @@ GenericMidiControlProtocol::get_feedback () const
return do_feedback;
}
-
-
-
int
GenericMidiControlProtocol::load_bindings (const string& xmlpath)
{
@@ -682,6 +680,8 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node)
ev = MIDI::on;
} else if ((prop = node.property (X_("pgm"))) != 0) {
ev = MIDI::program;
+ } else if ((prop = node.property (X_("pb"))) != 0) {
+ ev = MIDI::pitchbend;
} else {
return 0;
}
diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc
index 226502f0ae..dd94dfe063 100644
--- a/libs/surfaces/generic_midi/midicontrollable.cc
+++ b/libs/surfaces/generic_midi/midicontrollable.cc
@@ -137,30 +137,26 @@ MIDIControllable::stop_learning ()
float
MIDIControllable::control_to_midi (float val)
{
- const float midi_range = 127.0f; // TODO: NRPN etc.
-
if (controllable->is_gain_like()) {
- return gain_to_slider_position (val/midi_range);
+ return gain_to_slider_position (val) * max_value_for_type ();
}
float control_min = controllable->lower ();
float control_max = controllable->upper ();
const float control_range = control_max - control_min;
- return (val - control_min) / control_range * midi_range;
+ return (val - control_min) / control_range * max_value_for_type ();
}
float
-MIDIControllable::midi_to_control(float val)
+MIDIControllable::midi_to_control (float 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
-
- TODO: 14bit values
*/
- val = (val == 0.0f ? 0.0f : (val-1.0f) / 126.0f);
+ val = (val == 0.0f ? 0.0f : (val-1.0f) / (max_value_for_type() - 1));
if (controllable->is_gain_like()) {
return slider_position_to_gain (val);
@@ -192,11 +188,9 @@ MIDIControllable::midi_sense_note (Parser &, EventTwoBytes *msg, bool /*is_on*/)
return;
}
-
if (!controllable->is_toggle()) {
- controllable->set_value (msg->note_number/127.0);
+ controllable->set_value (midi_to_control (msg->note_number));
} else {
-
if (control_additional == msg->note_number) {
controllable->set_value (controllable->get_value() > 0.5f ? 0.0f : 1.0f);
}
@@ -253,7 +247,7 @@ MIDIControllable::midi_sense_program_change (Parser &, byte msg)
}
if (!controllable->is_toggle()) {
- controllable->set_value (msg/127.0);
+ controllable->set_value (midi_to_control (msg));
} else {
controllable->set_value (controllable->get_value() > 0.5f ? 0.0f : 1.0f);
}
@@ -269,13 +263,12 @@ MIDIControllable::midi_sense_pitchbend (Parser &, pitchbend_t pb)
}
if (!controllable->is_toggle()) {
- /* XXX gack - get rid of assumption about typeof pitchbend_t */
- controllable->set_value ((pb/(float) SHRT_MAX));
+ controllable->set_value (midi_to_control (pb));
} else {
controllable->set_value (controllable->get_value() > 0.5f ? 0.0f : 1.0f);
}
- last_value = (MIDI::byte) (controllable->get_value() * 127.0); // to prevent feedback fights
+ last_value = control_to_midi (controllable->get_value ());
}
void
@@ -360,49 +353,35 @@ MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional)
}
}
-void
-MIDIControllable::send_feedback ()
-{
- byte msg[3];
-
- if (!_learned || setting || !feedback || control_type == none || !controllable) {
- return;
- }
-
- msg[0] = (control_type & 0xF0) | (control_channel & 0xF);
- msg[1] = control_additional;
-
- if (controllable->is_gain_like()) {
- msg[2] = (byte) lrintf (gain_to_slider_position (controllable->get_value()) * 127.0f);
- } else {
- msg[2] = (byte) (control_to_midi(controllable->get_value()));
- }
-
- _port.write (msg, 3, 0);
-}
-
MIDI::byte*
MIDIControllable::write_feedback (MIDI::byte* buf, int32_t& bufsize, bool /*force*/)
{
- if (controllable && control_type != none && feedback && bufsize > 2) {
-
- MIDI::byte gm;
+ if (!controllable || control_type == none || !feedback || bufsize <= 2) {
+ return buf;
+ }
+
+ float const gm = control_to_midi (controllable->get_value());
- if (controllable->is_gain_like()) {
- gm = (byte) lrintf (gain_to_slider_position (controllable->get_value()) * 127.0f);
- } else {
- gm = (byte) (control_to_midi(controllable->get_value()));
- }
+ if (gm == last_value) {
+ return buf;
+ }
- if (gm != last_value) {
- *buf++ = (0xF0 & control_type) | (0xF & control_channel);
- *buf++ = control_additional; /* controller number */
- *buf++ = gm;
- last_value = gm;
- bufsize -= 3;
- }
+ *buf++ = (0xF0 & control_type) | (0xF & control_channel);
+
+ switch (control_type) {
+ case MIDI::pitchbend:
+ *buf++ = int (gm) & 127;
+ *buf++ = (int (gm) >> 7) & 127;
+ break;
+ default:
+ *buf++ = control_additional; /* controller number */
+ *buf++ = gm;
+ break;
}
+ last_value = gm;
+ bufsize -= 3;
+
return buf;
}
@@ -470,3 +449,17 @@ MIDIControllable::get_state ()
return *node;
}
+/** @return the maximum value for a control value transmitted
+ * using a given MIDI::eventType.
+ */
+int
+MIDIControllable::max_value_for_type () const
+{
+ /* XXX: this is not complete */
+
+ if (control_type == MIDI::pitchbend) {
+ return 16383;
+ }
+
+ return 127;
+}
diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h
index 5f188d1688..1c2579069e 100644
--- a/libs/surfaces/generic_midi/midicontrollable.h
+++ b/libs/surfaces/generic_midi/midicontrollable.h
@@ -54,7 +54,6 @@ class MIDIControllable : public PBD::Stateful
uint32_t rid() const { return _rid; }
std::string what() const { return _what; }
- void send_feedback ();
MIDI::byte* write_feedback (MIDI::byte* buf, int32_t& bufsize, bool force = false);
void midi_rebind (MIDI::channel_t channel=-1);
@@ -89,12 +88,15 @@ class MIDIControllable : public PBD::Stateful
MIDI::byte get_control_additional () { return control_additional; }
private:
+
+ int max_value_for_type () const;
+
PBD::Controllable* controllable;
PBD::ControllableDescriptor* _descriptor;
std::string _current_uri;
MIDI::Port& _port;
bool setting;
- MIDI::byte last_value;
+ int last_value;
float last_controllable_value;
bool _momentary;
bool _is_gain_controller;
@@ -102,6 +104,7 @@ class MIDIControllable : public PBD::Stateful
int midi_msg_id; /* controller ID or note number */
PBD::ScopedConnection midi_sense_connection[2];
PBD::ScopedConnection midi_learn_connection;
+ /** the type of MIDI message that is used for this control */
MIDI::eventType control_type;
MIDI::byte control_additional;
MIDI::channel_t control_channel;