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:
parent
c6396ca7ce
commit
fe86f97563
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user