summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorHans Baier <hansfbaier@googlemail.com>2008-04-09 15:33:01 +0000
committerHans Baier <hansfbaier@googlemail.com>2008-04-09 15:33:01 +0000
commit1a0044b35d2cca7e7316d6afbb8e4955b6d7a627 (patch)
tree43fe8bf5cfc170f6aa4a5ec2f821a909965f572e /libs
parentf39606f985223d211d218799c9e0de1e7c0e7f0c (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.h24
-rw-r--r--libs/ardour/ardour/note.h2
-rw-r--r--libs/ardour/midi_model.cc117
-rw-r--r--libs/ardour/midi_source.cc4
-rw-r--r--libs/ardour/session_state.cc10
-rw-r--r--libs/ardour/smf_source.cc2
-rw-r--r--libs/midi++2/midi++/event.h1
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); }