summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorHans Baier <hansfbaier@googlemail.com>2008-04-11 15:49:52 +0000
committerHans Baier <hansfbaier@googlemail.com>2008-04-11 15:49:52 +0000
commitaae8262a363b3d7b85b5baa3b2d0ffb07e604b73 (patch)
treef482717d2f895f3d9fb3b3f7faa5a4648c3b58d0 /libs/ardour
parentcb413146428ce5db5e281d70f2b3b7df27c1aaab (diff)
* persistent undo for MIDI edits works now
* fixed bug: dragging of notes beyond left region bounds made it disappear (unsigned int wrap around) git-svn-id: svn://localhost/ardour2/branches/3.0@3249 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/midi_model.h15
-rw-r--r--libs/ardour/ardour/note.h12
-rw-r--r--libs/ardour/midi_model.cc78
-rw-r--r--libs/ardour/midi_source.cc9
-rw-r--r--libs/ardour/session_state.cc2
-rw-r--r--libs/ardour/smf_source.cc2
6 files changed, 66 insertions, 52 deletions
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h
index 3ba0fc1279..b6cdac1864 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(MidiSource& s, size_t size=0);
+ MidiModel(MidiSource *s, size_t size=0);
// This is crap.
void write_lock();
@@ -108,9 +108,8 @@ public:
class DeltaCommand : public Command
{
public:
- DeltaCommand (MidiModel& m, const std::string& name)
- : Command(name), _model(m), _name(name) {}
- DeltaCommand (MidiModel&, const XMLNode& node);
+ DeltaCommand (boost::shared_ptr<MidiModel> m, const std::string& name);
+ DeltaCommand (boost::shared_ptr<MidiModel>, const XMLNode& node);
const std::string& name() const { return _name; }
@@ -127,7 +126,7 @@ public:
XMLNode &marshal_note(const boost::shared_ptr<Note> note);
boost::shared_ptr<Note> unmarshal_note(XMLNode *xml_note);
- MidiModel& _model;
+ boost::shared_ptr<MidiModel> _model;
const std::string _name;
typedef std::list< boost::shared_ptr<Note> > NoteList;
@@ -189,7 +188,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; }
+ const MidiSource *midi_source() const { return _midi_source; }
+ void set_midi_source(MidiSource *source) { _midi_source = source; }
private:
friend class DeltaCommand;
@@ -227,7 +227,8 @@ private:
LaterNoteEndComparator>
ActiveNotes;
- MidiSource& _midi_source;
+ // We cannot use a boost::shared_ptr here to avoid a retain cycle
+ MidiSource *_midi_source;
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/note.h b/libs/ardour/ardour/note.h
index a53b134be8..713d732113 100644
--- a/libs/ardour/ardour/note.h
+++ b/libs/ardour/ardour/note.h
@@ -40,14 +40,22 @@ public:
const Note& operator=(const Note& copy);
inline bool operator==(const Note& other)
- { return time() == other.time() && note() == other.note() && duration() == other.duration(); }
+ { return time() == other.time() &&
+ note() == other.note() &&
+ duration() == other.duration() &&
+ velocity() == other.velocity() &&
+ channel() == other.channel();
+ }
inline double time() const { return _on_event.time(); }
inline double end_time() const { return _off_event.time(); }
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 uint8_t channel() const {
+ assert(_on_event.channel() == _off_event.channel());
+ 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; }
diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc
index 14441d2ee4..439be8a481 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(MidiSource& s, size_t size)
- : Automatable(s.session(), "midi model")
+MidiModel::MidiModel(MidiSource *s, size_t size)
+ : Automatable(s->session(), "midi model")
, _notes(size)
, _note_mode(Sustained)
, _writing(false)
@@ -287,7 +287,6 @@ MidiModel::MidiModel(MidiSource& s, size_t size)
assert( ! _end_iter._locked);
}
-
/** Read events in frame range \a start .. \a start+cnt into \a dst,
* adding \a stamp_offset to each event's timestamp.
* \return number of events written to \a dst
@@ -521,9 +520,12 @@ void
MidiModel::remove_note_unlocked(const boost::shared_ptr<const Note> note)
{
//cerr << "MidiModel " << this << " remove note " << (int)note.note() << " @ " << note.time() << endl;
- Notes::iterator n = find(_notes.begin(), _notes.end(), note);
- if (n != _notes.end())
- _notes.erase(n);
+ for(Notes::iterator n = _notes.begin(); n != _notes.end(); ++n) {
+ if(**n == *note) {
+ _notes.erase(n);
+ }
+ }
+
}
/** Slow! for debugging only. */
@@ -551,7 +553,7 @@ MidiModel::is_sorted() const
MidiModel::DeltaCommand*
MidiModel::new_delta_command(const string name)
{
- DeltaCommand* cmd = new DeltaCommand(*this, name);
+ DeltaCommand* cmd = new DeltaCommand(_midi_source->model(), name);
return cmd;
}
@@ -574,6 +576,17 @@ MidiModel::apply_command(Command* cmd)
// MidiEditCommand
+MidiModel::DeltaCommand::DeltaCommand(boost::shared_ptr<MidiModel> m, const std::string& name)
+ : Command(name), _model(m), _name(name)
+{
+
+}
+
+MidiModel::DeltaCommand::DeltaCommand(boost::shared_ptr<MidiModel> m, const XMLNode& node)
+ : _model(m)
+{
+ set_state(node);
+}
void
MidiModel::DeltaCommand::add(const boost::shared_ptr<Note> note)
@@ -602,28 +615,28 @@ MidiModel::DeltaCommand::operator()()
// removed notes (or sort here), and doing a single iteration over _model
// Need to reset iterator to drop the read lock it holds, or we'll deadlock
- const bool reset_iter = (_model._read_iter.locked());
- const double iter_time = _model._read_iter->time();
+ const bool reset_iter = (_model->_read_iter.locked());
+ const double iter_time = _model->_read_iter->time();
if (reset_iter)
- _model._read_iter = _model.end(); // drop read lock
+ _model->_read_iter = _model->end(); // drop read lock
- assert( ! _model._read_iter.locked());
+ assert( ! _model->_read_iter.locked());
- _model.write_lock();
+ _model->write_lock();
for (std::list< boost::shared_ptr<Note> >::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
- _model.add_note_unlocked(*i);
+ _model->add_note_unlocked(*i);
for (std::list< boost::shared_ptr<Note> >::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
- _model.remove_note_unlocked(*i);
+ _model->remove_note_unlocked(*i);
- _model.write_unlock();
+ _model->write_unlock();
if (reset_iter)
- _model._read_iter = const_iterator(_model, iter_time);
+ _model->_read_iter = const_iterator(*_model.get(), iter_time);
- _model.ContentsChanged(); /* EMIT SIGNAL */
+ _model->ContentsChanged(); /* EMIT SIGNAL */
}
@@ -634,28 +647,28 @@ MidiModel::DeltaCommand::undo()
// removed notes (or sort here), and doing a single iteration over _model
// Need to reset iterator to drop the read lock it holds, or we'll deadlock
- const bool reset_iter = (_model._read_iter.locked());
- const double iter_time = _model._read_iter->time();
+ const bool reset_iter = (_model->_read_iter.locked());
+ const double iter_time = _model->_read_iter->time();
if (reset_iter)
- _model._read_iter = _model.end(); // drop read lock
+ _model->_read_iter = _model->end(); // drop read lock
- assert( ! _model._read_iter.locked());
+ assert( ! _model->_read_iter.locked());
- _model.write_lock();
+ _model->write_lock();
for (std::list< boost::shared_ptr<Note> >::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i)
- _model.remove_note_unlocked(*i);
+ _model->remove_note_unlocked(*i);
for (std::list< boost::shared_ptr<Note> >::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i)
- _model.add_note_unlocked(*i);
+ _model->add_note_unlocked(*i);
- _model.write_unlock();
+ _model->write_unlock();
if (reset_iter)
- _model._read_iter = const_iterator(_model, iter_time);
+ _model->_read_iter = const_iterator(*_model.get(), iter_time);
- _model.ContentsChanged(); /* EMIT SIGNAL */
+ _model->ContentsChanged(); /* EMIT SIGNAL */
}
XMLNode &
@@ -708,9 +721,6 @@ MidiModel::DeltaCommand::unmarshal_note(XMLNode *xml_note)
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;
}
@@ -745,8 +755,7 @@ 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());
- delta_command->add_property("midi_source_name", _model.midi_source().name());
+ delta_command->add_property("midi_source", _model->midi_source()->id().to_s());
XMLNode *added_notes = delta_command->add_child(ADDED_NOTES_ELEMENT);
for_each(_added_notes.begin(), _added_notes.end(),
@@ -761,11 +770,6 @@ MidiModel::DeltaCommand::get_state ()
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 7b2c4009bb..aa93729d37 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(*this))
+ , _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(*this))
+ , _model(new MidiModel(this))
, _writing (false)
{
_read_data_count = 0;
@@ -192,12 +192,13 @@ MidiSource::session_saved()
newsrc->set_timeline_position(_timeline_position);
_model->write_to(newsrc);
+ // cyclic dependency here, ugly :(
newsrc->set_model(_model);
- _model.reset();
+ _model->set_midi_source(newsrc.get());
newsrc->flush_header();
newsrc->flush_footer();
-
+
Switched.emit(newsrc);
}
}
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index a2575caadd..0d0499b5a1 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -2994,7 +2994,7 @@ Session::restore_history (string snapshot_name)
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));
+ ut->add_command(new MidiModel::DeltaCommand(midi_source->model(), *n));
} else {
error << "FIXME: Failed to downcast MidiSource for DeltaCommand" << endmsg;
}
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index bee3fd96d4..aef011ed00 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(*this));
+ _model = boost::shared_ptr<MidiModel>(new MidiModel(this));
cerr << _name << " loaded new model " << _model.get() << endl;
} else {
cerr << _name << " reloading model " << _model.get()