Fix various MIDI locking issues.
Attempt to make mistakes much less likely in the future by statically requiring caller to pass scoped locks where necessary.
This commit is contained in:
parent
1fa9edd872
commit
a706755710
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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() {}
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
||||
|
|
|
@ -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]--;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue