Fix several MIDI timestamp related problems:
authorDavid Robillard <d@drobilla.net>
Sun, 7 Oct 2007 07:20:09 +0000 (07:20 +0000)
committerDavid Robillard <d@drobilla.net>
Sun, 7 Oct 2007 07:20:09 +0000 (07:20 +0000)
Fix recording MIDI regions that start at t != 0.
Fix display of MIDI events in regions that start at t != 0.
Fix recording after relocating an already rec-armed MIDI track.

git-svn-id: svn://localhost/ardour2/trunk@2528 d708f5d6-7413-0410-9779-e7cbd77b26cf

13 files changed:
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_streamview.cc
libs/ardour/ardour/diskstream.h
libs/ardour/ardour/midi_diskstream.h
libs/ardour/ardour/midi_model.h
libs/ardour/ardour/midi_source.h
libs/ardour/ardour/session.h
libs/ardour/ardour/smf_source.h
libs/ardour/midi_diskstream.cc
libs/ardour/midi_model.cc
libs/ardour/midi_source.cc
libs/ardour/session_transport.cc
libs/ardour/smf_source.cc

index 5defec64139c36b3d1490d8945d5c2c5db942dce..7dcba64baea63a42d53b5bfbb678563f3418117a 100644 (file)
@@ -90,8 +90,8 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
        if (wfd)
                midi_region()->midi_source(0)->load_model();
        
-       const Meter& m = trackview.session().tempo_map().meter_at(_region->start());
-       const Tempo& t = trackview.session().tempo_map().tempo_at(_region->start());
+       const Meter& m = trackview.session().tempo_map().meter_at(_region->position());
+       const Tempo& t = trackview.session().tempo_map().tempo_at(_region->position());
        _default_note_length = m.frames_per_bar(t, trackview.session().frame_rate())
                        / m.beats_per_bar();
 
@@ -596,7 +596,7 @@ MidiRegionView::extend_active_notes()
  * event arrives, to properly display the note.
  */
 void
-MidiRegionView::add_note (const Note& note, bool copy_note)
+MidiRegionView::add_note(const Note& note, bool copy_note)
 {
        assert(note.time() >= 0);
        //assert(note.time() < _region->length());
index 73f14a2e406b0107c4e28ff960684e4af9e645e9..a2b4229650eb6f835b085f4036e7783c7c03c9b2 100644 (file)
@@ -304,7 +304,7 @@ MidiStreamView::setup_rec_box ()
                                
                                jack_nframes_t start = 0;
                                if (rec_regions.size() > 0) {
-                                       start = rec_regions.back().first->start() + _trackview.get_diskstream()->get_captured_frames(rec_regions.size()-1);
+                                       start = rec_regions.back().first->position() + _trackview.get_diskstream()->get_captured_frames(rec_regions.size()-1);
                                }
                                
                                boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion>
@@ -439,22 +439,19 @@ MidiStreamView::update_rec_regions (boost::shared_ptr<MidiModel> data, nframes_t
 
                        nframes_t origlen = region->length();
                        
-                       //cerr << "MIDI URR: " << start << " * " << dur
-                       //      << " (origlen " << origlen << ")" << endl;
-
                        if (region == rec_regions.back().first && rec_active) {
 
-                               if (start >= region->start()) {
-
-                                       nframes_t nlen = start + dur - region->start();
+                               if (start >= region->midi_source(0)->timeline_position()) {
+                               
+                                       nframes_t nlen = start + dur - region->position();
 
                                        if (nlen != region->length()) {
-
+                                       
                                                region->freeze ();
                                                region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this);
-                                               region->set_length (nlen, this);
+                                               region->set_length (start + dur - region->position(), this);
                                                region->thaw ("updated");
-
+                                               
                                                if (origlen == 1) {
                                                        /* our special initial length */
                                                        iter->second = add_region_view_internal (region, false);
@@ -468,14 +465,17 @@ MidiStreamView::update_rec_regions (boost::shared_ptr<MidiModel> data, nframes_t
 
                                                /* draw events */
                                                MidiRegionView* mrv = (MidiRegionView*)iter->second;
-                                               // FIXME: slow
                                                for (size_t i=0; i < data->n_notes(); ++i) {
+
                                                        const Note& note = data->note_at(i);
-                                                       if (note.time() > start + dur)
+
+                                                       if (note.time() + region->position() < start)
+                                                               continue;
+
+                                                       if (note.time() + region->position() > start + dur)
                                                                break;
 
-                                                       if (note.time() >= start)
-                                                               mrv->add_note(note, true);
+                                                       mrv->add_note(note, true);
                                                        
                                                        if (note.duration() > 0 && note.end_time() >= start)
                                                                mrv->resolve_note(note.note(), note.end_time());
@@ -490,17 +490,16 @@ MidiStreamView::update_rec_regions (boost::shared_ptr<MidiModel> data, nframes_t
                                                }
                                                
                                                mrv->extend_active_notes();
-
                                        }
                                }
 
                        } else {
-
+                               
                                nframes_t nlen = _trackview.get_diskstream()->get_captured_frames(n);
 
                                if (nlen != region->length()) {
 
-                                       if (region->source(0)->length() >= region->start() + nlen) {
+                                       if (region->source(0)->length() >= region->position() + nlen) {
 
                                                region->freeze ();
                                                region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this);
@@ -537,9 +536,6 @@ MidiStreamView::rec_data_range_ready (jack_nframes_t start, jack_nframes_t dur,
        
        boost::shared_ptr<SMFSource> src (boost::dynamic_pointer_cast<SMFSource>(weak_src.lock()));
        
-       //cerr << src.get() << " MIDI READY: " << start << " * " << dur
-       //      << " -- " << data->size() << " events!" << endl;
-       
        this->update_rec_regions (src->model(), start, dur);
 }
 
index 9842ea006080c78b02a3614119ce0d3fd2b25c48..2a5c94dd686555b2abad38a62d1e3ca0a2f662a9 100644 (file)
@@ -101,6 +101,7 @@ class Diskstream : public SessionObject
 
        void set_speed (double);
        void non_realtime_set_speed ();
+       virtual void non_realtime_locate (nframes_t location) {};
        virtual void playlist_modified ();
 
        boost::shared_ptr<Playlist> playlist () { return _playlist; }
index 53c7a7e22cf92f0175612c4e49b0e778b914dbbe..d08f00b72fc2562b7669b7599dce31505996982e 100644 (file)
@@ -79,7 +79,6 @@ class MidiDiskstream : public Diskstream
        int use_copy_playlist ();
 
        /* stateful */
-
        XMLNode& get_state(void);
        int set_state(const XMLNode& node);
 
@@ -107,6 +106,7 @@ class MidiDiskstream : public Diskstream
        int  rename_write_sources ();
        void reset_write_sources (bool, bool force = false);
        void non_realtime_input_change ();
+       void non_realtime_locate (nframes_t location);
 
   protected:
        int seek (nframes_t which_sample, bool complete_refill = false);
index 6337ca8e652d2337614b1cbb0effa6640655fd1f..28a747683c3643bfdc04a63859edf72c7b415710 100644 (file)
@@ -69,9 +69,6 @@ public:
 
        size_t read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const;
 
-       /** Resizes vector if necessary (NOT realtime safe) */
-       void append(const MidiBuffer& data);
-       
        /** Resizes vector if necessary (NOT realtime safe) */
        void append(const MidiEvent& ev);
        
index 95d2a38c4e45ee939a1f2d0904810363a6585246..433e7ceee95c9d72edc3d05214bc46832f647ef9 100644 (file)
@@ -54,11 +54,12 @@ class MidiSource : public Source
        virtual void append_event_unlocked(const MidiEvent& ev) = 0;
 
        virtual void mark_for_remove() = 0;
-       virtual void mark_streaming_midi_write_started (NoteMode mode);
+       virtual void mark_streaming_midi_write_started (NoteMode mode, nframes_t start_time);
        virtual void mark_streaming_write_started ();
        virtual void mark_streaming_write_completed ();
        
-       void set_timeline_position (nframes_t when) { _timeline_position = when; }
+       uint64_t timeline_position ()                   { return _timeline_position; }
+       void     set_timeline_position (nframes_t when) { _timeline_position = when; }
        
        virtual void session_saved();
 
index 8709fff148575adf12aec3066f492ab88a54c50f..540ad08011c58eb3731047ea56d933859eeb8cdc 100644 (file)
@@ -1385,6 +1385,7 @@ class Session : public PBD::StatefulDestructible
        void realtime_stop (bool abort);
        void non_realtime_start_scrub ();
        void non_realtime_set_speed ();
+       void non_realtime_locate ();
        void non_realtime_stop (bool abort, int entry_request_count, bool& finished);
        void non_realtime_overwrite (int entry_request_count, bool& finished);
        void butler_transport_work ();
index 302fb15838a39c272a833efd7067dc35367b0d9a..bb3950f2eef2b96ed3f72fbf43dc0b9c090cd3a6 100644 (file)
@@ -77,6 +77,7 @@ class SMFSource : public MidiSource {
        int move_to_trash (const string trash_dir_name);
 
        bool is_empty () const;
+       void mark_streaming_midi_write_started (NoteMode mode, nframes_t start_time);
        void mark_streaming_write_completed ();
 
        void   mark_take (string);
index 54f4c1069880e09ed9482f47bb73ac01ee9e7357..2b8f70a307c6e1b6d9437e87ac1e08f4c076b3ef 100644 (file)
@@ -137,6 +137,14 @@ MidiDiskstream::~MidiDiskstream ()
        Glib::Mutex::Lock lm (state_lock);
 }
 
+       
+void
+MidiDiskstream::non_realtime_locate (nframes_t position)
+{
+       _write_source->set_timeline_position (position);
+}
+
+
 void
 MidiDiskstream::non_realtime_input_change ()
 {
@@ -1195,7 +1203,7 @@ MidiDiskstream::engage_record_enable ()
                _source_port->request_monitor_input (!(Config->get_auto_input() && rolling));
        }
 
-       _write_source->mark_streaming_midi_write_started (_note_mode);
+       _write_source->mark_streaming_midi_write_started (_note_mode, _session.transport_frame());
 
        RecordEnableChanged (); /* EMIT SIGNAL */
 }
index 7c02f5095f9060aa6a58ab31f99f65f81baccc8b..d7167ed2ecfb8e43a57463213fec9aebf16f1816 100644 (file)
@@ -450,30 +450,6 @@ MidiModel::end_write(bool delete_stuck)
 }
 
 
-/** Append contents of \a buf to model.  NOT realtime safe.
- *
- * Timestamps of events in \a buf are 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.
- *
- * Events in buf are deep copied.
- */
-void
-MidiModel::append(const MidiBuffer& buf)
-{ 
-       write_lock();
-
-       assert(_writing);
-
-       for (MidiBuffer::const_iterator i = buf.begin(); i != buf.end(); ++i) {
-               assert(_notes.empty() || (*i).time() >= _notes.back().time());
-               append(*i);
-       }
-       
-       write_unlock();
-}
-
-
 /** Append \a in_event to model.  NOT realtime safe.
  *
  * Timestamps of events in \a buf are expected to be relative to
index 4c97bb4e6d083351a29fe37f11afef476efe3a44..f072c2a7ef85ecac8cb4993fb5eaa41553b8b79e 100644 (file)
@@ -131,8 +131,10 @@ MidiSource::file_changed (string path)
 }
 
 void
-MidiSource::mark_streaming_midi_write_started (NoteMode mode)
+MidiSource::mark_streaming_midi_write_started (NoteMode mode, nframes_t start_frame)
 {
+       set_timeline_position(start_frame); // why do I have a feeling this can break somehow...
+
        if (_model) {
                _model->set_note_mode(mode);
                _model->start_write();
index c122989b68ee6875cfc18792e249b08b18ed44f9..2776fbf41dac5135ed0ee7d10bea7a6e23fa5445 100644 (file)
@@ -238,8 +238,12 @@ Session::butler_transport_work ()
                        }
                }
        }
+       
+       if (post_transport_work & PostTransportLocate) {
+               non_realtime_locate ();
+       }
 
-       if (post_transport_work & (PostTransportStop|PostTransportLocate)) {
+       if (post_transport_work & PostTransportStop) {
                non_realtime_stop (post_transport_work & PostTransportAbort, on_entry, finished);
                if (!finished) {
                        g_atomic_int_dec_and_test (&butler_should_do_transport_work);
@@ -288,6 +292,18 @@ Session::non_realtime_overwrite (int on_entry, bool& finished)
        }
 }
 
+       
+void
+Session::non_realtime_locate ()
+{
+       boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
+
+       for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
+               (*i)->non_realtime_locate (_transport_frame);
+       }
+}
+
+
 void
 Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
 {
index 4ad8f80b4bb2285f539ca3d8a38eb34c09d9b7d0..3bc53cb5382b9d07b5f3f1d101917071354f1f54 100644 (file)
@@ -159,7 +159,6 @@ SMFSource::open()
                _track_size = 4;
 
                // Write a tentative header just to pad things out so writing happens in the right spot
-               set_timeline_position(0);
                flush_header();
                write_footer();
                seek_to_end();
@@ -403,7 +402,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
 
        while (true) {
                bool ret = src.full_peek(sizeof(double), (Byte*)&time);
-               if (!ret || time > _length + cnt)
+               if (!ret || time - _timeline_position > _length + cnt)
                        break;
 
                ret = src.read_prefix(&time, &size);
@@ -423,10 +422,9 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
                
                assert(time >= _timeline_position);
                time -= _timeline_position;
-               assert(time >= _last_ev_time);
 
                const MidiEvent ev(time, size, buf);
-               append_event_unlocked(MidiEvent(ev));
+               append_event_unlocked(ev);
 
                if (_model)
                        _model->append(ev);
@@ -438,7 +436,7 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
        const nframes_t oldlen = _length;
        update_length(oldlen, cnt);
 
-       ViewDataRangeReady (oldlen, cnt); /* EMIT SIGNAL */
+       ViewDataRangeReady (_timeline_position + oldlen, cnt); /* EMIT SIGNAL */
        
        return cnt;
 }
@@ -453,6 +451,8 @@ SMFSource::append_event_unlocked(const MidiEvent& ev)
        }
        printf("\n");*/
 
+       assert(ev.time() >= 0);
+
        assert(ev.time() >= _last_ev_time);
        
        // FIXME: assumes tempo never changes after start
@@ -516,6 +516,13 @@ SMFSource::mark_for_remove ()
        _flags = Flag (_flags | RemoveAtDestroy);
 }
 
+void
+SMFSource::mark_streaming_midi_write_started (NoteMode mode, nframes_t start_frame)
+{
+       MidiSource::mark_streaming_midi_write_started (mode, start_frame);
+       _last_ev_time = 0;
+}
+
 void
 SMFSource::mark_streaming_write_completed ()
 {