Fix various MIDI locking issues.
authorDavid Robillard <d@drobilla.net>
Wed, 17 Dec 2014 21:05:27 +0000 (16:05 -0500)
committerDavid Robillard <d@drobilla.net>
Wed, 17 Dec 2014 21:07:29 +0000 (16:07 -0500)
Attempt to make mistakes much less likely in the future by statically requiring
caller to pass scoped locks where necessary.

24 files changed:
gtk2_ardour/automation_streamview.cc
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_streamview.cc
libs/ardour/ardour/audiofilesource.h
libs/ardour/ardour/audiosource.h
libs/ardour/ardour/midi_model.h
libs/ardour/ardour/midi_playlist_source.h
libs/ardour/ardour/midi_source.h
libs/ardour/ardour/midi_state_tracker.h
libs/ardour/ardour/smf_source.h
libs/ardour/ardour/source.h
libs/ardour/audio_diskstream.cc
libs/ardour/audiofilesource.cc
libs/ardour/audiosource.cc
libs/ardour/import.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_model.cc
libs/ardour/midi_playlist_source.cc
libs/ardour/midi_region.cc
libs/ardour/midi_source.cc
libs/ardour/midi_state_tracker.cc
libs/ardour/midi_stretch.cc
libs/ardour/smf_source.cc
libs/ardour/source_factory.cc

index 89ae7fa07980336203681efb56aaf1ed104599b1..e504d13931d551981194cb9748e67c946c81a1d9 100644 (file)
@@ -76,7 +76,8 @@ AutomationStreamView::add_region_view_internal (boost::shared_ptr<Region> region
        if (wait_for_data) {
                boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
                if (mr) {
-                       mr->midi_source()->load_model();
+                       Source::Lock lock(mr->midi_source()->mutex());
+                       mr->midi_source()->load_model(lock);
                }
        }
 
index 0b14ca6a7afacf3a833650efc977b22e26ce1b9b..e072d7c7ceee884c0d8cd292e99eb94baf9f6524 100644 (file)
@@ -270,7 +270,8 @@ MidiRegionView::init (bool wfd)
                                           gui_context());
        
        if (wfd) {
-               midi_region()->midi_source(0)->load_model();
+               Glib::Threads::Mutex::Lock lm(midi_region()->midi_source(0)->mutex());
+               midi_region()->midi_source(0)->load_model(lm);
        }
 
        _model = midi_region()->midi_source(0)->model();
index d124426cc9dcca4f0db5f70f1a8a2fbf237ed0fe..8a5fd53150955cb5bbd2ac6b9f3351492a220c38 100644 (file)
@@ -193,7 +193,8 @@ MidiStreamView::display_region(MidiRegionView* region_view, bool load_model)
        }
 
        if (load_model) {
-               source->load_model();
+               Glib::Threads::Mutex::Lock lm(source->mutex());
+               source->load_model(lm);
        }
 
        if (!source->model()) {
@@ -225,7 +226,8 @@ MidiStreamView::update_contents_metrics(boost::shared_ptr<Region> r)
 {
        boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(r);
        if (mr) {
-               mr->midi_source(0)->load_model();
+               Glib::Threads::Mutex::Lock lm(mr->midi_source(0)->mutex());
+               mr->midi_source(0)->load_model(lm);
                _range_dirty = update_data_note_range(
                        mr->model()->lowest_note(),
                        mr->model()->highest_note());
index 4831eb208166e812499b3ac8a12d4b93952fd1f0..9e63f4c81d84bf9fee6a101ca7cee6415adc9e56 100644 (file)
@@ -64,7 +64,7 @@ public:
        virtual int update_header (framepos_t when, struct tm&, time_t) = 0;
        virtual int flush_header () = 0;
 
-       void mark_streaming_write_completed ();
+       void mark_streaming_write_completed (const Lock& lock);
 
        int setup_peakfile ();
 
index 7d1878f286c630fd7d6167ebbff10d6e937d3427..622bc6052aa709fe85f8919d7dd1d9995d894fc5 100644 (file)
@@ -60,7 +60,7 @@ class LIBARDOUR_API AudioSource : virtual public Source,
 
        virtual float sample_rate () const = 0;
 
-       virtual void mark_streaming_write_completed ();
+       virtual void mark_streaming_write_completed (const Lock& lock);
 
        virtual bool can_truncate_peaks() const { return true; }
 
index 4d12839625f65c78ba53b7877cf0183507e47943..1988c1a2d11c99350ed3a2494604e1f917a12920 100644 (file)
@@ -238,10 +238,15 @@ public:
        void apply_command (Session& session, Command* cmd);
        void apply_command_as_subcommand (Session& session, Command* cmd);
 
-       bool sync_to_source ();
-       bool write_to(boost::shared_ptr<MidiSource> source);
-       bool write_section_to (boost::shared_ptr<MidiSource> source, Evoral::MusicalTime begin = Evoral::MinMusicalTime,
-       Evoral::MusicalTime end = Evoral::MaxMusicalTime);
+       bool sync_to_source (const Glib::Threads::Mutex::Lock& source_lock);
+
+       bool write_to(boost::shared_ptr<MidiSource>     source,
+                     const Glib::Threads::Mutex::Lock& source_lock);
+
+       bool write_section_to(boost::shared_ptr<MidiSource>     source,
+                             const Glib::Threads::Mutex::Lock& source_lock,
+                             Evoral::MusicalTime               begin = Evoral::MinMusicalTime,
+                             Evoral::MusicalTime               end   = Evoral::MaxMusicalTime);
 
        // MidiModel doesn't use the normal AutomationList serialisation code
        // since controller data is stored in the .mid
index 7a61f5aa02ddc5083d02bc6d128f5e55989153fe..f0645533426fbd4e880a30129f1ad91246bb0d11 100644 (file)
@@ -45,10 +45,10 @@ public:
        XMLNode& get_state ();
        int set_state (const XMLNode&, int version);
 
-       void append_event_unlocked_beats(const Evoral::Event<Evoral::MusicalTime>& ev);
-       void append_event_unlocked_frames(const Evoral::Event<framepos_t>& ev, framepos_t source_start);
-       void load_model(bool lock=true, bool force_reload=false);
-       void destroy_model();
+       void append_event_beats(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<Evoral::MusicalTime>& ev);
+       void append_event_frames(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<framepos_t>& ev, framepos_t source_start);
+       void load_model(const Glib::Threads::Mutex::Lock& lock, bool force_reload=false);
+       void destroy_model(const Glib::Threads::Mutex::Lock& lock);
 
 protected:
        friend class SourceFactory;
@@ -58,15 +58,17 @@ protected:
        MidiPlaylistSource (Session&, const XMLNode&);
 
 
-       void flush_midi();
+       void flush_midi(const Lock& lock);
 
-       framecnt_t read_unlocked (Evoral::EventSink<framepos_t>& dst,
+       framecnt_t read_unlocked (const Lock&                    lock,
+                                 Evoral::EventSink<framepos_t>& dst,
                                  framepos_t                     position,
                                  framepos_t                     start,
                                  framecnt_t                     cnt,
                                  MidiStateTracker*              tracker) const;
 
-       framecnt_t write_unlocked (MidiRingBuffer<framepos_t>& dst,
+       framecnt_t write_unlocked (const Lock&                 lock,
+                                  MidiRingBuffer<framepos_t>& dst,
                                   framepos_t                  position,
                                   framecnt_t                  cnt);
 
index 2ce92ba3cfd41d4a2af9987cf825b6129e5cd591..2b78230a00d328a9abe69cea335e79bede014e8f 100644 (file)
@@ -57,7 +57,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
         * \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 (boost::shared_ptr<MidiSource> newsrc,
+       int write_to (const Lock&                   lock,
+                     boost::shared_ptr<MidiSource> newsrc,
                      Evoral::MusicalTime           begin = Evoral::MinMusicalTime,
                      Evoral::MusicalTime           end   = Evoral::MaxMusicalTime);
 
@@ -70,7 +71,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
         * \param tracker an optional pointer to MidiStateTracker object, for note on/off tracking.
         * \param filtered Parameters whose MIDI messages will not be returned.
         */
-       virtual framecnt_t midi_read (Evoral::EventSink<framepos_t>&     dst,
+       virtual framecnt_t midi_read (const Lock&                        lock,
+                                     Evoral::EventSink<framepos_t>&     dst,
                                      framepos_t                         source_start,
                                      framepos_t                         start,
                                      framecnt_t                         cnt,
@@ -82,22 +84,33 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
         *  @param source_start This source's start position in session frames.
         *  @param cnt The length of time to write.
         */
-       virtual framecnt_t midi_write (MidiRingBuffer<framepos_t>& src,
+       virtual framecnt_t midi_write (const Lock&                 lock,
+                                      MidiRingBuffer<framepos_t>& src,
                                       framepos_t                  source_start,
                                       framecnt_t                  cnt);
 
-       virtual void append_event_unlocked_beats(const Evoral::Event<Evoral::MusicalTime>& ev) = 0;
+       /** Append a single event with a timestamp in beats.
+        *
+        * Caller must ensure that the event is later than the last written event.
+        */
+       virtual void append_event_beats(const Lock&                               lock,
+                                       const Evoral::Event<Evoral::MusicalTime>& ev) = 0;
 
-       virtual void append_event_unlocked_frames(const Evoral::Event<framepos_t>& ev,
-                                                 framepos_t                       source_start) = 0;
+       /** Append a single event with a timestamp in frames.
+        *
+        * Caller must ensure that the event is later than the last written event.
+        */
+       virtual void append_event_frames(const Lock&                      lock,
+                                        const Evoral::Event<framepos_t>& ev,
+                                        framepos_t                       source_start) = 0;
 
        virtual bool       empty () const;
        virtual framecnt_t length (framepos_t pos) const;
        virtual void       update_length (framecnt_t);
 
-       virtual void mark_streaming_midi_write_started (NoteMode mode);
-       virtual void mark_streaming_write_started ();
-       virtual void mark_streaming_write_completed ();
+       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);
 
        /** Mark write starting with the given time parameters.
         *
@@ -119,6 +132,7 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
         * etc.
         */
        virtual void mark_midi_streaming_write_completed (
+               const Lock&                                            lock,
                Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_option,
                Evoral::MusicalTime                                    when = Evoral::MusicalTime());
 
@@ -137,19 +151,17 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
        void     set_length_beats(TimeType l) { _length_beats = l; }
        TimeType length_beats() const         { return _length_beats; }
 
-       virtual void load_model(bool lock=true, bool force_reload=false) = 0;
-       virtual void destroy_model() = 0;
+       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;
 
-       /** This must be called with the source lock held whenever the
-        *  source/model contents have been changed (reset iterators/cache/etc).
-        */
-       void invalidate();
+       /** Reset cached information (like iterators) when things have changed. */
+       void invalidate(const Glib::Threads::Mutex::Lock& lock);
 
-       void set_note_mode(NoteMode mode);
+       void set_note_mode(const Glib::Threads::Mutex::Lock& lock, NoteMode mode);
 
        boost::shared_ptr<MidiModel> model() { return _model; }
-       void set_model (boost::shared_ptr<MidiModel>);
-       void drop_model();
+       void set_model(const Glib::Threads::Mutex::Lock& lock, boost::shared_ptr<MidiModel>);
+       void drop_model(const Glib::Threads::Mutex::Lock& lock);
 
        Evoral::ControlList::InterpolationStyle interpolation_of (Evoral::Parameter) const;
        void set_interpolation_of (Evoral::Parameter, Evoral::ControlList::InterpolationStyle);
@@ -169,9 +181,10 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
        PBD::Signal2<void, Evoral::Parameter, AutoState> AutomationStateChanged;
 
   protected:
-       virtual void flush_midi() = 0;
+       virtual void flush_midi(const Lock& lock) = 0;
 
-       virtual framecnt_t read_unlocked (Evoral::EventSink<framepos_t>& dst,
+       virtual framecnt_t read_unlocked (const Lock&                    lock,
+                                         Evoral::EventSink<framepos_t>& dst,
                                          framepos_t                     position,
                                          framepos_t                     start,
                                          framecnt_t                     cnt,
@@ -182,7 +195,8 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
         *  @param position This source's start position in session frames.
         *  @param cnt The duration of this block to write for.
         */
-       virtual framecnt_t write_unlocked (MidiRingBuffer<framepos_t>& source,
+       virtual framecnt_t write_unlocked (const Lock&                 lock,
+                                          MidiRingBuffer<framepos_t>& source,
                                           framepos_t                  position,
                                           framecnt_t                  cnt) = 0;
 
index d8a31c10aaddc8df3974424de45ddc85bcd8c8ee..98611bc72249f8a9838fbdff6b4411a661816cf9 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __ardour_midi_state_tracker_h__
 #define __ardour_midi_state_tracker_h__
 
+#include <glibmm/threads.h>
+
 #include "ardour/midi_buffer.h"
 
 namespace Evoral {
@@ -44,7 +46,7 @@ public:
        void remove (uint8_t note, uint8_t chn);
        void resolve_notes (MidiBuffer& buffer, framepos_t time);
        void resolve_notes (Evoral::EventSink<framepos_t>& buffer, framepos_t time);
-       void resolve_notes (MidiSource& src, Evoral::MusicalTime time);
+       void resolve_notes (MidiSource& src, const Glib::Threads::Mutex::Lock& lock, Evoral::MusicalTime time);
        void dump (std::ostream&);
        void reset ();
        bool empty() const { return _on == 0; }
index 56b70b15bd49ca3d8e9353ed6b983b7dcdcf5ce7..d93fdb8506322ed6a6bb53978b9526745af17192 100644 (file)
@@ -47,26 +47,24 @@ public:
 
        virtual ~SMFSource ();
 
-        bool safe_file_extension (const std::string& path) const {
+       bool safe_file_extension (const std::string& path) const {
                return safe_midi_file_extension(path);
        }
 
-       void append_event_unlocked_beats (const Evoral::Event<Evoral::MusicalTime>& ev);
-       void append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, framepos_t source_start);
+       void append_event_beats (const Lock& lock, const Evoral::Event<Evoral::MusicalTime>& ev);
+       void append_event_frames (const Lock& lock, const Evoral::Event<framepos_t>& ev, framepos_t source_start);
 
-       void mark_streaming_midi_write_started (NoteMode mode);
-       void mark_streaming_write_completed ();
-       void mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption,
+       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,
+                                                 Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption,
                                                  Evoral::MusicalTime when = Evoral::MusicalTime());
 
        XMLNode& get_state ();
        int set_state (const XMLNode&, int version);
 
-       void load_model (bool lock=true, bool force_reload=false);
-       void destroy_model ();
-
-       void flush_midi ();
-       void ensure_disk_file ();
+       void load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload=false);
+       void destroy_model (const Glib::Threads::Mutex::Lock& lock);
 
        static bool safe_midi_file_extension (const std::string& path);
        static bool valid_midi_file (const std::string& path);
@@ -75,6 +73,7 @@ public:
 
   protected:
        void set_path (const std::string& newpath);
+       void flush_midi (const Lock& lock);
 
   private:
        bool _open;
@@ -87,13 +86,17 @@ public:
 
        int open_for_write ();
        
-       framecnt_t read_unlocked (Evoral::EventSink<framepos_t>& dst,
+       void ensure_disk_file (const Lock& lock);
+
+       framecnt_t read_unlocked (const Lock&                    lock,
+                                 Evoral::EventSink<framepos_t>& dst,
                                  framepos_t                     position,
                                  framepos_t                     start,
                                  framecnt_t                     cnt,
                                  MidiStateTracker*              tracker) const;
 
-       framecnt_t write_unlocked (MidiRingBuffer<framepos_t>& src,
+       framecnt_t write_unlocked (const Lock&                 lock,
+                                  MidiRingBuffer<framepos_t>& src,
                                   framepos_t                  position,
                                   framecnt_t                  cnt);
 
index e009e0ef51e49c5dff84e159870b3f6c18535665..18de40771c9799bddec7668d6d8a7fe66ad908a5 100644 (file)
@@ -51,6 +51,8 @@ class LIBARDOUR_API Source : public SessionObject
                Empty = 0x100, /* used for MIDI only */
        };
 
+       typedef Glib::Threads::Mutex::Lock Lock;
+
        Source (Session&, DataType type, const std::string& name, Flag flags=Flag(0));
        Source (Session&, const XMLNode&);
 
@@ -69,8 +71,8 @@ class LIBARDOUR_API Source : public SessionObject
 
        void mark_for_remove();
 
-       virtual void mark_streaming_write_started () {}
-       virtual void mark_streaming_write_completed () = 0;
+       virtual void mark_streaming_write_started (const Lock& lock) {}
+       virtual void mark_streaming_write_completed (const Lock& lock) = 0;
 
        virtual void session_saved() {}
 
index 4c3f7e6437f6f859d7fb97cc715714bca6670610..eb855388113c61a9a7673b186da587bc786b09fe 100644 (file)
@@ -1771,13 +1771,15 @@ AudioDiskstream::prep_record_enable ()
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
                        (*chan)->source.request_input_monitoring (!(_session.config.get_auto_input() && rolling));
                        capturing_sources.push_back ((*chan)->write_source);
-                       (*chan)->write_source->mark_streaming_write_started ();
+                       (*chan)->write_source->mark_streaming_write_started (
+                               Source::Lock((*chan)->write_source->mutex()));
                }
 
        } else {
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
                        capturing_sources.push_back ((*chan)->write_source);
-                       (*chan)->write_source->mark_streaming_write_started ();
+                       (*chan)->write_source->mark_streaming_write_started (
+                               Source::Lock((*chan)->write_source->mutex()));
                }
        }
 
@@ -1963,7 +1965,8 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/)
                        if ((*chan)->write_source) {
 
                                if (mark_write_complete) {
-                                       (*chan)->write_source->mark_streaming_write_completed ();
+                                       (*chan)->write_source->mark_streaming_write_completed (
+                                               Source::Lock((*chan)->write_source->mutex()));
                                        (*chan)->write_source->done_with_peakfile_writes ();
                                }
 
index 40c3d2f012757c43371a7a0c0433614fbd8ec45a..6d9414a5cb6c20368af50ff52424576a3ccf1c95 100644 (file)
@@ -302,13 +302,13 @@ AudioFileSource::set_state (const XMLNode& node, int version)
 }
 
 void
-AudioFileSource::mark_streaming_write_completed ()
+AudioFileSource::mark_streaming_write_completed (const Lock& lock)
 {
        if (!writable()) {
                return;
        }
 
-       AudioSource::mark_streaming_write_completed ();
+       AudioSource::mark_streaming_write_completed (lock);
 }
 
 int
index b0b229a57aee885fc0245551a06672be404a92d6..93a0ca4fee9ce6201939f8275889d8fa388ef96b 100644 (file)
@@ -923,7 +923,7 @@ AudioSource::available_peaks (double zoom_factor) const
 }
 
 void
-AudioSource::mark_streaming_write_completed ()
+AudioSource::mark_streaming_write_completed (const Lock& lock)
 {
        Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
 
index 38a3da2fdcf52030ca78a2582c145611df5e2b60..2b3f1058792b60b8fcb18fe41851cfcf40cf59d6 100644 (file)
@@ -354,7 +354,9 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
 
                        boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource> (*s);
 
-                       smfs->drop_model ();
+                       Glib::Threads::Mutex::Lock source_lock(smfs->mutex());
+
+                       smfs->drop_model (source_lock);
                        source->seek_to_track (i);
 
                        uint64_t t       = 0;
@@ -384,11 +386,12 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
                                }
 
                                if (first) {
-                                       smfs->mark_streaming_write_started ();
+                                       smfs->mark_streaming_write_started (source_lock);
                                        first = false;
                                }
 
-                               smfs->append_event_unlocked_beats(
+                               smfs->append_event_beats(
+                                       source_lock,
                                        Evoral::Event<Evoral::MusicalTime>(
                                                0,
                                                Evoral::MusicalTime::ticks_at_rate(t, source->ppqn()),
@@ -408,7 +411,7 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
                                const Evoral::MusicalTime length_beats = Evoral::MusicalTime::ticks_at_rate(t, source->ppqn());
                                BeatsFramesConverter      converter(smfs->session().tempo_map(), pos);
                                smfs->update_length(pos + converter.to(length_beats.round_up_to_beat()));
-                               smfs->mark_streaming_write_completed ();
+                               smfs->mark_streaming_write_completed (source_lock);
 
                                if (status.cancel) {
                                        break;
index 27ec409b1517131b808a45f83051776ace8ce797..e2fd6d168144fb09809124e359449a98cd6c3c66 100644 (file)
@@ -851,7 +851,8 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
        }
 
        if (record_enabled() && ((total > disk_io_chunk_frames) || force_flush)) {
-               if (_write_source->midi_write (*_capture_buf, get_capture_start_frame (0), to_write) != to_write) {
+               Source::Lock lm(_write_source->mutex());
+               if (_write_source->midi_write (lm, *_capture_buf, get_capture_start_frame (0), to_write) != to_write) {
                        error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg;
                        return -1;
                } 
@@ -919,6 +920,8 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
 
                        /* phew, we have data */
 
+                       Source::Lock source_lock(_write_source->mutex());
+
                        /* figure out the name for this take */
 
                        srcs.push_back (_write_source);
@@ -936,7 +939,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
                           where all the data is already on disk.
                        */
 
-                       _write_source->mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, total_capture_beats);
+                       _write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, total_capture_beats);
 
                        /* we will want to be able to keep (over)writing the source
                           but we don't want it to be removable. this also differs
@@ -1280,7 +1283,8 @@ MidiDiskstream::reset_write_sources (bool mark_write_complete, bool /*force*/)
        }
 
        if (_write_source && mark_write_complete) {
-               _write_source->mark_streaming_write_completed ();
+               Source::Lock lm(_write_source->mutex());
+               _write_source->mark_streaming_write_completed (lm);
        }
        use_new_write_source (0);
 }
index 6c2132562a09c06ab027884b7246b925d72bb17f..f64a5f6d0c6c62deac07dd08551effad8ec84818 100644 (file)
@@ -1426,25 +1426,23 @@ MidiModel::PatchChangeDiffCommand::get_state ()
  * `Discrete' mode).
  */
 bool
-MidiModel::write_to (boost::shared_ptr<MidiSource> source)
+MidiModel::write_to (boost::shared_ptr<MidiSource>     source,
+                     const Glib::Threads::Mutex::Lock& source_lock)
 {
        ReadLock lock(read_lock());
 
        const bool old_percussive = percussive();
        set_percussive(false);
 
-       boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
-       assert (ms);
-
-       source->drop_model();
-       source->mark_streaming_midi_write_started (note_mode());
+       source->drop_model(source_lock);
+       source->mark_streaming_midi_write_started (source_lock, note_mode());
 
        for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
-               source->append_event_unlocked_beats(*i);
+               source->append_event_beats(source_lock, *i);
        }
 
        set_percussive(old_percussive);
-       source->mark_streaming_write_completed();
+       source->mark_streaming_write_completed(source_lock);
 
        set_edited(false);
 
@@ -1457,7 +1455,7 @@ MidiModel::write_to (boost::shared_ptr<MidiSource> source)
     of the model.
 */
 bool
-MidiModel::sync_to_source ()
+MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock)
 {
        ReadLock lock(read_lock());
 
@@ -1465,16 +1463,19 @@ MidiModel::sync_to_source ()
        set_percussive(false);
 
        boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
-       assert (ms);
+       if (!ms) {
+               error << "MIDI model has no source to sync to" << endmsg;
+               return false;
+       }
 
-       ms->mark_streaming_midi_write_started (note_mode());
+       ms->mark_streaming_midi_write_started (source_lock, note_mode());
 
        for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
-               ms->append_event_unlocked_beats(*i);
+               ms->append_event_beats(source_lock, *i);
        }
 
        set_percussive (old_percussive);
-       ms->mark_streaming_write_completed ();
+       ms->mark_streaming_write_completed (source_lock);
 
        set_edited (false);
 
@@ -1489,7 +1490,10 @@ MidiModel::sync_to_source ()
  * destroying the original note durations.
  */
 bool
-MidiModel::write_section_to (boost::shared_ptr<MidiSource> source, Evoral::MusicalTime begin_time, Evoral::MusicalTime end_time)
+MidiModel::write_section_to (boost::shared_ptr<MidiSource>     source,
+                             const Glib::Threads::Mutex::Lock& source_lock,
+                             Evoral::MusicalTime               begin_time,
+                             Evoral::MusicalTime               end_time)
 {
        ReadLock lock(read_lock());
        MidiStateTracker mst;
@@ -1497,11 +1501,8 @@ MidiModel::write_section_to (boost::shared_ptr<MidiSource> source, Evoral::Music
        const bool old_percussive = percussive();
        set_percussive(false);
 
-       boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
-       assert (ms);
-
-       source->drop_model();
-       source->mark_streaming_midi_write_started (note_mode());
+       source->drop_model(source_lock);
+       source->mark_streaming_midi_write_started (source_lock, note_mode());
 
        for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
                const Evoral::Event<Evoral::MusicalTime>& ev (*i);
@@ -1526,22 +1527,22 @@ MidiModel::write_section_to (boost::shared_ptr<MidiSource> source, Evoral::Music
                                        continue;
                                }
 
-                               source->append_event_unlocked_beats (*i);
+                               source->append_event_beats (source_lock, *i);
                                mst.remove (mev->note(), mev->channel());
 
                        } else if (mev->is_note_on()) {
                                mst.add (mev->note(), mev->channel());
-                               source->append_event_unlocked_beats(*i);
+                               source->append_event_beats(source_lock, *i);
                        } else {
-                               source->append_event_unlocked_beats(*i);
+                               source->append_event_beats(source_lock, *i);
                        }
                }
        }
 
-       mst.resolve_notes (*source, end_time);
+       mst.resolve_notes (*source, source_lock, end_time);
 
        set_percussive(old_percussive);
-       source->mark_streaming_write_completed();
+       source->mark_streaming_write_completed(source_lock);
 
        set_edited(false);
 
@@ -1630,7 +1631,7 @@ MidiModel::edit_lock()
        assert (ms);
 
        Glib::Threads::Mutex::Lock* source_lock = new Glib::Threads::Mutex::Lock (ms->mutex());
-       ms->invalidate(); // Release cached iterator's read lock on model
+       ms->invalidate(*source_lock); // Release cached iterator's read lock on model
        return WriteLock(new WriteLockImpl(source_lock, _lock, _control_lock));
 }
 
@@ -1855,7 +1856,8 @@ MidiModel::set_midi_source (boost::shared_ptr<MidiSource> s)
        boost::shared_ptr<MidiSource> old = _midi_source.lock ();
 
        if (old) {
-               old->invalidate ();
+               Source::Lock lm(old->mutex());
+               old->invalidate (lm);
        }
 
        _midi_source_connections.drop_connections ();
index cd5362c3dafb822d166519e19f935e6120f97ca1..587bc7b12fe034419f7fe816bcb83d0f8a6f0d7a 100644 (file)
@@ -122,7 +122,8 @@ MidiPlaylistSource::length (framepos_t)  const
 }
 
 framecnt_t
-MidiPlaylistSource::read_unlocked (Evoral::EventSink<framepos_t>& dst,
+MidiPlaylistSource::read_unlocked (const Lock& lock,
+                                  Evoral::EventSink<framepos_t>& dst,
                                   framepos_t /*position*/,
                                   framepos_t start, framecnt_t cnt,
                                   MidiStateTracker*) const
@@ -137,7 +138,8 @@ MidiPlaylistSource::read_unlocked (Evoral::EventSink<framepos_t>& dst,
 }
 
 framecnt_t
-MidiPlaylistSource::write_unlocked (MidiRingBuffer<framepos_t>&,
+MidiPlaylistSource::write_unlocked (const Lock&,
+                                    MidiRingBuffer<framepos_t>&,
                                     framepos_t,
                                     framecnt_t)
 {
@@ -147,33 +149,33 @@ MidiPlaylistSource::write_unlocked (MidiRingBuffer<framepos_t>&,
 }
 
 void
-MidiPlaylistSource::append_event_unlocked_beats(const Evoral::Event<Evoral::MusicalTime>& /*ev*/)
+MidiPlaylistSource::append_event_beats(const Glib::Threads::Mutex::Lock& /*lock*/, const Evoral::Event<Evoral::MusicalTime>& /*ev*/)
 {
-       fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_unlocked_beats() called - should be impossible") << endmsg;
+       fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_beats() called - should be impossible") << endmsg;
        abort(); /*NOTREACHED*/
 }
 
 void
-MidiPlaylistSource::append_event_unlocked_frames(const Evoral::Event<framepos_t>& /* ev */, framepos_t /*source_start*/)
+MidiPlaylistSource::append_event_frames(const Glib::Threads::Mutex::Lock& /*lock*/, const Evoral::Event<framepos_t>& /* ev */, framepos_t /*source_start*/)
 {
-       fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_unlocked_frames() called - should be impossible") << endmsg;
+       fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_frames() called - should be impossible") << endmsg;
        abort(); /*NOTREACHED*/
 }
 
 void
-MidiPlaylistSource::load_model (bool, bool)
+MidiPlaylistSource::load_model (const Glib::Threads::Mutex::Lock&, bool)
 {
        /* nothing to do */
 }
 
 void
-MidiPlaylistSource::destroy_model ()
+MidiPlaylistSource::destroy_model (const Glib::Threads::Mutex::Lock&)
 {
        /* nothing to do */
 }
 
 void
-MidiPlaylistSource::flush_midi ()
+MidiPlaylistSource::flush_midi (const Lock& lock)
 {
 }
 
index f6631b9de5a5e3af905c6aac1afbd48fe78bbbd6..f79e5ef2034b122b253f9a863f89c52007216fd9 100644 (file)
@@ -150,8 +150,11 @@ MidiRegion::clone (boost::shared_ptr<MidiSource> newsrc) const
        Evoral::MusicalTime const bbegin = bfc.from (_start);
        Evoral::MusicalTime const bend = bfc.from (_start + _length);
 
-       if (midi_source(0)->write_to (newsrc, bbegin, bend)) {
-               return boost::shared_ptr<MidiRegion> ();
+       {
+               Source::Lock lm(newsrc->mutex());
+               if (midi_source(0)->write_to (lm, newsrc, bbegin, bend)) {
+                       return boost::shared_ptr<MidiRegion> ();
+               }
        }
 
        PropertyList plist;
@@ -272,7 +275,10 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, Evoral::EventSink<framepos_t>&
        }
 
        boost::shared_ptr<MidiSource> src = midi_source(chan_n);
-       src->set_note_mode(mode);
+
+       Glib::Threads::Mutex::Lock lm(src->mutex());
+
+       src->set_note_mode(lm, mode);
 
        /*
          cerr << "MR " << name () << " read @ " << position << " * " << to_read
@@ -285,6 +291,7 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, Evoral::EventSink<framepos_t>&
        /* This call reads events from a source and writes them to `dst' timed in session frames */
 
        if (src->midi_read (
+                   lm, // source lock
                        dst, // destination buffer
                        _position - _start, // start position of the source in session frames
                        _start + internal_offset, // where to start reading in the source
@@ -429,7 +436,7 @@ MidiRegion::model_automation_state_changed (Evoral::Parameter const & p)
           the iterator.
        */
        Glib::Threads::Mutex::Lock lm (midi_source(0)->mutex());
-       midi_source(0)->invalidate ();
+       midi_source(0)->invalidate (lm);
 }
 
 /** This is called when a trim drag has resulted in a -ve _start time for this region.
index adf28cff09fe741af8e24bbe190f6df5edc8f0e4..1b1cf20c68b34b528cf7978ca86b762c77712221 100644 (file)
@@ -177,22 +177,21 @@ MidiSource::update_length (framecnt_t)
 }
 
 void
-MidiSource::invalidate ()
+MidiSource::invalidate (const Lock& lock)
 {
        _model_iter_valid = false;
        _model_iter.invalidate();
 }
 
 framecnt_t
-MidiSource::midi_read (Evoral::EventSink<framepos_t>&     dst,
+MidiSource::midi_read (const Lock&                        lm,
+                       Evoral::EventSink<framepos_t>&     dst,
                        framepos_t                         source_start,
                        framepos_t                         start,
                        framecnt_t                         cnt,
                        MidiStateTracker*                  tracker,
                        const std::set<Evoral::Parameter>& filtered) const
 {
-       Glib::Threads::Mutex::Lock lm (_lock);
-
        BeatsFramesConverter converter(_session.tempo_map(), source_start);
 
        DEBUG_TRACE (DEBUG::MidiSourceIO,
@@ -233,22 +232,21 @@ MidiSource::midi_read (Evoral::EventSink<framepos_t>&     dst,
                }
                return cnt;
        } else {
-               return read_unlocked (dst, source_start, start, cnt, tracker);
+               return read_unlocked (lm, dst, source_start, start, cnt, tracker);
        }
 }
 
 framecnt_t
-MidiSource::midi_write (MidiRingBuffer<framepos_t>& source,
+MidiSource::midi_write (const Lock&                 lm,
+                        MidiRingBuffer<framepos_t>& source,
                         framepos_t                  source_start,
                         framecnt_t                  cnt)
 {
-       Glib::Threads::Mutex::Lock lm (_lock);
-
-       const framecnt_t ret = write_unlocked (source, source_start, cnt);
+       const framecnt_t ret = write_unlocked (lm, source, source_start, cnt);
 
        if (cnt == max_framecnt) {
                _last_read_end = 0;
-               invalidate();
+               invalidate(lm);
        } else {
                _capture_length += cnt;
        }
@@ -257,7 +255,7 @@ MidiSource::midi_write (MidiRingBuffer<framepos_t>& source,
 }
 
 void
-MidiSource::mark_streaming_midi_write_started (NoteMode mode)
+MidiSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
 {
        if (_model) {
                _model->set_note_mode (mode);
@@ -292,14 +290,15 @@ MidiSource::mark_write_starting_now (framecnt_t position,
 }
 
 void
-MidiSource::mark_streaming_write_started ()
+MidiSource::mark_streaming_write_started (const Lock& lock)
 {
        NoteMode note_mode = _model ? _model->note_mode() : Sustained;
-       mark_streaming_midi_write_started (note_mode);
+       mark_streaming_midi_write_started (lock, note_mode);
 }
 
 void
-MidiSource::mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption option,
+MidiSource::mark_midi_streaming_write_completed (const Lock&                                            lock,
+                                                 Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption option,
                                                  Evoral::MusicalTime                                    end)
 {
        if (_model) {
@@ -318,37 +317,39 @@ MidiSource::mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::Musica
 }
 
 void
-MidiSource::mark_streaming_write_completed ()
+MidiSource::mark_streaming_write_completed (const Lock& lock)
 {
-       mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::DeleteStuckNotes);
+       mark_midi_streaming_write_completed (lock, Evoral::Sequence<Evoral::MusicalTime>::DeleteStuckNotes);
 }
 
 int
-MidiSource::write_to (boost::shared_ptr<MidiSource> newsrc, Evoral::MusicalTime begin, Evoral::MusicalTime end)
+MidiSource::write_to (const Lock& lock, boost::shared_ptr<MidiSource> newsrc, Evoral::MusicalTime begin, Evoral::MusicalTime end)
 {
+       Lock newsrc_lock (newsrc->mutex ());
+
        newsrc->set_timeline_position (_timeline_position);
        newsrc->copy_interpolation_from (this);
        newsrc->copy_automation_state_from (this);
 
        if (_model) {
                if (begin == Evoral::MinMusicalTime && end == Evoral::MaxMusicalTime) {
-                       _model->write_to (newsrc);
+                       _model->write_to (newsrc, newsrc_lock);
                } else {
-                       _model->write_section_to (newsrc, begin, end);
+                       _model->write_section_to (newsrc, newsrc_lock, begin, end);
                }
        } else {
                error << string_compose (_("programming error: %1"), X_("no model for MidiSource during ::clone()"));
                return -1;
        }
 
-       newsrc->flush_midi();
+       newsrc->flush_midi(newsrc_lock);
 
        /* force a reload of the model if the range is partial */
 
        if (begin != Evoral::MinMusicalTime || end != Evoral::MaxMusicalTime) {
-               newsrc->load_model (true, true);
+               newsrc->load_model (newsrc_lock, true);
        } else {
-               newsrc->set_model (_model);
+               newsrc->set_model (newsrc_lock, _model);
        }
 
        /* this file is not removable (but since it is MIDI, it is mutable) */
@@ -361,6 +362,8 @@ MidiSource::write_to (boost::shared_ptr<MidiSource> newsrc, Evoral::MusicalTime
 void
 MidiSource::session_saved()
 {
+       Lock lm (_lock);
+
        /* this writes a copy of the data to disk.
           XXX do we need to do this every time?
        */
@@ -375,18 +378,18 @@ MidiSource::session_saved()
                _model.reset ();
 
                /* Flush model contents to disk. */
-               mm->sync_to_source ();
+               mm->sync_to_source (lm);
 
                /* Reacquire model. */
                _model = mm;
 
        } else {
-               flush_midi();
+               flush_midi(lm);
        }
 }
 
 void
-MidiSource::set_note_mode(NoteMode mode)
+MidiSource::set_note_mode(const Lock& lock, NoteMode mode)
 {
        if (_model) {
                _model->set_note_mode(mode);
@@ -394,18 +397,18 @@ MidiSource::set_note_mode(NoteMode mode)
 }
 
 void
-MidiSource::drop_model ()
+MidiSource::drop_model (const Lock& lock)
 {
        _model.reset();
-       invalidate();
+       invalidate(lock);
        ModelChanged (); /* EMIT SIGNAL */
 }
 
 void
-MidiSource::set_model (boost::shared_ptr<MidiModel> m)
+MidiSource::set_model (const Lock& lock, boost::shared_ptr<MidiModel> m)
 {
        _model = m;
-       invalidate();
+       invalidate(lock);
        ModelChanged (); /* EMIT SIGNAL */
 }
 
index afe6f07db7438ea35c2293489bdd46d4ae3e5f38..f919a02f355ecdb3907ea78c43d958eacfc8b457 100644 (file)
@@ -168,7 +168,7 @@ MidiStateTracker::resolve_notes (Evoral::EventSink<framepos_t> &dst, framepos_t
 }
 
 void
-MidiStateTracker::resolve_notes (MidiSource& src, Evoral::MusicalTime time)
+MidiStateTracker::resolve_notes (MidiSource& src, const MidiSource::Lock& lock, Evoral::MusicalTime time)
 {
        DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 MS-resolve notes @ %2 on = %3\n", this, time, _on));
 
@@ -186,7 +186,7 @@ MidiStateTracker::resolve_notes (MidiSource& src, Evoral::MusicalTime time)
                                ev.set_channel (channel);
                                ev.set_note (note);
                                ev.set_velocity (0);
-                               src.append_event_unlocked_beats (ev);
+                               src.append_event_beats (lock, ev);
                                DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1: MS-resolved note %2/%3 at %4\n", 
                                                                                       this, (int) note, (int) channel, time));
                                _active_notes[note + 128 * channel]--;
index f5b3a47b41e7e2831e55efafee93115ff624f6db..0e75cdca1d25a02acf03a5a1fb788fb69b3a4f90 100644 (file)
@@ -76,7 +76,7 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
                return -1;
 
        boost::shared_ptr<MidiSource> src = region->midi_source(0);
-       src->load_model();
+       src->load_model(Glib::Threads::Mutex::Lock(src->mutex()));
 
        boost::shared_ptr<MidiModel> old_model = src->model();
 
@@ -88,7 +88,7 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
 
        Glib::Threads::Mutex::Lock sl (new_src->mutex ());
 
-       new_src->load_model(false, true);
+       new_src->load_model(sl, true);
        boost::shared_ptr<MidiModel> new_model = new_src->model();
        new_model->start_write();
 
index b25977fe8d437a5b8a71eb510d60580deabb22d0..519d8bbf1089ab172e25c81298ef27dd29eb5ff1 100644 (file)
@@ -203,7 +203,8 @@ SMFSource::open_for_write ()
 
 /** All stamps in audio frames */
 framecnt_t
-SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination,
+SMFSource::read_unlocked (const Lock&                    lock,
+                          Evoral::EventSink<framepos_t>& destination,
                           framepos_t const               source_start,
                           framepos_t                     start,
                           framecnt_t                     duration,
@@ -303,12 +304,13 @@ SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination,
 }
 
 framecnt_t
-SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source,
+SMFSource::write_unlocked (const Lock&                 lock,
+                           MidiRingBuffer<framepos_t>& source,
                            framepos_t                  position,
                            framecnt_t                  cnt)
 {
        if (!_writing) {
-               mark_streaming_write_started ();
+               mark_streaming_write_started (lock);
        }
 
        framepos_t        time;
@@ -372,7 +374,7 @@ SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source,
                        continue;
                }
 
-               append_event_unlocked_frames(ev, position);
+               append_event_frames(lock, ev, position);
        }
 
        Evoral::SMF::flush ();
@@ -383,13 +385,14 @@ SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source,
 
 /** Append an event with a timestamp in beats */
 void
-SMFSource::append_event_unlocked_beats (const Evoral::Event<Evoral::MusicalTime>& ev)
+SMFSource::append_event_beats (const Glib::Threads::Mutex::Lock&         lock,
+                               const Evoral::Event<Evoral::MusicalTime>& ev)
 {
        if (!_writing || ev.size() == 0)  {
                return;
        }
 
-       /*printf("SMFSource: %s - append_event_unlocked_beats ID = %d time = %lf, size = %u, data = ",
+       /*printf("SMFSource: %s - append_event_beats ID = %d time = %lf, size = %u, data = ",
                name().c_str(), ev.id(), ev.time(), ev.size());
               for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/
 
@@ -435,13 +438,15 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<Evoral::MusicalTime>
 
 /** Append an event with a timestamp in frames (framepos_t) */
 void
-SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, framepos_t position)
+SMFSource::append_event_frames (const Glib::Threads::Mutex::Lock& lock,
+                                const Evoral::Event<framepos_t>&  ev,
+                                framepos_t                        position)
 {
        if (!_writing || ev.size() == 0)  {
                return;
        }
 
-       // printf("SMFSource: %s - append_event_unlocked_frames ID = %d time = %u, size = %u, data = ",
+       // printf("SMFSource: %s - append_event_frames ID = %d time = %u, size = %u, data = ",
        // name().c_str(), ev.id(), ev.time(), ev.size());
        // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
 
@@ -508,33 +513,30 @@ SMFSource::set_state (const XMLNode& node, int version)
 }
 
 void
-SMFSource::mark_streaming_midi_write_started (NoteMode mode)
+SMFSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
 {
-       /* CALLER MUST HOLD LOCK */
-
        if (!_open && open_for_write()) {
                error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
                /* XXX should probably throw or return something */
                return;
        }
 
-       MidiSource::mark_streaming_midi_write_started (mode);
+       MidiSource::mark_streaming_midi_write_started (lock, mode);
        Evoral::SMF::begin_write ();
        _last_ev_time_beats  = Evoral::MusicalTime();
        _last_ev_time_frames = 0;
 }
 
 void
-SMFSource::mark_streaming_write_completed ()
+SMFSource::mark_streaming_write_completed (const Lock& lock)
 {
-       mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::DeleteStuckNotes);
+       mark_midi_streaming_write_completed (lock, Evoral::Sequence<Evoral::MusicalTime>::DeleteStuckNotes);
 }
 
 void
-SMFSource::mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_notes_option, Evoral::MusicalTime when)
+SMFSource::mark_midi_streaming_write_completed (const Lock& lm, Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_notes_option, Evoral::MusicalTime when)
 {
-       Glib::Threads::Mutex::Lock lm (_lock);
-       MidiSource::mark_midi_streaming_write_completed (stuck_notes_option, when);
+       MidiSource::mark_midi_streaming_write_completed (lm, stuck_notes_option, when);
 
        if (!writable()) {
                warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
@@ -596,16 +598,12 @@ static bool compare_eventlist (
 }
 
 void
-SMFSource::load_model (bool lock, bool force_reload)
+SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload)
 {
        if (_writing) {
                return;
        }
 
-       boost::shared_ptr<Glib::Threads::Mutex::Lock> lm;
-       if (lock)
-               lm = boost::shared_ptr<Glib::Threads::Mutex::Lock>(new Glib::Threads::Mutex::Lock(_lock));
-
        if (_model && !force_reload) {
                return;
        }
@@ -616,7 +614,7 @@ SMFSource::load_model (bool lock, bool force_reload)
                _model->clear();
        }
 
-       invalidate();
+       invalidate(lock);
 
        if (writable() && !_open) {
                return;
@@ -707,33 +705,33 @@ SMFSource::load_model (bool lock, bool force_reload)
 
        _model->end_write (Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, _length_beats);
        _model->set_edited (false);
-       invalidate();
+       invalidate(lock);
 
        free(buf);
 }
 
 void
-SMFSource::destroy_model ()
+SMFSource::destroy_model (const Glib::Threads::Mutex::Lock& lock)
 {
        //cerr << _name << " destroying model " << _model.get() << endl;
        _model.reset();
-       invalidate();
+       invalidate(lock);
 }
 
 void
-SMFSource::flush_midi ()
+SMFSource::flush_midi (const Lock& lock)
 {
        if (!writable() || _length_beats == 0.0) {
                return;
        }
 
-       ensure_disk_file ();
+       ensure_disk_file (lock);
 
        Evoral::SMF::end_write ();
        /* data in the file means its no longer removable */
        mark_nonremovable ();
 
-       invalidate();
+       invalidate(lock);
 }
 
 void
@@ -745,7 +743,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 ()
+SMFSource::ensure_disk_file (const Lock& lock)
 {
        if (!writable()) {
                return;
@@ -757,9 +755,9 @@ SMFSource::ensure_disk_file ()
                */
                boost::shared_ptr<MidiModel> mm = _model;
                _model.reset ();
-               mm->sync_to_source ();
+               mm->sync_to_source (lock);
                _model = mm;
-               invalidate();
+               invalidate(lock);
        } else {
                /* No model; if it's not already open, it's an empty source, so create
                   and open it for writing.
index 6d2bb80b30be8859716bb09fea2a3d17b6e27c07..40051485648326c5058bf7cad832fa70d607aa41 100644 (file)
@@ -205,7 +205,7 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
                }
        } else if (type == DataType::MIDI) {
                boost::shared_ptr<SMFSource> src (new SMFSource (s, node));
-               src->load_model (true, true);
+               src->load_model (Glib::Threads::Mutex::Lock(src->mutex()), true);
 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
                // boost_debug_shared_ptr_mark_interesting (src, "Source");
 #endif
@@ -273,7 +273,7 @@ SourceFactory::createExternal (DataType type, Session& s, const string& path,
        } else if (type == DataType::MIDI) {
 
                boost::shared_ptr<SMFSource> src (new SMFSource (s, path));
-               src->load_model (true, true);
+               src->load_model (Glib::Threads::Mutex::Lock(src->mutex()), true);
 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
                // boost_debug_shared_ptr_mark_interesting (src, "Source");
 #endif
@@ -324,7 +324,7 @@ SourceFactory::createWritable (DataType type, Session& s, const std::string& pat
                boost::shared_ptr<SMFSource> src (new SMFSource (s, path, SndFileSource::default_writable_flags));
                assert (src->writable ());
 
-               src->load_model (true, true);
+               src->load_model (Glib::Threads::Mutex::Lock(src->mutex()), true);
 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
                // boost_debug_shared_ptr_mark_interesting (src, "Source");
 #endif