X-Git-Url: https://main.carlh.net/gitweb/?p=ardour.git;a=blobdiff_plain;f=libs%2Fardour%2Fmidi_source.cc;h=97bce4b1abc9f9c3b92c3a9f6d3bb9e842b9bf98;hp=1887b74302104db67fc2018d8bc3bb43f5d5994e;hb=c8c6bca6587450ff64303dbc994a4cd28d6ce7aa;hpb=cf806123ca5faaef483f898daba3f7bd38ec62eb diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 1887b74302..97bce4b1ab 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -34,15 +34,21 @@ #include "pbd/pthread_utils.h" #include "pbd/basename.h" +#include "evoral/Control.hpp" +#include "evoral/EventSink.hpp" + #include "ardour/debug.h" +#include "ardour/file_source.h" +#include "ardour/midi_channel_filter.h" #include "ardour/midi_model.h" -#include "ardour/midi_state_tracker.h" #include "ardour/midi_source.h" +#include "ardour/midi_state_tracker.h" #include "ardour/session.h" +#include "ardour/tempo.h" #include "ardour/session_directory.h" #include "ardour/source_factory.h" -#include "i18n.h" +#include "pbd/i18n.h" namespace ARDOUR { template class MidiRingBuffer; } @@ -77,7 +83,6 @@ MidiSource::MidiSource (Session& s, const XMLNode& node) } } - MidiSource::~MidiSource () { } @@ -109,8 +114,7 @@ MidiSource::get_state () int MidiSource::set_state (const XMLNode& node, int /*version*/) { - const XMLProperty* prop; - + XMLProperty const * prop; if ((prop = node.property ("captured-for")) != 0) { _captured_for = prop->value(); } @@ -118,39 +122,31 @@ MidiSource::set_state (const XMLNode& node, int /*version*/) XMLNodeList children = node.children (); for (XMLNodeConstIterator i = children.begin(); i != children.end(); ++i) { if ((*i)->name() == X_("InterpolationStyle")) { - XMLProperty* prop; - if ((prop = (*i)->property (X_("parameter"))) == 0) { error << _("Missing parameter property on InterpolationStyle") << endmsg; return -1; } - - Evoral::Parameter p = EventTypeMap::instance().new_parameter (prop->value()); + Evoral::Parameter p = EventTypeMap::instance().from_symbol (prop->value()); if ((prop = (*i)->property (X_("style"))) == 0) { error << _("Missing style property on InterpolationStyle") << endmsg; return -1; } - - Evoral::ControlList::InterpolationStyle s = static_cast (string_2_enum (prop->value(), s)); + Evoral::ControlList::InterpolationStyle s = static_cast( + string_2_enum (prop->value(), s)); set_interpolation_of (p, s); } else if ((*i)->name() == X_("AutomationState")) { - - XMLProperty* prop; - if ((prop = (*i)->property (X_("parameter"))) == 0) { error << _("Missing parameter property on AutomationState") << endmsg; return -1; } - - Evoral::Parameter p = EventTypeMap::instance().new_parameter (prop->value()); + Evoral::Parameter p = EventTypeMap::instance().from_symbol (prop->value()); if ((prop = (*i)->property (X_("state"))) == 0) { error << _("Missing state property on AutomationState") << endmsg; return -1; } - AutoState s = static_cast (string_2_enum (prop->value(), s)); set_automation_state_of (p, s); } @@ -162,13 +158,13 @@ MidiSource::set_state (const XMLNode& node, int /*version*/) bool MidiSource::empty () const { - return _length_beats == 0; + return !_length_beats; } framecnt_t MidiSource::length (framepos_t pos) const { - if (_length_beats == 0) { + if (!_length_beats) { return 0; } @@ -183,89 +179,135 @@ MidiSource::update_length (framecnt_t) } void -MidiSource::invalidate () +MidiSource::invalidate (const Lock& lock, std::set::WeakNotePtr>* notes) { _model_iter_valid = false; - _model_iter.invalidate(); + _model_iter.invalidate(notes); } -/** @param filtered A set of parameters whose MIDI messages will not be returned */ framecnt_t -MidiSource::midi_read (Evoral::EventSink& dst, framepos_t source_start, - framepos_t start, framecnt_t cnt, - MidiStateTracker* tracker, - std::set const & filtered) const +MidiSource::midi_read (const Lock& lm, + Evoral::EventSink& dst, + framepos_t source_start, + framepos_t start, + framecnt_t cnt, + MidiStateTracker* tracker, + MidiChannelFilter* filter, + const std::set& filtered, + double beat, + double start_beat) 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, string_compose ("MidiSource::midi-read() %5 sstart %1 start %2 cnt %3 tracker %4\n", - source_start, start, cnt, tracker, name())); + DEBUG_TRACE (DEBUG::MidiSourceIO, + string_compose ("MidiSource::midi_read() %5 sstart %1 start %2 cnt %3 tracker %4\n", + source_start, start, cnt, tracker, name())); if (_model) { - Evoral::Sequence::const_iterator& i = _model_iter; - - // If the cached iterator is invalid, search for the first event past start - if (_last_read_end == 0 || start != _last_read_end || !_model_iter_valid) { - DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("*** %1 search for relevant iterator for %1 / %2\n", _name, source_start, start)); - for (i = _model->begin(0, false, filtered); i != _model->end(); ++i) { - if (converter.to(i->time()) >= start) { - DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("***\tstop iterator search @ %1\n", i->time())); + // Find appropriate model iterator + Evoral::Sequence::const_iterator& i = _model_iter; + const bool linear_read = _last_read_end != 0 && start == _last_read_end; + if (!linear_read || !_model_iter_valid) { +#if 0 + // Cached iterator is invalid, search for the first event past start + i = _model->begin(converter.from(start), false, filtered, + linear_read ? &_model->active_notes() : NULL); + _model_iter_valid = true; + if (!linear_read) { + _model->active_notes().clear(); + } +#else + /* hot-fix http://tracker.ardour.org/view.php?id=6541 + * "parallel playback of linked midi regions -> no note-offs" + * + * A midi source can be used by multiple tracks simultaneously, + * in which case midi_read() may be called from different tracks for + * overlapping time-ranges. + * + * However there is only a single iterator for a given midi-source. + * This results in every midi_read() performing a seek. + * + * If seeking is performed with + * _model->begin(converter.from(start),...) + * the model is used for seeking. That method seeks to the first + * *note-on* event after 'start'. + * + * _model->begin(converter.from( ) ,..) eventually calls + * Sequence