summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2020-05-04 18:48:01 -0600
committerPaul Davis <paul@linuxaudiosystems.com>2020-05-04 18:48:17 -0600
commit9b070eefb106c25032d6e077090d9f8a959aefc4 (patch)
tree689ea306607f0f2461d0940c7ad560a81439c18e /libs
parent7644168536a37b79eb13f598ca884e0fb7209a3a (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')
-rw-r--r--libs/ardour/ardour/audio_track.h3
-rw-r--r--libs/ardour/ardour/auditioner.h6
-rw-r--r--libs/ardour/ardour/midi_track.h3
-rw-r--r--libs/ardour/ardour/track.h4
-rw-r--r--libs/ardour/audio_track.cc3
-rw-r--r--libs/ardour/midi_track.cc17
-rw-r--r--libs/ardour/session.cc64
7 files changed, 78 insertions, 22 deletions
diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h
index 55def29b99..6b8f01986c 100644
--- a/libs/ardour/ardour/audio_track.h
+++ b/libs/ardour/ardour/audio_track.h
@@ -48,7 +48,8 @@ class LIBARDOUR_API AudioTrack : public Track
boost::shared_ptr<Region> bounce_range (samplepos_t start, samplepos_t end, InterThreadInfo&,
boost::shared_ptr<Processor> endpoint, bool include_endpoint);
int export_stuff (BufferSet& bufs, samplepos_t start_sample, samplecnt_t nframes,
- boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export, bool for_freeze);
+ boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export, bool for_freeze,
+ MidiStateTracker&);
int set_state (const XMLNode&, int version);
diff --git a/libs/ardour/ardour/auditioner.h b/libs/ardour/ardour/auditioner.h
index 6ca51fc0d6..2ad2fba96d 100644
--- a/libs/ardour/ardour/auditioner.h
+++ b/libs/ardour/ardour/auditioner.h
@@ -87,16 +87,16 @@ public:
return boost::shared_ptr<Region> ();
}
- int export_stuff (BufferSet&, samplepos_t, samplecnt_t, boost::shared_ptr<Processor>, bool, bool, bool) { return -1; }
+ int export_stuff (BufferSet&, samplepos_t, samplecnt_t, boost::shared_ptr<Processor>, bool, bool, bool, MidiStateTracker&) { return -1; }
void set_audition_synth_info(PluginInfoPtr in) { audition_synth_info = in; }
samplecnt_t output_latency () const { return 0; }
private:
-
+
PluginInfoPtr audition_synth_info; //we will use this to create a new synth on-the-fly each time an audition is requested
-
+
boost::shared_ptr<AudioRegion> the_region;
boost::shared_ptr<MidiRegion> midi_region;
samplepos_t current_sample;
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 5a1c1aadc4..6e98267b26 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -66,7 +66,8 @@ public:
boost::shared_ptr<Processor> endpoint,
bool include_endpoint,
bool for_export,
- bool for_freeze);
+ bool for_freeze,
+ MidiStateTracker& tracker);
int set_state (const XMLNode&, int version);
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index bb6b0dca37..3da9902c13 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -42,6 +42,7 @@ class DiskWriter;
class IO;
class RecordEnableControl;
class RecordSafeControl;
+class MidiStateTracker;
/** A track is an route (bus) with a recordable diskstream and
* related objects relevant to recording, playback and editing.
@@ -110,7 +111,8 @@ public:
virtual boost::shared_ptr<Region> bounce_range (samplepos_t start, samplepos_t end, InterThreadInfo& itt,
boost::shared_ptr<Processor> endpoint, bool include_endpoint) = 0;
virtual int export_stuff (BufferSet& bufs, samplepos_t start_sample, samplecnt_t nframes,
- boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export, bool for_freeze) = 0;
+ boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export, bool for_freeze,
+ MidiStateTracker&) = 0;
virtual int set_state (const XMLNode&, int version);
static void zero_diskstream_id_in_xml (XMLNode&);
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index 74ecaeb6c3..1b0ed67ffd 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -251,7 +251,8 @@ AudioTrack::set_state_part_two ()
int
AudioTrack::export_stuff (BufferSet& buffers, samplepos_t start, samplecnt_t nframes,
- boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export, bool for_freeze)
+ boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export, bool for_freeze,
+ MidiStateTracker& /* ignored, this is audio */)
{
boost::scoped_array<gain_t> gain_buffer (new gain_t[nframes]);
boost::scoped_array<Sample> mix_buffer (new Sample[nframes]);
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 346ceff5a1..2e7d063048 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -482,7 +482,8 @@ MidiTrack::export_stuff (BufferSet& buffers,
boost::shared_ptr<Processor> endpoint,
bool include_endpoint,
bool for_export,
- bool for_freeze)
+ bool for_freeze,
+ MidiStateTracker& tracker)
{
if (buffers.count().n_midi() == 0) {
return -1;
@@ -498,18 +499,18 @@ MidiTrack::export_stuff (BufferSet& buffers,
buffers.get_midi(0).clear();
-
/* Can't use a note tracker here, because the note off's might be in a
* subsequent call
*/
MidiStateTracker ignored;
- /* XXX thsi doesn't fail, other than if the lock cannot be obtained */
- mpl->rendered()->read(buffers.get_midi(0), start, start+nframes, ignored, start);
+ /* XXX this doesn't fail, other than if the lock cannot be obtained */
+ mpl->rendered()->read (buffers.get_midi(0), start, start+nframes, ignored, start);
+
+ MidiBuffer& buf = buffers.get_midi(0);
if (endpoint && !for_export) {
- MidiBuffer& buf = buffers.get_midi(0);
for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
MidiBuffer::TimeType *t = i.timeptr ();
*t -= start;
@@ -518,6 +519,12 @@ MidiTrack::export_stuff (BufferSet& buffers,
}
mpl->reset_note_trackers ();
+ /* Add to tracker so that we can resolve at the end of the export (in Session::write_one_track()) */
+
+ for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
+ tracker.track (*i);
+ }
+
return 0;
}
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);