diff options
author | Hans Baier <hansfbaier@googlemail.com> | 2008-04-09 15:33:01 +0000 |
---|---|---|
committer | Hans Baier <hansfbaier@googlemail.com> | 2008-04-09 15:33:01 +0000 |
commit | 1a0044b35d2cca7e7316d6afbb8e4955b6d7a627 (patch) | |
tree | 43fe8bf5cfc170f6aa4a5ec2f821a909965f572e /libs | |
parent | f39606f985223d211d218799c9e0de1e7c0e7f0c (diff) |
* implemented persistent undo for MidiModel::DeltaCommand. Deserializing works, but weirdly has no effect when undo/redo is applied in the editor
git-svn-id: svn://localhost/ardour2/branches/3.0@3240 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/midi_model.h | 24 | ||||
-rw-r--r-- | libs/ardour/ardour/note.h | 2 | ||||
-rw-r--r-- | libs/ardour/midi_model.cc | 117 | ||||
-rw-r--r-- | libs/ardour/midi_source.cc | 4 | ||||
-rw-r--r-- | libs/ardour/session_state.cc | 10 | ||||
-rw-r--r-- | libs/ardour/smf_source.cc | 2 | ||||
-rw-r--r-- | libs/midi++2/midi++/event.h | 1 |
7 files changed, 149 insertions, 11 deletions
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index f99855d238..5d16c30836 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -55,7 +55,7 @@ typedef std::pair<boost::shared_ptr<const AutomationList>, std::pair<double,doub */ class MidiModel : public boost::noncopyable, public Automatable { public: - MidiModel(Session& s, size_t size=0); + MidiModel(MidiSource& s, size_t size=0); // This is crap. void write_lock(); @@ -110,20 +110,30 @@ public: public: DeltaCommand (MidiModel& m, const std::string& name) : Command(name), _model(m), _name(name) {} - //DeltaCommand (MidiModel&, const XMLNode& node); + DeltaCommand (MidiModel&, const XMLNode& node); const std::string& name() const { return _name; } void operator()(); void undo(); - /*int set_state (const XMLNode&); - XMLNode& get_state ();*/ + int set_state (const XMLNode&); + XMLNode& get_state (); void add(const boost::shared_ptr<Note> note); void remove(const boost::shared_ptr<Note> note); private: + class NoteMarshaller { + public: + XMLNode *operator()(const boost::shared_ptr<Note> note); + }; + + class NoteUnmarshaller { + public: + boost::shared_ptr<Note> operator()(XMLNode *xml_note); + }; + MidiModel& _model; const std::string _name; std::list< boost::shared_ptr<Note> > _added_notes; @@ -164,7 +174,7 @@ public: friend class MidiModel; const MidiModel* _model; - MIDI::Event _event; + MIDI::Event _event; typedef std::priority_queue< boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >, @@ -183,6 +193,8 @@ public: const_iterator begin() const { return const_iterator(*this, 0); } const const_iterator& end() const { return _end_iter; } + const MidiSource& midi_source() const { return _midi_source; } + private: friend class DeltaCommand; void add_note_unlocked(const boost::shared_ptr<Note> note); @@ -218,6 +230,8 @@ private: boost::shared_ptr<Note>, std::deque< boost::shared_ptr<Note> >, LaterNoteEndComparator> ActiveNotes; + + MidiSource& _midi_source; }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/note.h b/libs/ardour/ardour/note.h index 5b5a38d645..a53b134be8 100644 --- a/libs/ardour/ardour/note.h +++ b/libs/ardour/ardour/note.h @@ -47,11 +47,13 @@ public: inline uint8_t note() const { return _on_event.note(); } inline uint8_t velocity() const { return _on_event.velocity(); } inline double duration() const { return _off_event.time() - _on_event.time(); } + inline uint8_t channel() const { return _on_event.channel(); } inline void set_time(double t) { _off_event.time() = t + duration(); _on_event.time() = t; } inline void set_note(uint8_t n) { _on_event.buffer()[1] = n; _off_event.buffer()[1] = n; } inline void set_velocity(uint8_t n) { _on_event.buffer()[2] = n; } inline void set_duration(double d) { _off_event.time() = _on_event.time() + d; } + inline void set_channel(uint8_t channel) { _on_event.set_channel(channel); _off_event.set_channel(channel); } inline MIDI::Event& on_event() { return _on_event; } inline MIDI::Event& off_event() { return _off_event; } diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 43ac4b0f96..94a725d272 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -272,8 +272,8 @@ MidiModel::const_iterator::operator=(const const_iterator& other) // MidiModel -MidiModel::MidiModel(Session& s, size_t size) - : Automatable(s, "midi model") +MidiModel::MidiModel(MidiSource& s, size_t size) + : Automatable(s.session(), "midi model") , _notes(size) , _note_mode(Sustained) , _writing(false) @@ -281,6 +281,7 @@ MidiModel::MidiModel(Session& s, size_t size) , _end_iter(*this, DBL_MAX) , _next_read(UINT32_MAX) , _read_iter(*this, DBL_MAX) + , _midi_source(s) { assert(_end_iter._is_end); assert( ! _end_iter._locked); @@ -657,6 +658,118 @@ MidiModel::DeltaCommand::undo() _model.ContentsChanged(); /* EMIT SIGNAL */ } +XMLNode * +MidiModel::DeltaCommand::NoteMarshaller::operator()(const boost::shared_ptr<Note> note) +{ + XMLNode *xml_note = new XMLNode("note"); + ostringstream note_str(ios::ate); + note_str << int(note->note()); + xml_note->add_property("note", note_str.str()); + + ostringstream channel_str(ios::ate); + channel_str << int(note->channel()); + xml_note->add_property("channel", channel_str.str()); + + ostringstream time_str(ios::ate); + time_str << int(note->time()); + xml_note->add_property("time", time_str.str()); + + ostringstream duration_str(ios::ate); + duration_str <<(unsigned int) note->duration(); + xml_note->add_property("duration", duration_str.str()); + + ostringstream velocity_str(ios::ate); + velocity_str << (unsigned int) note->velocity(); + xml_note->add_property("velocity", velocity_str.str()); + + return xml_note; +} + +boost::shared_ptr<Note> +MidiModel::DeltaCommand::NoteUnmarshaller::operator()(XMLNode *xml_note) +{ + unsigned int note; + istringstream note_str(xml_note->property("note")->value()); + note_str >> note; + + unsigned int channel; + istringstream channel_str(xml_note->property("channel")->value()); + channel_str >> channel; + + unsigned int time; + istringstream time_str(xml_note->property("time")->value()); + time_str >> time; + + unsigned int duration; + istringstream duration_str(xml_note->property("duration")->value()); + duration_str >> duration; + + unsigned int velocity; + istringstream velocity_str(xml_note->property("velocity")->value()); + velocity_str >> velocity; + + cerr << "creating note channel: " << channel_str.str() << " time " << time_str.str() << " duration " << duration_str.str() << " pitch " << note_str.str() << " velo " << velocity_str.str() <<endl; + cerr << "creating note channel: " << channel << " time " << time << " duration " << duration << " pitch " << note << " velo " << velocity <<endl; + + boost::shared_ptr<Note> note_ptr(new Note(channel, time, duration, note, velocity)); + return note_ptr; +} + +#define ADDED_NOTES_ELEMENT "added_notes" +#define REMOVED_NOTES_ELEMENT "removed_notes" +#define DELTA_COMMAND_ELEMENT "DeltaCommand" + +int +MidiModel::DeltaCommand::set_state (const XMLNode& delta_command) +{ + + cerr << "Unmarshalling Deltacommand" << endl; + + if(delta_command.name() != string(DELTA_COMMAND_ELEMENT)) { + return 1; + } + + _added_notes.clear(); + XMLNode *added_notes = delta_command.child(ADDED_NOTES_ELEMENT); + XMLNodeList notes = added_notes->children(); + transform(notes.begin(), notes.end(), back_inserter(_added_notes), + MidiModel::DeltaCommand::NoteUnmarshaller()); + + _removed_notes.clear(); + XMLNode *removed_notes = delta_command.child(REMOVED_NOTES_ELEMENT); + notes = removed_notes->children(); + transform(notes.begin(), notes.end(), back_inserter(_removed_notes), + MidiModel::DeltaCommand::NoteUnmarshaller()); + + return 0; +} + +XMLNode& +MidiModel::DeltaCommand::get_state () +{ + XMLNode *delta_command = new XMLNode(DELTA_COMMAND_ELEMENT); + delta_command->add_property("midi_source", _model.midi_source().id().to_s()); + + XMLNode *added_notes = delta_command->add_child(ADDED_NOTES_ELEMENT); + for (std::list< boost::shared_ptr<Note> >::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) { + NoteMarshaller marshaller; + added_notes->add_child_nocopy(*marshaller(*i)); + } + + XMLNode *removed_notes = delta_command->add_child(REMOVED_NOTES_ELEMENT); + for (std::list< boost::shared_ptr<Note> >::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i) { + NoteMarshaller marshaller; + removed_notes->add_child_nocopy(*marshaller(*i)); + } + + return *delta_command; +} + +MidiModel::DeltaCommand::DeltaCommand (MidiModel& m, const XMLNode& node) + : _model(m) +{ + set_state(node); +} bool MidiModel::write_to(boost::shared_ptr<MidiSource> source) diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index aeb898a31b..7b2c4009bb 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -49,7 +49,7 @@ sigc::signal<void,MidiSource *> MidiSource::MidiSourceCreated; MidiSource::MidiSource (Session& s, string name) : Source (s, name, DataType::MIDI) , _timeline_position(0) - , _model(new MidiModel(s)) + , _model(new MidiModel(*this)) , _writing (false) { _read_data_count = 0; @@ -59,7 +59,7 @@ MidiSource::MidiSource (Session& s, string name) MidiSource::MidiSource (Session& s, const XMLNode& node) : Source (s, node) , _timeline_position(0) - , _model(new MidiModel(s)) + , _model(new MidiModel(*this)) , _writing (false) { _read_data_count = 0; diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 41261fdfbc..a2575caadd 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -2989,8 +2989,16 @@ Session::restore_history (string snapshot_name) ut->add_command (c); } + } else if (n->name() == "DeltaCommand") { + PBD::ID id(n->property("midi_source")->value()); + boost::shared_ptr<MidiSource> midi_source = + boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id)); + if(midi_source) { + ut->add_command(new MidiModel::DeltaCommand(*(midi_source->model()), *n)); + } else { + error << "FIXME: Failed to downcast MidiSource for DeltaCommand" << endmsg; + } } else { - error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg; } } diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 18d7e87d88..bee3fd96d4 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -872,7 +872,7 @@ SMFSource::load_model(bool lock, bool force_reload) } if (! _model) { - _model = boost::shared_ptr<MidiModel>(new MidiModel(_session)); + _model = boost::shared_ptr<MidiModel>(new MidiModel(*this)); cerr << _name << " loaded new model " << _model.get() << endl; } else { cerr << _name << " reloading model " << _model.get() diff --git a/libs/midi++2/midi++/event.h b/libs/midi++2/midi++/event.h index 6ef1c49ee9..cce17b0625 100644 --- a/libs/midi++2/midi++/event.h +++ b/libs/midi++2/midi++/event.h @@ -167,6 +167,7 @@ struct Event { inline uint32_t& size() { return _size; } inline uint8_t type() const { return (_buffer[0] & 0xF0); } inline uint8_t channel() const { return (_buffer[0] & 0x0F); } + inline void set_channel(uint8_t channel) { _buffer[0] = (0xF0 & _buffer[0]) | channel; } inline bool is_note_on() const { return (type() == MIDI_CMD_NOTE_ON); } inline bool is_note_off() const { return (type() == MIDI_CMD_NOTE_OFF); } inline bool is_cc() const { return (type() == MIDI_CMD_CONTROL); } |