summaryrefslogtreecommitdiff
path: root/gtk2_ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2009-09-09 16:46:18 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2009-09-09 16:46:18 +0000
commit5f319d0a08a4950f4cb8ee1bdc39f35bfce088bc (patch)
treecb5bec0a2fabe857984c7022c4b624562137a107 /gtk2_ardour
parent58f5ad640672d3ac0193b36befaa8d53dddefecf (diff)
re-use canvas note items when the model changes ; slightly more efficient (probably) and avoids invalidating references to said items in, for example, ResizeData in a copied region
git-svn-id: svn://localhost/ardour2/branches/3.0@5650 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/canvas-note-event.cc13
-rw-r--r--gtk2_ardour/canvas-note-event.h5
-rw-r--r--gtk2_ardour/editor_drag.cc1
-rw-r--r--gtk2_ardour/midi_region_view.cc162
-rw-r--r--gtk2_ardour/midi_region_view.h6
5 files changed, 143 insertions, 44 deletions
diff --git a/gtk2_ardour/canvas-note-event.cc b/gtk2_ardour/canvas-note-event.cc
index 9404c15c2d..55e31db4e1 100644
--- a/gtk2_ardour/canvas-note-event.cc
+++ b/gtk2_ardour/canvas-note-event.cc
@@ -47,6 +47,7 @@ CanvasNoteEvent::CanvasNoteEvent(MidiRegionView& region, Item* item,
, _state(None)
, _note(note)
, _selected(false)
+ , _valid (true)
{
}
@@ -60,6 +61,18 @@ CanvasNoteEvent::~CanvasNoteEvent()
delete _channel_selector_widget;
}
+void
+CanvasNoteEvent::invalidate ()
+{
+ _valid = false;
+}
+
+void
+CanvasNoteEvent::validate ()
+{
+ _valid = true;
+}
+
void
CanvasNoteEvent::move_event(double dx, double dy)
{
diff --git a/gtk2_ardour/canvas-note-event.h b/gtk2_ardour/canvas-note-event.h
index ec306d29b8..6b394e1bb5 100644
--- a/gtk2_ardour/canvas-note-event.h
+++ b/gtk2_ardour/canvas-note-event.h
@@ -66,6 +66,10 @@ public:
virtual void hide() = 0;
virtual bool on_event(GdkEvent* ev);
+ bool valid() const { return _valid; }
+ void invalidate ();
+ void validate ();
+
bool selected() const { return _selected; }
void selected(bool yn);
@@ -129,6 +133,7 @@ protected:
const boost::shared_ptr<NoteType> _note;
bool _own_note;
bool _selected;
+ bool _valid;
};
} // namespace Gnome
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index 0469e45e36..e54f4877bd 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -1457,6 +1457,7 @@ NoteResizeDrag::finished (GdkEvent* event, bool movement_occurred)
MidiRegionSelection::iterator next;
next = r;
++next;
+ cerr << "Working on MRV " << (*r)->midi_region()->name() << endl;
(*r)->commit_resizing (at_front, _current_pointer_x - _grab_x, relative);
r = next;
}
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 4ef0ead38e..a033148cb8 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -724,6 +724,20 @@ MidiRegionView::abort_command()
clear_selection();
}
+CanvasNoteEvent*
+MidiRegionView::find_canvas_note (boost::shared_ptr<NoteType> note)
+{
+ /* XXX optimize the crap out of this SOON */
+
+ for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
+ if ((*i)->note() == note) {
+ return *i;
+ }
+ }
+
+ return 0;
+}
+
void
MidiRegionView::redisplay_model()
{
@@ -738,17 +752,51 @@ MidiRegionView::redisplay_model()
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
_marked_for_selection.insert((*i)->note());
}
+
+ for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
+ (*i)->invalidate ();
+ }
- clear_events();
_model->read_lock();
MidiModel::Notes notes = _model->notes();
for (size_t i = 0; i < _model->n_notes(); ++i) {
boost::shared_ptr<NoteType> note (_model->note_at (i));
+
if (note_in_visible_range (note)) {
- add_note (note);
+ CanvasNoteEvent* cne;
+
+ if ((cne = find_canvas_note (note)) != 0) {
+
+ cne->validate ();
+
+ CanvasNote* cn;
+ CanvasHit* ch;
+
+ if ((cn = dynamic_cast<CanvasNote*>(cne)) != 0) {
+ update_note (cn);
+ } else if ((ch = dynamic_cast<CanvasHit*>(cne)) != 0) {
+ update_hit (ch);
+ }
+
+ } else {
+
+ add_note (note);
+ }
+ }
+ }
+
+ /* remove note items that are no longer valid */
+
+ for (Events::iterator i = _events.begin(); i != _events.end(); ) {
+ if (!(*i)->valid ()) {
+ cerr << "Canvas note " << *i << " is invalid, deleting\n";
+ delete *i;
+ i = _events.erase (i);
+ } else {
+ ++i;
}
}
@@ -1100,6 +1148,64 @@ MidiRegionView::note_in_visible_range(const boost::shared_ptr<NoteType> note) co
return !outside;
}
+void
+MidiRegionView::update_note (CanvasNote* ev)
+{
+ boost::shared_ptr<NoteType> note = ev->note();
+
+ const nframes64_t note_start_frames = beats_to_frames(note->time());
+ const nframes64_t note_end_frames = beats_to_frames(note->end_time());
+
+ const double x = trackview.editor().frame_to_pixel(note_start_frames - _region->start());
+
+
+ const double y1 = midi_stream_view()->note_to_y(note->note());
+ const double note_endpixel =
+ trackview.editor().frame_to_pixel(note_end_frames - _region->start());
+
+ ev->property_x1() = x;
+ ev->property_y1() = y1;
+ if (note->length() > 0) {
+ ev->property_x2() = note_endpixel;
+ } else {
+ ev->property_x2() = trackview.editor().frame_to_pixel(_region->length());
+ }
+ ev->property_y2() = y1 + floor(midi_stream_view()->note_height());
+
+ if (note->length() == 0) {
+ if (_active_notes) {
+ assert(note->note() < 128);
+ // If this note is already active there's a stuck note,
+ // finish the old note rectangle
+ if (_active_notes[note->note()]) {
+ CanvasNote* const old_rect = _active_notes[note->note()];
+ boost::shared_ptr<NoteType> old_note = old_rect->note();
+ old_rect->property_x2() = x;
+ old_rect->property_outline_what() = (guint32) 0xF;
+ }
+ _active_notes[note->note()] = ev;
+ }
+ /* outline all but right edge */
+ ev->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8);
+ } else {
+ /* outline all edges */
+ ev->property_outline_what() = (guint32) 0xF;
+ }
+}
+
+void
+MidiRegionView::update_hit (CanvasHit* ev)
+{
+ boost::shared_ptr<NoteType> note = ev->note();
+
+ const nframes64_t note_start_frames = beats_to_frames(note->time());
+ const double x = trackview.editor().frame_to_pixel(note_start_frames - _region->start());
+ const double diamond_size = midi_stream_view()->note_height() / 2.0;
+ const double y = midi_stream_view()->note_to_y(note->note()) + ((diamond_size-2) / 4.0);
+
+ ev->move(x, y);
+}
+
/** Add a MIDI note to the view (with length).
*
* If in sustained mode, notes with length 0 will be considered active
@@ -1109,56 +1215,23 @@ MidiRegionView::note_in_visible_range(const boost::shared_ptr<NoteType> note) co
void
MidiRegionView::add_note(const boost::shared_ptr<NoteType> note)
{
+ CanvasNoteEvent* event = 0;
+
assert(note->time() >= 0);
assert(midi_view()->note_mode() == Sustained || midi_view()->note_mode() == Percussive);
- const nframes64_t note_start_frames = beats_to_frames(note->time());
- const nframes64_t note_end_frames = beats_to_frames(note->end_time());
-
ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
- CanvasNoteEvent* event = 0;
-
- const double x = trackview.editor().frame_to_pixel(note_start_frames - _region->start());
-
if (midi_view()->note_mode() == Sustained) {
- const double y1 = midi_stream_view()->note_to_y(note->note());
- const double note_endpixel =
- trackview.editor().frame_to_pixel(note_end_frames - _region->start());
CanvasNote* ev_rect = new CanvasNote(*this, *group, note);
- ev_rect->property_x1() = x;
- ev_rect->property_y1() = y1;
- if (note->length() > 0) {
- ev_rect->property_x2() = note_endpixel;
- } else {
- ev_rect->property_x2() = trackview.editor().frame_to_pixel(_region->length());
- }
- ev_rect->property_y2() = y1 + floor(midi_stream_view()->note_height());
-
- if (note->length() == 0) {
- if (_active_notes) {
- assert(note->note() < 128);
- // If this note is already active there's a stuck note,
- // finish the old note rectangle
- if (_active_notes[note->note()]) {
- CanvasNote* const old_rect = _active_notes[note->note()];
- boost::shared_ptr<NoteType> old_note = old_rect->note();
- old_rect->property_x2() = x;
- old_rect->property_outline_what() = (guint32) 0xF;
- }
- _active_notes[note->note()] = ev_rect;
- }
- /* outline all but right edge */
- ev_rect->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8);
- } else {
- /* outline all edges */
- ev_rect->property_outline_what() = (guint32) 0xF;
- }
+
+ update_note (ev_rect);
event = ev_rect;
MidiGhostRegion* gr;
+
for (std::vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) {
if ((gr = dynamic_cast<MidiGhostRegion*>(*g)) != 0) {
gr->add_note(ev_rect);
@@ -1166,12 +1239,15 @@ MidiRegionView::add_note(const boost::shared_ptr<NoteType> note)
}
} else if (midi_view()->note_mode() == Percussive) {
+
const double diamond_size = midi_stream_view()->note_height() / 2.0;
- const double y = midi_stream_view()->note_to_y(note->note()) + ((diamond_size-2) / 4.0);
CanvasHit* ev_diamond = new CanvasHit(*this, *group, diamond_size, note);
- ev_diamond->move(x, y);
+
+ update_hit (ev_diamond);
+
event = ev_diamond;
+
} else {
event = 0;
}
@@ -1860,8 +1936,6 @@ MidiRegionView::trim_note (CanvasNoteEvent* event, Evoral::MusicalTime front_del
if negative - move the end of the note earlier in time (shortening it)
*/
- cerr << "Trim front by " << front_delta << " end by " << end_delta << endl;
-
if (front_delta) {
if (front_delta < 0) {
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index 8bbd535a48..63c6a481de 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -37,6 +37,7 @@
#include "automation_line.h"
#include "enums.h"
#include "canvas.h"
+#include "canvas-hit.h"
#include "canvas-note.h"
#include "canvas-note-event.h"
#include "canvas-program-change.h"
@@ -381,6 +382,11 @@ class MidiRegionView : public RegionView
/* connection used to connect to model's ContentChanged signal */
sigc::connection content_connection;
+
+ ArdourCanvas::CanvasNoteEvent* find_canvas_note (boost::shared_ptr<NoteType>);
+ void update_note (ArdourCanvas::CanvasNote*);
+ void update_hit (ArdourCanvas::CanvasHit*);
+
};