add skeleton for i18n support
[ardour.git] / libs / evoral / src / Sequence.cpp
index 78c04a6759b6f327d8e84100d59e95836f348320..00ae5d5cfa8489cf51953a8135d35fc434b4fbca 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is part of Evoral.
- * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
+ * Copyright (C) 2008 David Robillard <http://drobilla.net>
  * Copyright (C) 2000-2008 Paul Davis
  *
  * Evoral is free software; you can redistribute it and/or modify it under the
@@ -75,13 +75,11 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq, Time t
 {
        DEBUG_TRACE (DEBUG::Sequence, string_compose ("Created Iterator @ %1 (is end: %2)\n)", t, _is_end));
 
-       if (!_is_end) {
-               _lock = seq.read_lock();
-       } else {
+       if (_is_end) {
                return;
        }
 
-       typename Sequence<Time>::ReadLock lock(seq.read_lock());
+       _lock = seq.read_lock();
 
        // Find first note which begins at or after t
        _note_iter = seq.note_lower_bound(t);
@@ -434,10 +432,11 @@ Sequence<Time>::const_iterator::operator=(const const_iterator& other)
        _force_discrete = other._force_discrete;
        _active_patch_change_message = other._active_patch_change_message;
 
-       if (other._lock)
+       if (other._lock) {
                _lock = _seq->read_lock();
-       else
+       } else {
                _lock.reset();
+       }
 
        if (other._control_iter == other._control_iters.end()) {
                _control_iter = _control_iters.end();
@@ -624,7 +623,7 @@ Sequence<Time>::start_write()
  */
 template<typename Time>
 void
-Sequence<Time>::end_write (bool delete_stuck)
+Sequence<Time>::end_write (StuckNoteOption option, Time when)
 {
        WriteLock lock(write_lock());
 
@@ -632,27 +631,40 @@ Sequence<Time>::end_write (bool delete_stuck)
                return;
        }
 
-       DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 : end_write (%2 notes)\n", this, _notes.size()));
+       DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 : end_write (%2 notes) delete stuck option %3 @ %4\n", this, _notes.size(), option, when));
+
+        if (!_percussive) {
 
-        if (!_percussive && delete_stuck) {
                 for (typename Notes::iterator n = _notes.begin(); n != _notes.end() ;) {
                         typename Notes::iterator next = n;
                         ++next;
                        
                         if ((*n)->length() == 0) {
-                                cerr << "WARNING: Stuck note lost: " << (*n)->note() << endl;
-                                _notes.erase(n);
-                        }
-                        
+                               switch (option) {
+                               case Relax:
+                                       break;
+                               case DeleteStuckNotes:
+                                       cerr << "WARNING: Stuck note lost: " << (*n)->note() << endl;
+                                       _notes.erase(n);
+                                       break;
+                               case ResolveStuckNotes:
+                                       if (when <= (*n)->time()) {
+                                               cerr << "WARNING: Stuck note resolution - end time @ " 
+                                                    << when << " is before note on: " << (**n) << endl;
+                                               _notes.erase (*n);
+                                       } else {
+                                               (*n)->set_length (when - (*n)->time());
+                                               cerr << "WARNING: resolved note-on with no note-off to generate " << (**n) << endl;
+                                       }
+                                       break;
+                               }
+                       }
+
                         n = next;
                 }
         }
 
        for (int i = 0; i < 16; ++i) {
-               if (!_write_notes[i].empty()) {
-                       cerr << "WARNING: Sequence<Time>::end_write: Channel " << i << " has "
-                                       << _write_notes[i].size() << " stuck notes" << endl;
-               }
                _write_notes[i].clear();
        }
 
@@ -688,7 +700,7 @@ Sequence<Time>::add_note_unlocked(const NotePtr note, void* arg)
  
        _edited = true;
 
-       return true;
+       return true;
 }
 
 template<typename Time>
@@ -743,7 +755,7 @@ Sequence<Time>::remove_note_unlocked(const constNotePtr note)
                ++tmp;
                
                 if (*j == note) {
-                        DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\terasing pitch %2 @ %3\n", this, (int)(*i)->note(), (*i)->time()));
+                        DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1\terasing pitch %2 @ %3\n", this, (int)(*j)->note(), (*j)->time()));
                         p.erase (j);
                 }
 
@@ -751,7 +763,7 @@ Sequence<Time>::remove_note_unlocked(const constNotePtr note)
         }
         
         if (!erased) {
-                cerr << "Unable to find note to erase" << endl;
+                cerr << "Unable to find note to erase matching " << *note.get() << endl;
         }
 }
 
@@ -819,10 +831,10 @@ Sequence<Time>::append(const Event<Time>& event, event_id_t evid)
        } else if (ev.is_cc() && (ev.cc_number() == MIDI_CTL_MSB_BANK || ev.cc_number() == MIDI_CTL_LSB_BANK)) {
                /* note bank numbers in our _bank[] array, so that we can write an event when the program change arrives */
                if (ev.cc_number() == MIDI_CTL_MSB_BANK) {
-                       _bank[ev.channel()] &= (0x7f << 7);
+                       _bank[ev.channel()] &= ~(0x7f << 7);
                        _bank[ev.channel()] |= ev.cc_value() << 7;
                } else {
-                       _bank[ev.channel()] &= 0x7f;
+                       _bank[ev.channel()] &= ~0x7f;
                        _bank[ev.channel()] |= ev.cc_value();
                }
         } else if (ev.is_cc()) {
@@ -890,7 +902,7 @@ template<typename Time>
 void
 Sequence<Time>::append_note_off_unlocked (NotePtr note)
 {
-        DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 c=%2 note %3 on @ %4 v=%5\n",
+        DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 c=%2 note %3 OFF @ %4 v=%5\n",
                                                       this, (int)note->channel(), 
                                                       (int)note->note(), note->time(), (int)note->velocity()));
         assert(note->note() <= 127);
@@ -926,7 +938,7 @@ Sequence<Time>::append_note_off_unlocked (NotePtr note)
                         nn->set_off_velocity (note->velocity());
 
                         _write_notes[note->channel()].erase(n);
-                        DEBUG_TRACE (DEBUG::Sequence, string_compose ("resolved note, length: %1\n", note->length()));
+                        DEBUG_TRACE (DEBUG::Sequence, string_compose ("resolved note @ %2 length: %1\n", nn->length(), nn->time()));
                         resolved = true;
                         break;
                 }
@@ -1215,5 +1227,17 @@ Sequence<Time>::control_list_marked_dirty ()
 
 template class Sequence<Evoral::MusicalTime>;
 
+template<typename Time>
+void
+Sequence<Time>::dump (ostream& str) const
+{
+       Sequence<Time>::const_iterator i;
+       str << "+++ dump\n";
+       for (i = begin(); i != end(); ++i) {
+               str << *i << endl;
+       }
+       str << "--- dump\n";
+}
+
 } // namespace Evoral