#include <sigc++/bind.h>
-#include <ardour/types.h>
-#include <ardour/configuration.h>
-#include <ardour/midi_playlist.h>
-#include <ardour/midi_region.h>
-#include <ardour/session.h>
-#include <ardour/midi_ring_buffer.h>
+#include "ardour/types.h"
+#include "ardour/configuration.h"
+#include "ardour/midi_playlist.h"
+#include "ardour/midi_region.h"
+#include "ardour/session.h"
+#include "ardour/midi_ring_buffer.h"
-#include <pbd/error.h>
+#include "pbd/error.h"
#include "i18n.h"
MidiPlaylist::MidiPlaylist (Session& session, const XMLNode& node, bool hidden)
: Playlist (session, node, DataType::MIDI, hidden)
+ , _note_mode(Sustained)
{
const XMLProperty* prop = node.property("type");
assert(prop && DataType(prop->value()) == DataType::MIDI);
- in_set_state = true;
+ in_set_state++;
set_state (node);
- in_set_state = false;
+ in_set_state--;
}
MidiPlaylist::MidiPlaylist (Session& session, string name, bool hidden)
MidiPlaylist::~MidiPlaylist ()
{
GoingAway (); /* EMIT SIGNAL */
+
+ /* drop connections to signals */
+
+ notify_callbacks ();
}
struct RegionSortByLayer {
/** Returns the number of frames in time duration read (eg could be large when 0 events are read) */
nframes_t
-MidiPlaylist::read (MidiRingBuffer& dst, nframes_t start,
- nframes_t dur, unsigned chan_n)
+MidiPlaylist::read (MidiRingBuffer<nframes_t>& dst, nframes_t start, nframes_t dur, unsigned chan_n)
{
/* this function is never called from a realtime thread, so
its OK to block (for short intervals).
*/
- Glib::Mutex::Lock rm (region_lock);
+ Glib::RecMutex::Lock rm (region_lock);
nframes_t end = start + dur - 1;
vector<boost::shared_ptr<Region> > regs;
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
-
if ((*i)->coverage (start, end) != OverlapNone) {
regs.push_back(*i);
}
sort(regs.begin(), regs.end(), layer_cmp);
for (vector<boost::shared_ptr<Region> >::iterator i = regs.begin(); i != regs.end(); ++i) {
- // FIXME: ensure time is monotonic here
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*i);
- mr->read_at (dst, start, dur, chan_n);
- _read_data_count += mr->read_data_count();
+ if (mr) {
+ mr->read_at (dst, start, dur, chan_n, _note_mode);
+ _read_data_count += mr->read_data_count();
+ }
}
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) */
}
void
-MidiPlaylist::flush_notifications ()
-{
- Playlist::flush_notifications();
-
- if (in_flush) {
- return;
- }
-
- in_flush = true;
-
- in_flush = false;
-}
-
-void
-MidiPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
+MidiPlaylist::refresh_dependents (boost::shared_ptr<Region> /*r*/)
{
+ /* MIDI regions have no dependents (crossfades) */
}
void
-MidiPlaylist::finalize_split_region (boost::shared_ptr<Region> original, boost::shared_ptr<Region> left, boost::shared_ptr<Region> right)
+MidiPlaylist::finalize_split_region (boost::shared_ptr<Region> /*original*/, boost::shared_ptr<Region> /*left*/, boost::shared_ptr<Region> /*right*/)
{
- throw; // I don't wanna
- /*
- MidiRegion *orig = dynamic_cast<MidiRegion*>(o);
- MidiRegion *left = dynamic_cast<MidiRegion*>(l);
- MidiRegion *right = dynamic_cast<MidiRegion*>(r);
-
- for (Crossfades::iterator x = _crossfades.begin(); x != _crossfades.end();) {
- Crossfades::iterator tmp;
- tmp = x;
- ++tmp;
-
- Crossfade *fade = 0;
-
- if ((*x)->_in == orig) {
- if (! (*x)->covers(right->position())) {
- fade = new Crossfade( *(*x), left, (*x)->_out);
- } else {
- // Overlap, the crossfade is copied on the left side of the right region instead
- fade = new Crossfade( *(*x), right, (*x)->_out);
- }
- }
-
- if ((*x)->_out == orig) {
- if (! (*x)->covers(right->position())) {
- fade = new Crossfade( *(*x), (*x)->_in, right);
- } else {
- // Overlap, the crossfade is copied on the right side of the left region instead
- fade = new Crossfade( *(*x), (*x)->_in, left);
- }
- }
-
- if (fade) {
- _crossfades.remove( (*x) );
- add_crossfade (*fade);
- }
- x = tmp;
- }*/
+ /* No MIDI crossfading (yet?), so nothing to do here */
}
void
-MidiPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
+MidiPlaylist::check_dependents (boost::shared_ptr<Region> /*r*/, bool /*norefresh*/)
{
+ /* MIDI regions have no dependents (crossfades) */
}
int
MidiPlaylist::set_state (const XMLNode& node)
{
- if (!in_set_state) {
- Playlist::set_state (node);
- }
+ in_set_state++;
+ freeze ();
- // Actually Charles, I don't much care for children
-
- /*
- XMLNodeList nlist = node.children();
-
- for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
-
- XMLNode* const child = *niter;
+ Playlist::set_state (node);
- }*/
+ thaw();
+ in_set_state--;
return 0;
}
-XMLNode&
-MidiPlaylist::state (bool full_state)
-{
- XMLNode& node = Playlist::state (full_state);
-
- return node;
-}
-
void
MidiPlaylist::dump () const
{
return changed;
}
+set<Evoral::Parameter>
+MidiPlaylist::contained_automation()
+{
+ /* this function is never called from a realtime thread, so
+ its OK to block (for short intervals).
+ */
+
+ Glib::RecMutex::Lock rm (region_lock);
+
+ set<Evoral::Parameter> ret;
+
+ for (RegionList::const_iterator r = regions.begin(); r != regions.end(); ++r) {
+ boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*r);
+
+ for (Automatable::Controls::iterator c = mr->model()->controls().begin();
+ c != mr->model()->controls().end(); ++c) {
+ ret.insert(c->first);
+ }
+ }
+
+ return ret;
+}
+
+
bool
MidiPlaylist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
{