summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-06-03 20:06:01 +0000
committerDavid Robillard <d@drobilla.net>2007-06-03 20:06:01 +0000
commitb0e91bfa0899435c7b798ebd35363147eb1b2823 (patch)
tree0efa702f1d76ca2fadf309674cb2ee11fbc876db /libs
parent41c128155a5eec412f138bcb90b8eb65bd1c5b3d (diff)
Fix MIDI region loading.
Add model loading and destroying to SMFSource. Load and display MIDI region data on session load. git-svn-id: svn://localhost/ardour2/trunk@1947 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/midi_model.h5
-rw-r--r--libs/ardour/ardour/midi_playlist.h2
-rw-r--r--libs/ardour/ardour/midi_region.h7
-rw-r--r--libs/ardour/ardour/midi_source.h3
-rw-r--r--libs/ardour/ardour/midi_track.h3
-rw-r--r--libs/ardour/ardour/smf_source.h3
-rw-r--r--libs/ardour/midi_model.cc23
-rw-r--r--libs/ardour/midi_playlist.cc50
-rw-r--r--libs/ardour/midi_region.cc62
-rw-r--r--libs/ardour/midi_track.cc87
-rw-r--r--libs/ardour/session_command.cc6
-rw-r--r--libs/ardour/session_state.cc24
-rw-r--r--libs/ardour/smf_source.cc30
13 files changed, 179 insertions, 126 deletions
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h
index 5d343d7fa9..509504a472 100644
--- a/libs/ardour/ardour/midi_model.h
+++ b/libs/ardour/ardour/midi_model.h
@@ -35,9 +35,14 @@ public:
MidiModel(size_t size=0);
~MidiModel();
+ void clear() { _events.clear(); }
+
/** Resizes vector if necessary (NOT realtime safe) */
void append(const MidiBuffer& data);
+ /** Resizes vector if necessary (NOT realtime safe) */
+ void append(const MidiEvent& ev);
+
inline const MidiEvent& event_at(unsigned i) const { return _events[i]; }
inline size_t n_events() const { return _events.size(); }
diff --git a/libs/ardour/ardour/midi_playlist.h b/libs/ardour/ardour/midi_playlist.h
index 44f04b781b..3162debbd5 100644
--- a/libs/ardour/ardour/midi_playlist.h
+++ b/libs/ardour/ardour/midi_playlist.h
@@ -57,7 +57,6 @@ public:
protected:
/* playlist "callbacks" */
- void flush_notifications ();
void finalize_split_region (boost::shared_ptr<Region> original, boost::shared_ptr<Region> left, boost::shared_ptr<Region> right);
@@ -66,7 +65,6 @@ protected:
void remove_dependents (boost::shared_ptr<Region> region);
private:
- XMLNode& state (bool full_state);
void dump () const;
bool region_changed (Change, boost::shared_ptr<Region>);
diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h
index 2b783a92a8..83487e456a 100644
--- a/libs/ardour/ardour/midi_region.h
+++ b/libs/ardour/ardour/midi_region.h
@@ -79,9 +79,6 @@ class MidiRegion : public Region
MidiRegion (SourceList &, const XMLNode&);
private:
- friend class Playlist;
-
- private:
nframes_t _read_at (const SourceList&, MidiRingBuffer& dst,
nframes_t position,
nframes_t dur,
@@ -89,6 +86,10 @@ class MidiRegion : public Region
void recompute_at_start ();
void recompute_at_end ();
+
+ protected:
+
+ int set_live_state (const XMLNode&, Change&, bool send);
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h
index 40ef87f8c9..fd5aa15376 100644
--- a/libs/ardour/ardour/midi_source.h
+++ b/libs/ardour/ardour/midi_source.h
@@ -69,6 +69,9 @@ class MidiSource : public Source
XMLNode& get_state ();
int set_state (const XMLNode&);
+ virtual void load_model(bool lock=true) = 0;
+ virtual void destroy_model() = 0;
+
MidiModel& model() { return _model; }
protected:
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 0dad40a973..c88878c167 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -75,10 +75,11 @@ public:
protected:
XMLNode& state (bool full);
+
+ int _set_state (const XMLNode&, bool call_base);
private:
int set_diskstream (boost::shared_ptr<MidiDiskstream> ds);
-
void set_state_part_two ();
void set_state_part_three ();
};
diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h
index 6ab81a2ac3..ed1a0edb76 100644
--- a/libs/ardour/ardour/smf_source.h
+++ b/libs/ardour/ardour/smf_source.h
@@ -87,6 +87,9 @@ class SMFSource : public MidiSource {
int set_state (const XMLNode&);
void seek_to(nframes_t time);
+
+ void load_model(bool lock=true);
+ void destroy_model();
private:
diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc
index 1509b5c866..f12d91ba8a 100644
--- a/libs/ardour/midi_model.cc
+++ b/libs/ardour/midi_model.cc
@@ -63,3 +63,26 @@ MidiModel::append(const MidiBuffer& buf)
}
}
+
+/** Append \a in_event to model. NOT (even remotely) realtime safe.
+ *
+ * Timestamps of events in \a buf are expected to be relative to
+ * the start of this model (t=0) and MUST be monotonically increasing
+ * and MUST be >= the latest event currently in the model.
+ *
+ * Events in buf are deep copied.
+ */
+void
+MidiModel::append(const MidiEvent& in_event)
+{
+ assert(_events.empty() || in_event.time >= _events.back().time);
+
+ _events.push_back(in_event);
+ MidiEvent& my_event = _events.back();
+ assert(my_event.time == in_event.time);
+ assert(my_event.size == in_event.size);
+
+ my_event.buffer = new Byte[my_event.size];
+ memcpy(my_event.buffer, in_event.buffer, my_event.size);
+}
+
diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc
index f99ef299a7..0aa3779034 100644
--- a/libs/ardour/midi_playlist.cc
+++ b/libs/ardour/midi_playlist.cc
@@ -46,9 +46,9 @@ MidiPlaylist::MidiPlaylist (Session& session, const XMLNode& node, bool hidden)
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)
@@ -109,6 +109,10 @@ MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, nframes
MidiPlaylist::~MidiPlaylist ()
{
GoingAway (); /* EMIT SIGNAL */
+
+ /* drop connections to signals */
+
+ notify_callbacks ();
}
struct RegionSortByLayer {
@@ -159,26 +163,14 @@ MidiPlaylist::read (MidiRingBuffer& dst, nframes_t start,
void
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)
{
+ /* MIDI regions have no dependents (crossfades) */
}
void
@@ -226,38 +218,24 @@ MidiPlaylist::finalize_split_region (boost::shared_ptr<Region> original, boost::
void
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);
- }
-
- // Actually Charles, I don't much care for children
-
- /*
- XMLNodeList nlist = node.children();
-
- for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
+ in_set_state++;
+ freeze ();
- 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
{
diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc
index 27861677fd..860d0ec672 100644
--- a/libs/ardour/midi_region.cc
+++ b/libs/ardour/midi_region.cc
@@ -31,6 +31,7 @@
#include <pbd/basename.h>
#include <pbd/xml++.h>
+#include <pbd/enumwriter.h>
#include <ardour/midi_region.h>
#include <ardour/session.h>
@@ -174,29 +175,18 @@ XMLNode&
MidiRegion::state (bool full)
{
XMLNode& node (Region::state (full));
- XMLNode *child;
char buf[64];
char buf2[64];
LocaleGuard lg (X_("POSIX"));
- snprintf (buf, sizeof (buf), "0x%x", (int) _flags);
- node.add_property ("flags", buf);
-
+ node.add_property ("flags", enum_2_string (_flags));
+
for (uint32_t n=0; n < _sources.size(); ++n) {
snprintf (buf2, sizeof(buf2), "source-%d", n);
_sources[n]->id().print (buf, sizeof(buf));
node.add_property (buf2, buf);
}
- snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size());
- node.add_property ("channels", buf);
-
- child = node.add_child ("Envelope");
-
- if ( ! full) {
- child->add_property ("default", "yes");
- }
-
if (full && _extra_xml) {
node.add_child_copy (*_extra_xml);
}
@@ -205,32 +195,52 @@ MidiRegion::state (bool full)
}
int
-MidiRegion::set_state (const XMLNode& node)
+MidiRegion::set_live_state (const XMLNode& node, Change& what_changed, bool send)
{
- const XMLNodeList& nlist = node.children();
const XMLProperty *prop;
LocaleGuard lg (X_("POSIX"));
- Region::set_state (node);
+ Region::set_live_state (node, what_changed, false);
+ uint32_t old_flags = _flags;
+
if ((prop = node.property ("flags")) != 0) {
- _flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
+ _flags = Flag (string_2_enum (prop->value(), _flags));
+
+ //_flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
+
+ _flags = Flag (_flags & ~Region::LeftOfSplit);
+ _flags = Flag (_flags & ~Region::RightOfSplit);
}
- /* Now find child items */
- for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
-
- XMLNode *child;
- //XMLProperty *prop;
-
- child = (*niter);
-
- /** Hello, children */
+ if ((old_flags ^ _flags) & Muted) {
+ what_changed = Change (what_changed|MuteChanged);
+ }
+ if ((old_flags ^ _flags) & Opaque) {
+ what_changed = Change (what_changed|OpacityChanged);
+ }
+ if ((old_flags ^ _flags) & Locked) {
+ what_changed = Change (what_changed|LockChanged);
+ }
+
+ if (send) {
+ send_change (what_changed);
}
return 0;
}
+int
+MidiRegion::set_state (const XMLNode& node)
+{
+ /* Region::set_state() calls the virtual set_live_state(),
+ which will get us back to AudioRegion::set_live_state()
+ to handle the relevant stuff.
+ */
+
+ return Region::set_state (node);
+}
+
void
MidiRegion::recompute_at_end ()
{
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 226476e380..cf08cc9072 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -21,6 +21,8 @@
#include <sigc++/retype_return.h>
#include <sigc++/bind.h>
+#include <pbd/enumwriter.h>
+
#include <ardour/midi_track.h>
#include <ardour/midi_diskstream.h>
#include <ardour/session.h>
@@ -72,10 +74,7 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo
MidiTrack::MidiTrack (Session& sess, const XMLNode& node)
: Track (sess, node)
{
- _freeze_record.state = NoFreeze;
- set_state (node);
- _declickable = true;
- _saved_meter_point = _meter_point;
+ _set_state(node, false);
set_input_minimum(ChanCount(DataType::MIDI, 1));
set_input_maximum(ChanCount(DataType::MIDI, 1));
@@ -141,22 +140,21 @@ MidiTrack::midi_diskstream() const
int
MidiTrack::set_state (const XMLNode& node)
{
+ return _set_state (node, true);
+}
+
+int
+MidiTrack::_set_state (const XMLNode& node, bool call_base)
+{
const XMLProperty *prop;
XMLNodeConstIterator iter;
- if (Route::set_state (node)) {
+ if (Route::_set_state (node, call_base)) {
return -1;
}
-
+
if ((prop = node.property (X_("mode"))) != 0) {
- if (prop->value() == X_("normal")) {
- _mode = Normal;
- } else if (prop->value() == X_("destructive")) {
- _mode = Destructive;
- } else {
- warning << string_compose ("unknown midi track mode \"%1\" seen and ignored", prop->value()) << endmsg;
- _mode = Normal;
- }
+ _mode = TrackMode (string_2_enum (prop->value(), _mode));
} else {
_mode = Normal;
}
@@ -193,12 +191,9 @@ MidiTrack::set_state (const XMLNode& node)
for (niter = nlist.begin(); niter != nlist.end(); ++niter){
child = *niter;
- if (child->name() == X_("remote_control")) {
- if ((prop = child->property (X_("id"))) != 0) {
- int32_t x;
- sscanf (prop->value().c_str(), "%d", &x);
- set_remote_control_id (x);
- }
+ if (child->name() == X_("recenable")) {
+ _rec_enable_control.set_state (*child);
+ _session.add_controllable (&_rec_enable_control);
}
}
@@ -221,8 +216,7 @@ MidiTrack::state(bool full_state)
freeze_node = new XMLNode (X_("freeze-info"));
freeze_node->add_property ("playlist", _freeze_record.playlist->name());
- snprintf (buf, sizeof (buf), "%d", (int) _freeze_record.state);
- freeze_node->add_property ("state", buf);
+ freeze_node->add_property ("state", enum_2_string (_freeze_record.state));
for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
inode = new XMLNode (X_("insert"));
@@ -239,31 +233,12 @@ MidiTrack::state(bool full_state)
/* Alignment: act as a proxy for the diskstream */
XMLNode* align_node = new XMLNode (X_("alignment"));
- switch (_diskstream->alignment_style()) {
- case ExistingMaterial:
- snprintf (buf, sizeof (buf), X_("existing"));
- break;
- case CaptureTime:
- snprintf (buf, sizeof (buf), X_("capture"));
- break;
- }
- align_node->add_property (X_("style"), buf);
+ AlignStyle as = _diskstream->alignment_style ();
+ align_node->add_property (X_("style"), enum_2_string (as));
root.add_child_nocopy (*align_node);
- XMLNode* remote_control_node = new XMLNode (X_("remote_control"));
- snprintf (buf, sizeof (buf), "%d", _remote_control_id);
- remote_control_node->add_property (X_("id"), buf);
- root.add_child_nocopy (*remote_control_node);
-
- switch (_mode) {
- case Normal:
- root.add_property (X_("mode"), X_("normal"));
- break;
- case Destructive:
- root.add_property (X_("mode"), X_("destructive"));
- break;
- }
-
+ root.add_property (X_("mode"), enum_2_string (_mode));
+
/* we don't return diskstream state because we don't
own the diskstream exclusively. control of the diskstream
state is ceded to the Session, even if we create the
@@ -272,6 +247,8 @@ MidiTrack::state(bool full_state)
_diskstream->id().print (buf, sizeof(buf));
root.add_property ("diskstream-id", buf);
+
+ root.add_child_nocopy (_rec_enable_control.get_state());
return root;
}
@@ -314,7 +291,7 @@ MidiTrack::set_state_part_two ()
}
if ((prop = fnode->property (X_("state"))) != 0) {
- _freeze_record.state = (FreezeState) atoi (prop->value().c_str());
+ _freeze_record.state = FreezeState (string_2_enum (prop->value(), _freeze_record.state));
}
XMLNodeConstIterator citer;
@@ -341,11 +318,21 @@ MidiTrack::set_state_part_two ()
if ((fnode = find_named_node (*pending_state, X_("alignment"))) != 0) {
if ((prop = fnode->property (X_("style"))) != 0) {
- if (prop->value() == "existing") {
- _diskstream->set_persistent_align_style (ExistingMaterial);
- } else if (prop->value() == "capture") {
- _diskstream->set_persistent_align_style (CaptureTime);
+
+ /* fix for older sessions from before EnumWriter */
+
+ string pstr;
+
+ if (prop->value() == "capture") {
+ pstr = "CaptureTime";
+ } else if (prop->value() == "existing") {
+ pstr = "ExistingMaterial";
+ } else {
+ pstr = prop->value();
}
+
+ AlignStyle as = AlignStyle (string_2_enum (pstr, as));
+ _diskstream->set_persistent_align_style (as);
}
}
return;
diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc
index 10f319ace8..534f2ffe81 100644
--- a/libs/ardour/session_command.cc
+++ b/libs/ardour/session_command.cc
@@ -24,6 +24,8 @@
#include <ardour/playlist.h>
#include <ardour/audioplaylist.h>
#include <ardour/audio_track.h>
+#include <ardour/midi_playlist.h>
+#include <ardour/midi_track.h>
#include <ardour/tempo.h>
#include <ardour/audiosource.h>
#include <ardour/audioregion.h>
@@ -93,11 +95,11 @@ Session::memento_command_factory(XMLNode *n)
return new MementoCommand<Locations>(_locations, before, after);
} else if (obj_T == typeid (TempoMap).name()) {
return new MementoCommand<TempoMap>(*_tempo_map, before, after);
- } else if (obj_T == typeid (Playlist).name() || obj_T == typeid (AudioPlaylist).name()) {
+ } else if (obj_T == typeid (Playlist).name() || obj_T == typeid (AudioPlaylist).name() || obj_T == typeid (MidiPlaylist).name()) {
if (boost::shared_ptr<Playlist> pl = playlist_by_name(child->property("name")->value())) {
return new MementoCommand<Playlist>(*(pl.get()), before, after);
}
- } else if (obj_T == typeid (Route).name() || obj_T == typeid (AudioTrack).name()) {
+ } else if (obj_T == typeid (Route).name() || obj_T == typeid (AudioTrack).name() || obj_T == typeid(MidiTrack).name()) {
return new MementoCommand<Route>(*route_by_id(id), before, after);
} else if (obj_T == typeid (Curve).name() || obj_T == typeid (AutomationList).name()) {
if (automation_lists.count(id))
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index e2043899c5..285e3fd4c4 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -1110,7 +1110,7 @@ Session::set_state (const XMLNode& node)
/* Object loading order:
- MIDI
+ MIDI Control
Path
extra
Options/Config
@@ -1397,7 +1397,6 @@ Session::XMLAudioRegionFactory (const XMLNode& node, bool full)
nchans = atoi (prop->value().c_str());
}
-
if ((prop = node.property ("name")) == 0) {
cerr << "no name for this region\n";
abort ();
@@ -1461,7 +1460,6 @@ Session::XMLAudioRegionFactory (const XMLNode& node, bool full)
}
}
-
return region;
}
@@ -1477,7 +1475,7 @@ Session::XMLMidiRegionFactory (const XMLNode& node, bool full)
const XMLProperty* prop;
boost::shared_ptr<Source> source;
boost::shared_ptr<MidiSource> ms;
- MidiRegion::SourceList sources;
+ SourceList sources;
uint32_t nchans = 1;
if (node.name() != X_("Region")) {
@@ -1487,6 +1485,11 @@ Session::XMLMidiRegionFactory (const XMLNode& node, bool full)
if ((prop = node.property (X_("channels"))) != 0) {
nchans = atoi (prop->value().c_str());
}
+
+ if ((prop = node.property ("name")) == 0) {
+ cerr << "no name for this region\n";
+ abort ();
+ }
// Multiple midi channels? that's just crazy talk
assert(nchans == 1);
@@ -1515,6 +1518,17 @@ Session::XMLMidiRegionFactory (const XMLNode& node, bool full)
try {
boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
+ /* a final detail: this is the one and only place that we know how long missing files are */
+
+ if (region->whole_file()) {
+ for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
+ boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
+ if (sfp) {
+ sfp->set_length (region->length());
+ }
+ }
+ }
+
return region;
}
@@ -1534,8 +1548,6 @@ Session::get_sources_as_xml ()
node->add_child_nocopy (i->second->get_state());
}
- /* XXX get MIDI and other sources here */
-
return *node;
}
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index 061a2f1234..e48e89a6e5 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -754,3 +754,33 @@ SMFSource::read_var_len() const
return value;
}
+
+void
+SMFSource::load_model(bool lock)
+{
+ if (lock)
+ Glib::Mutex::Lock lm (_lock);
+
+ _model.clear();
+
+ fseek(_fd, _header_size, 0);
+
+ nframes_t time = 0;
+ MidiEvent ev;
+
+ int ret;
+ while ((ret = read_event(ev)) >= 0) {
+ time += ev.time;
+ ev.time = time;
+ if (ret > 0) { // didn't skip (meta) event
+ _model.append(ev);
+ }
+ }
+}
+
+void
+SMFSource::destroy_model()
+{
+ _model.clear();
+}
+