diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index 19bafd52ef..62343dce3c 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -75,6 +75,7 @@ public: void midi_panic(void); bool write_immediate_event (Evoral::EventType event_type, size_t size, const uint8_t* buf); + bool write_user_immediate_event (Evoral::EventType event_type, size_t size, const uint8_t* buf); std::shared_ptr velocity_control() const { return _velocity_control; } @@ -135,7 +136,9 @@ public: MonitorState get_input_monitoring_state (bool recording, bool talkback) const; MidiBuffer const& immediate_event_buffer () const { return _immediate_event_buffer; } + MidiBuffer const& user_immediate_event_buffer () const { return _user_immediate_event_buffer; } MidiRingBuffer& immediate_events () { return _immediate_events; } + MidiRingBuffer& user_immediate_events () { return _user_immediate_events; } void set_input_active (bool); bool input_active () const; @@ -160,7 +163,9 @@ protected: private: MidiRingBuffer _immediate_events; + MidiRingBuffer _user_immediate_events; MidiBuffer _immediate_event_buffer; + MidiBuffer _user_immediate_event_buffer; MidiRingBuffer _step_edit_ring_buffer; NoteMode _note_mode; bool _step_editing; diff --git a/libs/ardour/disk_writer.cc b/libs/ardour/disk_writer.cc index befd043c71..541f5ba73a 100644 --- a/libs/ardour/disk_writer.cc +++ b/libs/ardour/disk_writer.cc @@ -572,8 +572,8 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp /* AUDIO */ const size_t n_buffers = bufs.count().n_audio(); - uint32_t n = 0; + for (auto const& chaninfo : *c) { AudioBuffer& buf (bufs.get_audio (n%n_buffers)); ++n; @@ -611,6 +611,8 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp /* MIDI */ + uint32_t cnt = 0; + if (_midi_buf) { // Pump entire port buffer into the ring buffer (TODO: split cycles?) @@ -658,7 +660,10 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp bool skip_event = false; if (mt) { - /* skip injected immediate/out-of-band events */ + /* skip injected immediate/out-of-band + * events, but allow those from + * user_immediate_event_buffer + */ MidiBuffer const& ieb (mt->immediate_event_buffer()); for (MidiBuffer::const_iterator j = ieb.begin(); j != ieb.end(); ++j) { if (*j == ev) { @@ -672,6 +677,7 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp if (!filter || !filter->filter(ev.buffer(), ev.size())) { _midi_buf->write (event_time, ev.event_type(), ev.size(), ev.buffer()); + cnt++; } } @@ -697,6 +703,9 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp } } + } + + if (cnt) { DataRecorded (_midi_write_source); /* EMIT SIGNAL */ } } diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index f9a05b7b3f..e56f0bfa60 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -82,7 +82,9 @@ using namespace PBD; MidiTrack::MidiTrack (Session& sess, string name, TrackMode mode) : Track (sess, name, PresentationInfo::MidiTrack, mode, DataType::MIDI) , _immediate_events(6096) // FIXME: size? + , _user_immediate_events(2048) // FIXME: size? , _immediate_event_buffer(6096) + , _user_immediate_event_buffer(2048) , _step_edit_ring_buffer(64) // FIXME: size? , _note_mode (Sustained) , _step_editing (false) @@ -502,7 +504,7 @@ MidiTrack::snapshot_out_of_band_data (samplecnt_t nframes) { _immediate_event_buffer.clear (); if (0 == _immediate_events.read_space()) { - return; + goto user; } assert (nframes > 0); @@ -519,6 +521,28 @@ MidiTrack::snapshot_out_of_band_data (samplecnt_t nframes) */ _immediate_events.read (_immediate_event_buffer, 0, 1, nframes - 1, true); + + user: + _user_immediate_event_buffer.clear (); + if (0 == _user_immediate_events.read_space()) { + return; + } + + assert (nframes > 0); + + DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 has %2 of user immediate events to deliver\n", name(), _user_immediate_events.read_space())); + + /* write as many of the user immediate events as we can, but give "true" as + * the last argument ("stop on overflow in destination") so that we'll + * ship the rest out next time. + * + * the (nframes-1) argument puts all these events at the last + * possible position of the output buffer, so that we do not + * violate monotonicity when writing. + */ + + _user_immediate_events.read (_user_immediate_event_buffer, 0, 1, nframes - 1, true); + } void @@ -526,6 +550,7 @@ MidiTrack::write_out_of_band_data (BufferSet& bufs, samplecnt_t nframes) const { MidiBuffer& buf (bufs.get_midi (0)); buf.merge_from (_immediate_event_buffer, nframes); + buf.merge_from (_user_immediate_event_buffer, nframes); } int @@ -650,6 +675,16 @@ MidiTrack::write_immediate_event(Evoral::EventType event_type, size_t size, cons return (_immediate_events.write (0, event_type, size, buf) == size); } +bool +MidiTrack::write_user_immediate_event(Evoral::EventType event_type, 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; + } + return (_user_immediate_events.write (0, event_type, size, buf) == size); +} + void MidiTrack::set_parameter_automation_state (Evoral::Parameter param, AutoState state) { @@ -952,6 +987,7 @@ MidiTrack::realtime_handle_transport_stopped () { Route::realtime_handle_transport_stopped (); _disk_reader->resolve_tracker (_immediate_events, 0); + _disk_reader->resolve_tracker (_user_immediate_events, 0); } void