mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-16 03:36:32 +01:00
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
24 changed files with 228 additions and 174 deletions
|
|
@ -76,7 +76,8 @@ AutomationStreamView::add_region_view_internal (boost::shared_ptr<Region> region
|
||||||
if (wait_for_data) {
|
if (wait_for_data) {
|
||||||
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
|
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
|
||||||
if (mr) {
|
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());
|
gui_context());
|
||||||
|
|
||||||
if (wfd) {
|
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();
|
_model = midi_region()->midi_source(0)->model();
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,8 @@ MidiStreamView::display_region(MidiRegionView* region_view, bool load_model)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (load_model) {
|
if (load_model) {
|
||||||
source->load_model();
|
Glib::Threads::Mutex::Lock lm(source->mutex());
|
||||||
|
source->load_model(lm);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!source->model()) {
|
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);
|
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(r);
|
||||||
if (mr) {
|
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(
|
_range_dirty = update_data_note_range(
|
||||||
mr->model()->lowest_note(),
|
mr->model()->lowest_note(),
|
||||||
mr->model()->highest_note());
|
mr->model()->highest_note());
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ public:
|
||||||
virtual int update_header (framepos_t when, struct tm&, time_t) = 0;
|
virtual int update_header (framepos_t when, struct tm&, time_t) = 0;
|
||||||
virtual int flush_header () = 0;
|
virtual int flush_header () = 0;
|
||||||
|
|
||||||
void mark_streaming_write_completed ();
|
void mark_streaming_write_completed (const Lock& lock);
|
||||||
|
|
||||||
int setup_peakfile ();
|
int setup_peakfile ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ class LIBARDOUR_API AudioSource : virtual public Source,
|
||||||
|
|
||||||
virtual float sample_rate () const = 0;
|
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; }
|
virtual bool can_truncate_peaks() const { return true; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -238,10 +238,15 @@ public:
|
||||||
void apply_command (Session& session, Command* cmd);
|
void apply_command (Session& session, Command* cmd);
|
||||||
void apply_command_as_subcommand (Session& session, Command* cmd);
|
void apply_command_as_subcommand (Session& session, Command* cmd);
|
||||||
|
|
||||||
bool sync_to_source ();
|
bool sync_to_source (const Glib::Threads::Mutex::Lock& source_lock);
|
||||||
bool write_to(boost::shared_ptr<MidiSource> source);
|
|
||||||
bool write_section_to (boost::shared_ptr<MidiSource> source, Evoral::MusicalTime begin = Evoral::MinMusicalTime,
|
bool write_to(boost::shared_ptr<MidiSource> source,
|
||||||
Evoral::MusicalTime end = Evoral::MaxMusicalTime);
|
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
|
// MidiModel doesn't use the normal AutomationList serialisation code
|
||||||
// since controller data is stored in the .mid
|
// since controller data is stored in the .mid
|
||||||
|
|
|
||||||
|
|
@ -45,10 +45,10 @@ public:
|
||||||
XMLNode& get_state ();
|
XMLNode& get_state ();
|
||||||
int set_state (const XMLNode&, int version);
|
int set_state (const XMLNode&, int version);
|
||||||
|
|
||||||
void append_event_unlocked_beats(const Evoral::Event<Evoral::MusicalTime>& ev);
|
void append_event_beats(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<Evoral::MusicalTime>& ev);
|
||||||
void append_event_unlocked_frames(const Evoral::Event<framepos_t>& ev, framepos_t source_start);
|
void append_event_frames(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<framepos_t>& ev, framepos_t source_start);
|
||||||
void load_model(bool lock=true, bool force_reload=false);
|
void load_model(const Glib::Threads::Mutex::Lock& lock, bool force_reload=false);
|
||||||
void destroy_model();
|
void destroy_model(const Glib::Threads::Mutex::Lock& lock);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class SourceFactory;
|
friend class SourceFactory;
|
||||||
|
|
@ -58,15 +58,17 @@ protected:
|
||||||
MidiPlaylistSource (Session&, const XMLNode&);
|
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 position,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
framecnt_t cnt,
|
||||||
MidiStateTracker* tracker) const;
|
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,
|
framepos_t position,
|
||||||
framecnt_t cnt);
|
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.
|
* \param end time of latest event that can be written.
|
||||||
* \return zero on success, non-zero if the write failed for any reason.
|
* \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 begin = Evoral::MinMusicalTime,
|
||||||
Evoral::MusicalTime end = Evoral::MaxMusicalTime);
|
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 tracker an optional pointer to MidiStateTracker object, for note on/off tracking.
|
||||||
* \param filtered Parameters whose MIDI messages will not be returned.
|
* \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 source_start,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
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 source_start This source's start position in session frames.
|
||||||
* @param cnt The length of time to write.
|
* @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,
|
framepos_t source_start,
|
||||||
framecnt_t cnt);
|
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,
|
/** Append a single event with a timestamp in frames.
|
||||||
framepos_t source_start) = 0;
|
*
|
||||||
|
* 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 bool empty () const;
|
||||||
virtual framecnt_t length (framepos_t pos) const;
|
virtual framecnt_t length (framepos_t pos) const;
|
||||||
virtual void update_length (framecnt_t);
|
virtual void update_length (framecnt_t);
|
||||||
|
|
||||||
virtual void mark_streaming_midi_write_started (NoteMode mode);
|
virtual void mark_streaming_midi_write_started (const Lock& lock, NoteMode mode);
|
||||||
virtual void mark_streaming_write_started ();
|
virtual void mark_streaming_write_started (const Lock& lock);
|
||||||
virtual void mark_streaming_write_completed ();
|
virtual void mark_streaming_write_completed (const Lock& lock);
|
||||||
|
|
||||||
/** Mark write starting with the given time parameters.
|
/** Mark write starting with the given time parameters.
|
||||||
*
|
*
|
||||||
|
|
@ -119,6 +132,7 @@ class LIBARDOUR_API MidiSource : virtual public Source, public boost::enable_sha
|
||||||
* etc.
|
* etc.
|
||||||
*/
|
*/
|
||||||
virtual void mark_midi_streaming_write_completed (
|
virtual void mark_midi_streaming_write_completed (
|
||||||
|
const Lock& lock,
|
||||||
Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_option,
|
Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_option,
|
||||||
Evoral::MusicalTime when = Evoral::MusicalTime());
|
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; }
|
void set_length_beats(TimeType l) { _length_beats = l; }
|
||||||
TimeType length_beats() const { return _length_beats; }
|
TimeType length_beats() const { return _length_beats; }
|
||||||
|
|
||||||
virtual void load_model(bool lock=true, bool force_reload=false) = 0;
|
virtual void load_model(const Glib::Threads::Mutex::Lock& lock, bool force_reload=false) = 0;
|
||||||
virtual void destroy_model() = 0;
|
virtual void destroy_model(const Glib::Threads::Mutex::Lock& lock) = 0;
|
||||||
|
|
||||||
/** This must be called with the source lock held whenever the
|
/** Reset cached information (like iterators) when things have changed. */
|
||||||
* source/model contents have been changed (reset iterators/cache/etc).
|
void invalidate(const Glib::Threads::Mutex::Lock& lock);
|
||||||
*/
|
|
||||||
void invalidate();
|
|
||||||
|
|
||||||
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; }
|
boost::shared_ptr<MidiModel> model() { return _model; }
|
||||||
void set_model (boost::shared_ptr<MidiModel>);
|
void set_model(const Glib::Threads::Mutex::Lock& lock, boost::shared_ptr<MidiModel>);
|
||||||
void drop_model();
|
void drop_model(const Glib::Threads::Mutex::Lock& lock);
|
||||||
|
|
||||||
Evoral::ControlList::InterpolationStyle interpolation_of (Evoral::Parameter) const;
|
Evoral::ControlList::InterpolationStyle interpolation_of (Evoral::Parameter) const;
|
||||||
void set_interpolation_of (Evoral::Parameter, Evoral::ControlList::InterpolationStyle);
|
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;
|
PBD::Signal2<void, Evoral::Parameter, AutoState> AutomationStateChanged;
|
||||||
|
|
||||||
protected:
|
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 position,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
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 position This source's start position in session frames.
|
||||||
* @param cnt The duration of this block to write for.
|
* @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,
|
framepos_t position,
|
||||||
framecnt_t cnt) = 0;
|
framecnt_t cnt) = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
#ifndef __ardour_midi_state_tracker_h__
|
#ifndef __ardour_midi_state_tracker_h__
|
||||||
#define __ardour_midi_state_tracker_h__
|
#define __ardour_midi_state_tracker_h__
|
||||||
|
|
||||||
|
#include <glibmm/threads.h>
|
||||||
|
|
||||||
#include "ardour/midi_buffer.h"
|
#include "ardour/midi_buffer.h"
|
||||||
|
|
||||||
namespace Evoral {
|
namespace Evoral {
|
||||||
|
|
@ -44,7 +46,7 @@ public:
|
||||||
void remove (uint8_t note, uint8_t chn);
|
void remove (uint8_t note, uint8_t chn);
|
||||||
void resolve_notes (MidiBuffer& buffer, framepos_t time);
|
void resolve_notes (MidiBuffer& buffer, framepos_t time);
|
||||||
void resolve_notes (Evoral::EventSink<framepos_t>& 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 dump (std::ostream&);
|
||||||
void reset ();
|
void reset ();
|
||||||
bool empty() const { return _on == 0; }
|
bool empty() const { return _on == 0; }
|
||||||
|
|
|
||||||
|
|
@ -47,26 +47,24 @@ public:
|
||||||
|
|
||||||
virtual ~SMFSource ();
|
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);
|
return safe_midi_file_extension(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void append_event_unlocked_beats (const Evoral::Event<Evoral::MusicalTime>& ev);
|
void append_event_beats (const Lock& lock, const Evoral::Event<Evoral::MusicalTime>& ev);
|
||||||
void append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, framepos_t source_start);
|
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_midi_write_started (const Lock& lock, NoteMode mode);
|
||||||
void mark_streaming_write_completed ();
|
void mark_streaming_write_completed (const Lock& lock);
|
||||||
void mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption,
|
void mark_midi_streaming_write_completed (const Lock& lock,
|
||||||
|
Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption,
|
||||||
Evoral::MusicalTime when = Evoral::MusicalTime());
|
Evoral::MusicalTime when = Evoral::MusicalTime());
|
||||||
|
|
||||||
XMLNode& get_state ();
|
XMLNode& get_state ();
|
||||||
int set_state (const XMLNode&, int version);
|
int set_state (const XMLNode&, int version);
|
||||||
|
|
||||||
void load_model (bool lock=true, bool force_reload=false);
|
void load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload=false);
|
||||||
void destroy_model ();
|
void destroy_model (const Glib::Threads::Mutex::Lock& lock);
|
||||||
|
|
||||||
void flush_midi ();
|
|
||||||
void ensure_disk_file ();
|
|
||||||
|
|
||||||
static bool safe_midi_file_extension (const std::string& path);
|
static bool safe_midi_file_extension (const std::string& path);
|
||||||
static bool valid_midi_file (const std::string& path);
|
static bool valid_midi_file (const std::string& path);
|
||||||
|
|
@ -75,6 +73,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void set_path (const std::string& newpath);
|
void set_path (const std::string& newpath);
|
||||||
|
void flush_midi (const Lock& lock);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _open;
|
bool _open;
|
||||||
|
|
@ -87,13 +86,17 @@ public:
|
||||||
|
|
||||||
int open_for_write ();
|
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 position,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
framecnt_t cnt,
|
||||||
MidiStateTracker* tracker) const;
|
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,
|
framepos_t position,
|
||||||
framecnt_t cnt);
|
framecnt_t cnt);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ class LIBARDOUR_API Source : public SessionObject
|
||||||
Empty = 0x100, /* used for MIDI only */
|
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&, DataType type, const std::string& name, Flag flags=Flag(0));
|
||||||
Source (Session&, const XMLNode&);
|
Source (Session&, const XMLNode&);
|
||||||
|
|
||||||
|
|
@ -69,8 +71,8 @@ class LIBARDOUR_API Source : public SessionObject
|
||||||
|
|
||||||
void mark_for_remove();
|
void mark_for_remove();
|
||||||
|
|
||||||
virtual void mark_streaming_write_started () {}
|
virtual void mark_streaming_write_started (const Lock& lock) {}
|
||||||
virtual void mark_streaming_write_completed () = 0;
|
virtual void mark_streaming_write_completed (const Lock& lock) = 0;
|
||||||
|
|
||||||
virtual void session_saved() {}
|
virtual void session_saved() {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1771,13 +1771,15 @@ AudioDiskstream::prep_record_enable ()
|
||||||
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
||||||
(*chan)->source.request_input_monitoring (!(_session.config.get_auto_input() && rolling));
|
(*chan)->source.request_input_monitoring (!(_session.config.get_auto_input() && rolling));
|
||||||
capturing_sources.push_back ((*chan)->write_source);
|
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 {
|
} else {
|
||||||
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
||||||
capturing_sources.push_back ((*chan)->write_source);
|
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 ((*chan)->write_source) {
|
||||||
|
|
||||||
if (mark_write_complete) {
|
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 ();
|
(*chan)->write_source->done_with_peakfile_writes ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -302,13 +302,13 @@ AudioFileSource::set_state (const XMLNode& node, int version)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioFileSource::mark_streaming_write_completed ()
|
AudioFileSource::mark_streaming_write_completed (const Lock& lock)
|
||||||
{
|
{
|
||||||
if (!writable()) {
|
if (!writable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSource::mark_streaming_write_completed ();
|
AudioSource::mark_streaming_write_completed (lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
||||||
|
|
@ -923,7 +923,7 @@ AudioSource::available_peaks (double zoom_factor) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioSource::mark_streaming_write_completed ()
|
AudioSource::mark_streaming_write_completed (const Lock& lock)
|
||||||
{
|
{
|
||||||
Glib::Threads::Mutex::Lock lm (_peaks_ready_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);
|
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);
|
source->seek_to_track (i);
|
||||||
|
|
||||||
uint64_t t = 0;
|
uint64_t t = 0;
|
||||||
|
|
@ -384,11 +386,12 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
smfs->mark_streaming_write_started ();
|
smfs->mark_streaming_write_started (source_lock);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
smfs->append_event_unlocked_beats(
|
smfs->append_event_beats(
|
||||||
|
source_lock,
|
||||||
Evoral::Event<Evoral::MusicalTime>(
|
Evoral::Event<Evoral::MusicalTime>(
|
||||||
0,
|
0,
|
||||||
Evoral::MusicalTime::ticks_at_rate(t, source->ppqn()),
|
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());
|
const Evoral::MusicalTime length_beats = Evoral::MusicalTime::ticks_at_rate(t, source->ppqn());
|
||||||
BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
|
BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
|
||||||
smfs->update_length(pos + converter.to(length_beats.round_up_to_beat()));
|
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) {
|
if (status.cancel) {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -851,7 +851,8 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (record_enabled() && ((total > disk_io_chunk_frames) || 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;
|
error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -919,6 +920,8 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
|
||||||
|
|
||||||
/* phew, we have data */
|
/* phew, we have data */
|
||||||
|
|
||||||
|
Source::Lock source_lock(_write_source->mutex());
|
||||||
|
|
||||||
/* figure out the name for this take */
|
/* figure out the name for this take */
|
||||||
|
|
||||||
srcs.push_back (_write_source);
|
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.
|
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
|
/* we will want to be able to keep (over)writing the source
|
||||||
but we don't want it to be removable. this also differs
|
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) {
|
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);
|
use_new_write_source (0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1426,25 +1426,23 @@ MidiModel::PatchChangeDiffCommand::get_state ()
|
||||||
* `Discrete' mode).
|
* `Discrete' mode).
|
||||||
*/
|
*/
|
||||||
bool
|
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());
|
ReadLock lock(read_lock());
|
||||||
|
|
||||||
const bool old_percussive = percussive();
|
const bool old_percussive = percussive();
|
||||||
set_percussive(false);
|
set_percussive(false);
|
||||||
|
|
||||||
boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
|
source->drop_model(source_lock);
|
||||||
assert (ms);
|
source->mark_streaming_midi_write_started (source_lock, note_mode());
|
||||||
|
|
||||||
source->drop_model();
|
|
||||||
source->mark_streaming_midi_write_started (note_mode());
|
|
||||||
|
|
||||||
for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
|
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);
|
set_percussive(old_percussive);
|
||||||
source->mark_streaming_write_completed();
|
source->mark_streaming_write_completed(source_lock);
|
||||||
|
|
||||||
set_edited(false);
|
set_edited(false);
|
||||||
|
|
||||||
|
|
@ -1457,7 +1455,7 @@ MidiModel::write_to (boost::shared_ptr<MidiSource> source)
|
||||||
of the model.
|
of the model.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
MidiModel::sync_to_source ()
|
MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock)
|
||||||
{
|
{
|
||||||
ReadLock lock(read_lock());
|
ReadLock lock(read_lock());
|
||||||
|
|
||||||
|
|
@ -1465,16 +1463,19 @@ MidiModel::sync_to_source ()
|
||||||
set_percussive(false);
|
set_percussive(false);
|
||||||
|
|
||||||
boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
|
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) {
|
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);
|
set_percussive (old_percussive);
|
||||||
ms->mark_streaming_write_completed ();
|
ms->mark_streaming_write_completed (source_lock);
|
||||||
|
|
||||||
set_edited (false);
|
set_edited (false);
|
||||||
|
|
||||||
|
|
@ -1489,7 +1490,10 @@ MidiModel::sync_to_source ()
|
||||||
* destroying the original note durations.
|
* destroying the original note durations.
|
||||||
*/
|
*/
|
||||||
bool
|
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());
|
ReadLock lock(read_lock());
|
||||||
MidiStateTracker mst;
|
MidiStateTracker mst;
|
||||||
|
|
@ -1497,11 +1501,8 @@ MidiModel::write_section_to (boost::shared_ptr<MidiSource> source, Evoral::Music
|
||||||
const bool old_percussive = percussive();
|
const bool old_percussive = percussive();
|
||||||
set_percussive(false);
|
set_percussive(false);
|
||||||
|
|
||||||
boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
|
source->drop_model(source_lock);
|
||||||
assert (ms);
|
source->mark_streaming_midi_write_started (source_lock, note_mode());
|
||||||
|
|
||||||
source->drop_model();
|
|
||||||
source->mark_streaming_midi_write_started (note_mode());
|
|
||||||
|
|
||||||
for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
|
for (Evoral::Sequence<TimeType>::const_iterator i = begin(TimeType(), true); i != end(); ++i) {
|
||||||
const Evoral::Event<Evoral::MusicalTime>& ev (*i);
|
const Evoral::Event<Evoral::MusicalTime>& ev (*i);
|
||||||
|
|
@ -1526,22 +1527,22 @@ MidiModel::write_section_to (boost::shared_ptr<MidiSource> source, Evoral::Music
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
source->append_event_unlocked_beats (*i);
|
source->append_event_beats (source_lock, *i);
|
||||||
mst.remove (mev->note(), mev->channel());
|
mst.remove (mev->note(), mev->channel());
|
||||||
|
|
||||||
} else if (mev->is_note_on()) {
|
} else if (mev->is_note_on()) {
|
||||||
mst.add (mev->note(), mev->channel());
|
mst.add (mev->note(), mev->channel());
|
||||||
source->append_event_unlocked_beats(*i);
|
source->append_event_beats(source_lock, *i);
|
||||||
} else {
|
} 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);
|
set_percussive(old_percussive);
|
||||||
source->mark_streaming_write_completed();
|
source->mark_streaming_write_completed(source_lock);
|
||||||
|
|
||||||
set_edited(false);
|
set_edited(false);
|
||||||
|
|
||||||
|
|
@ -1630,7 +1631,7 @@ MidiModel::edit_lock()
|
||||||
assert (ms);
|
assert (ms);
|
||||||
|
|
||||||
Glib::Threads::Mutex::Lock* source_lock = new Glib::Threads::Mutex::Lock (ms->mutex());
|
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));
|
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 ();
|
boost::shared_ptr<MidiSource> old = _midi_source.lock ();
|
||||||
|
|
||||||
if (old) {
|
if (old) {
|
||||||
old->invalidate ();
|
Source::Lock lm(old->mutex());
|
||||||
|
old->invalidate (lm);
|
||||||
}
|
}
|
||||||
|
|
||||||
_midi_source_connections.drop_connections ();
|
_midi_source_connections.drop_connections ();
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,8 @@ MidiPlaylistSource::length (framepos_t) const
|
||||||
}
|
}
|
||||||
|
|
||||||
framecnt_t
|
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 /*position*/,
|
||||||
framepos_t start, framecnt_t cnt,
|
framepos_t start, framecnt_t cnt,
|
||||||
MidiStateTracker*) const
|
MidiStateTracker*) const
|
||||||
|
|
@ -137,7 +138,8 @@ MidiPlaylistSource::read_unlocked (Evoral::EventSink<framepos_t>& dst,
|
||||||
}
|
}
|
||||||
|
|
||||||
framecnt_t
|
framecnt_t
|
||||||
MidiPlaylistSource::write_unlocked (MidiRingBuffer<framepos_t>&,
|
MidiPlaylistSource::write_unlocked (const Lock&,
|
||||||
|
MidiRingBuffer<framepos_t>&,
|
||||||
framepos_t,
|
framepos_t,
|
||||||
framecnt_t)
|
framecnt_t)
|
||||||
{
|
{
|
||||||
|
|
@ -147,33 +149,33 @@ MidiPlaylistSource::write_unlocked (MidiRingBuffer<framepos_t>&,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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*/
|
abort(); /*NOTREACHED*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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*/
|
abort(); /*NOTREACHED*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiPlaylistSource::load_model (bool, bool)
|
MidiPlaylistSource::load_model (const Glib::Threads::Mutex::Lock&, bool)
|
||||||
{
|
{
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiPlaylistSource::destroy_model ()
|
MidiPlaylistSource::destroy_model (const Glib::Threads::Mutex::Lock&)
|
||||||
{
|
{
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 bbegin = bfc.from (_start);
|
||||||
Evoral::MusicalTime const bend = bfc.from (_start + _length);
|
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;
|
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);
|
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
|
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 */
|
/* This call reads events from a source and writes them to `dst' timed in session frames */
|
||||||
|
|
||||||
if (src->midi_read (
|
if (src->midi_read (
|
||||||
|
lm, // source lock
|
||||||
dst, // destination buffer
|
dst, // destination buffer
|
||||||
_position - _start, // start position of the source in session frames
|
_position - _start, // start position of the source in session frames
|
||||||
_start + internal_offset, // where to start reading in the source
|
_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.
|
the iterator.
|
||||||
*/
|
*/
|
||||||
Glib::Threads::Mutex::Lock lm (midi_source(0)->mutex());
|
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.
|
/** 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
|
void
|
||||||
MidiSource::invalidate ()
|
MidiSource::invalidate (const Lock& lock)
|
||||||
{
|
{
|
||||||
_model_iter_valid = false;
|
_model_iter_valid = false;
|
||||||
_model_iter.invalidate();
|
_model_iter.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
framecnt_t
|
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 source_start,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t cnt,
|
framecnt_t cnt,
|
||||||
MidiStateTracker* tracker,
|
MidiStateTracker* tracker,
|
||||||
const std::set<Evoral::Parameter>& filtered) const
|
const std::set<Evoral::Parameter>& filtered) const
|
||||||
{
|
{
|
||||||
Glib::Threads::Mutex::Lock lm (_lock);
|
|
||||||
|
|
||||||
BeatsFramesConverter converter(_session.tempo_map(), source_start);
|
BeatsFramesConverter converter(_session.tempo_map(), source_start);
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiSourceIO,
|
DEBUG_TRACE (DEBUG::MidiSourceIO,
|
||||||
|
|
@ -233,22 +232,21 @@ MidiSource::midi_read (Evoral::EventSink<framepos_t>& dst,
|
||||||
}
|
}
|
||||||
return cnt;
|
return cnt;
|
||||||
} else {
|
} else {
|
||||||
return read_unlocked (dst, source_start, start, cnt, tracker);
|
return read_unlocked (lm, dst, source_start, start, cnt, tracker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
framecnt_t
|
framecnt_t
|
||||||
MidiSource::midi_write (MidiRingBuffer<framepos_t>& source,
|
MidiSource::midi_write (const Lock& lm,
|
||||||
|
MidiRingBuffer<framepos_t>& source,
|
||||||
framepos_t source_start,
|
framepos_t source_start,
|
||||||
framecnt_t cnt)
|
framecnt_t cnt)
|
||||||
{
|
{
|
||||||
Glib::Threads::Mutex::Lock lm (_lock);
|
const framecnt_t ret = write_unlocked (lm, source, source_start, cnt);
|
||||||
|
|
||||||
const framecnt_t ret = write_unlocked (source, source_start, cnt);
|
|
||||||
|
|
||||||
if (cnt == max_framecnt) {
|
if (cnt == max_framecnt) {
|
||||||
_last_read_end = 0;
|
_last_read_end = 0;
|
||||||
invalidate();
|
invalidate(lm);
|
||||||
} else {
|
} else {
|
||||||
_capture_length += cnt;
|
_capture_length += cnt;
|
||||||
}
|
}
|
||||||
|
|
@ -257,7 +255,7 @@ MidiSource::midi_write (MidiRingBuffer<framepos_t>& source,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiSource::mark_streaming_midi_write_started (NoteMode mode)
|
MidiSource::mark_streaming_midi_write_started (const Lock& lock, NoteMode mode)
|
||||||
{
|
{
|
||||||
if (_model) {
|
if (_model) {
|
||||||
_model->set_note_mode (mode);
|
_model->set_note_mode (mode);
|
||||||
|
|
@ -292,14 +290,15 @@ MidiSource::mark_write_starting_now (framecnt_t position,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiSource::mark_streaming_write_started ()
|
MidiSource::mark_streaming_write_started (const Lock& lock)
|
||||||
{
|
{
|
||||||
NoteMode note_mode = _model ? _model->note_mode() : Sustained;
|
NoteMode note_mode = _model ? _model->note_mode() : Sustained;
|
||||||
mark_streaming_midi_write_started (note_mode);
|
mark_streaming_midi_write_started (lock, note_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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)
|
Evoral::MusicalTime end)
|
||||||
{
|
{
|
||||||
if (_model) {
|
if (_model) {
|
||||||
|
|
@ -318,37 +317,39 @@ MidiSource::mark_midi_streaming_write_completed (Evoral::Sequence<Evoral::Musica
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
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->set_timeline_position (_timeline_position);
|
||||||
newsrc->copy_interpolation_from (this);
|
newsrc->copy_interpolation_from (this);
|
||||||
newsrc->copy_automation_state_from (this);
|
newsrc->copy_automation_state_from (this);
|
||||||
|
|
||||||
if (_model) {
|
if (_model) {
|
||||||
if (begin == Evoral::MinMusicalTime && end == Evoral::MaxMusicalTime) {
|
if (begin == Evoral::MinMusicalTime && end == Evoral::MaxMusicalTime) {
|
||||||
_model->write_to (newsrc);
|
_model->write_to (newsrc, newsrc_lock);
|
||||||
} else {
|
} else {
|
||||||
_model->write_section_to (newsrc, begin, end);
|
_model->write_section_to (newsrc, newsrc_lock, begin, end);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error << string_compose (_("programming error: %1"), X_("no model for MidiSource during ::clone()"));
|
error << string_compose (_("programming error: %1"), X_("no model for MidiSource during ::clone()"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
newsrc->flush_midi();
|
newsrc->flush_midi(newsrc_lock);
|
||||||
|
|
||||||
/* force a reload of the model if the range is partial */
|
/* force a reload of the model if the range is partial */
|
||||||
|
|
||||||
if (begin != Evoral::MinMusicalTime || end != Evoral::MaxMusicalTime) {
|
if (begin != Evoral::MinMusicalTime || end != Evoral::MaxMusicalTime) {
|
||||||
newsrc->load_model (true, true);
|
newsrc->load_model (newsrc_lock, true);
|
||||||
} else {
|
} else {
|
||||||
newsrc->set_model (_model);
|
newsrc->set_model (newsrc_lock, _model);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this file is not removable (but since it is MIDI, it is mutable) */
|
/* 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
|
void
|
||||||
MidiSource::session_saved()
|
MidiSource::session_saved()
|
||||||
{
|
{
|
||||||
|
Lock lm (_lock);
|
||||||
|
|
||||||
/* this writes a copy of the data to disk.
|
/* this writes a copy of the data to disk.
|
||||||
XXX do we need to do this every time?
|
XXX do we need to do this every time?
|
||||||
*/
|
*/
|
||||||
|
|
@ -375,18 +378,18 @@ MidiSource::session_saved()
|
||||||
_model.reset ();
|
_model.reset ();
|
||||||
|
|
||||||
/* Flush model contents to disk. */
|
/* Flush model contents to disk. */
|
||||||
mm->sync_to_source ();
|
mm->sync_to_source (lm);
|
||||||
|
|
||||||
/* Reacquire model. */
|
/* Reacquire model. */
|
||||||
_model = mm;
|
_model = mm;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
flush_midi();
|
flush_midi(lm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiSource::set_note_mode(NoteMode mode)
|
MidiSource::set_note_mode(const Lock& lock, NoteMode mode)
|
||||||
{
|
{
|
||||||
if (_model) {
|
if (_model) {
|
||||||
_model->set_note_mode(mode);
|
_model->set_note_mode(mode);
|
||||||
|
|
@ -394,18 +397,18 @@ MidiSource::set_note_mode(NoteMode mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiSource::drop_model ()
|
MidiSource::drop_model (const Lock& lock)
|
||||||
{
|
{
|
||||||
_model.reset();
|
_model.reset();
|
||||||
invalidate();
|
invalidate(lock);
|
||||||
ModelChanged (); /* EMIT SIGNAL */
|
ModelChanged (); /* EMIT SIGNAL */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiSource::set_model (boost::shared_ptr<MidiModel> m)
|
MidiSource::set_model (const Lock& lock, boost::shared_ptr<MidiModel> m)
|
||||||
{
|
{
|
||||||
_model = m;
|
_model = m;
|
||||||
invalidate();
|
invalidate(lock);
|
||||||
ModelChanged (); /* EMIT SIGNAL */
|
ModelChanged (); /* EMIT SIGNAL */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ MidiStateTracker::resolve_notes (Evoral::EventSink<framepos_t> &dst, framepos_t
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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));
|
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_channel (channel);
|
||||||
ev.set_note (note);
|
ev.set_note (note);
|
||||||
ev.set_velocity (0);
|
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",
|
DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1: MS-resolved note %2/%3 at %4\n",
|
||||||
this, (int) note, (int) channel, time));
|
this, (int) note, (int) channel, time));
|
||||||
_active_notes[note + 128 * channel]--;
|
_active_notes[note + 128 * channel]--;
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
boost::shared_ptr<MidiSource> src = region->midi_source(0);
|
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();
|
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 ());
|
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();
|
boost::shared_ptr<MidiModel> new_model = new_src->model();
|
||||||
new_model->start_write();
|
new_model->start_write();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,8 @@ SMFSource::open_for_write ()
|
||||||
|
|
||||||
/** All stamps in audio frames */
|
/** All stamps in audio frames */
|
||||||
framecnt_t
|
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 const source_start,
|
||||||
framepos_t start,
|
framepos_t start,
|
||||||
framecnt_t duration,
|
framecnt_t duration,
|
||||||
|
|
@ -303,12 +304,13 @@ SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination,
|
||||||
}
|
}
|
||||||
|
|
||||||
framecnt_t
|
framecnt_t
|
||||||
SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source,
|
SMFSource::write_unlocked (const Lock& lock,
|
||||||
|
MidiRingBuffer<framepos_t>& source,
|
||||||
framepos_t position,
|
framepos_t position,
|
||||||
framecnt_t cnt)
|
framecnt_t cnt)
|
||||||
{
|
{
|
||||||
if (!_writing) {
|
if (!_writing) {
|
||||||
mark_streaming_write_started ();
|
mark_streaming_write_started (lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
framepos_t time;
|
framepos_t time;
|
||||||
|
|
@ -372,7 +374,7 @@ SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
append_event_unlocked_frames(ev, position);
|
append_event_frames(lock, ev, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
Evoral::SMF::flush ();
|
Evoral::SMF::flush ();
|
||||||
|
|
@ -383,13 +385,14 @@ SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source,
|
||||||
|
|
||||||
/** Append an event with a timestamp in beats */
|
/** Append an event with a timestamp in beats */
|
||||||
void
|
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) {
|
if (!_writing || ev.size() == 0) {
|
||||||
return;
|
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());
|
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");*/
|
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) */
|
/** Append an event with a timestamp in frames (framepos_t) */
|
||||||
void
|
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) {
|
if (!_writing || ev.size() == 0) {
|
||||||
return;
|
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());
|
// 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");
|
// 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
|
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()) {
|
if (!_open && open_for_write()) {
|
||||||
error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
|
error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
|
||||||
/* XXX should probably throw or return something */
|
/* XXX should probably throw or return something */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiSource::mark_streaming_midi_write_started (mode);
|
MidiSource::mark_streaming_midi_write_started (lock, mode);
|
||||||
Evoral::SMF::begin_write ();
|
Evoral::SMF::begin_write ();
|
||||||
_last_ev_time_beats = Evoral::MusicalTime();
|
_last_ev_time_beats = Evoral::MusicalTime();
|
||||||
_last_ev_time_frames = 0;
|
_last_ev_time_frames = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
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 (lm, stuck_notes_option, when);
|
||||||
MidiSource::mark_midi_streaming_write_completed (stuck_notes_option, when);
|
|
||||||
|
|
||||||
if (!writable()) {
|
if (!writable()) {
|
||||||
warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
|
warning << string_compose ("attempt to write to unwritable SMF file %1", _path) << endmsg;
|
||||||
|
|
@ -596,16 +598,12 @@ static bool compare_eventlist (
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SMFSource::load_model (bool lock, bool force_reload)
|
SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload)
|
||||||
{
|
{
|
||||||
if (_writing) {
|
if (_writing) {
|
||||||
return;
|
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) {
|
if (_model && !force_reload) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -616,7 +614,7 @@ SMFSource::load_model (bool lock, bool force_reload)
|
||||||
_model->clear();
|
_model->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidate();
|
invalidate(lock);
|
||||||
|
|
||||||
if (writable() && !_open) {
|
if (writable() && !_open) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -707,33 +705,33 @@ SMFSource::load_model (bool lock, bool force_reload)
|
||||||
|
|
||||||
_model->end_write (Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, _length_beats);
|
_model->end_write (Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, _length_beats);
|
||||||
_model->set_edited (false);
|
_model->set_edited (false);
|
||||||
invalidate();
|
invalidate(lock);
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SMFSource::destroy_model ()
|
SMFSource::destroy_model (const Glib::Threads::Mutex::Lock& lock)
|
||||||
{
|
{
|
||||||
//cerr << _name << " destroying model " << _model.get() << endl;
|
//cerr << _name << " destroying model " << _model.get() << endl;
|
||||||
_model.reset();
|
_model.reset();
|
||||||
invalidate();
|
invalidate(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SMFSource::flush_midi ()
|
SMFSource::flush_midi (const Lock& lock)
|
||||||
{
|
{
|
||||||
if (!writable() || _length_beats == 0.0) {
|
if (!writable() || _length_beats == 0.0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_disk_file ();
|
ensure_disk_file (lock);
|
||||||
|
|
||||||
Evoral::SMF::end_write ();
|
Evoral::SMF::end_write ();
|
||||||
/* data in the file means its no longer removable */
|
/* data in the file means its no longer removable */
|
||||||
mark_nonremovable ();
|
mark_nonremovable ();
|
||||||
|
|
||||||
invalidate();
|
invalidate(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 */
|
/** Ensure that this source has some file on disk, even if it's just a SMF header */
|
||||||
void
|
void
|
||||||
SMFSource::ensure_disk_file ()
|
SMFSource::ensure_disk_file (const Lock& lock)
|
||||||
{
|
{
|
||||||
if (!writable()) {
|
if (!writable()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -757,9 +755,9 @@ SMFSource::ensure_disk_file ()
|
||||||
*/
|
*/
|
||||||
boost::shared_ptr<MidiModel> mm = _model;
|
boost::shared_ptr<MidiModel> mm = _model;
|
||||||
_model.reset ();
|
_model.reset ();
|
||||||
mm->sync_to_source ();
|
mm->sync_to_source (lock);
|
||||||
_model = mm;
|
_model = mm;
|
||||||
invalidate();
|
invalidate(lock);
|
||||||
} else {
|
} else {
|
||||||
/* No model; if it's not already open, it's an empty source, so create
|
/* No model; if it's not already open, it's an empty source, so create
|
||||||
and open it for writing.
|
and open it for writing.
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
|
||||||
}
|
}
|
||||||
} else if (type == DataType::MIDI) {
|
} else if (type == DataType::MIDI) {
|
||||||
boost::shared_ptr<SMFSource> src (new SMFSource (s, node));
|
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
|
#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
|
||||||
// boost_debug_shared_ptr_mark_interesting (src, "Source");
|
// boost_debug_shared_ptr_mark_interesting (src, "Source");
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -273,7 +273,7 @@ SourceFactory::createExternal (DataType type, Session& s, const string& path,
|
||||||
} else if (type == DataType::MIDI) {
|
} else if (type == DataType::MIDI) {
|
||||||
|
|
||||||
boost::shared_ptr<SMFSource> src (new SMFSource (s, path));
|
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
|
#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
|
||||||
// boost_debug_shared_ptr_mark_interesting (src, "Source");
|
// boost_debug_shared_ptr_mark_interesting (src, "Source");
|
||||||
#endif
|
#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));
|
boost::shared_ptr<SMFSource> src (new SMFSource (s, path, SndFileSource::default_writable_flags));
|
||||||
assert (src->writable ());
|
assert (src->writable ());
|
||||||
|
|
||||||
src->load_model (true, true);
|
src->load_model (Glib::Threads::Mutex::Lock(src->mutex()), true);
|
||||||
#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
|
#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
|
||||||
// boost_debug_shared_ptr_mark_interesting (src, "Source");
|
// boost_debug_shared_ptr_mark_interesting (src, "Source");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue