diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2020-05-04 18:48:01 -0600 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2020-05-04 18:48:17 -0600 |
commit | 9b070eefb106c25032d6e077090d9f8a959aefc4 (patch) | |
tree | 689ea306607f0f2461d0940c7ad560a81439c18e /libs/ardour/session.cc | |
parent | 7644168536a37b79eb13f598ca884e0fb7209a3a (diff) |
fix note-tracking in Editor::write_one_track()
We need a MidiStateTracker to determine notes whose end is not reached
during the call to ::write_one_track(), so that we can resolve them
in the output (SMF) source. This required some changes to the ::export_stuff()
API for tracks.
In addition, we now take the source "lock" just once during ::write_one_track()
rather than every time we write. This isn't an integral part of the
note tracking, but fell out along the way.
Finally, note that although we use a vector to handle MIDI "sources" here,
it is expected that there is only 1 MIDI source at present. Leave vectors in
place since it is possible that ::write_one_track() could be modified
in the future to change that.
Diffstat (limited to 'libs/ardour/session.cc')
-rw-r--r-- | libs/ardour/session.cc | 64 |
1 files changed, 54 insertions, 10 deletions
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 690b318035..3908fa755e 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -5655,6 +5655,14 @@ Session::freeze_all (InterThreadInfo& itt) return 0; } +struct MidiSourceLockMap +{ + boost::shared_ptr<MidiSource> src; + Source::Lock lock; + + MidiSourceLockMap (boost::shared_ptr<MidiSource> midi_source) : src (midi_source), lock (src->mutex()) {} +}; + boost::shared_ptr<Region> Session::write_one_track (Track& track, samplepos_t start, samplepos_t end, bool /*overwrite*/, vector<boost::shared_ptr<Source> >& srcs, @@ -5676,8 +5684,10 @@ Session::write_one_track (Track& track, samplepos_t start, samplepos_t end, ChanCount const max_proc = track.max_processor_streams (); string legal_playlist_name; string possible_path; - + MidiBuffer resolved (256); + MidiStateTracker tracker; DataType data_type = track.data_type(); + std::vector<MidiSourceLockMap*> midi_source_locks; if (end <= start) { error << string_compose (_("Cannot write a range where end <= start (e.g. %1 <= %2)"), @@ -5761,14 +5771,25 @@ Session::write_one_track (Track& track, samplepos_t start, samplepos_t end, } buffers.set_count (max_proc); + + /* prepare MIDI files */ + + for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) { + + boost::shared_ptr<MidiSource> ms = boost::dynamic_pointer_cast<MidiSource>(*src); + + if (ms) { + midi_source_locks.push_back (new MidiSourceLockMap (ms)); + ms->mark_streaming_write_started (midi_source_locks.back()->lock); + } + } + + /* prepare audio files */ + for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) { boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src); - boost::shared_ptr<MidiSource> ms; if (afs) { afs->prepare_for_peakfile_writes (); - } else if ((ms = boost::dynamic_pointer_cast<MidiSource>(*src))) { - Source::Lock lock(ms->mutex()); - ms->mark_streaming_write_started(lock); } } @@ -5776,7 +5797,7 @@ Session::write_one_track (Track& track, samplepos_t start, samplepos_t end, this_chunk = min (to_do, bounce_chunk_size); - if (track.export_stuff (buffers, start, this_chunk, endpoint, include_endpoint, for_export, for_freeze)) { + if (track.export_stuff (buffers, start, this_chunk, endpoint, include_endpoint, for_export, for_freeze, tracker)) { goto out; } @@ -5800,22 +5821,45 @@ Session::write_one_track (Track& track, samplepos_t start, samplepos_t end, if (afs->write (buffers.get_audio(n).data(latency_skip), current_chunk) != current_chunk) { goto out; } - } else if ((ms = boost::dynamic_pointer_cast<MidiSource>(*src))) { - Source::Lock lock(ms->mutex()); + } + } + for (vector<MidiSourceLockMap*>::iterator m = midi_source_locks.begin(); m != midi_source_locks.end(); ++m) { const MidiBuffer& buf = buffers.get_midi(0); for (MidiBuffer::const_iterator i = buf.begin(); i != buf.end(); ++i) { Evoral::Event<samplepos_t> ev = *i; if (!endpoint || for_export) { ev.set_time(ev.time() - position); } - ms->append_event_samples(lock, ev, ms->natural_position()); + (*m)->src->append_event_samples ((*m)->lock, ev, (*m)->src->natural_position()); } - } } latency_skip = 0; } + tracker.resolve_notes (resolved, end-1); + + if (!resolved.empty()) { + + for (vector<MidiSourceLockMap*>::iterator m = midi_source_locks.begin(); m != midi_source_locks.end(); ++m) { + + for (MidiBuffer::iterator i = resolved.begin(); i != resolved.end(); ++i) { + Evoral::Event<samplepos_t> ev = *i; + if (!endpoint || for_export) { + ev.set_time(ev.time() - position); + } + (*m)->src->append_event_samples ((*m)->lock, ev, (*m)->src->natural_position()); + } + } + } + + for (vector<MidiSourceLockMap*>::iterator m = midi_source_locks.begin(); m != midi_source_locks.end(); ++m) { + delete *m; + } + + midi_source_locks.clear (); + + /* post-roll, pick up delayed processor output */ latency_skip = track.bounce_get_latency (endpoint, include_endpoint, for_export, for_freeze); |