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
This commit is contained in:
parent
58f5ad6406
commit
5f319d0a08
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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*);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user