diff --git a/flower/include/pqueue.hh b/flower/include/pqueue.hh index 981a37e..4c7c259 100644 --- a/flower/include/pqueue.hh +++ b/flower/include/pqueue.hh @@ -107,7 +107,44 @@ public: T max_t; return max_t; } - void delmin () + void del (vsize i) + { + assert (i < size ()); + T last = heap_array_.back (); + heap_array_.pop_back (); + + if (i == size ()) + return; + + vsize tgt = ++i; + + vsize next = i / 2; + while (next && compare (elt (next), last) > 0) + { + elt (tgt) = elt (next); + tgt = next; + next = tgt / 2; + } + + if (tgt == i) + { + next = tgt * 2; + while (next <= size ()) + { + if (((next + 1) <= size ()) && + (compare (elt (next + 1), elt (next)) < 0)) + next++; + if (compare (last, elt (next)) < 0) + break; + elt (tgt) = elt (next); + tgt = next; + next = tgt * 2; + } + } + elt (tgt) = last; + OK (); + } + void delmin () { assert (size ()); T last = heap_array_.back (); diff --git a/lily/include/midi-walker.hh b/lily/include/midi-walker.hh index 4fd1ae3..3f6c410 100644 --- a/lily/include/midi-walker.hh +++ b/lily/include/midi-walker.hh @@ -25,7 +25,7 @@ #include "lily-proto.hh" #include "moment.hh" -struct Midi_note_event : PQueue_ent +struct Midi_note_event : PQueue_ent > { bool ignore_; Midi_note_event (); diff --git a/lily/lily-guile.cc b/lily/lily-guile.cc index 1763a5c..6b5a018 100644 --- a/lily/midi-walker.cc +++ b/lily/midi-walker.cc @@ -81,47 +81,56 @@ Midi_walker::do_start_note (Midi_note *note) { Audio_item *ptr = items_[index_]; assert (note->audio_ == ptr); - int stop_ticks = int (moment_to_real (note->audio_->length_mom_) * Real (384 * 4)) - + ptr->audio_column_->ticks (); + int now_ticks = ptr->audio_column_->ticks (); + int stop_ticks = int (moment_to_real (note->audio_->length_mom_) * + Real (384 * 4)) + now_ticks; - bool play_start = true; for (vsize i = 0; i < stop_note_queue.size (); i++) { - /* if this pith already in queue */ - if (stop_note_queue[i].val->get_semitone_pitch () + /* if this pitch already in queue */ + if (stop_note_queue[i].val.second->get_semitone_pitch () == note->get_semitone_pitch ()) { - if (stop_note_queue[i].key < stop_ticks) - { - /* let stopnote in queue be ignored, - new stop note wins */ - stop_note_queue[i].ignore_ = true; - - /* don't replay start note, */ - play_start = false; - break; - } - else - { - /* skip this stopnote, - don't play the start note */ - note = 0; - break; - } + if (now_ticks == stop_note_queue[i].val.first) + { + // The two notes started at the same time. Merge them. + if (stop_note_queue[i].key < stop_ticks) + { + Midi_note_event e; + e.val = stop_note_queue[i].val; + e.key = stop_ticks; + stop_note_queue.del (i); + stop_note_queue.insert (e); + } + note = 0; + break; + } + else + { + // A note was played that interruped a played note. + // Stop the old note, and continue to the greatest moment + // between the two. + if (stop_note_queue[i].key > stop_ticks) + { + stop_ticks = stop_note_queue[i].key; + } + output_event (now_ticks, stop_note_queue[i].val.second); + stop_note_queue.del(i); + break; + } } } if (note) { Midi_note_event e; - e.val = new Midi_note_off (note); + e.val = std::make_pair(now_ticks, new Midi_note_off (note)); - midi_events_.push_back (e.val); - e.key = int (stop_ticks); + midi_events_.push_back (e.val.second); + e.key = stop_ticks; stop_note_queue.insert (e); - if (play_start) - output_event (ptr->audio_column_->ticks (), note); + output_event (ptr->audio_column_->ticks (), note); } } @@ -137,7 +146,7 @@ Midi_walker::do_stop_notes (int max_ticks) } int stop_ticks = e.key; - Midi_note *note = e.val; + Midi_note *note = e.val.second; output_event (stop_ticks, note); }