tentative redesign of MIDI looping, will probably fix #5050 but needs more extensive...
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 8 Jan 2013 21:36:42 +0000 (21:36 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 8 Jan 2013 21:36:42 +0000 (21:36 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@13810 d708f5d6-7413-0410-9779-e7cbd77b26cf

14 files changed:
gtk2_ardour/lxvst_plugin_ui.cc
gtk2_ardour/mixer_strip.cc
gtk2_ardour/vst_plugin_ui.cc
libs/ardour/ardour/event_type_map.h
libs/ardour/ardour/midi_ring_buffer.h
libs/ardour/ardour/midi_state_tracker.h
libs/ardour/automation_list.cc
libs/ardour/lv2_plugin.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_port.cc
libs/ardour/midi_ring_buffer.cc
libs/ardour/midi_state_tracker.cc
libs/ardour/midi_track.cc
libs/ardour/plugin.cc

index 5d86f428c2fc823b88b7ef4bd527e9e6ab12b97b..d31038755b54b1116b10ebdc9a66b9e17e5f17f5 100644 (file)
@@ -46,7 +46,7 @@ LXVSTPluginUI::~LXVSTPluginUI ()
 
 
 bool
-LXVSTPluginUI::start_updating (GdkEventAny* ignored)
+LXVSTPluginUI::start_updating (GdkEventAny*)
 {
        _screen_update_connection.disconnect();
        _screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect (mem_fun(*this, &LXVSTPluginUI::resize_callback));
@@ -54,7 +54,7 @@ LXVSTPluginUI::start_updating (GdkEventAny* ignored)
 }
 
 bool
-LXVSTPluginUI::stop_updating (GdkEventAny* ignored)
+LXVSTPluginUI::stop_updating (GdkEventAny*)
 {
        _screen_update_connection.disconnect();
        return false;
@@ -116,7 +116,7 @@ LXVSTPluginUI::package (Gtk::Window& win)
 }
 
 void
-LXVSTPluginUI::forward_key_event (GdkEventKey* ev)
+LXVSTPluginUI::forward_key_event (GdkEventKey*)
 {
        std::cerr << "LXVSTPluginUI : keypress forwarding to linuxVSTs unsupported" << std::endl;
 }
@@ -163,7 +163,7 @@ static error_handler_t vstfx_error_handler;
 static error_handler_t gtk_error_handler;
 
 static int 
-gtk_xerror_handler (Display* disp, XErrorEvent* ev)
+gtk_xerror_handler (Display*, XErrorEvent*)
 {
        std::cerr << "** ERROR ** LXVSTPluginUI : Trapped an X Window System Error" << std::endl;
        
index e686be80b7684a63f87825512843750e6272e491..68c27f9ca9912ec6e5f92f72f6c9487033dddf3d 100644 (file)
@@ -941,7 +941,7 @@ MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
 }
 
 void
-MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const & current)
+MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
 {
        using namespace Menu_Helpers;
 
@@ -969,7 +969,7 @@ MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR:
 }
 
 void
-MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const & current)
+MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
 {
        using namespace Menu_Helpers;
 
index 303fb8b8dd956358c9d236cc1a9c8ee966a6449a..6c308138218d5262b0b9c8d10887ff2c2ece940f 100644 (file)
@@ -79,7 +79,7 @@ VSTPluginUI::package (Gtk::Window& win)
 }
 
 bool
-VSTPluginUI::configure_handler (GdkEventConfigure* ev)
+VSTPluginUI::configure_handler (GdkEventConfigure*)
 {
        XEvent event;
        gint x, y;
index 5068029db71eb3c185b5faac059047a90f794bb9..02852e9711f627e22d97f7f9742b284af9cbf79d 100644 (file)
@@ -50,10 +50,6 @@ private:
        static EventTypeMap event_type_map;
 };
 
-enum InternalEventType {
-       LoopEventType = 1000
-};
-
 } // namespace ARDOUR
 
 #endif /* __ardour_event_type_map_h__ */
index f4580b37a6fddaf23c46e1ce67c9b19461434027..7f5774054a33797fc6a640b063496a04ca214aec 100644 (file)
@@ -79,7 +79,8 @@ public:
        }
 
        void reset_tracker ();
-       
+        void loop_resolve (MidiBuffer& dst, framepos_t);
+
 protected:
        inline bool is_channel_event(uint8_t event_type_byte) {
                // mask out channel information
index 64e4aace2d2f66f4d5e82721964582aec52b79ef..24d3ab73a192614a27b9f1623e4dbc323f57a24e 100644 (file)
@@ -37,7 +37,7 @@ class MidiStateTracker
 public:
        MidiStateTracker();
 
-       void track (const MidiBuffer::iterator& from, const MidiBuffer::iterator& to, bool& looped);
+       void track (const MidiBuffer::iterator& from, const MidiBuffer::iterator& to);
        void add (uint8_t note, uint8_t chn);
        void remove (uint8_t note, uint8_t chn);
        void resolve_notes (MidiBuffer& buffer, framepos_t time);
index 00d9f624ed184f36d0493f6ad38e9d7474ffb98f..83df92488b02087b3adf6357992ffe57da0224de 100644 (file)
@@ -204,7 +204,7 @@ AutomationList::start_touch (double when)
 }
 
 void
-AutomationList::stop_touch (bool mark, double when)
+AutomationList::stop_touch (bool mark, double)
 {
        if (g_atomic_int_get (&_touching) == 0) {
                /* this touch has already been stopped (probably by Automatable::transport_stopped),
index 3c557b7d2fa016d95a94eea9dd6e2eabd7b4a606..85605d346a0ea3e026786afa528f6f1309baea37 100644 (file)
@@ -175,7 +175,7 @@ work_respond(LV2_Worker_Respond_Handle handle,
 /* log extension */
 
 static int
-log_vprintf(LV2_Log_Handle handle,
+log_vprintf(LV2_Log_Handle /*handle*/,
             LV2_URID       type,
             const char*    fmt,
             va_list        args)
index ede50370def12820e9628fea011a5311bd6d93e9..c151b776c2fd34fdb1ec5f380bab5a75e732be45 100644 (file)
@@ -613,7 +613,7 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed)
                                        id(), this_read, start) << endmsg;
                        return -1;
                }
-
+               
                g_atomic_int_add (&_frames_written_to_ringbuffer, this_read);
 
                if (reversed) {
@@ -625,11 +625,9 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed)
                } else {
 
                        /* if we read to the end of the loop, go back to the beginning */
-
                        if (reloop) {
                                // Synthesize LoopEvent here, because the next events
                                // written will have non-monotonic timestamps.
-                               _playback_buf->write(loop_end - 1, LoopEventType, sizeof (framepos_t), (uint8_t *) &loop_start);
                                start = loop_start;
                        } else {
                                start += this_read;
@@ -1297,23 +1295,77 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes)
        dst.clear();
        assert(dst.size() == 0);
 
-#ifndef NDEBUG
+       Location* loc = loop_location;
+
        DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose (
-                            "%1 MDS pre-read read %4..%5 from %2 write to %3\n", _name,
-                            _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr(), playback_sample, playback_sample + nframes));
-//        cerr << "================\n";
-//        _playback_buf->dump (cerr);
-//        cerr << "----------------\n";
+                            "%1 MDS pre-read read %8 @ %4..%5 from %2 write to %3, LOOPED ? %6-%7\n", _name,
+                            _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr(), playback_sample, playback_sample + nframes, 
+                            (loc ? loc->start() : -1), (loc ? loc->end() : -1), nframes));
+
+        // cerr << "================\n";
+        // _playback_buf->dump (cerr);
+        // cerr << "----------------\n";
+
+       size_t events_read = 0; 
+
+       if (loc) {
+               framepos_t effective_start;
+
+               if (playback_sample >= loc->end()) {
+                       effective_start = loc->start() + ((playback_sample - loc->end()) % loc->length());
+               } else {
+                       effective_start = playback_sample;
+               }
+               
+               DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("looped, effective start adjusted to %1\n", effective_start));
+
+               if (effective_start == loc->start()) {
+                       /* We need to turn off notes that may extend
+                          beyond the loop end.
+                       */
+
+                       _playback_buf->loop_resolve (dst, 0);
+               }
+
+               if (loc->end() >= effective_start && loc->end() < effective_start + nframes) {
+                       /* end of loop is within the range we are reading, so
+                          split the read in two, and lie about the location
+                          for the 2nd read
+                       */
+                       framecnt_t first, second;
+
+                       first = loc->end() - effective_start;
+                       second = nframes - first;
+
+                       DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read for eff %1 end %2: %3 and %4\n",
+                                                                             effective_start, loc->end(), first, second));
+
+                       if (first) {
+                               DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read #1, from %1 for %2\n",
+                                                                                     effective_start, first));
+                               events_read = _playback_buf->read (dst, effective_start, first);
+                       } 
+
+                       if (second) {
+                               DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read #2, from %1 for %2\n",
+                                                                                     loc->start(), second));
+                               events_read += _playback_buf->read (dst, loc->start(), second);
+                       }
+                                                                   
+               } else {
+                       DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read #3, adjusted start as %1 for %2\n",
+                                                                             effective_start, nframes));
+                       events_read = _playback_buf->read (dst, effective_start, effective_start + nframes);
+               }
+       } else {
+               events_read = _playback_buf->read (dst, playback_sample, playback_sample + nframes);
+       }
 
-       const size_t events_read = _playback_buf->read (dst, playback_sample, playback_sample + nframes);
        DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose (
                             "%1 MDS events read %2 range %3 .. %4 rspace %5 wspace %6 r@%7 w@%8\n",
                             _name, events_read, playback_sample, playback_sample + nframes,
                             _playback_buf->read_space(), _playback_buf->write_space(),
                             _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr()));
-#else
-       _playback_buf->read (dst, playback_sample, playback_sample + nframes);
-#endif
 
        g_atomic_int_add (&_frames_read_from_ringbuffer, nframes);
 }
index 63004f658b975c7f7f13311fbb8a0a47ec05f435..0856666159c9f2e381799a40bc432159704a88c0 100644 (file)
@@ -170,11 +170,6 @@ MidiPort::flush_buffers (pframes_t nframes)
 
                        assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_offset));
 
-                       if (ev.event_type() == LoopEventType) {
-                               resolve_notes (jack_buffer, ev.time());
-                               continue;
-                       }
-
                        if (ev.time() >= _global_port_buffer_offset + _port_buffer_offset) {
                                if (jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size()) != 0) {
                                        cerr << "write failed, drop flushed note off on the floor, time "
index 786ed3c080d33fb1f7b7748076896bf4a6ec7042..0f08247cb94837f8457f931c9ec7ff1e950790e5 100644 (file)
@@ -45,93 +45,42 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
        T                 ev_time;
        Evoral::EventType ev_type;
        uint32_t          ev_size;
-
-       /* If we see the end of a loop during this read, we must write the events after it
-          to the MidiBuffer with adjusted times.  The situation is as follows:
-
-          session frames----------------------------->
-
-                    |                            |                    |
-               start_of_loop                   start              end_of_loop
-
-          The MidiDiskstream::read method which will have happened before this checks for
-          loops ending, and helpfully inserts a magic LoopEvent into the ringbuffer.  After this,
-          the MidiDiskstream continues to write events with their proper session frame times,
-          so after the LoopEvent event times will go backwards (ie non-monotonically).
-
-          Once we hit end_of_loop, we need to fake it to make it look as though the loop has been
-          immediately repeated.  Say that an event E after the end_of_loop in the ringbuffer
-          has time E_t, which is a time in session frames.  Its offset from the start
-          of the loop will be E_t - start_of_loop.  Its `faked' time will therefore be
-          end_of_loop + E_t - start_of_loop.  And so its port-buffer-relative time (for
-          writing to the MidiBuffer) will be end_of_loop + E_t - start_of_loop - start.
-
-          The subtraction of start is already taken care of, so if we see a LoopEvent, we'll
-          set up loop_offset to equal end_of_loop - start_of_loop, so that given an event
-          time E_t in the ringbuffer we can get the port-buffer-relative time as
-          E_t + offset - start.
-       */
-
-       frameoffset_t loop_offset = 0;
-
-       size_t count = 0;
-
-       const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);
+       size_t            count = 0;
+       const size_t      prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);
 
        while (this->read_space() >= prefix_size) {
 
                uint8_t peekbuf[prefix_size];
-               bool success;
 
-               success = this->peek (peekbuf, prefix_size);
                /* this cannot fail, because we've already verified that there
                   is prefix_space to read
                */
-               assert (success);
+               assert (this->peek (peekbuf, prefix_size));
 
                ev_time = *((T*) peekbuf);
                ev_type = *((Evoral::EventType*)(peekbuf + sizeof (T)));
                ev_size = *((uint32_t*)(peekbuf + sizeof(T) + sizeof (Evoral::EventType)));
 
-               if (ev_time + loop_offset >= end) {
+               if (ev_time >= end) {
                        DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 past end @ %2\n", ev_time, end));
                        break;
-               } else if (ev_time + loop_offset < start) {
+               } else if (ev_time < start) {
                        DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 before start @ %2\n", ev_time, start));
-                       this->increment_read_ptr (prefix_size);
-                       this->increment_read_ptr (ev_size);
-                       continue;
+                       break;
                } else {
                        DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 in range %2 .. %3\n", ev_time, start, end));
                }
 
-               assert(ev_time >= start);
-
                ev_time -= start;
                ev_time += offset;
 
-               // This event marks a loop end (i.e. the next event's timestamp
-               // will be non-monotonic). Don't write it into the buffer - the
-               // significance of this event ends here.
-               
-               if (ev_type == LoopEventType) {
-                       assert (ev_size == sizeof (framepos_t));
-                       framepos_t loop_start;
-                       read_contents (ev_size, (uint8_t *) &loop_start);
-                       loop_offset = ev_time - loop_start;
-                       _tracker.resolve_notes (dst, ev_time);
-                       continue;
-               }
-
                /* we're good to go ahead and read the data now but since we
                 * have the prefix data already, just skip over that
                 */
                this->increment_read_ptr (prefix_size);
-               ev_time += loop_offset;
 
                uint8_t status;
-               success = this->peek (&status, sizeof(uint8_t));
-               assert(success); // If this failed, buffer is corrupt, all hope is lost
+               assert (this->peek (&status, sizeof(uint8_t))); // If this failed, buffer is corrupt, all hope is lost
 
                // Ignore event if it doesn't match channel filter
                if (is_channel_event(status) && get_channel_mode() == FilterChannels) {
@@ -158,7 +107,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
                }
 
                // write MIDI buffer contents
-               success = read_contents (ev_size, write_loc);
+               bool success = read_contents (ev_size, write_loc);
 
 #ifndef NDEBUG
                if (DEBUG::MidiDiskstreamIO && PBD::debug_bits) {
@@ -197,7 +146,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
 
 template<typename T>
 void
-MidiRingBuffer<T>::flush (framepos_t start, framepos_t end)
+MidiRingBuffer<T>::flush (framepos_t /*start*/, framepos_t end)
 {
        const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t);
 
@@ -310,6 +259,13 @@ MidiRingBuffer<T>::reset_tracker ()
        _tracker.reset ();
 }
 
+template<typename T>
+void
+MidiRingBuffer<T>::loop_resolve (MidiBuffer& dst, framepos_t t)
+{
+       _tracker.resolve_notes (dst, t);
+}
+
 template class MidiRingBuffer<framepos_t>;
 
 }  // namespace ARDOUR
index 99a6cd991ddf624133df12f215b696460d945e5a..73b6fb639e1ea0e1db4823fcdc92449e5863ea44 100644 (file)
@@ -94,18 +94,12 @@ MidiStateTracker::remove (uint8_t note, uint8_t chn)
 }
 
 void
-MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::iterator &to, bool& looped)
+MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::iterator &to)
 {
-       looped = false;
-
-       // DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 track notes, looped = %2\n", this, looped));
+       // DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 track notes\n", this));
 
        for (MidiBuffer::iterator i = from; i != to; ++i) {
                const Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
-               if (ev.event_type() == LoopEventType) {
-                       looped = true;
-                       continue;
-               }
 
                /* catch AllNotesOff message and turn off all notes
                 */
index 7f2bb641e18dc25e6a403ceb26c7816d59588a88..525db3ab96b9c7f14b0505cb05d1ad39a0836b10 100644 (file)
@@ -360,6 +360,8 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
                c.set_midi (1);
                bufs.set_count (c);
 
+               assert (nframes > 0);
+
                diskstream->get_playback (mbuf, nframes);
 
                /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
index 9f39e067874cba9e119018395952ff2e31a30212..57198475d72f9ad81d355924e91a19da7acd4ea5 100644 (file)
@@ -256,9 +256,8 @@ Plugin::connect_and_run (BufferSet& bufs,
                /* Track notes that we are sending to the plugin */
 
                MidiBuffer& b = bufs.get_midi (0);
-               bool looped;
 
-               _tracker.track (b.begin(), b.end(), looped);
+               _tracker.track (b.begin(), b.end());
 
                if (_have_pending_stop_events) {
                        /* Transmit note-offs that are pending from the last transport stop */
@@ -339,7 +338,7 @@ Plugin::clear_preset ()
 
 /** @param val `plugin' value */
 void
-Plugin::set_parameter (uint32_t which, float val)
+Plugin::set_parameter (uint32_t which, float)
 {
        _parameter_changed_since_last_preset = true;
        _session.set_dirty ();