diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/midi_playlist.h | 5 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_region.h | 19 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_source.h | 15 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_state_tracker.h | 5 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_track.h | 5 | ||||
-rw-r--r-- | libs/ardour/ardour/smf_source.h | 13 | ||||
-rw-r--r-- | libs/ardour/midi_playlist.cc | 38 | ||||
-rw-r--r-- | libs/ardour/midi_region.cc | 14 | ||||
-rw-r--r-- | libs/ardour/midi_source.cc | 16 | ||||
-rw-r--r-- | libs/ardour/midi_state_tracker.cc | 33 | ||||
-rw-r--r-- | 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<Region>); NoteMode _note_mode; + + typedef std::map<Region*,MidiStateTracker*> 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<typename T> 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<nframes_t>& 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<nframes_t>& dst, sframes_t position, @@ -104,10 +106,11 @@ class MidiRegion : public Region private: nframes_t _read_at (const SourceList&, MidiRingBuffer<nframes_t>& 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<typename T> 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<nframes_t>& 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<nframes_t>& 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<nframes_t>& 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<nframes_t>& 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 <bitset> - #include "ardour/midi_buffer.h" namespace ARDOUR { +template <typename T> 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<nframes_t>& 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<MidiDiskstream> 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<nframes_t>& 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<nframes_t>& 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<nframes_t>& 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<nframes_t>& dst, nframes_t start, nframes_t d for (vector<boost::shared_ptr<Region> >::iterator i = regs.begin(); i != regs.end(); ++i) { boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*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<Region*,MidiStateTracker*> 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<nframes_t>& dst, nframes_t start, nframes_t d return dur; } - void -MidiPlaylist::remove_dependents (boost::shared_ptr<Region> /*region*/) +MidiPlaylist::remove_dependents (boost::shared_ptr<Region> 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<nframes_t>& out, sframes_t position, nframes_t dur, uint32_t chan_n, NoteMode mode) const +MidiRegion::read_at (MidiRingBuffer<nframes_t>& 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<nframes_t>& 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<nframes_t>& dst, nframes_t position, nframes_t dur, uint32_t chan_n, NoteMode mode) const +MidiRegion::_read_at (const SourceList& /*srcs*/, MidiRingBuffer<nframes_t>& 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<nframes_t>& 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<nframes_t>& 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<nframes_t>& 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<Evoral::MusicalTime>& ev (*(Evoral::MIDIEvent<Evoral::MusicalTime>*) (&(*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 <iostream> #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<MidiBuffer::TimeTyp } } } +void +MidiStateTracker::add (uint8_t note, uint8_t chn) +{ + cerr << "Added note " << note << " chan " << chn << endl; + _active_notes[note + 128 * chn]++; +} + +void +MidiStateTracker::remove (uint8_t note, uint8_t chn) +{ + if (_active_notes[note + 128 * chn]) { + cerr << "Removed note " << note << " chan " << chn << endl; + _active_notes[note + 128 * chn]--; + } +} void MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::iterator &to, bool& looped) @@ -82,6 +98,23 @@ MidiStateTracker::resolve_notes (MidiBuffer &dst, nframes64_t time) } void +MidiStateTracker::resolve_notes (MidiRingBuffer<nframes_t> &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) { o << "******\n"; 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<nframes_t>& 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<nframes_t>& 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) { |