13
0

Work around problems with some JACK<->ALSA midi bridges which don't

transfer multiple MIDI messages when they are written in one
jack_midi_event_write.  Support pitch bend messages in the
generic midi control surface code.


git-svn-id: svn://localhost/ardour2/branches/3.0@11601 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2012-03-06 15:08:17 +00:00
parent c6396ca7ce
commit fe86f97563
3 changed files with 64 additions and 68 deletions

View File

@ -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;
for (MIDIControllables::iterator r = controllables.begin(); r != controllables.end(); ++r) {
end = (*r)->write_feedback (end, bsize);
}
if (end == buf) {
return;
}
_output_port->write (buf, (int32_t) (end - buf), 0);
/* 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) {
MIDI::byte* end = (*r)->write_feedback (buf, bsize);
if (end != buf) {
_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;
}

View File

@ -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,48 +353,34 @@ 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->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) {
*buf++ = (0xF0 & control_type) | (0xF & control_channel);
*buf++ = control_additional; /* controller number */
*buf++ = gm;
last_value = gm;
bufsize -= 3;
}
if (!controllable || control_type == none || !feedback || bufsize <= 2) {
return buf;
}
float const gm = control_to_midi (controllable->get_value());
if (gm == last_value) {
return buf;
}
*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;
}

View File

@ -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;