diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc index 1ac33413d0..1c5a42dd1d 100644 --- a/gtk2_ardour/midi_streamview.cc +++ b/gtk2_ardour/midi_streamview.cc @@ -219,10 +219,10 @@ void MidiStreamView::update_contents_metrics(boost::shared_ptr r) { boost::shared_ptr mr = boost::dynamic_pointer_cast(r); + if (mr) { - _range_dirty = update_data_note_range( - mr->model()->lowest_note(), - mr->model()->highest_note()); + Source::ReaderLock lm (mr->midi_source(0)->mutex()); + _range_dirty = update_data_note_range (mr->model()->lowest_note(), mr->model()->highest_note()); } } diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h index 05b11c5976..4394dfbccf 100644 --- a/libs/ardour/ardour/audiofilesource.h +++ b/libs/ardour/ardour/audiofilesource.h @@ -61,7 +61,7 @@ public: virtual int update_header (samplepos_t when, struct tm&, time_t) = 0; virtual int flush_header () = 0; - void mark_streaming_write_completed (const Lock& lock); + void mark_streaming_write_completed (const WriterLock& lock); int setup_peakfile (); void set_gain (float g, bool temporarily = false); diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h index 021abfafb8..b33ead1541 100644 --- a/libs/ardour/ardour/audiosource.h +++ b/libs/ardour/ardour/audiosource.h @@ -60,7 +60,7 @@ class LIBARDOUR_API AudioSource : virtual public Source, public ARDOUR::AudioRea virtual float sample_rate () const = 0; - virtual void mark_streaming_write_completed (const Lock& lock); + virtual void mark_streaming_write_completed (const WriterLock& lock); virtual bool can_truncate_peaks() const { return true; } diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index a09e535894..08ea562120 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -36,6 +36,7 @@ #include "ardour/automatable_sequence.h" #include "ardour/libardour_visibility.h" #include "ardour/libardour_visibility.h" +#include "ardour/source.h" #include "ardour/types.h" #include "ardour/types.h" #include "ardour/variant.h" @@ -280,13 +281,13 @@ public: */ void apply_command_as_subcommand (Session& session, Command* cmd); - bool sync_to_source (const Glib::Threads::Mutex::Lock& source_lock); + bool sync_to_source (const Source::WriterLock& source_lock); bool write_to(boost::shared_ptr source, - const Glib::Threads::Mutex::Lock& source_lock); + const Source::WriterLock& source_lock); bool write_section_to(boost::shared_ptr source, - const Glib::Threads::Mutex::Lock& source_lock, + const Source::WriterLock& source_lock, Temporal::Beats begin = Temporal::Beats(), Temporal::Beats end = std::numeric_limits::max(), bool offset_events = false); @@ -331,7 +332,7 @@ public: ~WriteLockImpl() { delete source_lock; } - Glib::Threads::Mutex::Lock* source_lock; + Source::WriterLock* source_lock; }; public: diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index 5cd5fc6109..8343bbd177 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -67,7 +67,7 @@ class LIBARDOUR_API MidiSource : virtual public Source * @param end time of latest event that can be written. * @return zero on success, non-zero if the write failed for any reason. */ - int write_to (const Lock& lock, + int write_to (const ReaderLock& lock, boost::shared_ptr newsrc, Temporal::Beats begin = Temporal::Beats(), Temporal::Beats end = std::numeric_limits::max()); @@ -81,7 +81,7 @@ class LIBARDOUR_API MidiSource : virtual public Source * @param end time of latest event that can be written. * @return zero on success, non-zero if the write failed for any reason. */ - int export_write_to (const Lock& lock, + int export_write_to (const ReaderLock& lock, boost::shared_ptr newsrc, Temporal::Beats begin, Temporal::Beats end); @@ -99,7 +99,7 @@ class LIBARDOUR_API MidiSource : virtual public Source * @param tracker an optional pointer to MidiNoteTracker object, for note on/off tracking. * @param filtered Parameters whose MIDI messages will not be returned. */ - virtual timecnt_t midi_read (const Lock& lock, + virtual timecnt_t midi_read (const ReaderLock& lock, Evoral::EventSink& dst, timepos_t const & source_start, timepos_t const & start, @@ -116,7 +116,7 @@ class LIBARDOUR_API MidiSource : virtual public Source * @param source_start This source's start position in session samples. * @param cnt The length of time to write. */ - virtual timecnt_t midi_write (const Lock& lock, + virtual timecnt_t midi_write (const WriterLock& lock, MidiRingBuffer& source, timepos_t const & source_start, timecnt_t const & cnt); @@ -125,20 +125,20 @@ class LIBARDOUR_API MidiSource : virtual public Source * * Caller must ensure that the event is later than the last written event. */ - virtual void append_event_beats(const Lock& lock, + virtual void append_event_beats(const WriterLock& lock, const Evoral::Event& ev) = 0; /** Append a single event with a timestamp in samples. * * Caller must ensure that the event is later than the last written event. */ - virtual void append_event_samples(const Lock& lock, + virtual void append_event_samples(const WriterLock& lock, const Evoral::Event& ev, samplepos_t source_start) = 0; - virtual void mark_streaming_midi_write_started (const Lock& lock, NoteMode mode); - virtual void mark_streaming_write_started (const Lock& lock); - virtual void mark_streaming_write_completed (const Lock& lock); + virtual void mark_streaming_midi_write_started (const WriterLock& lock, NoteMode mode); + virtual void mark_streaming_write_started (const WriterLock& lock); + virtual void mark_streaming_write_completed (const WriterLock& lock); /** Mark write starting with the given time parameters. * @@ -158,7 +158,7 @@ class LIBARDOUR_API MidiSource : virtual public Source * etc. */ virtual void mark_midi_streaming_write_completed ( - const Lock& lock, + const WriterLock& lock, Evoral::Sequence::StuckNoteOption stuck_option, Temporal::Beats when = Temporal::Beats()); @@ -169,22 +169,22 @@ class LIBARDOUR_API MidiSource : virtual public Source bool length_mutable() const { return true; } - virtual void load_model(const Glib::Threads::Mutex::Lock& lock, bool force_reload=false) = 0; - virtual void destroy_model(const Glib::Threads::Mutex::Lock& lock) = 0; + virtual void load_model(const WriterLock& lock, bool force_reload=false) = 0; + virtual void destroy_model(const WriterLock& lock) = 0; /** Reset cached information (like iterators) when things have changed. * @param lock Source lock, which must be held by caller. */ - void invalidate(const Glib::Threads::Mutex::Lock& lock); + void invalidate(const WriterLock& lock); /** Thou shalt not emit this directly, use invalidate() instead. */ mutable PBD::Signal1 Invalidated; - void set_note_mode(const Glib::Threads::Mutex::Lock& lock, NoteMode mode); + void set_note_mode(const WriterLock& lock, NoteMode mode); boost::shared_ptr model() { return _model; } - void set_model(const Glib::Threads::Mutex::Lock& lock, boost::shared_ptr); - void drop_model(const Glib::Threads::Mutex::Lock& lock); + void set_model(const WriterLock& lock, boost::shared_ptr); + void drop_model(const WriterLock& lock); Evoral::ControlList::InterpolationStyle interpolation_of (Evoral::Parameter) const; void set_interpolation_of (Evoral::Parameter, Evoral::ControlList::InterpolationStyle); @@ -204,9 +204,9 @@ class LIBARDOUR_API MidiSource : virtual public Source PBD::Signal2 AutomationStateChanged; protected: - virtual void flush_midi(const Lock& lock) = 0; + virtual void flush_midi(const WriterLock& lock) = 0; - virtual timecnt_t read_unlocked (const Lock& lock, + virtual timecnt_t read_unlocked (const ReaderLock& lock, Evoral::EventSink& dst, timepos_t const & position, timepos_t const & start, @@ -221,7 +221,7 @@ class LIBARDOUR_API MidiSource : virtual public Source * @param position This source's start position in session samples. * @param cnt The duration of this block to write for. */ - virtual timecnt_t write_unlocked (const Lock& lock, + virtual timecnt_t write_unlocked (const WriterLock& lock, MidiRingBuffer& source, timepos_t const & position, timecnt_t const & cnt) = 0; diff --git a/libs/ardour/ardour/midi_state_tracker.h b/libs/ardour/ardour/midi_state_tracker.h index 10528c1494..91d081649d 100644 --- a/libs/ardour/ardour/midi_state_tracker.h +++ b/libs/ardour/ardour/midi_state_tracker.h @@ -25,6 +25,7 @@ #include "temporal/beats.h" #include "ardour/midi_buffer.h" +#include "ardour/source.h" namespace Evoral { template class EventSink; @@ -52,7 +53,7 @@ public: void remove (uint8_t note, uint8_t chn); void resolve_notes (MidiBuffer& buffer, samplepos_t time, bool reset = true); void resolve_notes (Evoral::EventSink& buffer, samplepos_t time); - void resolve_notes (MidiSource& src, const Glib::Threads::Mutex::Lock& lock, Temporal::Beats time); + void resolve_notes (MidiSource& src, const Source::WriterLock& lock, Temporal::Beats time); void flush_notes (MidiBuffer& buffer, samplepos_t time, bool reset = true); diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h index 8dc8689bb2..f20790762c 100644 --- a/libs/ardour/ardour/smf_source.h +++ b/libs/ardour/ardour/smf_source.h @@ -53,14 +53,14 @@ public: return safe_midi_file_extension(path); } - void append_event_beats (const Lock& lock, const Evoral::Event& ev); - void append_event_samples (const Lock& lock, const Evoral::Event& ev, samplepos_t source_start); + void append_event_beats (const WriterLock& lock, const Evoral::Event& ev); + void append_event_samples (const WriterLock& lock, const Evoral::Event& ev, samplepos_t source_start); void update_length (timepos_t const & dur); - void mark_streaming_midi_write_started (const Lock& lock, NoteMode mode); - void mark_streaming_write_completed (const Lock& lock); - void mark_midi_streaming_write_completed (const Lock& lock, + void mark_streaming_midi_write_started (const WriterLock& lock, NoteMode mode); + void mark_streaming_write_completed (const WriterLock& lock); + void mark_midi_streaming_write_completed (const WriterLock& lock, Evoral::Sequence::StuckNoteOption, Temporal::Beats when = Temporal::Beats()); @@ -81,7 +81,7 @@ public: protected: void close (); - void flush_midi (const Lock& lock); + void flush_midi (const WriterLock& lock); private: bool _open; @@ -94,9 +94,9 @@ public: int open_for_write (); - void ensure_disk_file (const Lock& lock); + void ensure_disk_file (const WriterLock& lock); - timecnt_t read_unlocked (const Lock& lock, + timecnt_t read_unlocked (const ReaderLock& lock, Evoral::EventSink& dst, timepos_t const & position, timepos_t const & start, @@ -105,7 +105,7 @@ public: MidiNoteTracker* tracker, MidiChannelFilter* filter) const; - timecnt_t write_unlocked (const Lock& lock, + timecnt_t write_unlocked (const WriterLock& lock, MidiRingBuffer& src, timepos_t const & position, timecnt_t const & cnt); diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h index 0b6f19cf0b..c4fc443d55 100644 --- a/libs/ardour/ardour/source.h +++ b/libs/ardour/ardour/source.h @@ -63,7 +63,8 @@ public: Missing = 0x400, /* used for MIDI only */ }; - typedef Glib::Threads::Mutex::Lock Lock; + typedef Glib::Threads::RWLock::ReaderLock ReaderLock; + typedef Glib::Threads::RWLock::WriterLock WriterLock; Source (Session&, DataType type, const std::string& name, Flag flags=Flag(0)); Source (Session&, const XMLNode&); @@ -85,8 +86,8 @@ public: void mark_for_remove(); - virtual void mark_streaming_write_started (const Lock& lock) {} - virtual void mark_streaming_write_completed (const Lock& lock) = 0; + virtual void mark_streaming_write_started (const WriterLock& lock) {} + virtual void mark_streaming_write_completed (const WriterLock& lock) = 0; virtual void session_saved() {} @@ -129,7 +130,7 @@ public: void set_allow_remove_if_empty (bool yn); - Glib::Threads::Mutex& mutex() { return _lock; } + Glib::Threads::RWLock& mutex() { return _lock; } Flag flags() const { return _flags; } virtual void inc_use_count (); @@ -167,7 +168,7 @@ public: typedef std::vector SegmentDescriptors; SegmentDescriptors segment_descriptors; - mutable Glib::Threads::Mutex _lock; + mutable Glib::Threads::RWLock _lock; mutable Glib::Threads::Mutex _analysis_lock; private: diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc index 13b08a53d4..e076d17cfb 100644 --- a/libs/ardour/audiofilesource.cc +++ b/libs/ardour/audiofilesource.cc @@ -249,7 +249,7 @@ AudioFileSource::set_state (const XMLNode& node, int version) } void -AudioFileSource::mark_streaming_write_completed (const Lock& lock) +AudioFileSource::mark_streaming_write_completed (const WriterLock& lock) { if (!writable()) { return; diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc index b57411ae07..bdc432363c 100644 --- a/libs/ardour/audiosource.cc +++ b/libs/ardour/audiosource.cc @@ -308,14 +308,14 @@ AudioSource::read (Sample *dst, samplepos_t start, samplecnt_t cnt, int /*channe { assert (cnt >= 0); - Glib::Threads::Mutex::Lock lm (_lock); + ReaderLock lm (_lock); return read_unlocked (dst, start, cnt); } samplecnt_t AudioSource::write (Sample *dst, samplecnt_t cnt) { - Glib::Threads::Mutex::Lock lm (_lock); + WriterLock lm (_lock); /* any write makes the file not removable */ _flags = Flag (_flags & ~Removable); return write_unlocked (dst, cnt); @@ -335,7 +335,7 @@ int AudioSource::read_peaks_with_fpp (PeakData *peaks, samplecnt_t npeaks, samplepos_t start, samplecnt_t cnt, double samples_per_visual_peak, samplecnt_t samples_per_file_peak) const { - Glib::Threads::Mutex::Lock lm (_lock); + ReaderLock lm (_lock); #if 0 // DEBUG ONLY /* Bypass peak-file cache, compute peaks using raw data from source */ @@ -762,7 +762,7 @@ AudioSource::build_peaks_from_scratch () { /* hold lock while building peaks */ - Glib::Threads::Mutex::Lock lp (_lock); + ReaderLock lp (_lock); if (prepare_for_peakfile_writes ()) { goto out; @@ -827,7 +827,7 @@ AudioSource::build_peaks_from_scratch () int AudioSource::close_peakfile () { - Glib::Threads::Mutex::Lock lp (_lock); + WriterLock lp (_lock); if (_peakfile_fd >= 0) { close (_peakfile_fd); _peakfile_fd = -1; @@ -1117,7 +1117,7 @@ AudioSource::available_peaks (double zoom_factor) const } void -AudioSource::mark_streaming_write_completed (const Lock& lock) +AudioSource::mark_streaming_write_completed (const WriterLock& lock) { Glib::Threads::Mutex::Lock lm (_peaks_ready_lock); diff --git a/libs/ardour/disk_writer.cc b/libs/ardour/disk_writer.cc index 75a87b8f63..0164341997 100644 --- a/libs/ardour/disk_writer.cc +++ b/libs/ardour/disk_writer.cc @@ -860,7 +860,7 @@ DiskWriter::prep_record_enable () for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { capturing_sources.push_back ((*chan)->write_source); - Source::Lock lock((*chan)->write_source->mutex()); + Source::WriterLock lock ((*chan)->write_source->mutex()); (*chan)->write_source->mark_streaming_write_started (lock); } @@ -1034,7 +1034,7 @@ DiskWriter::do_flush (RunContext ctxt, bool force_flush) } if ((total > _chunk_samples) || force_flush) { - Source::Lock lm(_midi_write_source->mutex()); + Source::WriterLock lm(_midi_write_source->mutex()); if (_midi_write_source->midi_write (lm, *_midi_buf, timepos_t (get_capture_start_sample (0)), timecnt_t (to_write)) != to_write) { error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg; return -1; @@ -1066,7 +1066,7 @@ DiskWriter::reset_write_sources (bool mark_write_complete, bool /*force*/) if ((*chan)->write_source) { if (mark_write_complete) { - Source::Lock lock((*chan)->write_source->mutex()); + Source::WriterLock lock((*chan)->write_source->mutex()); (*chan)->write_source->mark_streaming_write_completed (lock); (*chan)->write_source->done_with_peakfile_writes (); } @@ -1088,7 +1088,7 @@ DiskWriter::reset_write_sources (bool mark_write_complete, bool /*force*/) if (_midi_write_source) { if (mark_write_complete) { - Source::Lock lm(_midi_write_source->mutex()); + Source::WriterLock lm(_midi_write_source->mutex()); _midi_write_source->mark_streaming_write_completed (lm); } } @@ -1267,7 +1267,7 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo /* phew, we have data */ - Source::Lock source_lock(_midi_write_source->mutex()); + Source::WriterLock source_lock(_midi_write_source->mutex()); /* figure out the name for this take */ diff --git a/libs/ardour/file_source.cc b/libs/ardour/file_source.cc index 4deece2f49..ef1019efba 100644 --- a/libs/ardour/file_source.cc +++ b/libs/ardour/file_source.cc @@ -584,7 +584,7 @@ FileSource::is_stub () const int FileSource::rename (const string& newpath) { - Glib::Threads::Mutex::Lock lm (_lock); + WriterLock lm (_lock); string oldpath = _path; // Test whether newpath exists, if yes notify the user but continue. diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index cc616accd2..500a19369c 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -394,7 +394,7 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status, continue; //should never happen. The calling code should provide exactly the number of tracks&channels we need } - Glib::Threads::Mutex::Lock source_lock(smfs->mutex()); + Source::WriterLock source_lock(smfs->mutex()); smfs->drop_model (source_lock); if (type0) { diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 4728fdd285..b10750fe94 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -1224,10 +1224,9 @@ MidiModel::PatchChangeDiffCommand::get_state () */ bool MidiModel::write_to (boost::shared_ptr source, - const Glib::Threads::Mutex::Lock& source_lock) + const Source::WriterLock& source_lock) { - ReadLock lock(read_lock()); - + ReadLock lock (read_lock()); /* Sequence read-lock */ source->drop_model(source_lock); /* as of March 2022 or long before , the note mode argument does nothing */ @@ -1250,7 +1249,7 @@ MidiModel::write_to (boost::shared_ptr source, of the model. */ bool -MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock) +MidiModel::sync_to_source (const Source::WriterLock& source_lock) { ReadLock lock(read_lock()); @@ -1281,7 +1280,7 @@ MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock) */ bool MidiModel::write_section_to (boost::shared_ptr source, - const Glib::Threads::Mutex::Lock& source_lock, + const Source::WriterLock& source_lock, TimeType begin_time, TimeType end_time, bool offset_events) @@ -1414,17 +1413,15 @@ MidiModel::find_sysex (Evoral::event_id_t sysex_id) MidiModel::WriteLock MidiModel::edit_lock() { - Glib::Threads::Mutex::Lock* source_lock = 0; + Source::WriterLock* source_lock = 0; - if (ms) { - /* Take source lock and invalidate iterator to release its lock on model. - Add currently active notes to _active_notes so we can restore them - if playback resumes at the same point after the edit. */ - source_lock = new Glib::Threads::Mutex::Lock(ms->mutex()); - ms->invalidate(*source_lock); - } - - return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock)); + /* Take source lock and invalidate iterator to release its lock on model. + * Add currently active notes to _active_notes so we can restore them + * if playback resumes at the same point after the edit. + */ + source_lock = new Source::WriterLock (_midi_source.mutex()); + _midi_source.invalidate(*source_lock); + return WriteLock (new WriteLockImpl (source_lock, _lock, _control_lock)); } int diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index 23e0e53aba..54b955a2a5 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -109,8 +109,9 @@ MidiRegion::do_export (string const& path) const { /* Lock our source since we'll be reading from it. write_to() will - take a lock on newsrc. */ - Source::Lock lm (midi_source(0)->mutex()); + * take a lock on newsrc. + */ + Source::ReaderLock lm (midi_source(0)->mutex()); if (midi_source(0)->export_write_to (lm, newsrc, _start.val().beats(), _start.val().beats() + _length.val().beats())) { return false; } @@ -235,8 +236,7 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, boost::shared_ptr src = midi_source(chan_n); - Glib::Threads::Mutex::Lock lm(src->mutex()); - + Source::ReaderLock lm (src->mutex()); #if 0 cerr << "MR " << name () << " read @ " << pos << " + " << to_read @@ -298,8 +298,6 @@ MidiRegion::render_range (Evoral::EventSink& dst, boost::shared_ptr src = midi_source(chan_n); - Glib::Threads::Mutex::Lock lm(src->mutex()); - #if 0 cerr << "MR " << name () << " render " @@ -317,6 +315,8 @@ MidiRegion::render_range (Evoral::EventSink& dst, /* This call reads events from a source and writes them to `dst' timed in session samples */ + Source::ReaderLock lm (src->mutex()); + src->midi_read ( lm, // source lock dst, // destination buffer @@ -505,7 +505,7 @@ MidiRegion::model_automation_state_changed (Evoral::Parameter const & p) for a given set of filtered_parameters, so now that we've changed that list we must invalidate the iterator. */ - Glib::Threads::Mutex::Lock lm (midi_source(0)->mutex(), Glib::Threads::TRY_LOCK); + Source::WriterLock lm (midi_source(0)->mutex(), Glib::Threads::TRY_LOCK); if (lm.locked()) { /* TODO: This is too aggressive, we need more fine-grained invalidation. */ midi_source(0)->invalidate (lm); diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 6d83e41f2d..9effb9ee29 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -167,23 +167,26 @@ MidiSource::set_state (const XMLNode& node, int /*version*/) } void -MidiSource::invalidate (const Lock& lock) +MidiSource::invalidate (const WriterLock& lock) { Invalidated(_session.transport_rolling()); } timecnt_t -MidiSource::midi_read (const Lock& lm, +MidiSource::midi_read (const ReaderLock& lm, Evoral::EventSink& dst, timepos_t const & source_start, timepos_t const & start, timecnt_t const & cnt, Temporal::Range* loop_range, MidiCursor& cursor, - MidiNoteTracker* tracker, + MidiNoteTracker* tracker, MidiChannelFilter* filter, const std::set& filtered) { + Timing t; + uint32_t ecnt = 0; + DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("MidiSource::midi_read() %5 sstart %1 start %2 cnt %3 tracker %4\n", source_start, start, cnt, tracker, name())); @@ -289,12 +292,14 @@ MidiSource::midi_read (const Lock& lm, } } } + t.update (); + std::cout << "MIDI read added " << ecnt << " events and took " << t.elapsed_msecs() << std::endl; return cnt; } timecnt_t -MidiSource::midi_write (const Lock& lm, +MidiSource::midi_write (const WriterLock& lm, MidiRingBuffer& source, timepos_t const & source_start, timecnt_t const & cnt) @@ -311,7 +316,7 @@ MidiSource::midi_write (const Lock& lm, } void -MidiSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode) +MidiSource::mark_streaming_midi_write_started (const WriterLock& lock, NoteMode mode) { if (_model) { /* XXX do something with note mode? */ @@ -348,14 +353,14 @@ MidiSource::mark_write_starting_now (timepos_t const & position, samplecnt_t cap } void -MidiSource::mark_streaming_write_started (const Lock& lock) +MidiSource::mark_streaming_write_started (const WriterLock& lock) { /* as of March 2022 or long before , the note mode argument does nothing */ mark_streaming_midi_write_started (lock, Sustained); } void -MidiSource::mark_midi_streaming_write_completed (const Lock& lock, +MidiSource::mark_midi_streaming_write_completed (const WriterLock& lock, Evoral::Sequence::StuckNoteOption option, Temporal::Beats end) { @@ -376,15 +381,15 @@ MidiSource::mark_midi_streaming_write_completed (const Lock& } void -MidiSource::mark_streaming_write_completed (const Lock& lock) +MidiSource::mark_streaming_write_completed (const WriterLock& lock) { mark_midi_streaming_write_completed (lock, Evoral::Sequence::DeleteStuckNotes); } int -MidiSource::export_write_to (const Lock& lock, boost::shared_ptr newsrc, Temporal::Beats begin, Temporal::Beats end) +MidiSource::export_write_to (const ReaderLock& lock, boost::shared_ptr newsrc, Temporal::Beats begin, Temporal::Beats end) { - Lock newsrc_lock (newsrc->mutex ()); + WriterLock newsrc_lock (newsrc->mutex ()); if (!_model) { error << string_compose (_("programming error: %1"), X_("no model for MidiSource during export")); @@ -399,9 +404,9 @@ MidiSource::export_write_to (const Lock& lock, boost::shared_ptr new } int -MidiSource::write_to (const Lock& lock, boost::shared_ptr newsrc, Temporal::Beats begin, Temporal::Beats end) +MidiSource::write_to (const ReaderLock& lock, boost::shared_ptr newsrc, Temporal::Beats begin, Temporal::Beats end) { - Lock newsrc_lock (newsrc->mutex ()); + WriterLock newsrc_lock (newsrc->mutex ()); newsrc->set_natural_position (_natural_position); newsrc->copy_interpolation_from (this); @@ -440,7 +445,7 @@ MidiSource::write_to (const Lock& lock, boost::shared_ptr newsrc, Te void MidiSource::session_saved() { - Lock lm (_lock); + WriterLock lm (_lock); /* this writes a copy of the data to disk. XXX do we need to do this every time? @@ -467,7 +472,7 @@ MidiSource::session_saved() } void -MidiSource::drop_model (const Lock& lock) +MidiSource::drop_model (const WriterLock& lock) { _model.reset(); invalidate(lock); @@ -475,7 +480,7 @@ MidiSource::drop_model (const Lock& lock) } void -MidiSource::set_model (const Lock& lock, boost::shared_ptr m) +MidiSource::set_model (const WriterLock& lock, boost::shared_ptr m) { _model = m; invalidate(lock); diff --git a/libs/ardour/midi_state_tracker.cc b/libs/ardour/midi_state_tracker.cc index 084888e356..e1e012e37a 100644 --- a/libs/ardour/midi_state_tracker.cc +++ b/libs/ardour/midi_state_tracker.cc @@ -181,7 +181,7 @@ MidiNoteTracker::resolve_notes (Evoral::EventSink &dst, samplepos_t } void -MidiNoteTracker::resolve_notes (MidiSource& src, const MidiSource::Lock& lock, Temporal::Beats time) +MidiNoteTracker::resolve_notes (MidiSource& src, const MidiSource::WriterLock& lock, Temporal::Beats time) { DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 MS-resolve notes @ %2 on = %3\n", this, time, _on)); diff --git a/libs/ardour/midi_stretch.cc b/libs/ardour/midi_stretch.cc index 21fbde7bf0..aa6bc18bf5 100644 --- a/libs/ardour/midi_stretch.cc +++ b/libs/ardour/midi_stretch.cc @@ -70,26 +70,24 @@ MidiStretch::run (boost::shared_ptr r, Progress*) /* create new sources */ - if (make_new_sources (region, nsrcs, suffix)) + if (make_new_sources (region, nsrcs, suffix)) { return -1; - - boost::shared_ptr src = region->midi_source(0); - { - Source::Lock lock(src->mutex()); - src->load_model(lock); } - boost::shared_ptr old_model = src->model(); + boost::shared_ptr src = region->midi_source(0); + Source::ReaderLock lock (src->mutex()); + boost::shared_ptr old_model = src->model(); boost::shared_ptr new_src = boost::dynamic_pointer_cast(nsrcs[0]); + if (!new_src) { error << _("MIDI stretch created non-MIDI source") << endmsg; return -1; } - Glib::Threads::Mutex::Lock sl (new_src->mutex ()); + Source::WriterLock sl (new_src->mutex ()); - new_src->load_model(sl, true); + new_src->load_model (sl, true); boost::shared_ptr new_model = new_src->model(); new_model->start_write(); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 0c3e1dd8a1..8dfb92a606 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -5717,7 +5717,7 @@ Session::freeze_all (InterThreadInfo& itt) struct MidiSourceLockMap { boost::shared_ptr src; - Source::Lock lock; + Source::WriterLock lock; MidiSourceLockMap (boost::shared_ptr midi_source) : src (midi_source), lock (src->mutex()) {} }; @@ -6013,7 +6013,7 @@ Session::write_one_track (Track& track, samplepos_t start, samplepos_t end, afs->flush_header (); plist.add (Properties::start, timepos_t (0)); } else if ((ms = boost::dynamic_pointer_cast(*src))) { - Source::Lock lock(ms->mutex()); + Source::WriterLock lock (ms->mutex()); ms->mark_streaming_write_completed(lock); plist.add (Properties::start, timepos_t (Beats())); } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index cd165a7e5e..586fc8306b 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -1339,11 +1339,14 @@ Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_ass /* use SMF-API to clone data (use the midi_model, not data on disk) */ boost::shared_ptr newsrc (new SMFSource (*this, path, ms->flags())); - Source::Lock lm (ms->mutex()); + { + Source::WriterLock lm (ms->mutex()); - if (!ms->model()) { - ms->load_model (lm); + if (!ms->model()) { + ms->load_model (lm); + } } + Source::ReaderLock lm (ms->mutex()); /* write_to() calls newsrc->flush_midi () to write the file to disk */ if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits::max())) { error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg; diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index b9ee73931f..1ba1292c71 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -218,13 +218,13 @@ SMFSource::close () extern PBD::Timing minsert; timecnt_t -SMFSource::read_unlocked (const Lock& lock, +SMFSource::read_unlocked (const ReaderLock& lock, Evoral::EventSink& destination, timepos_t const & source_start, timepos_t const & start, timecnt_t const & duration, Temporal::Range* loop_range, - MidiNoteTracker* tracker, + MidiNoteTracker* tracker, MidiChannelFilter* filter) const { int ret = 0; @@ -320,7 +320,7 @@ SMFSource::read_unlocked (const Lock& lock, } timecnt_t -SMFSource::write_unlocked (const Lock& lock, +SMFSource::write_unlocked (const WriterLock& lock, MidiRingBuffer& source, timepos_t const & position, timecnt_t const & cnt) @@ -411,7 +411,7 @@ SMFSource::update_length (timepos_t const & dur) /** Append an event with a timestamp in beats */ void -SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock, +SMFSource::append_event_beats (const WriterLock& lock, const Evoral::Event& ev) { if (!_writing || ev.size() == 0) { @@ -468,7 +468,7 @@ SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock& lock, /** Append an event with a timestamp in samples (samplepos_t) */ void -SMFSource::append_event_samples (const Glib::Threads::Mutex::Lock& lock, +SMFSource::append_event_samples (const WriterLock& lock, const Evoral::Event& ev, samplepos_t position) { @@ -551,7 +551,7 @@ SMFSource::set_state (const XMLNode& node, int version) } void -SMFSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode) +SMFSource::mark_streaming_midi_write_started (const WriterLock& lock, NoteMode mode) { if (!_open && open_for_write()) { error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg; @@ -566,13 +566,13 @@ SMFSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode) } void -SMFSource::mark_streaming_write_completed (const Lock& lock) +SMFSource::mark_streaming_write_completed (const WriterLock& lock) { mark_midi_streaming_write_completed (lock, Evoral::Sequence::DeleteStuckNotes); } void -SMFSource::mark_midi_streaming_write_completed (const Lock& lm, Evoral::Sequence::StuckNoteOption stuck_notes_option, Temporal::Beats when) +SMFSource::mark_midi_streaming_write_completed (const WriterLock& lm, Evoral::Sequence::StuckNoteOption stuck_notes_option, Temporal::Beats when) { MidiSource::mark_midi_streaming_write_completed (lm, stuck_notes_option, when); @@ -640,7 +640,7 @@ static bool compare_eventlist ( } void -SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload) +SMFSource::load_model (const WriterLock& lock, bool force_reload) { invalidate (lock); load_model_unlocked (force_reload); @@ -787,7 +787,7 @@ SMFSource::used_midi_channels() } void -SMFSource::destroy_model (const Glib::Threads::Mutex::Lock& lock) +SMFSource::destroy_model (const WriterLock& lock) { //cerr << _name << " destroying model " << _model.get() << endl; _model.reset(); @@ -795,7 +795,7 @@ SMFSource::destroy_model (const Glib::Threads::Mutex::Lock& lock) } void -SMFSource::flush_midi (const Lock& lock) +SMFSource::flush_midi (const WriterLock& lock) { if (!writable() || _length.is_zero()) { return; @@ -818,7 +818,7 @@ SMFSource::set_path (const string& p) /** Ensure that this source has some file on disk, even if it's just a SMF header */ void -SMFSource::ensure_disk_file (const Lock& lock) +SMFSource::ensure_disk_file (const WriterLock& lock) { if (!writable()) { return; diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc index f406bae273..5237a6b199 100644 --- a/libs/ardour/source_factory.cc +++ b/libs/ardour/source_factory.cc @@ -306,6 +306,7 @@ SourceFactory::createExternal (DataType type, Session& s, const string& path, } else if (type == DataType::MIDI) { try { boost::shared_ptr src (new SMFSource (s, path)); + Source::WriterLock lock (src->mutex ()); BOOST_MARK_SOURCE (src); if (announce) { diff --git a/libs/ardour/step_sequencer.cc b/libs/ardour/step_sequencer.cc index d495c510b9..1f898c9dd7 100644 --- a/libs/ardour/step_sequencer.cc +++ b/libs/ardour/step_sequencer.cc @@ -887,7 +887,7 @@ StepSequencer::fill_midi_source (boost::shared_ptr src) const { Temporal::Beats smf_beats; - Source::Lock lck (src->mutex()); + Source::WriterLock lck (src->mutex()); /* first pass: run through the sequence one time to get all events, and * then sort them. We have no idea what order they are in when we pull