From 539a692b0e9d249cab75a2d1c255f8cbef8bcf6b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 19 Oct 2009 17:05:22 +0000 Subject: track notes at the region level in MidiPlaylist; resolve them (deliver note offs) if a note spans the end of the region git-svn-id: svn://localhost/ardour2/branches/3.0@5804 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/midi_playlist.h | 5 +++++ libs/ardour/ardour/midi_region.h | 19 ++++++++++------- libs/ardour/ardour/midi_source.h | 15 +++++++------ libs/ardour/ardour/midi_state_tracker.h | 5 ++++- libs/ardour/ardour/midi_track.h | 5 ++--- libs/ardour/ardour/smf_source.h | 13 +++++------ libs/ardour/midi_playlist.cc | 38 +++++++++++++++++++++++++++++---- libs/ardour/midi_region.cc | 14 ++++++------ libs/ardour/midi_source.cc | 16 +++++++++++--- libs/ardour/midi_state_tracker.cc | 33 ++++++++++++++++++++++++++++ libs/ardour/smf_source.cc | 17 +++++++++++---- 11 files changed, 139 insertions(+), 41 deletions(-) diff --git a/libs/ardour/ardour/midi_playlist.h b/libs/ardour/ardour/midi_playlist.h index c83bf80a28..6d617ad0f0 100644 --- a/libs/ardour/ardour/midi_playlist.h +++ b/libs/ardour/ardour/midi_playlist.h @@ -25,6 +25,7 @@ #include "ardour/ardour.h" #include "ardour/playlist.h" +#include "ardour/midi_state_tracker.h" #include "evoral/Parameter.hpp" namespace ARDOUR @@ -74,6 +75,10 @@ private: bool region_changed (Change, boost::shared_ptr); NoteMode _note_mode; + + typedef std::map NoteTrackers; + NoteTrackers _note_trackers; + }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index c796ee742b..f8f663bc78 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -42,6 +42,7 @@ class Playlist; class Session; class MidiFilter; class MidiSource; +class MidiStateTracker; template class MidiRingBuffer; class MidiRegion : public Region @@ -56,10 +57,11 @@ class MidiRegion : public Region virtual sframes_t readable_length() const { return length(); } nframes_t read_at (MidiRingBuffer& dst, - sframes_t position, - nframes_t dur, - uint32_t chan_n = 0, - NoteMode mode = Sustained) const; + sframes_t position, + nframes_t dur, + uint32_t chan_n = 0, + NoteMode mode = Sustained, + MidiStateTracker* tracker = 0) const; nframes_t master_read_at (MidiRingBuffer& dst, sframes_t position, @@ -104,10 +106,11 @@ class MidiRegion : public Region private: nframes_t _read_at (const SourceList&, MidiRingBuffer& dst, - nframes_t position, - nframes_t dur, - uint32_t chan_n = 0, - NoteMode mode = Sustained) const; + sframes_t position, + nframes_t dur, + uint32_t chan_n = 0, + NoteMode mode = Sustained, + MidiStateTracker* tracker = 0) const; void recompute_at_start (); void recompute_at_end (); diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index bffcde5192..5298ab2f4f 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -34,6 +34,7 @@ namespace ARDOUR { +class MidiStateTracker; class MidiModel; template class MidiRingBuffer; @@ -55,11 +56,12 @@ class MidiSource : virtual public Source * \param cnt Length of range to be read (in audio frames) * \param stamp_offset Offset to add to event times written to dst * \param negative_stamp_offset Offset to subtract from event times written to dst + * \param tracker an optional pointer to MidiStateTracker object, for note on/off tracking */ virtual nframes_t midi_read (MidiRingBuffer& dst, - sframes_t source_start, - sframes_t start, nframes_t cnt, - sframes_t stamp_offset, sframes_t negative_stamp_offset) const; + sframes_t source_start, + sframes_t start, nframes_t cnt, + sframes_t stamp_offset, sframes_t negative_stamp_offset, MidiStateTracker*) const; virtual nframes_t midi_write (MidiRingBuffer& src, sframes_t source_start, @@ -113,9 +115,10 @@ class MidiSource : virtual public Source virtual void flush_midi() = 0; virtual nframes_t read_unlocked (MidiRingBuffer& dst, - sframes_t position, - sframes_t start, nframes_t cnt, - sframes_t stamp_offset, sframes_t negative_stamp_offset) const = 0; + sframes_t position, + sframes_t start, nframes_t cnt, + sframes_t stamp_offset, sframes_t negative_stamp_offset, + MidiStateTracker* tracker) const = 0; virtual nframes_t write_unlocked (MidiRingBuffer& dst, sframes_t position, diff --git a/libs/ardour/ardour/midi_state_tracker.h b/libs/ardour/ardour/midi_state_tracker.h index a058121da8..7b95772cac 100644 --- a/libs/ardour/ardour/midi_state_tracker.h +++ b/libs/ardour/ardour/midi_state_tracker.h @@ -21,11 +21,11 @@ #define __ardour_midi_state_tracker_h__ #include - #include "ardour/midi_buffer.h" namespace ARDOUR { +template class MidiRingBuffer; /** Tracks played notes, so they can be resolved in potential stuck note * situations (e.g. looping, transport stop, etc). @@ -36,7 +36,10 @@ public: MidiStateTracker(); void track (const MidiBuffer::iterator& from, const MidiBuffer::iterator& to, bool& looped); + void add (uint8_t note, uint8_t chn); + void remove (uint8_t note, uint8_t chn); void resolve_notes (MidiBuffer& buffer, nframes64_t time); + void resolve_notes (MidiRingBuffer& buffer, nframes64_t time); void dump (std::ostream&); void reset (); diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index c273395a74..bc636eea83 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -22,6 +22,7 @@ #include "ardour/track.h" #include "ardour/midi_ring_buffer.h" +#include "ardour/midi_state_tracker.h" namespace ARDOUR { @@ -96,8 +97,7 @@ protected: int _set_state (const XMLNode&, int, bool call_base); private: - void write_out_of_band_data ( - BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); + void write_out_of_band_data (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); int set_diskstream (boost::shared_ptr ds); void use_new_diskstream (); @@ -111,7 +111,6 @@ private: uint8_t _default_channel; bool _midi_thru; - int no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, bool state_changing, bool can_record, bool rec_monitors_input); void push_midi_input_to_step_edit_ringbuffer (nframes_t nframes); diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h index fbaa049d8a..7793b6a91c 100644 --- a/libs/ardour/ardour/smf_source.h +++ b/libs/ardour/ardour/smf_source.h @@ -71,12 +71,13 @@ public: private: nframes_t read_unlocked (MidiRingBuffer& dst, - sframes_t position, - sframes_t start, - nframes_t cnt, - sframes_t stamp_offset, - sframes_t negative_stamp_offset) const; - + sframes_t position, + sframes_t start, + nframes_t cnt, + sframes_t stamp_offset, + sframes_t negative_stamp_offset, + MidiStateTracker* tracker) const; + nframes_t write_unlocked (MidiRingBuffer& src, sframes_t position, nframes_t cnt); diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc index 8d030b949e..991e709651 100644 --- a/libs/ardour/midi_playlist.cc +++ b/libs/ardour/midi_playlist.cc @@ -142,6 +142,16 @@ MidiPlaylist::read (MidiRingBuffer& dst, nframes_t start, nframes_t d for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { if ((*i)->coverage (start, end) != OverlapNone) { regs.push_back(*i); + } else { + /* region does not cover the current read boundaries, so make + sure that we silence any notes that it had turned on + */ + NoteTrackers::iterator t = _note_trackers.find ((*i).get()); + if (t != _note_trackers.end()) { + t->second->resolve_notes (dst, (*i)->last_frame()); + delete t->second; + _note_trackers.erase (t); + } } } @@ -151,7 +161,20 @@ MidiPlaylist::read (MidiRingBuffer& dst, nframes_t start, nframes_t d for (vector >::iterator i = regs.begin(); i != regs.end(); ++i) { boost::shared_ptr mr = boost::dynamic_pointer_cast(*i); if (mr) { - mr->read_at (dst, start, dur, chan_n, _note_mode); + + NoteTrackers::iterator t = _note_trackers.find ((*i).get()); + MidiStateTracker* tracker; + + if (t == _note_trackers.end()) { + pair newpair; + newpair.first = (*i).get(); + tracker = newpair.second = new MidiStateTracker; + _note_trackers.insert (newpair); + } else { + tracker = t->second; + } + + mr->read_at (dst, start, dur, chan_n, _note_mode, tracker); _read_data_count += mr->read_data_count(); } } @@ -159,11 +182,18 @@ MidiPlaylist::read (MidiRingBuffer& dst, nframes_t start, nframes_t d return dur; } - void -MidiPlaylist::remove_dependents (boost::shared_ptr /*region*/) +MidiPlaylist::remove_dependents (boost::shared_ptr region) { - /* MIDI regions have no dependents (crossfades) */ + /* MIDI regions have no dependents (crossfades) but we might be tracking notes */ + NoteTrackers::iterator t = _note_trackers.find (region.get()); + + /* GACK! THREAD SAFETY! */ + + if (t != _note_trackers.end()) { + delete t->second; + _note_trackers.erase (t); + } } diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index 3ced46df9f..afa1c0f8cc 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -130,19 +130,20 @@ MidiRegion::set_position_internal (nframes_t pos, bool allow_bbt_recompute) } nframes_t -MidiRegion::read_at (MidiRingBuffer& out, sframes_t position, nframes_t dur, uint32_t chan_n, NoteMode mode) const +MidiRegion::read_at (MidiRingBuffer& out, sframes_t position, nframes_t dur, uint32_t chan_n, NoteMode mode, MidiStateTracker* tracker) const { - return _read_at (_sources, out, position, dur, chan_n, mode); + return _read_at (_sources, out, position, dur, chan_n, mode, tracker); } nframes_t MidiRegion::master_read_at (MidiRingBuffer& out, sframes_t position, nframes_t dur, uint32_t chan_n, NoteMode mode) const { - return _read_at (_master_sources, out, position, dur, chan_n, mode); + return _read_at (_master_sources, out, position, dur, chan_n, mode); /* no tracker */ } nframes_t -MidiRegion::_read_at (const SourceList& /*srcs*/, MidiRingBuffer& dst, nframes_t position, nframes_t dur, uint32_t chan_n, NoteMode mode) const +MidiRegion::_read_at (const SourceList& /*srcs*/, MidiRingBuffer& dst, sframes_t position, nframes_t dur, uint32_t chan_n, + NoteMode mode, MidiStateTracker* tracker) const { nframes_t internal_offset = 0; nframes_t src_offset = 0; @@ -207,8 +208,9 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, MidiRingBuffer& dst _start + internal_offset, // where to start reading in the source to_read, // read duration in frames output_buffer_position, // the offset in the output buffer - negative_output_buffer_position // amount to substract from note times - ) != to_read) { + negative_output_buffer_position, // amount to substract from note times + tracker + ) != to_read) { return 0; /* "read nothing" */ } diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 53b1d2c9a5..20119e20b6 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -35,6 +35,7 @@ #include "ardour/audioengine.h" #include "ardour/midi_model.h" #include "ardour/midi_ring_buffer.h" +#include "ardour/midi_state_tracker.h" #include "ardour/midi_source.h" #include "ardour/session.h" #include "ardour/session_directory.h" @@ -126,8 +127,9 @@ MidiSource::invalidate () nframes_t MidiSource::midi_read (MidiRingBuffer& dst, sframes_t source_start, - sframes_t start, nframes_t cnt, - sframes_t stamp_offset, sframes_t negative_stamp_offset) const + sframes_t start, nframes_t cnt, + sframes_t stamp_offset, sframes_t negative_stamp_offset, + MidiStateTracker* tracker) const { Glib::Mutex::Lock lm (_lock); @@ -152,13 +154,21 @@ MidiSource::midi_read (MidiRingBuffer& dst, sframes_t source_start, const sframes_t time_frames = BEATS_TO_FRAMES(i->time()); if (time_frames < source_start + start + cnt) { dst.write(time_frames, i->event_type(), i->size(), i->buffer()); + if (tracker) { + Evoral::MIDIEvent& ev (*(Evoral::MIDIEvent*) (&(*i))); + if (ev.is_note_on()) { + tracker->add (ev.note(), ev.channel()); + } else if (ev.is_note_off()) { + tracker->remove (ev.note(), ev.channel()); + } + } } else { break; } } return cnt; } else { - return read_unlocked (dst, source_start, start, cnt, stamp_offset, negative_stamp_offset); + return read_unlocked (dst, source_start, start, cnt, stamp_offset, negative_stamp_offset, tracker); } } diff --git a/libs/ardour/midi_state_tracker.cc b/libs/ardour/midi_state_tracker.cc index 8d58969d57..e3c66e4df8 100644 --- a/libs/ardour/midi_state_tracker.cc +++ b/libs/ardour/midi_state_tracker.cc @@ -19,6 +19,7 @@ #include #include "ardour/event_type_map.h" +#include "ardour/midi_ring_buffer.h" #include "ardour/midi_state_tracker.h" using namespace std; @@ -47,6 +48,21 @@ MidiStateTracker::track_note_onoffs (const Evoral::MIDIEvent &dst, nframes64_t time) +{ + uint8_t buf[3]; + for (int channel = 0; channel < 16; ++channel) { + for (int note = 0; note < 128; ++note) { + while (_active_notes[channel * 128 + note]) { + buf[0] = MIDI_CMD_NOTE_OFF|channel; + buf[1] = note; + buf[2] = 0; + dst.write (time, EventTypeMap::instance().midi_event_type (buf[0]), 3, buf); + _active_notes[channel * 128 + note]--; + } + } + } +} + void MidiStateTracker::dump (ostream& o) { diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index eb8d844949..169fcaf619 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -39,6 +39,7 @@ #include "ardour/event_type_map.h" #include "ardour/midi_model.h" #include "ardour/midi_ring_buffer.h" +#include "ardour/midi_state_tracker.h" #include "ardour/session.h" #include "ardour/smf_source.h" @@ -98,8 +99,9 @@ SMFSource::~SMFSource () /** All stamps in audio frames */ nframes_t SMFSource::read_unlocked (MidiRingBuffer& destination, sframes_t source_start, - sframes_t start, nframes_t duration, - sframes_t stamp_offset, sframes_t negative_stamp_offset) const + sframes_t start, nframes_t duration, + sframes_t stamp_offset, sframes_t negative_stamp_offset, + MidiStateTracker* tracker) const { int ret = 0; uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn @@ -166,11 +168,18 @@ SMFSource::read_unlocked (MidiRingBuffer& destination, sframes_t sour if (ev_frame_time < start + duration) { destination.write(ev_frame_time - negative_stamp_offset, ev_type, ev_size, ev_buffer); + + if (tracker) { + if (ev_buffer[0] & MIDI_CMD_NOTE_ON) { + tracker->add (ev_buffer[1], ev_buffer[0] & 0xf); + } else if (ev_buffer[0] & MIDI_CMD_NOTE_OFF) { + tracker->remove (ev_buffer[1], ev_buffer[0] & 0xf); + } + } } else { break; } - - + _read_data_count += ev_size; if (ev_size > scratch_size) { -- cgit v1.2.3