diff options
author | David Robillard <d@drobilla.net> | 2007-06-03 20:06:01 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2007-06-03 20:06:01 +0000 |
commit | b0e91bfa0899435c7b798ebd35363147eb1b2823 (patch) | |
tree | 0efa702f1d76ca2fadf309674cb2ee11fbc876db /libs | |
parent | 41c128155a5eec412f138bcb90b8eb65bd1c5b3d (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.h | 5 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_playlist.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_region.h | 7 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_source.h | 3 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_track.h | 3 | ||||
-rw-r--r-- | libs/ardour/ardour/smf_source.h | 3 | ||||
-rw-r--r-- | libs/ardour/midi_model.cc | 23 | ||||
-rw-r--r-- | libs/ardour/midi_playlist.cc | 50 | ||||
-rw-r--r-- | libs/ardour/midi_region.cc | 62 | ||||
-rw-r--r-- | libs/ardour/midi_track.cc | 87 | ||||
-rw-r--r-- | libs/ardour/session_command.cc | 6 | ||||
-rw-r--r-- | libs/ardour/session_state.cc | 24 | ||||
-rw-r--r-- | libs/ardour/smf_source.cc | 30 |
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(); +} + |