summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2009-10-19 17:05:22 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2009-10-19 17:05:22 +0000
commit539a692b0e9d249cab75a2d1c255f8cbef8bcf6b (patch)
tree9c40db2f5651a57bd90e034c8750209915db2363
parenta86b994c683b981c395f829082abef67add2424a (diff)
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
-rw-r--r--libs/ardour/ardour/midi_playlist.h5
-rw-r--r--libs/ardour/ardour/midi_region.h19
-rw-r--r--libs/ardour/ardour/midi_source.h15
-rw-r--r--libs/ardour/ardour/midi_state_tracker.h5
-rw-r--r--libs/ardour/ardour/midi_track.h5
-rw-r--r--libs/ardour/ardour/smf_source.h13
-rw-r--r--libs/ardour/midi_playlist.cc38
-rw-r--r--libs/ardour/midi_region.cc14
-rw-r--r--libs/ardour/midi_source.cc16
-rw-r--r--libs/ardour/midi_state_tracker.cc33
-rw-r--r--libs/ardour/smf_source.cc17
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) {