summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-07-17 01:48:42 +0000
committerDavid Robillard <d@drobilla.net>2007-07-17 01:48:42 +0000
commitf542fa693cef524c066d9bf632ac6c12263d8fe6 (patch)
tree47d90d349ff8caa53b5b2ab6a2fedb196b072d42 /libs
parent37c74810d22f6ef392366e40a9f03dd8da16da18 (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.h43
-rw-r--r--libs/ardour/ardour/session.h87
-rw-r--r--libs/ardour/midi_model.cc102
-rw-r--r--libs/ardour/midi_source.cc4
-rw-r--r--libs/ardour/smf_source.cc2
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();