summaryrefslogtreecommitdiff
path: root/libs/evoral
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2015-03-01 13:33:25 -0500
committerDavid Robillard <d@drobilla.net>2015-03-05 17:30:31 -0500
commita8aae56d92699e4545b5f8a69742f9a1c75ad238 (patch)
treeae3c14f1b78fbfddf126b44e533692b137d93f28 /libs/evoral
parent09f1571fc0c9dd164601cfd3d12fac31a084b9f6 (diff)
Handle edits while playing precisely.
This avoids stuck notes if active notes are edited, but without stopping all active notes in the region on any edit as before. This implementation injects note ons in places that aren't actually note starts. Depending on how percussive the instrument is, this may not be desired. In the future, an option for this would be an improvement, but there are other places where "start notes in the middle" is a reasonable option. I think that should be handled universally if we're to do it at all, so not considering it a part of this fix for now.
Diffstat (limited to 'libs/evoral')
-rw-r--r--libs/evoral/evoral/Event.hpp2
-rw-r--r--libs/evoral/evoral/Sequence.hpp30
-rw-r--r--libs/evoral/src/Event.cpp16
-rw-r--r--libs/evoral/src/Sequence.cpp30
4 files changed, 57 insertions, 21 deletions
diff --git a/libs/evoral/evoral/Event.hpp b/libs/evoral/evoral/Event.hpp
index 1682028335..ec92d575d0 100644
--- a/libs/evoral/evoral/Event.hpp
+++ b/libs/evoral/evoral/Event.hpp
@@ -49,6 +49,8 @@ public:
#ifdef EVORAL_EVENT_ALLOC
Event (EventType type=0, Time time=Time(), uint32_t size=0, uint8_t* buf=NULL, bool alloc=false);
+ Event (EventType type, Time time, uint32_t size, const uint8_t* buf);
+
/** Copy \a copy.
*
* If \a alloc is true, the buffer will be copied and this method
diff --git a/libs/evoral/evoral/Sequence.hpp b/libs/evoral/evoral/Sequence.hpp
index 639a85730c..a5e95de1be 100644
--- a/libs/evoral/evoral/Sequence.hpp
+++ b/libs/evoral/evoral/Sequence.hpp
@@ -82,14 +82,15 @@ protected:
public:
- typedef typename boost::shared_ptr<Evoral::Note<Time> > NotePtr;
- typedef typename boost::shared_ptr<const Evoral::Note<Time> > constNotePtr;
+ typedef typename boost::shared_ptr<Evoral::Note<Time> > NotePtr;
+ typedef typename boost::weak_ptr<Evoral::Note<Time> > WeakNotePtr;
+ typedef typename boost::shared_ptr<const Evoral::Note<Time> > constNotePtr;
typedef boost::shared_ptr<Glib::Threads::RWLock::ReaderLock> ReadLock;
- typedef boost::shared_ptr<WriteLockImpl> WriteLock;
+ typedef boost::shared_ptr<WriteLockImpl> WriteLock;
virtual ReadLock read_lock() const { return ReadLock(new Glib::Threads::RWLock::ReaderLock(_lock)); }
- virtual WriteLock write_lock() { return WriteLock(new WriteLockImpl(_lock, _control_lock)); }
+ virtual WriteLock write_lock() { return WriteLock(new WriteLockImpl(_lock, _control_lock)); }
void clear();
@@ -182,7 +183,7 @@ public:
OverlapPitchResolution overlap_pitch_resolution() const { return _overlap_pitch_resolution; }
void set_overlap_pitch_resolution(OverlapPitchResolution opr);
- void set_notes (const typename Sequence<Time>::Notes& n);
+ void set_notes (const Sequence<Time>::Notes& n);
typedef boost::shared_ptr< Event<Time> > SysExPtr;
typedef boost::shared_ptr<const Event<Time> > constSysExPtr;
@@ -220,13 +221,15 @@ public:
class LIBEVORAL_API const_iterator {
public:
const_iterator();
- const_iterator(const Sequence<Time>& seq, Time t, bool, std::set<Evoral::Parameter> const &);
- ~const_iterator();
+ const_iterator(const Sequence<Time>& seq,
+ Time t,
+ bool force_discrete,
+ const std::set<Evoral::Parameter>& filtered,
+ const std::set<WeakNotePtr>* active_notes=NULL);
inline bool valid() const { return !_is_end && _event; }
- //inline bool locked() const { return _locked; }
- void invalidate();
+ void invalidate(std::set<WeakNotePtr>* notes);
const Event<Time>& operator*() const { return *_event; }
const boost::shared_ptr< Event<Time> > operator->() const { return _event; }
@@ -267,10 +270,11 @@ public:
};
const_iterator begin (
- Time t = Time(),
- bool force_discrete = false,
- std::set<Evoral::Parameter> const & f = std::set<Evoral::Parameter> ()) const {
- return const_iterator (*this, t, force_discrete, f);
+ Time t = Time(),
+ bool force_discrete = false,
+ const std::set<Evoral::Parameter>& f = std::set<Evoral::Parameter>(),
+ const std::set<WeakNotePtr>* active_notes = NULL) const {
+ return const_iterator (*this, t, force_discrete, f, active_notes);
}
const const_iterator& end() const { return _end_iter; }
diff --git a/libs/evoral/src/Event.cpp b/libs/evoral/src/Event.cpp
index 66e45ab2ad..da31662951 100644
--- a/libs/evoral/src/Event.cpp
+++ b/libs/evoral/src/Event.cpp
@@ -64,6 +64,22 @@ Event<Timestamp>::Event(EventType type, Timestamp time, uint32_t size, uint8_t*
}
template<typename Timestamp>
+Event<Timestamp>::Event(EventType type,
+ Timestamp time,
+ uint32_t size,
+ const uint8_t* buf)
+ : _type(type)
+ , _original_time(time)
+ , _nominal_time(time)
+ , _size(size)
+ , _buf((uint8_t*)malloc(size))
+ , _id(-1)
+ , _owns_buf(true)
+{
+ memcpy(_buf, buf, _size);
+}
+
+template<typename Timestamp>
Event<Timestamp>::Event(const Event& copy, bool owns_buf)
: _type(copy._type)
, _original_time(copy._original_time)
diff --git a/libs/evoral/src/Sequence.cpp b/libs/evoral/src/Sequence.cpp
index 1d52a12e4f..c8a0dd4f23 100644
--- a/libs/evoral/src/Sequence.cpp
+++ b/libs/evoral/src/Sequence.cpp
@@ -72,7 +72,11 @@ Sequence<Time>::const_iterator::const_iterator()
/** @param force_discrete true to force ControlLists to use discrete evaluation, otherwise false to get them to use their configured mode */
template<typename Time>
-Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t, bool force_discrete, std::set<Evoral::Parameter> const & filtered)
+Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq,
+ Time t,
+ bool force_discrete,
+ const std::set<Evoral::Parameter>& filtered,
+ const std::set<WeakNotePtr>* active_notes)
: _seq(&seq)
, _active_patch_change_message (0)
, _type(NIL)
@@ -91,6 +95,17 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t
_lock = seq.read_lock();
+ // Add currently active notes, if given
+ if (active_notes) {
+ for (typename std::set<WeakNotePtr>::const_iterator i = active_notes->begin();
+ i != active_notes->end(); ++i) {
+ NotePtr note = i->lock();
+ if (note && note->time() <= t && note->end_time() > t) {
+ _active_notes.push(note);
+ }
+ }
+ }
+
// Find first note which begins at or after t
_note_iter = seq.note_lower_bound(t);
@@ -193,15 +208,13 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t
}
template<typename Time>
-Sequence<Time>::const_iterator::~const_iterator()
-{
-}
-
-template<typename Time>
void
-Sequence<Time>::const_iterator::invalidate()
+Sequence<Time>::const_iterator::invalidate(std::set< boost::weak_ptr< Note<Time> > >* notes)
{
while (!_active_notes.empty()) {
+ if (notes) {
+ notes->insert(_active_notes.top());
+ }
_active_notes.pop();
}
_type = NIL;
@@ -278,7 +291,7 @@ Sequence<Time>::const_iterator::set_event()
DEBUG_TRACE(DEBUG::Sequence, "iterator = note off\n");
assert(!_active_notes.empty());
*_event = _active_notes.top()->off_event();
- _active_notes.pop();
+ // We don't pop the active note until we increment past it
break;
case SYSEX:
DEBUG_TRACE(DEBUG::Sequence, "iterator = sysex\n");
@@ -338,6 +351,7 @@ Sequence<Time>::const_iterator::operator++()
++_note_iter;
break;
case NOTE_OFF:
+ _active_notes.pop();
break;
case CONTROL:
// Increment current controller iterator