From e258b2622a4386b405c2216d79b34887c3ed55bf Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 19 May 2010 03:03:28 +0000 Subject: MIDI region forking, plus Playlist::regions_to_read() fix forward ported from 2.X. region forking requires a few cleanups git-svn-id: svn://localhost/ardour2/branches/3.0@7118 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/audioregion.h | 1 - libs/ardour/ardour/automatable.h | 1 + libs/ardour/ardour/automatable_sequence.h | 9 +++- libs/ardour/ardour/debug.h | 1 + libs/ardour/ardour/midi_model.h | 5 +- libs/ardour/ardour/midi_region.h | 2 + libs/ardour/ardour/midi_source.h | 3 ++ libs/ardour/ardour/midi_state_tracker.h | 6 ++- libs/ardour/ardour/utils.h | 2 +- libs/ardour/audio_playlist.cc | 5 +- libs/ardour/audioregion.cc | 6 --- libs/ardour/automatable.cc | 12 +++++ libs/ardour/debug.cc | 1 + libs/ardour/midi_model.cc | 64 ++++++++++++++++++++++--- libs/ardour/midi_region.cc | 23 +++++++++ libs/ardour/midi_source.cc | 80 +++++++++++++++++++------------ libs/ardour/midi_state_tracker.cc | 30 ++++++++++++ libs/ardour/playlist.cc | 38 +++++++++++++-- libs/ardour/route.cc | 2 +- libs/ardour/session_state.cc | 3 +- libs/ardour/utils.cc | 19 ++++---- libs/evoral/evoral/ControlSet.hpp | 1 + libs/evoral/evoral/MIDIEvent.hpp | 1 + libs/evoral/evoral/Sequence.hpp | 1 + libs/evoral/evoral/types.hpp | 3 ++ libs/evoral/src/ControlSet.cpp | 6 +++ libs/evoral/src/Sequence.cpp | 26 ++++++++++ 27 files changed, 288 insertions(+), 63 deletions(-) (limited to 'libs') diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index f9c13b2bbe..0a3e53039e 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -107,7 +107,6 @@ class AudioRegion : public Region }; virtual framecnt_t read (Sample*, framepos_t pos, framecnt_t cnt, int channel) const; - virtual framecnt_t read_with_ops (Sample*, framepos_t pos, framecnt_t cnt, int channel, ReadOps rops) const; virtual framecnt_t readable_length() const { return length(); } virtual framecnt_t read_at (Sample *buf, Sample *mixdown_buf, float *gain_buf, diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h index 3236d816c3..9b83705b0a 100644 --- a/libs/ardour/ardour/automatable.h +++ b/libs/ardour/ardour/automatable.h @@ -42,6 +42,7 @@ class Automatable : virtual public Evoral::ControlSet { public: Automatable(Session&); + Automatable (const Automatable& other); Automatable(); virtual ~Automatable() {} diff --git a/libs/ardour/ardour/automatable_sequence.h b/libs/ardour/ardour/automatable_sequence.h index 88e1733c1b..730ea33a7c 100644 --- a/libs/ardour/ardour/automatable_sequence.h +++ b/libs/ardour/ardour/automatable_sequence.h @@ -29,11 +29,18 @@ namespace ARDOUR { template class AutomatableSequence : public Automatable, public Evoral::Sequence { public: - AutomatableSequence(Session& s, size_t /*size*/) + AutomatableSequence(Session& s) : Evoral::ControlSet() , Automatable(s) , Evoral::Sequence(EventTypeMap::instance()) {} + + AutomatableSequence(const AutomatableSequence& other) + : Evoral::ControlSet(other) + , Automatable(other._a_session) + , Evoral::Sequence(other) + {} + }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/debug.h b/libs/ardour/ardour/debug.h index 57b66a8793..1cd8854fea 100644 --- a/libs/ardour/ardour/debug.h +++ b/libs/ardour/ardour/debug.h @@ -46,6 +46,7 @@ namespace PBD { extern uint64_t MidiClock; extern uint64_t Monitor; extern uint64_t Solo; + extern uint64_t AudioPlayback; } } diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index fcd285f98c..8d949cadbb 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -51,7 +51,7 @@ class MidiModel : public AutomatableSequence { public: typedef double TimeType; - MidiModel(MidiSource* s, size_t size=0); + MidiModel(MidiSource* s); NoteMode note_mode() const { return (percussive() ? Percussive : Sustained); } void set_note_mode(NoteMode mode) { set_percussive(mode == Percussive); }; @@ -151,7 +151,8 @@ public: void apply_command(Session& session, Command* cmd); void apply_command_as_subcommand(Session& session, Command* cmd); - bool write_to(boost::shared_ptr source); + bool write_to(boost::shared_ptr source, 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 diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index 671e4fca43..568638ed21 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -50,6 +50,8 @@ class MidiRegion : public Region public: ~MidiRegion(); + boost::shared_ptr clone (); + boost::shared_ptr midi_source (uint32_t n=0) const; /* Stub Readable interface */ diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index 7b867c70fd..2484d3575a 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -47,6 +47,9 @@ class MidiSource : virtual public Source MidiSource (Session& session, const XMLNode&); virtual ~MidiSource (); + boost::shared_ptr clone (Evoral::MusicalTime begin = Evoral::MinMusicalTime, + Evoral::MusicalTime end = Evoral::MaxMusicalTime); + /** Read the data in a given time range from the MIDI source. * All time stamps in parameters are in audio frames (even if the source has tempo time). * \param dst Ring buffer where read events are written diff --git a/libs/ardour/ardour/midi_state_tracker.h b/libs/ardour/ardour/midi_state_tracker.h index 76a669838a..5c65c1f018 100644 --- a/libs/ardour/ardour/midi_state_tracker.h +++ b/libs/ardour/ardour/midi_state_tracker.h @@ -28,7 +28,7 @@ template class EventSink; } namespace ARDOUR { - +class MidiSource; /** Tracks played notes, so they can be resolved in potential stuck note * situations (e.g. looping, transport stop, etc). @@ -43,10 +43,14 @@ public: void remove (uint8_t note, uint8_t chn); void resolve_notes (MidiBuffer& buffer, nframes64_t time); void resolve_notes (Evoral::EventSink& buffer, nframes64_t time); + void resolve_notes (MidiSource& src, Evoral::MusicalTime time); void dump (std::ostream&); void reset (); bool empty() const { return _on == 0; } uint16_t on() const { return _on; } + bool active (uint8_t note, uint8_t channel) { + return _active_notes[(channel*128)+note] > 0; + } private: void track_note_onoffs(const Evoral::MIDIEvent& event); diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h index e68f7a01df..e7e8f2b820 100644 --- a/libs/ardour/ardour/utils.h +++ b/libs/ardour/ardour/utils.h @@ -50,7 +50,7 @@ static inline float f_max(float x, float a) { return (x); } -std::string bump_name_once(std::string s); +std::string bump_name_once(const std::string& s, char delimiter); int cmp_nocase (const std::string& s, const std::string& s2); diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index 65b05b7c92..bd09af4e1f 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -23,6 +23,7 @@ #include "ardour/types.h" +#include "ardour/debug.h" #include "ardour/configuration.h" #include "ardour/audioplaylist.h" #include "ardour/audioregion.h" @@ -163,7 +164,7 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf if ((*i)->coverage (start, end) != OverlapNone) { relevant_regions[(*i)->layer()].push_back (*i); relevant_layers.push_back ((*i)->layer()); - } + } } for (Crossfades::iterator i = _crossfades.begin(); i != _crossfades.end(); ++i) { @@ -188,8 +189,10 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, nf vector > r (relevant_regions[*l]); vector >& x (relevant_xfades[*l]); + for (vector >::iterator i = r.begin(); i != r.end(); ++i) { boost::shared_ptr ar = boost::dynamic_pointer_cast(*i); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("read from region %1\n", ar->name())); assert(ar); ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames); _read_data_count += ar->read_data_count(); diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index c8e742555c..0ef79b7018 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -317,12 +317,6 @@ AudioRegion::read (Sample* buf, framepos_t timeline_position, framecnt_t cnt, in return _read_at (_sources, _length, buf, 0, 0, _position + timeline_position, cnt, channel, 0, 0, ReadOps (0)); } -framecnt_t -AudioRegion::read_with_ops (Sample* buf, framepos_t file_position, framecnt_t cnt, int channel, ReadOps rops) const -{ - return _read_at (_sources, _length, buf, 0, 0, file_position, cnt, channel, 0, 0, rops); -} - framecnt_t AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, framepos_t file_position, framecnt_t cnt, uint32_t chan_n, diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc index 1ef39a61f0..3d705b3ea7 100644 --- a/libs/ardour/automatable.cc +++ b/libs/ardour/automatable.cc @@ -49,6 +49,18 @@ Automatable::Automatable(Session& session) { } +Automatable::Automatable (const Automatable& other) + : ControlSet (other) + , _a_session (other._a_session) + , _last_automation_snapshot (0) +{ + Glib::Mutex::Lock lm (other._control_lock); + + for (Controls::const_iterator i = other._controls.begin(); i != other._controls.end(); ++i) { + boost::shared_ptr ac (control_factory (i->first)); + _controls[ac->parameter()] = ac; + } +} int Automatable::old_set_automation_state (const XMLNode& node) { diff --git a/libs/ardour/debug.cc b/libs/ardour/debug.cc index 268ec5d033..419579b977 100644 --- a/libs/ardour/debug.cc +++ b/libs/ardour/debug.cc @@ -43,4 +43,5 @@ uint64_t PBD::DEBUG::MackieControl = PBD::new_debug_bit ("mackiecontrol"); uint64_t PBD::DEBUG::MidiClock = PBD::new_debug_bit ("midiclock"); uint64_t PBD::DEBUG::Monitor = PBD::new_debug_bit ("monitor"); uint64_t PBD::DEBUG::Solo = PBD::new_debug_bit ("solo"); +uint64_t PBD::DEBUG::AudioPlayback = PBD::new_debug_bit ("audioplayback"); diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index ac3360ea2b..88ef60e8e5 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -30,6 +30,7 @@ #include "ardour/midi_model.h" #include "ardour/midi_source.h" +#include "ardour/midi_state_tracker.h" #include "ardour/smf_source.h" #include "ardour/types.h" #include "ardour/session.h" @@ -38,8 +39,8 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -MidiModel::MidiModel(MidiSource* s, size_t size) - : AutomatableSequence(s->session(), size) +MidiModel::MidiModel(MidiSource* s) + : AutomatableSequence(s->session()) , _midi_source(s) { } @@ -675,7 +676,7 @@ MidiModel::DiffCommand::get_state () return *diff_command; } -/** Write the model to a MidiSource (i.e. save the model). +/** Write part or all of the model to a MidiSource (i.e. save the model). * This is different from manually using read to write to a source in that * note off events are written regardless of the track mode. This is so the * user can switch a recorded track (with note durations from some instrument) @@ -683,9 +684,11 @@ MidiModel::DiffCommand::get_state () * destroying the original note durations. */ bool -MidiModel::write_to(boost::shared_ptr source) +MidiModel::write_to (boost::shared_ptr source, Evoral::MusicalTime begin_time, Evoral::MusicalTime end_time) { ReadLock lock(read_lock()); + MidiStateTracker mst; + Evoral::MusicalTime extra_note_on_time = end_time; const bool old_percussive = percussive(); set_percussive(false); @@ -694,8 +697,57 @@ MidiModel::write_to(boost::shared_ptr source) source->mark_streaming_midi_write_started(note_mode(), _midi_source->timeline_position()); for (Evoral::Sequence::const_iterator i = begin(); i != end(); ++i) { - source->append_event_unlocked_beats(*i); - } + const Evoral::Event& ev (*i); + + if (ev.time() >= begin_time && ev.time() < end_time) { + + const Evoral::MIDIEvent* mev = + static_cast* > (&ev); + + if (!mev) { + continue; + } + + + if (mev->is_note_off()) { + + if (!mst.active (mev->note(), mev->channel())) { + + /* add a note-on at the start of the range we're writing + to the file. velocity is just an arbitary reasonable value. + */ + + Evoral::MIDIEvent on (mev->event_type(), extra_note_on_time, 3, 0, true); + on.set_type (mev->type()); + on.set_note (mev->note()); + on.set_channel (mev->channel()); + on.set_velocity (mev->velocity()); + + cerr << "Add note on for odd note off, note = " << (int) on.note() << endl; + source->append_event_unlocked_beats (on); + mst.add (on.note(), on.channel()); + mst.dump (cerr); + extra_note_on_time += 1.0/128.0; + } + + cerr << "MIDI Note off (note = " << (int) mev->note() << endl; + source->append_event_unlocked_beats (*i); + mst.remove (mev->note(), mev->channel()); + mst.dump (cerr); + + } else if (mev->is_note_on()) { + cerr << "MIDI Note on (note = " << (int) mev->note() << endl; + mst.add (mev->note(), mev->channel()); + source->append_event_unlocked_beats(*i); + mst.dump (cerr); + } else { + cerr << "MIDI other event type\n"; + source->append_event_unlocked_beats(*i); + } + } + } + + mst.resolve_notes (*source, end_time); set_percussive(old_percussive); source->mark_streaming_write_completed(); diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index 936ce047ee..eaac23300b 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -37,6 +37,7 @@ #include "ardour/dB.h" #include "ardour/playlist.h" #include "ardour/midi_source.h" +#include "ardour/region_factory.h" #include "ardour/types.h" #include "ardour/midi_ring_buffer.h" @@ -68,6 +69,28 @@ MidiRegion::~MidiRegion () { } +/** Create a new MidiRegion that has its own version of some/all of the Source used by another. + */ +boost::shared_ptr +MidiRegion::clone () +{ + BeatsFramesConverter bfc (_session.tempo_map(), _position); + double bbegin = bfc.from (_position); + double bend = bfc.from (last_frame() + 1); + + boost::shared_ptr ms = midi_source(0)->clone (bbegin, bend); + + PropertyList plist; + + plist.add (Properties::name, ms->name()); + plist.add (Properties::whole_file, true); + plist.add (Properties::start, 0); + plist.add (Properties::length, _length); + plist.add (Properties::layer, 0); + + return boost::dynamic_pointer_cast (RegionFactory::create (ms, plist, true)); +} + void MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute) { diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 2b0efd78e1..5e8bda1ea2 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -28,6 +28,8 @@ #include #include +#include + #include "pbd/xml++.h" #include "pbd/pthread_utils.h" #include "pbd/basename.h" @@ -81,6 +83,7 @@ MidiSource::MidiSource (Session& s, const XMLNode& node) } } + MidiSource::~MidiSource () { } @@ -223,44 +226,59 @@ MidiSource::mark_streaming_write_completed () _writing = false; } +boost::shared_ptr +MidiSource::clone (Evoral::MusicalTime begin, Evoral::MusicalTime end) +{ + string newname = PBD::basename_nosuffix(_name.val()); + string newpath; + + /* get a new name for the MIDI file we're going to write to + */ + + do { + + newname = bump_name_once (newname, '-'); + /* XXX build path safely */ + newpath = _session.session_directory().midi_path().to_string() +"/"+ newname + ".mid"; + + } while (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)); + + boost::shared_ptr newsrc = boost::dynamic_pointer_cast( + SourceFactory::createWritable(DataType::MIDI, _session, + newpath, false, _session.frame_rate())); + + newsrc->set_timeline_position(_timeline_position); + + if (_model) { + _model->write_to (newsrc, begin, end); + } else { + error << string_compose (_("programming error: %1"), X_("no model for MidiSource during ::clone()")); + return boost::shared_ptr(); + } + + newsrc->flush_midi(); + + /* force a reload of the model if the range is partial */ + + if (begin != Evoral::MinMusicalTime || end != Evoral::MaxMusicalTime) { + newsrc->load_model (true, true); + } + + return newsrc; +} + void MidiSource::session_saved() { flush_midi(); if (_model && _model->edited()) { - string newname; - const string basename = PBD::basename_nosuffix(_name.val()); - string::size_type last_dash = basename.find_last_of("-"); - if (last_dash == string::npos || last_dash == basename.find_first_of("-")) { - newname = basename + "-1"; - } else { - stringstream ss(basename.substr(last_dash+1)); - unsigned write_count = 0; - ss >> write_count; - // cerr << "WRITE COUNT: " << write_count << endl; - ++write_count; // start at 1 - ss.clear(); - ss << basename.substr(0, last_dash) << "-" << write_count; - newname = ss.str(); - } - - string newpath = _session.session_directory().midi_path().to_string() +"/"+ newname + ".mid"; - - boost::shared_ptr newsrc = boost::dynamic_pointer_cast( - SourceFactory::createWritable(DataType::MIDI, _session, - newpath, false, _session.frame_rate())); - - newsrc->set_timeline_position(_timeline_position); - _model->write_to(newsrc); - - // cyclic dependency here, ugly :( - newsrc->set_model(_model); - _model->set_midi_source(newsrc.get()); - - newsrc->flush_midi(); + boost::shared_ptr newsrc = clone (); - Switched (newsrc); /* EMIT SIGNAL */ + if (newsrc) { + _model->set_midi_source (newsrc.get()); + Switched (newsrc); /* EMIT SIGNAL */ + } } } diff --git a/libs/ardour/midi_state_tracker.cc b/libs/ardour/midi_state_tracker.cc index b2c0086039..da6b8f40b4 100644 --- a/libs/ardour/midi_state_tracker.cc +++ b/libs/ardour/midi_state_tracker.cc @@ -20,6 +20,7 @@ #include #include "ardour/event_type_map.h" #include "ardour/midi_ring_buffer.h" +#include "ardour/midi_source.h" #include "ardour/midi_state_tracker.h" using namespace std; @@ -132,6 +133,35 @@ MidiStateTracker::resolve_notes (Evoral::EventSink &dst, nframes64_t _on = 0; } +void +MidiStateTracker::resolve_notes (MidiSource& src, Evoral::MusicalTime time) +{ + if (!_on) { + return; + } + + /* NOTE: the src must be locked */ + + for (int channel = 0; channel < 16; ++channel) { + for (int note = 0; note < 128; ++note) { + while (_active_notes[note + 128 * channel]) { + Evoral::MIDIEvent ev ((MIDI_CMD_NOTE_OFF|channel), time, 3, 0, true); + ev.set_type (MIDI_CMD_NOTE_OFF); + ev.set_channel (channel); + ev.set_note (note); + ev.set_velocity (0); + src.append_event_unlocked_beats (ev); + _active_notes[note + 128 * channel]--; + cerr << "Resolved " << ev << endl; + /* don't stack events up at the same time + */ + time += 1.0/128.0; + } + } + } + _on = 0; +} + void MidiStateTracker::dump (ostream& o) { diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index a5e662f4d0..7c9ac93c3c 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -1724,6 +1724,8 @@ Playlist::regions_to_read (framepos_t start, framepos_t end) to_check.insert (start); to_check.insert (end); + DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n"); + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { /* find all/any regions that span start+end */ @@ -1734,22 +1736,38 @@ Playlist::regions_to_read (framepos_t start, framepos_t end) case OverlapInternal: covering.push_back (*i); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name())); break; case OverlapStart: to_check.insert ((*i)->position()); + if ((*i)->position() != 0) { + to_check.insert ((*i)->position()-1); + } + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name())); covering.push_back (*i); break; case OverlapEnd: to_check.insert ((*i)->last_frame()); + to_check.insert ((*i)->last_frame()+1); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name())); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name())); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name())); covering.push_back (*i); break; case OverlapExternal: covering.push_back (*i); to_check.insert ((*i)->position()); + if ((*i)->position() != 0) { + to_check.insert ((*i)->position()-1); + } to_check.insert ((*i)->last_frame()); + to_check.insert ((*i)->last_frame()+1); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name())); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name())); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name())); break; } @@ -1767,6 +1785,7 @@ Playlist::regions_to_read (framepos_t start, framepos_t end) if (covering.size() == 1) { rlist->push_back (covering.front()); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name())); } else { @@ -1775,11 +1794,21 @@ Playlist::regions_to_read (framepos_t start, framepos_t end) here.clear (); + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t)); + for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) { if ((*x)->covers (*t)) { here.push_back (*x); - } + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n", + (*x)->name(), + (*t))); + } else { + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n", + (*x)->name(), + (*t))); + } + } RegionSortByLayer cmp; @@ -1794,7 +1823,8 @@ Playlist::regions_to_read (framepos_t start, framepos_t end) if ((*c)->opaque()) { /* the other regions at this position are hidden by this one */ - + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n", + (*c)->name())); break; } } @@ -1812,6 +1842,8 @@ Playlist::regions_to_read (framepos_t start, framepos_t end) } } + DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size())); + return rlist; } @@ -2311,7 +2343,7 @@ Playlist::bump_name (string name, Session &session) string newname = name; do { - newname = bump_name_once (newname); + newname = bump_name_once (newname, '.'); } while (session.playlists->by_name (newname)!=NULL); return newname; diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index c0edb1a996..86b4b89d16 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -272,7 +272,7 @@ Route::ensure_track_or_route_name(string name, Session &session) string newname = name; while (!session.io_name_is_legal (newname)) { - newname = bump_name_once (newname); + newname = bump_name_once (newname, '.'); } return newname; diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 2739302140..a78bfbfdd1 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -728,8 +728,9 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot /* tell sources we're saving first, in case they write out to a new file * which should be saved with the state rather than the old one */ - for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) + for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) { i->second->session_saved(); + } tree.set_root (&get_state()); diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc index af90c935c9..2bfe16222d 100644 --- a/libs/ardour/utils.cc +++ b/libs/ardour/utils.cc @@ -72,17 +72,19 @@ legalize_for_path (ustring str) return legal; } -string bump_name_once(std::string name) +string +bump_name_once (const std::string& name, char delimiter) { - string::size_type period; + string::size_type delim; string newname; - if ((period = name.find_last_of ('.')) == string::npos) { + if ((delim = name.find_last_of (delimiter)) == string::npos) { newname = name; - newname += ".1"; + newname += delimiter; + newname += "1"; } else { int isnumber = 1; - const char *last_element = name.c_str() + period + 1; + const char *last_element = name.c_str() + delim + 1; for (size_t i = 0; i < strlen(last_element); i++) { if (!isdigit(last_element[i])) { isnumber = 0; @@ -91,18 +93,19 @@ string bump_name_once(std::string name) } errno = 0; - long int version = strtol (name.c_str()+period+1, (char **)NULL, 10); + long int version = strtol (name.c_str()+delim+1, (char **)NULL, 10); if (isnumber == 0 || errno != 0) { // last_element is not a number, or is too large newname = name; - newname += ".1"; + newname += delimiter; + newname += "1"; } else { char buf[32]; snprintf (buf, sizeof(buf), "%ld", version+1); - newname = name.substr (0, period+1); + newname = name.substr (0, delim+1); newname += buf; } } diff --git a/libs/evoral/evoral/ControlSet.hpp b/libs/evoral/evoral/ControlSet.hpp index 39c3eba344..f0c6bd0807 100644 --- a/libs/evoral/evoral/ControlSet.hpp +++ b/libs/evoral/evoral/ControlSet.hpp @@ -36,6 +36,7 @@ class ControlEvent; class ControlSet : public boost::noncopyable { public: ControlSet(); + ControlSet (const ControlSet&); virtual ~ControlSet() {} virtual boost::shared_ptr diff --git a/libs/evoral/evoral/MIDIEvent.hpp b/libs/evoral/evoral/MIDIEvent.hpp index c06a323d73..359d640fe5 100644 --- a/libs/evoral/evoral/MIDIEvent.hpp +++ b/libs/evoral/evoral/MIDIEvent.hpp @@ -68,6 +68,7 @@ struct MIDIEvent : public Event