+ for (uint8_t channel = 0; channel <= 0xF; channel++) {
+ uint8_t ev[3] = { MIDI_CMD_CONTROL | channel, MIDI_CTL_SUSTAIN, 0 };
+ write_immediate_event(3, ev);
+ ev[1] = MIDI_CTL_ALL_NOTES_OFF;
+ write_immediate_event(3, ev);
+ ev[1] = MIDI_CTL_RESET_CONTROLLERS;
+ write_immediate_event(3, ev);
+ }
+}
+
+/** \return true on success, false on failure (no buffer space left)
+ */
+bool
+MidiTrack::write_immediate_event(size_t size, const uint8_t* buf)
+{
+ if (!Evoral::midi_event_is_valid(buf, size)) {
+ cerr << "WARNING: Ignoring illegal immediate MIDI event" << endl;
+ return false;
+ }
+ const uint32_t type = EventTypeMap::instance().midi_event_type(buf[0]);
+ return (_immediate_events.write(0, type, size, buf) == size);
+}
+
+void
+MidiTrack::MidiControl::set_value(float val)
+{
+ bool valid = false;
+ if (isinf(val)) {
+ cerr << "MIDIControl value is infinity" << endl;
+ } else if (isnan(val)) {
+ cerr << "MIDIControl value is NaN" << endl;
+ } else if (val < _list->parameter().min()) {
+ cerr << "MIDIControl value is < " << _list->parameter().min() << endl;
+ } else if (val > _list->parameter().max()) {
+ cerr << "MIDIControl value is > " << _list->parameter().max() << endl;
+ } else {
+ valid = true;
+ }
+
+ if (!valid) {
+ return;
+ }
+
+ assert(val <= _list->parameter().max());
+ size_t size = 3;
+
+ if ( ! automation_playback()) {
+ uint8_t ev[3] = { _list->parameter().channel(), int(val), 0 };
+ switch(_list->parameter().type()) {
+ case MidiCCAutomation:
+ ev[0] += MIDI_CMD_CONTROL;
+ ev[1] = _list->parameter().id();
+ ev[2] = int(val);
+ break;
+
+ case MidiPgmChangeAutomation:
+ size = 2;
+ ev[0] += MIDI_CMD_PGM_CHANGE;
+ ev[1] = int(val);
+ break;
+
+ case MidiChannelPressureAutomation:
+ size = 2;
+ ev[0] += MIDI_CMD_CHANNEL_PRESSURE;
+ ev[1] = int(val);
+ break;
+
+ case MidiPitchBenderAutomation:
+ ev[0] += MIDI_CMD_BENDER;
+ ev[1] = 0x7F & int(val);
+ ev[2] = 0x7F & (int(val) >> 7);
+ break;
+
+ default:
+ assert(false);