#include "pbd/controllable_descriptor.h"
#include "pbd/xml++.h"
#include "pbd/stacktrace.h"
+#include "pbd/compose.h"
#include "midi++/types.h" // Added by JE - 06-01-2009. All instances of 'byte' changed to 'MIDI::byte' (for clarification)
#include "midi++/port.h"
#include "ardour/automation_control.h"
#include "ardour/midi_ui.h"
#include "ardour/utils.h"
+#include "ardour/debug.h"
#include "midicontrollable.h"
#include "generic_midi_control_protocol.h"
, _momentary (m)
{
_learned = false; /* from URI */
+ _encoder = No_enc;
setting = false;
last_value = 0; // got a better idea ?
last_controllable_value = 0.0f;
, _momentary (m)
{
set_controllable (&c);
-
+
_learned = true; /* from controllable */
+ _encoder = No_enc;
setting = false;
last_value = 0; // got a better idea ?
last_controllable_value = 0.0f;
if (c == controllable) {
return;
}
-
+
controllable_death_connection.disconnect ();
controllable = c;
if (controllable) {
controllable->Destroyed.connect (controllable_death_connection, MISSING_INVALIDATOR,
- boost::bind (&MIDIControllable::drop_controllable, this),
+ boost::bind (&MIDIControllable::drop_controllable, this),
MidiControlUI::instance());
}
}
val = actl->internal_to_interface(val);
}
}
-
- return (val - control_min) / control_range * max_value_for_type ();
+ // fiddle value of max so value doesn't jump from 125 to 127 for 1.0
+ // otherwise decrement won't work.
+ return (val - control_min) / control_range * (max_value_for_type () - 1);
}
float
{
/* 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
+ the range 0..+1.0 (0 to 126)
*/
float fv = (val == 0 ? 0 : float (val - 1) / (max_value_for_type() - 1));
void
MIDIControllable::midi_sense_note (Parser &, EventTwoBytes *msg, bool /*is_on*/)
{
- if (!controllable) {
+ if (!controllable) {
if (lookup_controllable()) {
return;
}
if (!controllable->is_toggle()) {
if (control_additional == msg->note_number) {
controllable->set_value (midi_to_control (msg->velocity));
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Note %1 value %2 %3\n", (int) msg->note_number, (float) midi_to_control (msg->velocity), current_uri() ));
}
} else {
if (control_additional == msg->note_number) {
- controllable->set_value (controllable->get_value() > 0.5f ? 0.0f : 1.0f);
+ float new_value = controllable->get_value() > 0.5f ? 0.0f : 1.0f;
+ controllable->set_value (new_value);
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Note %1 Value %2 %3\n", (int) msg->note_number, (float) new_value, current_uri()));
}
}
void
MIDIControllable::midi_sense_controller (Parser &, EventTwoBytes *msg)
{
- if (!controllable) {
+ if (!controllable) {
if (lookup_controllable ()) {
return;
}
if (control_additional == msg->controller_number) {
if (!controllable->is_toggle()) {
+ if (get_encoder() == No_enc) {
+ float new_value = msg->value;
+ float max_value = max(last_controllable_value, new_value);
+ float min_value = min(last_controllable_value, new_value);
+ float range = max_value - min_value;
+ float threshold = (float) _surface->threshold ();
+
+ 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));
+ }
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI CC %1 value %2 %3\n", (int) msg->controller_number, (float) midi_to_control(new_value), current_uri() ));
+
+ last_controllable_value = new_value;
+ } else {
+ int offset = (msg->value & 0x3f);
+ switch (get_encoder()) {
+ case Enc_L:
+ if (msg->value > 0x40) {
+ controllable->set_value (midi_to_control (last_value - offset + 1));
+ } else {
+ controllable->set_value (midi_to_control (last_value + offset + 1));
+ }
+ break;
+ case Enc_R:
+ if (msg->value > 0x40) {
+ controllable->set_value (midi_to_control (last_value + offset + 1));
+ } else {
+ controllable->set_value (midi_to_control (last_value - offset + 1));
+ }
+ break;
+ case Enc_2:
+ if (msg->value > 0x40) {
+ controllable->set_value (midi_to_control (last_value - (0x7f - msg->value) + 1));
+ } else {
+ controllable->set_value (midi_to_control (last_value + offset + 1));
+ }
+ break;
+ case Enc_B:
+ if (msg->value > 0x40) {
+ controllable->set_value (midi_to_control (last_value + offset + 1));
+ } else {
+ controllable->set_value (midi_to_control (last_value - (0x40 - offset)));
+ }
+ break;
+ default:
+ break;
+ }
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI CC %1 value %2 %3\n", (int) msg->controller_number, (int) last_value, current_uri() ));
- float new_value = msg->value;
- float max_value = max(last_controllable_value, new_value);
- float min_value = min(last_controllable_value, new_value);
- float range = max_value - min_value;
- float threshold = (float) _surface->threshold ();
-
- 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;
} else {
if (msg->value > 64.0f) {
controllable->set_value (1);
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Midi CC %1 value 1 %2\n", (int) msg->controller_number, current_uri()));
} else {
controllable->set_value (0);
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Midi CC %1 value 0 %2\n", (int) msg->controller_number, current_uri()));
}
}
void
MIDIControllable::midi_sense_program_change (Parser &, MIDI::byte msg)
{
- if (!controllable) {
+ if (!controllable) {
if (lookup_controllable ()) {
return;
}
}
+ if (msg == control_additional) {
- if (!controllable->is_toggle()) {
- controllable->set_value (midi_to_control (msg));
- } else if (msg == control_additional) {
- controllable->set_value (controllable->get_value() > 0.5f ? 0.0f : 1.0f);
+ if (!controllable->is_toggle()) {
+ controllable->set_value (1.0);
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI program %1 value 1.0 %3\n", (int) msg, current_uri() ));
+ } else {
+ float new_value = controllable->get_value() > 0.5f ? 0.0f : 1.0f;
+ controllable->set_value (new_value);
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI program %1 value %2 %3\n", (int) msg, (float) new_value, current_uri()));
+ }
}
last_value = (MIDI::byte) (controllable->get_value() * 127.0); // to prevent feedback fights
void
MIDIControllable::midi_sense_pitchbend (Parser &, pitchbend_t pb)
{
- if (!controllable) {
+ if (!controllable) {
if (lookup_controllable ()) {
return;
}
if (!controllable->is_toggle()) {
controllable->set_value (midi_to_control (pb));
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI pitchbend %1 value %2 %3\n", (int) control_channel, (float) midi_to_control (pb), current_uri() ));
} else {
- controllable->set_value (controllable->get_value() > 0.5f ? 0.0f : 1.0f);
+ if (pb > 8065.0f) {
+ controllable->set_value (1);
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Midi pitchbend %1 value 1 %2\n", (int) control_channel, current_uri()));
+ } else {
+ controllable->set_value (0);
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Midi pitchbend %1 value 0 %2\n", (int) control_channel, current_uri()));
+ }
}
last_value = control_to_midi (controllable->get_value ());
return;
}
+ _surface->check_used_event(msg[0], msg[1]);
bind_midi ((channel_t) (msg[0] & 0xf), eventType (msg[0] & 0xF0), msg[1]);
if (controllable) {
if (_momentary) {
_parser.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2));
- }
+ }
_control_description = "MIDI control: NoteOff";
break;
}
_control_description = "MIDI control: NoteOn";
break;
-
+
case MIDI::controller:
_parser.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_controller, this, _1, _2));
snprintf (buf, sizeof (buf), "MIDI control: Controller %d", control_additional);
default:
break;
}
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Controlable: bind_midi: %1 on Channel %2 value %3 \n", _control_description, chn_i + 1, (int) additional));
}
MIDI::byte*
if (!controllable || control_type == none || !feedback || bufsize <= 2) {
return buf;
}
-
+
int const gm = control_to_midi (controllable->get_value());
if (gm == last_value) {
return buf;
}
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Feedback: %1 %2\n", control_description(), current_uri()));
+
*buf++ = (0xF0 & control_type) | (0xF & control_channel);
-
+ int ev_size = 3;
switch (control_type) {
case MIDI::pitchbend:
*buf++ = int (gm) & 127;
*buf++ = (int (gm) >> 7) & 127;
break;
+ case MIDI::program:
+ *buf++ = control_additional; /* program number */
+ ev_size = 2;
+ break;
default:
*buf++ = control_additional; /* controller number */
*buf++ = gm;
break;
}
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("MIDI out: Type %1 Channel %2 Bytes %3 %4\n", (int) control_type, (int) control_channel , (int) *(buf - 2), (int) *(buf - 1)));
last_value = gm;
- bufsize -= 3;
+ bufsize -= ev_size;
return buf;
}
MIDIControllable::max_value_for_type () const
{
/* XXX: this is not complete */
-
+
if (control_type == MIDI::pitchbend) {
return 16383;
}