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);
}
}
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();
}
if (load_model) {
- source->load_model();
+ Glib::Threads::Mutex::Lock lm(source->mutex());
+ source->load_model(lm);
}
if (!source->model()) {
{
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());
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 ();
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; }
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
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;
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);
* \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);
* \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,
* @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.
*
* etc.
*/
virtual void mark_midi_streaming_write_completed (
+ const Lock& lock,
Evoral::Sequence<Evoral::MusicalTime>::StuckNoteOption stuck_option,
Evoral::MusicalTime when = Evoral::MusicalTime());
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);
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,
* @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;
#ifndef __ardour_midi_state_tracker_h__
#define __ardour_midi_state_tracker_h__
+#include <glibmm/threads.h>
+
#include "ardour/midi_buffer.h"
namespace Evoral {
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; }
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);
protected:
void set_path (const std::string& newpath);
+ void flush_midi (const Lock& lock);
private:
bool _open;
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);
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&);
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() {}
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()));
}
}
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 ();
}
}
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
}
void
-AudioSource::mark_streaming_write_completed ()
+AudioSource::mark_streaming_write_completed (const Lock& lock)
{
Glib::Threads::Mutex::Lock lm (_peaks_ready_lock);
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;
}
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()),
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;
}
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;
}
/* phew, we have data */
+ Source::Lock source_lock(_write_source->mutex());
+
/* figure out the name for this take */
srcs.push_back (_write_source);
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
}
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);
}
* `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);
of the model.
*/
bool
-MidiModel::sync_to_source ()
+MidiModel::sync_to_source (const Glib::Threads::Mutex::Lock& source_lock)
{
ReadLock lock(read_lock());
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);
* 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;
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);
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);
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));
}
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 ();
}
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
}
framecnt_t
-MidiPlaylistSource::write_unlocked (MidiRingBuffer<framepos_t>&,
+MidiPlaylistSource::write_unlocked (const Lock&,
+ MidiRingBuffer<framepos_t>&,
framepos_t,
framecnt_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)
{
}
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;
}
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
/* 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
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.
}
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,
}
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;
}
}
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);
}
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) {
}
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) */
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?
*/
_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);
}
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 */
}
}
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));
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]--;
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();
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();
/** 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,
}
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;
continue;
}
- append_event_unlocked_frames(ev, position);
+ append_event_frames(lock, ev, position);
}
Evoral::SMF::flush ();
/** 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");*/
/** 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");
}
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;
}
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;
}
_model->clear();
}
- invalidate();
+ invalidate(lock);
if (writable() && !_open) {
return;
_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
/** 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;
*/
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.
}
} 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
} 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
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