track note on/off and send appropriate note offs at transport stop
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 11 Sep 2009 13:25:31 +0000 (13:25 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 11 Sep 2009 13:25:31 +0000 (13:25 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@5655 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/midi_region_view.cc
libs/ardour/ardour/midi_diskstream.h
libs/ardour/ardour/midi_state_tracker.h
libs/ardour/ardour/midi_track.h
libs/ardour/midi_diskstream.cc
libs/ardour/midi_state_tracker.cc
libs/ardour/midi_track.cc

index 6acbacc43990c6af69e6c34f86dca3fc6e37c3d8..9fdd71922ef48347c7981948b777ecc91a1bf7f4 100644 (file)
@@ -585,6 +585,7 @@ MidiRegionView::display_model(boost::shared_ptr<MidiModel> model)
        _model = model;
        content_connection.disconnect ();
        content_connection = _model->ContentsChanged.connect(sigc::mem_fun(this, &MidiRegionView::redisplay_model));
+       clear_events ();
 
        if (_enable_display) {
                redisplay_model();
index 872ffb78e3872498e46da9fbb5b3de2a251e9645..730d6c0276d40b9a1ea12493f8fe6e8e41ec92a2 100644 (file)
@@ -39,7 +39,6 @@
 #include "ardour/diskstream.h"
 #include "ardour/midi_playlist.h"
 #include "ardour/midi_ring_buffer.h"
-#include "ardour/midi_state_tracker.h"
 #include "ardour/utils.h"
 
 struct tm;
@@ -178,8 +177,6 @@ class MidiDiskstream : public Diskstream
        boost::shared_ptr<SMFSource> _write_source;
        nframes_t                    _last_flush_frame;
        NoteMode                     _note_mode;  
-       MidiStateTracker             _midi_state_tracker;
-       MidiStateTracker             _incoming_midi_state_tracker;
        volatile gint                _frames_written_to_ringbuffer;
        volatile gint                _frames_read_from_ringbuffer;
 };
index 4c15ab1e0f7940d8594b5b38d192d23a938fa8ab..f9b39f9295ea76beb67192d8a6e6eb39b04f2bdb 100644 (file)
@@ -35,7 +35,7 @@ class MidiStateTracker
 public:
        MidiStateTracker();
 
-       bool track (const MidiBuffer::iterator& from, const MidiBuffer::iterator& to);
+       void track (const MidiBuffer::iterator& from, const MidiBuffer::iterator& to, bool& looped);
        void resolve_notes (MidiBuffer& buffer, nframes_t time);
        void dump (std::ostream&);
        void reset ();
@@ -43,7 +43,7 @@ public:
 private:
        void track_note_onoffs(const Evoral::MIDIEvent<MidiBuffer::TimeType>& event);
 
-       std::bitset<128*16> _active_notes;
+       uint8_t _active_notes[128*16];
 };
 
 
index 0030fdc52049bd138f7856861ed1f17f31460e49..a1b0d2003e8a7b05d32a3b9591775054c17adff0 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "ardour/track.h"
 #include "ardour/midi_ring_buffer.h"
+#include "ardour/midi_state_tracker.h"
 
 namespace ARDOUR
 {
@@ -41,6 +42,8 @@ public:
        int roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, 
                  int declick, bool can_record, bool rec_monitors_input);
        
+       void handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
+
        boost::shared_ptr<MidiDiskstream> midi_diskstream() const;
 
        int use_diskstream (string name);
@@ -96,6 +99,8 @@ private:
        void set_state_part_two ();
        void set_state_part_three ();
 
+       MidiStateTracker _midi_state_tracker;
+
        MidiRingBuffer<nframes_t> _immediate_events;
        MidiRingBuffer<nframes_t> _step_edit_ring_buffer;
        NoteMode                  _note_mode;
index 3d4b188a8bca57dfca8b1b0a2eee40e429045664..b486a0fce060dfbbcc19635b20e82a78cdd98be9 100644 (file)
@@ -1648,9 +1648,6 @@ MidiDiskstream::get_playback (MidiBuffer& dst, nframes_t start, nframes_t end)
                return;
        }
 
-       // Check only events added this offset cycle
-       MidiBuffer::iterator this_cycle_start = dst.end();
-       
        // Translates stamps to be relative to start
 
        _playback_buf->read(dst, start, end);
@@ -1664,11 +1661,5 @@ MidiDiskstream::get_playback (MidiBuffer& dst, nframes_t start, nframes_t end)
        
        gint32 frames_read = end - start;
        g_atomic_int_add(&_frames_read_from_ringbuffer, frames_read);
-       
-       // Feed the data through the MidiStateTracker
-       // If it detects a LoopEvent it will add necessary note offs
-       if (_midi_state_tracker.track(this_cycle_start, dst.end())) {
-               _midi_state_tracker.resolve_notes(dst, end-start - 1);
-       }
 }
 
index 66d356f9a6c54acd3e2baee0c1ae2c34ac21144c..e25dbdd0942f84f73997d9ca1beb6b04e871eb73 100644 (file)
@@ -27,59 +27,55 @@ using namespace ARDOUR;
 
 MidiStateTracker::MidiStateTracker ()
 {
-       _active_notes.reset();
+       reset ();
 }
 
 void
 MidiStateTracker::reset ()
 {
-       _active_notes.reset ();
+       memset (_active_notes, 0, sizeof (_active_notes));
 }
 
 void
 MidiStateTracker::track_note_onoffs (const Evoral::MIDIEvent<MidiBuffer::TimeType>& event)
 {
        if (event.is_note_on()) {
-               _active_notes [event.note() + 128 * event.channel()] = true;
+               _active_notes [event.note() + 128 * event.channel()]++;
        } else if (event.is_note_off()){
-               _active_notes [event.note() + 128 * event.channel()] = false;
+               if (_active_notes[event.note() + 128 * event.channel()]) {
+                       _active_notes [event.note() + 128 * event.channel()]--;
+               }
        }
 }
 
-bool
-MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::iterator &to)
+void
+MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::iterator &to, bool& looped)
 {
-       bool ret = false;
+       looped = false;
 
        for (MidiBuffer::iterator i = from; i != to; ++i) {
                const Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
                if (ev.event_type() == LoopEventType) {
-                       ret = true;
+                       looped = true;
                        continue;
                }
 
                track_note_onoffs (ev);
        }
-       return ret;
 }
 
 void
 MidiStateTracker::resolve_notes (MidiBuffer &dst, nframes_t time)
 {
-       // Dunno if this is actually faster but at least it fills our cacheline.
-       if (_active_notes.none ())
-               return;
-
        for (int channel = 0; channel < 16; ++channel) {
                for (int note = 0; note < 128; ++note) {
-                       if (_active_notes[channel * 128 + note]) {
+                       while (_active_notes[channel * 128 + note]) {
                                uint8_t buffer[3] = { MIDI_CMD_NOTE_OFF | channel, note, 0 };
                                Evoral::MIDIEvent<MidiBuffer::TimeType> noteoff
-                                               (time, MIDI_CMD_NOTE_OFF, 3, buffer, false);
-
+                                       (time, MIDI_CMD_NOTE_OFF, 3, buffer, false);
+                               
                                dst.push_back (noteoff);        
-
-                               _active_notes [channel * 128 + note] = false;
+                               _active_notes[channel * 128 + note]--;
                        }
                }
        }
@@ -92,7 +88,8 @@ MidiStateTracker::dump (ostream& o)
        for (int c = 0; c < 16; ++c) {
                for (int x = 0; x < 128; ++x) {
                        if (_active_notes[c * 128 + x]) {
-                               o << "Channel " << c+1 << " Note " << x << " is on\n";
+                               o << "Channel " << c+1 << " Note " << x << " is on ("
+                                 << (int) _active_notes[c*128+x] <<  "times)\n";
                        }
                }
        }
index 876187656c7ba63bcaab2c9fba6e72f4a02e7120..7324196512f7046eabba1b59576d9f87202176bb 100644 (file)
@@ -441,15 +441,27 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
 
                //const size_t limit = n_process_buffers().n_audio();
                BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+               MidiBuffer& mbuf (bufs.get_midi (0));
                
-               diskstream->get_playback (bufs.get_midi(0), start_frame, end_frame);
+               diskstream->get_playback (mbuf, start_frame, end_frame);
 
                /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
 
                write_out_of_band_data (bufs, start_frame, end_frame, nframes); 
 
+               // Feed the data through the MidiStateTracker
+               bool did_loop;
+
+               _midi_state_tracker.track (mbuf.begin(), mbuf.end(), did_loop);
+
+               if (did_loop) {
+                       /* add necessary note offs */
+                       _midi_state_tracker.resolve_notes (mbuf, end_frame-start_frame - 1);
+               }
+
                process_output_buffers (bufs, start_frame, end_frame, nframes,
                                (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick);
+
        }
 
        _main_outs->flush (nframes);
@@ -470,6 +482,23 @@ MidiTrack::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_fram
        return ret;
 }
 
+void 
+MidiTrack::handle_transport_stopped (bool abort, bool did_locate, bool flush_processors)
+{
+       /* turn off any notes that are on */
+
+       MidiBuffer buf (1024); // XXX is this a reasonable size ? 
+       
+       _midi_state_tracker.resolve_notes (buf, 0); // time is zero because notes are immediate
+
+       for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
+               write_immediate_event ((*i).size(), (*i).buffer());
+       }
+
+       Route::handle_transport_stopped (abort, did_locate, flush_processors);
+}
+       
+
 void
 MidiTrack::push_midi_input_to_step_edit_ringbuffer (nframes_t nframes)
 {