diff options
author | David Robillard <d@drobilla.net> | 2007-07-17 01:48:42 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2007-07-17 01:48:42 +0000 |
commit | f542fa693cef524c066d9bf632ac6c12263d8fe6 (patch) | |
tree | 47d90d349ff8caa53b5b2ab6a2fedb196b072d42 /libs | |
parent | 37c74810d22f6ef392366e40a9f03dd8da16da18 (diff) |
Midi pencil undo (not yet serializable).
Formatting fixes for session.h (ie kill more of those damned 8 space expanded tabs).
git-svn-id: svn://localhost/ardour2/trunk@2135 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/midi_model.h | 43 | ||||
-rw-r--r-- | libs/ardour/ardour/session.h | 87 | ||||
-rw-r--r-- | libs/ardour/midi_model.cc | 102 | ||||
-rw-r--r-- | libs/ardour/midi_source.cc | 4 | ||||
-rw-r--r-- | libs/ardour/smf_source.cc | 2 |
5 files changed, 189 insertions, 49 deletions
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index ff52398180..36c5fe1212 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -22,11 +22,15 @@ #define __ardour_midi_model_h__ #include <boost/utility.hpp> +#include <pbd/command.h> #include <ardour/types.h> #include <ardour/midi_buffer.h> namespace ARDOUR { +class Session; + + /** This is a slightly higher level (than MidiBuffer) model of MIDI note data. * Currently it only represents note data, which is represented as complete * note events (ie with a start time and a duration) rather than separate @@ -39,13 +43,16 @@ public: Note(double s=0, double d=0, uint8_t n=0, uint8_t v=0) : start(s), duration(d), note(n), velocity(v) {} + inline bool operator==(const Note& other) + { return start == other.start && note == other.note; } + double start; double duration; uint8_t note; uint8_t velocity; }; - MidiModel(size_t size=0); + MidiModel(Session& s, size_t size=0); void clear() { _notes.clear(); } @@ -73,13 +80,47 @@ public: inline Notes& notes() { return _notes; } inline const Notes& notes() const { return _notes; } + void begin_command(); + Command* current_command() { return _command; } + void finish_command(); + + // Commands + void add_note(const Note& note); + void remove_note(const Note& note); + + sigc::signal<void> ContentsChanged; + private: + class MidiEditCommand : public Command + { + public: + MidiEditCommand (MidiModel& m) : _model(m) {} + //MidiEditCommand (MidiModel&, const XMLNode& node); + + void operator()(); + void undo(); + + /*int set_state (const XMLNode&); + XMLNode& get_state ();*/ + + void add_note(const Note& note); + void remove_note(const Note& note); + + private: + MidiModel& _model; + std::list<Note> _added_notes; + std::list<Note> _removed_notes; + }; void append_note_on(double time, uint8_t note, uint8_t velocity); void append_note_off(double time, uint8_t note); + Session& _session; + Notes _notes; Notes _write_notes; + + MidiEditCommand* _command; ///< In-progress command }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 8a51653968..5ba2e39526 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -487,7 +487,7 @@ class Session : public PBD::StatefulDestructible void resort_routes (); void resort_routes_using (boost::shared_ptr<RouteList>); - void set_remote_control_ids(); + void set_remote_control_ids(); AudioEngine &engine() { return _engine; }; @@ -538,7 +538,7 @@ class Session : public PBD::StatefulDestructible void request_slave_source (SlaveSource); bool synced_to_jack() const { return Config->get_slave_source() == JACK; } - float transport_speed() const { return _transport_speed; } + float transport_speed() const { return _transport_speed; } bool transport_stopped() const { return _transport_speed == 0.0f; } bool transport_rolling() const { return _transport_speed != 0.0f; } @@ -595,8 +595,8 @@ class Session : public PBD::StatefulDestructible void remove_source (boost::weak_ptr<Source>); struct cleanup_report { - vector<string> paths; - int64_t space; + vector<string> paths; + int64_t space; }; int cleanup_sources (cleanup_report&); @@ -673,8 +673,9 @@ class Session : public PBD::StatefulDestructible /* flattening stuff */ - int write_one_audio_track (AudioTrack&, nframes_t start, nframes_t cnt, bool overwrite, vector<boost::shared_ptr<Source> >&, - InterThreadInfo& wot); + int write_one_audio_track (AudioTrack&, nframes_t start, nframes_t cnt, bool overwrite, + vector<boost::shared_ptr<Source> >&, InterThreadInfo& wot); + int freeze (InterThreadInfo&); /* session-wide solo/mute/rec-enable */ @@ -803,8 +804,8 @@ class Session : public PBD::StatefulDestructible }; - class GlobalSoloStateCommand : public GlobalRouteStateCommand - { + class GlobalSoloStateCommand : public GlobalRouteStateCommand + { public: GlobalSoloStateCommand (Session &, void *src); GlobalSoloStateCommand (Session&, const XMLNode&); @@ -812,10 +813,10 @@ class Session : public PBD::StatefulDestructible void undo(); XMLNode &get_state(); void mark(); - }; + }; - class GlobalMuteStateCommand : public GlobalRouteStateCommand - { + class GlobalMuteStateCommand : public GlobalRouteStateCommand + { public: GlobalMuteStateCommand(Session &, void *src); GlobalMuteStateCommand (Session&, const XMLNode&); @@ -823,10 +824,10 @@ class Session : public PBD::StatefulDestructible void undo(); XMLNode &get_state(); void mark(); - }; + }; - class GlobalRecordEnableStateCommand : public GlobalRouteStateCommand - { + class GlobalRecordEnableStateCommand : public GlobalRouteStateCommand + { public: GlobalRecordEnableStateCommand(Session &, void *src); GlobalRecordEnableStateCommand (Session&, const XMLNode&); @@ -834,10 +835,10 @@ class Session : public PBD::StatefulDestructible void undo(); XMLNode &get_state(); void mark(); - }; + }; - class GlobalMeteringStateCommand : public Command - { + class GlobalMeteringStateCommand : public Command + { public: GlobalMeteringStateCommand(Session &, void *src); GlobalMeteringStateCommand (Session&, const XMLNode&); @@ -852,7 +853,7 @@ class Session : public PBD::StatefulDestructible void* src; GlobalRouteMeterState before; GlobalRouteMeterState after; - }; + }; /* clicking */ @@ -861,14 +862,14 @@ class Session : public PBD::StatefulDestructible /* tempo FX */ struct TimeStretchRequest { - boost::shared_ptr<ARDOUR::AudioRegion> region; - float fraction; /* session: read ; GUI: write */ - float progress; /* session: write ; GUI: read */ - bool running; /* read/write */ - bool quick_seek; /* GUI: write */ - bool antialias; /* GUI: write */ - - TimeStretchRequest () {} + boost::shared_ptr<ARDOUR::AudioRegion> region; + float fraction; /* session: read ; GUI: write */ + float progress; /* session: write ; GUI: read */ + bool running; /* read/write */ + bool quick_seek; /* GUI: write */ + bool antialias; /* GUI: write */ + + TimeStretchRequest () {} }; boost::shared_ptr<AudioRegion> tempoize_region (TimeStretchRequest&); @@ -1088,9 +1089,9 @@ class Session : public PBD::StatefulDestructible bool session_midi_feedback; bool play_loop; bool loop_changing; - nframes_t last_loopend; + nframes_t last_loopend; - boost::scoped_ptr<SessionDirectory> _session_dir; + boost::scoped_ptr<SessionDirectory> _session_dir; RingBuffer<Event*> pending_events; @@ -1110,11 +1111,11 @@ class Session : public PBD::StatefulDestructible int load_state (string snapshot_name); bool save_config_options_predicate (ConfigVariableBase::Owner owner) const; - nframes_t _last_roll_location; - nframes_t _last_record_location; - bool pending_locate_roll; - nframes_t pending_locate_frame; + nframes_t _last_roll_location; + nframes_t _last_record_location; + bool pending_locate_roll; + nframes_t pending_locate_frame; bool pending_locate_flush; bool pending_abort; bool pending_auto_loop; @@ -1123,7 +1124,7 @@ class Session : public PBD::StatefulDestructible float* butler_gain_buffer; pthread_t butler_thread; Glib::Mutex butler_request_lock; - Glib::Cond butler_paused; + Glib::Cond butler_paused; bool butler_should_run; mutable gint butler_should_do_transport_work; int butler_request_pipe[2]; @@ -1512,13 +1513,13 @@ class Session : public PBD::StatefulDestructible /* INSERT AND SEND MANAGEMENT */ - list<PortInsert *> _port_inserts; - list<PluginInsert *> _plugin_inserts; - list<Send *> _sends; - boost::dynamic_bitset<uint32_t> send_bitset; - boost::dynamic_bitset<uint32_t> insert_bitset; - uint32_t send_cnt; - uint32_t insert_cnt; + list<PortInsert *> _port_inserts; + list<PluginInsert *> _plugin_inserts; + list<Send *> _sends; + boost::dynamic_bitset<uint32_t> send_bitset; + boost::dynamic_bitset<uint32_t> insert_bitset; + uint32_t send_cnt; + uint32_t insert_cnt; void add_processor (Processor *); @@ -1605,7 +1606,7 @@ class Session : public PBD::StatefulDestructible pool.release (ptr); } - private: + private: static Pool pool; }; @@ -1620,9 +1621,9 @@ class Session : public PBD::StatefulDestructible nframes_t click_emphasis_length; mutable Glib::RWLock click_lock; - static const Sample default_click[]; + static const Sample default_click[]; static const nframes_t default_click_length; - static const Sample default_click_emphasis[]; + static const Sample default_click_emphasis[]; static const nframes_t default_click_emphasis_length; Click *get_click(); diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 98d29a2729..2d4a44d437 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -22,13 +22,16 @@ #include <ardour/midi_model.h> #include <ardour/midi_events.h> #include <ardour/types.h> +#include <ardour/session.h> using namespace std; using namespace ARDOUR; -MidiModel::MidiModel(size_t size) - : _notes(size) +MidiModel::MidiModel(Session& s, size_t size) + : _session(s) + , _notes(size) + , _command(NULL) { } @@ -140,3 +143,98 @@ MidiModel::append_note_off(double time, uint8_t note_num) } } + +void +MidiModel::add_note(const Note& note) +{ + Notes::iterator i = upper_bound(_notes.begin(), _notes.end(), note, NoteTimeComparator()); + _notes.insert(i, note); + if (_command) + _command->add_note(note); +} + + +void +MidiModel::remove_note(const Note& note) +{ + Notes::iterator n = find(_notes.begin(), _notes.end(), note); + if (n != _notes.end()) + _notes.erase(n); + + if (_command) + _command->remove_note(note); +} + + + +void +MidiModel::begin_command() +{ + assert(!_command); + _session.begin_reversible_command("midi edit"); + _command = new MidiEditCommand(*this); +} + + +void +MidiModel::finish_command() +{ + _session.commit_reversible_command(_command); + _command = NULL; +} + + +// MidiEditCommand + + +void +MidiModel::MidiEditCommand::add_note(const Note& note) +{ + //cerr << "MEC: apply" << endl; + + _removed_notes.remove(note); + _added_notes.push_back(note); +} + + +void +MidiModel::MidiEditCommand::remove_note(const Note& note) +{ + //cerr << "MEC: remove" << endl; + + _added_notes.remove(note); + _removed_notes.push_back(note); +} + + +void +MidiModel::MidiEditCommand::operator()() +{ + //cerr << "MEC: apply" << endl; + assert(!_model.current_command()); + + for (std::list<Note>::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) + _model.add_note(*i); + + for (std::list<Note>::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i) + _model.remove_note(*i); + + _model.ContentsChanged(); /* EMIT SIGNAL */ +} + + +void +MidiModel::MidiEditCommand::undo() +{ + //cerr << "MEC: undo" << endl; + assert(!_model.current_command()); + + for (std::list<Note>::iterator i = _added_notes.begin(); i != _added_notes.end(); ++i) + _model.remove_note(*i); + + for (std::list<Note>::iterator i = _removed_notes.begin(); i != _removed_notes.end(); ++i) + _model.add_note(*i); + + _model.ContentsChanged(); /* EMIT SIGNAL */ +} + diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index a346bfd4f2..f2a3121be2 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -44,7 +44,7 @@ sigc::signal<void,MidiSource *> MidiSource::MidiSourceCreated; MidiSource::MidiSource (Session& s, string name) : Source (s, name, DataType::MIDI) - , _model(new MidiModel()) + , _model(new MidiModel(s)) , _model_loaded (false) { _read_data_count = 0; @@ -53,7 +53,7 @@ MidiSource::MidiSource (Session& s, string name) MidiSource::MidiSource (Session& s, const XMLNode& node) : Source (s, node) - , _model(new MidiModel()) + , _model(new MidiModel(s)) , _model_loaded (false) { _read_data_count = 0; diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 39b8252a8a..e7ae4a3239 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -787,7 +787,7 @@ SMFSource::load_model(bool lock, bool force_reload) } if (! _model) - _model = new MidiModel(); + _model = new MidiModel(_session); _model->start_write(); |