add channel+pitch indexing for notes in a Sequence

git-svn-id: svn://localhost/ardour2/branches/3.0@7217 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2010-06-02 19:55:37 +00:00
parent baacf1c7b4
commit 460d2d0675
2 changed files with 320 additions and 242 deletions

View file

@ -137,6 +137,10 @@ public:
inline Notes& notes() { return _notes; }
inline const Notes& notes() const { return _notes; }
typedef std::multiset<boost::shared_ptr< Note<Time> >, NoteNumberComparator> Pitches;
inline Pitches& pitches(uint8_t chan) { return _pitches[chan&0xf]; }
inline const Pitches& pitches(uint8_t chan) const { return _pitches[chan&0xf]; }
enum NoteOperator {
PitchEqual,
PitchLessThan,
@ -244,9 +248,13 @@ private:
void append_control_unlocked(const Parameter& param, Time time, double value);
void append_sysex_unlocked(const MIDIEvent<Time>& ev);
void get_notes_by_pitch (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
void get_notes_by_velocity (Notes&, NoteOperator, uint8_t val, int chan_mask = 0) const;
const TypeMap& _type_map;
Notes _notes;
Notes _notes; // notes indexed by time
Pitches _pitches[16]; // notes indexed by channel+pitch
SysExes _sysexes;
typedef std::multiset<boost::shared_ptr< Note<Time> >, EarlierNoteComparator> WriteNotes;

View file

@ -598,7 +598,8 @@ Sequence<Time>::add_note_unlocked(const boost::shared_ptr< Note<Time> > note)
if (note->note() > _highest_note)
_highest_note = note->note();
_notes.insert(note);
_notes.insert (note);
_pitches[note->channel()].insert (note);
return true;
}
@ -618,6 +619,7 @@ Sequence<Time>::remove_note_unlocked(const boost::shared_ptr< const Note<Time> >
if (*i == note) {
DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\terasing note %2 @ %3\n", this, (int)(*i)->note(), (*i)->time()));
_notes.erase (i);
if ((*i)->note() == _lowest_note || (*i)->note() == _highest_note) {
@ -635,24 +637,35 @@ Sequence<Time>::remove_note_unlocked(const boost::shared_ptr< const Note<Time> >
erased = true;
}
}
Pitches& p (pitches (note->channel()));
boost::shared_ptr< Note<Time> > search_note(new Note<Time>(0, 0, 0, note->note(), 0));
for (typename Pitches::iterator i = p.lower_bound (search_note);
i != p.end() && (*i)->note() == note->note(); ++i) {
if (*i == note) {
DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\terasing pitch %2 @ %3\n", this, (int)(*i)->note(), (*i)->time()));
p.erase (i);
}
}
if (!erased) {
cerr << "Unable to find note to erase" << endl;
}
}
}
/** Append \a ev to model. NOT realtime safe.
/** Append \a ev to model. NOT realtime safe.
*
* The timestamp of event is expected to be relative to
* the start of this model (t=0) and MUST be monotonically increasing
* and MUST be >= the latest event currently in the model.
*/
template<typename Time>
void
Sequence<Time>::append(const Event<Time>& event)
{
template<typename Time>
void
Sequence<Time>::append(const Event<Time>& event)
{
WriteLock lock(write_lock());
_edited = true;
@ -700,12 +713,12 @@ Sequence<Time>::append(const Event<Time>& event)
} else {
printf("WARNING: Sequence: Unknown MIDI event type %X\n", ev.type());
}
}
}
template<typename Time>
void
Sequence<Time>::append_note_on_unlocked (boost::shared_ptr< Note<Time> > note)
{
template<typename Time>
void
Sequence<Time>::append_note_on_unlocked (boost::shared_ptr< Note<Time> > note)
{
DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 c=%2 note %3 on @ %4 v=%5\n", this,
(int) note->channel(), (int) note->note(),
note->time(), (int) note->velocity()));
@ -727,12 +740,12 @@ Sequence<Time>::append_note_on_unlocked (boost::shared_ptr< Note<Time> > note)
} else {
DEBUG_TRACE(DEBUG::Sequence, "Percussive: NOT appending active note on\n");
}
}
}
template<typename Time>
void
Sequence<Time>::append_note_off_unlocked (boost::shared_ptr< Note<Time> > note)
{
template<typename Time>
void
Sequence<Time>::append_note_off_unlocked (boost::shared_ptr< Note<Time> > note)
{
DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 c=%2 note %3 on @ %4 v=%5\n",
this, (int)note->channel(),
(int)note->note(), note->time(), (int)note->velocity()));
@ -773,22 +786,22 @@ Sequence<Time>::append_note_off_unlocked (boost::shared_ptr< Note<Time> > note)
cerr << this << " spurious note off chan " << (int)note->channel()
<< ", note " << (int)note->note() << " @ " << note->time() << endl;
}
}
}
template<typename Time>
void
Sequence<Time>::append_control_unlocked(const Parameter& param, Time time, double value)
{
template<typename Time>
void
Sequence<Time>::append_control_unlocked(const Parameter& param, Time time, double value)
{
DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 %2 @ %3\t=\t%4 # controls: %5\n",
this, _type_map.to_symbol(param), time, value, _controls.size()));
boost::shared_ptr<Control> c = control(param, true);
c->list()->rt_add(time, value);
}
}
template<typename Time>
void
Sequence<Time>::append_sysex_unlocked(const MIDIEvent<Time>& ev)
{
template<typename Time>
void
Sequence<Time>::append_sysex_unlocked(const MIDIEvent<Time>& ev)
{
#ifdef DEBUG_SEQUENCE
cerr << this << " SysEx @ " << ev.time() << " \t= \t [ " << hex;
for (size_t i=0; i < ev.size(); ++i) {
@ -798,19 +811,19 @@ Sequence<Time>::append_sysex_unlocked(const MIDIEvent<Time>& ev)
boost::shared_ptr<MIDIEvent<Time> > event(new MIDIEvent<Time>(ev, true));
_sysexes.push_back(event);
}
}
template<typename Time>
bool
Sequence<Time>::contains (const boost::shared_ptr< Note<Time> > note) const
{
template<typename Time>
bool
Sequence<Time>::contains (const boost::shared_ptr< Note<Time> > note) const
{
return contains_unlocked (note);
}
}
template<typename Time>
bool
Sequence<Time>::contains_unlocked (const boost::shared_ptr< Note<Time> > note) const
{
template<typename Time>
bool
Sequence<Time>::contains_unlocked (const boost::shared_ptr< Note<Time> > note) const
{
for (typename Sequence<Time>::Notes::const_iterator i = note_lower_bound(note->time());
i != _notes.end() && (*i)->time() == note->time(); ++i) {
if (*i == note) {
@ -819,20 +832,20 @@ Sequence<Time>::contains_unlocked (const boost::shared_ptr< Note<Time> > note) c
}
}
return false;
}
}
template<typename Time>
bool
Sequence<Time>::overlaps (const boost::shared_ptr< Note<Time> > note) const
{
template<typename Time>
bool
Sequence<Time>::overlaps (const boost::shared_ptr< Note<Time> > note) const
{
ReadLock lock (read_lock());
return overlaps_unlocked (note);
}
}
template<typename Time>
bool
Sequence<Time>::overlaps_unlocked (const boost::shared_ptr< Note<Time> > note) const
{
template<typename Time>
bool
Sequence<Time>::overlaps_unlocked (const boost::shared_ptr< Note<Time> > note) const
{
Time sa = note->time();
Time ea = note->end_time();
@ -855,64 +868,116 @@ Sequence<Time>::overlaps_unlocked (const boost::shared_ptr< Note<Time> > note) c
}
return false;
}
}
template<typename Time>
void
Sequence<Time>::set_notes (const Sequence<Time>::Notes& n)
{
template<typename Time>
void
Sequence<Time>::set_notes (const Sequence<Time>::Notes& n)
{
_notes = n;
}
}
/** Return the earliest note with time >= t */
template<typename Time>
typename Sequence<Time>::Notes::const_iterator
Sequence<Time>::note_lower_bound (Time t) const
{
/** Return the earliest note with time >= t */
template<typename Time>
typename Sequence<Time>::Notes::const_iterator
Sequence<Time>::note_lower_bound (Time t) const
{
boost::shared_ptr< Note<Time> > search_note(new Note<Time>(0, t, 0, 0, 0));
typename Sequence<Time>::Notes::const_iterator i = _notes.lower_bound(search_note);
assert(i == _notes.end() || (*i)->time() >= t);
return i;
}
}
template<typename Time>
void
Sequence<Time>::get_notes (Notes& n, NoteOperator op, uint8_t val, int chan_mask) const
{
ReadLock lock (read_lock());
switch (op) {
case PitchEqual:
case PitchLessThan:
case PitchLessThanOrEqual:
case PitchGreater:
case PitchGreaterThanOrEqual:
get_notes_by_pitch (n, op, val, chan_mask);
break;
for (typename Notes::const_iterator i = _notes.begin(); i != _notes.end(); ++i) {
case VelocityEqual:
case VelocityLessThan:
case VelocityLessThanOrEqual:
case VelocityGreater:
case VelocityGreaterThanOrEqual:
get_notes_by_velocity (n, op, val, chan_mask);
break;
}
}
if (chan_mask != 0 && !((1<<(*i)->channel()) & chan_mask)) {
template<typename Time>
void
Sequence<Time>::get_notes_by_pitch (Notes& n, NoteOperator op, uint8_t val, int chan_mask) const
{
for (uint8_t c = 0; c < 16; ++c) {
if (chan_mask != 0 && !((1<<c) & chan_mask)) {
continue;
}
const Pitches& p (pitches (c));
boost::shared_ptr< Note<Time> > search_note(new Note<Time>(0, 0, 0, val, 0));
typename Pitches::const_iterator i;
switch (op) {
case PitchEqual:
if ((*i)->note() == val) {
i = p.lower_bound (search_note);
while (i != p.end() && (*i)->note() == val) {
n.insert (*i);
}
break;
case PitchLessThan:
if ((*i)->note() < val) {
i = p.upper_bound (search_note);
while (i != p.end() && (*i)->note() < val) {
n.insert (*i);
}
break;
case PitchLessThanOrEqual:
if ((*i)->note() <= val) {
i = p.upper_bound (search_note);
while (i != p.end() && (*i)->note() <= val) {
n.insert (*i);
}
break;
case PitchGreater:
if ((*i)->note() > val) {
i = p.lower_bound (search_note);
while (i != p.end() && (*i)->note() > val) {
n.insert (*i);
}
break;
case PitchGreaterThanOrEqual:
if ((*i)->note() >= val) {
i = p.lower_bound (search_note);
while (i != p.end() && (*i)->note() >= val) {
n.insert (*i);
}
break;
default:
//fatal << string_compose (_("programming error: %1 %2", X_("get_notes_by_pitch() called with illegal operator"), op)) << endmsg;
abort ();
/* NOTREACHED*/
}
}
}
template<typename Time>
void
Sequence<Time>::get_notes_by_velocity (Notes& n, NoteOperator op, uint8_t val, int chan_mask) const
{
ReadLock lock (read_lock());
for (typename Notes::const_iterator i = _notes.begin(); i != _notes.end(); ++i) {
if (chan_mask != 0 && !((1<<((*i)->channel())) & chan_mask)) {
continue;
}
switch (op) {
case VelocityEqual:
if ((*i)->velocity() == val) {
n.insert (*i);
@ -938,6 +1003,11 @@ Sequence<Time>::get_notes (Notes& n, NoteOperator op, uint8_t val, int chan_mask
n.insert (*i);
}
break;
default:
// fatal << string_compose (_("programming error: %1 %2", X_("get_notes_by_velocity() called with illegal operator"), op)) << endmsg;
abort ();
/* NOTREACHED*/
}
}
}