, _channel_selection_scoped_note (0)
, _mouse_state(None)
, _pressed_button(0)
- , _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, _no_sound_notes (false)
, _channel_selection_scoped_note (0)
, _mouse_state(None)
, _pressed_button(0)
- , _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, _no_sound_notes (false)
if (_enable_display) {
redisplay_model();
}
+ } else if (p == "color-regions-using-track-color") {
+ set_colors ();
}
}
, _channel_selection_scoped_note (0)
, _mouse_state(None)
, _pressed_button(0)
- , _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, _no_sound_notes (false)
, _channel_selection_scoped_note (0)
, _mouse_state(None)
, _pressed_button(0)
- , _sort_needed (true)
, _optimization_iterator (_events.end())
, _list_editor (0)
, _no_sound_notes (false)
gui_context ());
Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
+ UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MidiRegionView::parameter_changed));
connect_to_diskstream ();
}
start_note_diff_command(_("add note"));
- clear_editor_note_selection ();
note_diff_add_note (new_note, true, false);
apply_diff();
}
}
- for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- delete *i;
- }
+ _note_group->clear (true);
_events.clear();
_patch_changes.clear();
_sys_exes.clear();
content_connection.disconnect ();
_model->ContentsChanged.connect (content_connection, invalidator (*this), boost::bind (&MidiRegionView::redisplay_model, this), gui_context());
/* Don't signal as nobody else needs to know until selection has been altered. */
- clear_events ();
+ clear_events();
if (_enable_display) {
redisplay_model();
}
void
-MidiRegionView::apply_diff (bool as_subcommand)
+MidiRegionView::apply_diff (bool as_subcommand, bool was_copy)
{
bool add_or_remove;
bool commit = false;
return;
}
- if ((add_or_remove = _note_diff_command->adds_or_removes())) {
+ if (!was_copy && (add_or_remove = _note_diff_command->adds_or_removes())) {
// Mark all selected notes for selection when model reloads
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
_marked_for_selection.insert((*i)->note());
}
}
- midi_view()->midi_track()->midi_playlist()->region_edited(
- _region, _note_diff_command);
+ midi_view()->midi_track()->midi_playlist()->region_edited (_region, _note_diff_command);
if (as_subcommand) {
_model->apply_command_as_subcommand (*trackview.session(), _note_diff_command);
{
delete _note_diff_command;
_note_diff_command = 0;
+ trackview.editor().abort_reversible_command();
clear_editor_note_selection();
}
NoteBase*
MidiRegionView::find_canvas_note (boost::shared_ptr<NoteType> note)
{
+
if (_optimization_iterator != _events.end()) {
++_optimization_iterator;
}
- if (_optimization_iterator != _events.end() && (*_optimization_iterator)->note() == note) {
- return *_optimization_iterator;
+ if (_optimization_iterator != _events.end() && _optimization_iterator->first == note) {
+ return _optimization_iterator->second;
}
- for (_optimization_iterator = _events.begin(); _optimization_iterator != _events.end(); ++_optimization_iterator) {
- if ((*_optimization_iterator)->note() == note) {
- return *_optimization_iterator;
- }
+ _optimization_iterator = _events.find (note);
+ if (_optimization_iterator != _events.end()) {
+ return _optimization_iterator->second;
}
return 0;
Events::iterator it;
for (it = _events.begin(); it != _events.end(); ++it) {
- if ((*it)->note()->id() == id) {
- return *it;
+ if (it->first->id() == id) {
+ return it->second;
}
}
boost::shared_ptr<PatchChange>
MidiRegionView::find_canvas_patch_change (MidiModel::PatchChangePtr p)
{
- for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) {
- if ((*x)->patch() == p) {
- return (*x);
- }
+ PatchChanges::const_iterator f = _patch_changes.find (p);
+
+ if (f != _patch_changes.end()) {
+ return f->second;
}
return boost::shared_ptr<PatchChange>();
}
+boost::shared_ptr<SysEx>
+MidiRegionView::find_canvas_sys_ex (MidiModel::SysExPtr s)
+{
+ SysExes::const_iterator f = _sys_exes.find (s);
+
+ if (f != _sys_exes.end()) {
+ return f->second;
+ }
+
+ return boost::shared_ptr<SysEx>();
+}
+
void
MidiRegionView::get_events (Events& e, Evoral::Sequence<Evoral::Beats>::NoteOperator op, uint8_t val, int chan_mask)
{
for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) {
NoteBase* cne = find_canvas_note (*n);
if (cne) {
- e.push_back (cne);
+ e.insert (make_pair (*n, cne));
}
}
}
touching model. Leave active notes (with length 0) alone since
they are being extended. */
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->note()->length() > 0) {
- update_note(*i);
+ if (i->second->note()->length() > 0) {
+ update_note(i->second);
}
}
_last_display_zoom = zoom;
return;
}
+ for (_optimization_iterator = _events.begin(); _optimization_iterator != _events.end(); ++_optimization_iterator) {
+ _optimization_iterator->second->invalidate();
+ }
+
bool empty_when_starting = _events.empty();
- MidiModel::ReadLock lock(_model->read_lock());
- MidiModel::Notes missing_notes = _model->notes(); // copy
+ _optimization_iterator = _events.begin();
+ MidiModel::Notes missing_notes;
Note* sus = NULL;
Hit* hit = NULL;
- if (!empty_when_starting) {
- MidiModel::Notes::iterator f;
- for (Events::iterator i = _events.begin(); i != _events.end(); ) {
- boost::shared_ptr<NoteType> note = (*i)->note();
+ MidiModel::ReadLock lock(_model->read_lock());
+ MidiModel::Notes& notes (_model->notes());
- /* if event item's note exists in the model, we can just update it.
- * don't mark it as missing.
- */
- if ((f = missing_notes.find (note)) != missing_notes.end()) {
- if ((*f) == note) {
- (*i)->validate();
- missing_notes.erase (f);
+ NoteBase* cne;
+ for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) {
+
+ boost::shared_ptr<NoteType> note (*n);
+ bool visible;
+
+ if (note_in_region_range (note, visible)) {
+ if (!empty_when_starting && (cne = find_canvas_note (note)) != 0) {
+ cne->validate ();
+ if (visible) {
+ cne->show ();
} else {
- (*i)->invalidate();
+ cne->hide ();
}
-
} else {
- (*i)->invalidate();
+ missing_notes.insert (note);
}
+ }
+ }
+
+ if (!empty_when_starting) {
+ MidiModel::Notes::iterator f;
+ for (Events::iterator i = _events.begin(); i != _events.end(); ) {
+
+ NoteBase* cne = i->second;
+
/* remove note items that are no longer valid */
- if (!(*i)->valid()) {
+ if (!cne->valid()) {
for (vector<GhostRegion*>::iterator j = ghosts.begin(); j != ghosts.end(); ++j) {
MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*j);
if (gr) {
- gr->remove_note (*i);
+ gr->remove_note (cne);
}
}
- delete *i;
+ delete cne;
i = _events.erase (i);
} else {
- NoteBase* cne = (*i);
- bool visible;
- bool update = false;
+ bool visible = cne->item()->visible();
- if (note_in_region_range (note, visible)) {
- if (visible) {
- update = true;
- cne->show ();
- } else {
- cne->hide ();
- }
- } else {
- cne->hide ();
- }
if ((sus = dynamic_cast<Note*>(cne))) {
- if (update) {
+ if (visible) {
update_sustained (sus);
}
- for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
- MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
- if (gr) {
- gr->update_note (sus);
- }
- }
} else if ((hit = dynamic_cast<Hit*>(cne))) {
- if (update) {
+ if (visible) {
update_hit (hit);
}
- for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
- MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
- if (gr) {
- gr->update_hit (hit);
- }
- }
}
++i;
}
}
}
-
for (MidiModel::Notes::iterator n = missing_notes.begin(); n != missing_notes.end(); ++n) {
boost::shared_ptr<NoteType> note (*n);
- NoteBase* cne = add_note (note, true);
+ NoteBase* cne;
bool visible;
+ if (note_in_region_range (note, visible)) {
+ if (visible) {
+ cne = add_note (note, true);
+ } else {
+ cne = add_note (note, false);
+ }
+ } else {
+ cne = add_note (note, false);
+ }
+
for (set<Evoral::event_id_t>::iterator it = _pending_note_selection.begin(); it != _pending_note_selection.end(); ++it) {
if ((*it) == note->id()) {
add_to_selection (cne);
}
}
+ }
- if (note_in_region_range (note, visible)) {
- if (!visible) {
- cne->hide ();
- }
- } else {
- cne->hide ();
+ for (vector<GhostRegion*>::iterator j = ghosts.begin(); j != ghosts.end(); ++j) {
+ MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*j);
+ if (gr && !gr->trackview.hidden()) {
+ gr->redisplay_model ();
}
}
- _sys_exes.clear();
-
display_sysexes();
display_patch_changes ();
_marked_for_velocity.clear ();
_pending_note_selection.clear ();
- /* we may have caused _events to contain things out of order (e.g. if a note
- moved earlier or later). we don't generally need them in time order, but
- make a note that a sort is required for those cases that require it.
- */
-
- _sort_needed = true;
}
void
}
if ((p = find_canvas_patch_change (*i)) != 0) {
- framecnt_t region_frames = source_beats_to_region_frames ((*i)->time());
- const double x = trackview.editor().sample_to_pixel (region_frames);
- const string patch_name = instrument_info().get_patch_name ((*i)->bank(), (*i)->program(), channel);
- p->canvas_item()->set_position (ArdourCanvas::Duple (x, 1.0));
- p->flag()->set_text (patch_name);
+
+ const framecnt_t region_frames = source_beats_to_region_frames ((*i)->time());
+
+ if (region_frames < 0 || region_frames >= _region->length()) {
+ p->hide();
+ } else {
+ const double x = trackview.editor().sample_to_pixel (region_frames);
+ const string patch_name = instrument_info().get_patch_name ((*i)->bank(), (*i)->program(), channel);
+ p->canvas_item()->set_position (ArdourCanvas::Duple (x, 1.0));
+ p->set_text (patch_name);
+
+ p->show();
+ }
+
} else {
const string patch_name = instrument_info().get_patch_name ((*i)->bank(), (*i)->program(), channel);
add_canvas_patch_change (*i, patch_name, active_channel);
}
for (MidiModel::SysExes::const_iterator i = _model->sysexes().begin(); i != _model->sysexes().end(); ++i) {
- Evoral::Beats time = (*i)->time();
+ MidiModel::SysExPtr sysex_ptr = *i;
+ Evoral::Beats time = sysex_ptr->time();
if ((*i)->is_spp() || (*i)->is_mtc_quarter() || (*i)->is_mtc_full()) {
if (!display_periodic_messages) {
// CAIROCANVAS: no longer passing *i (the sysex event) to the
// SysEx canvas object!!!
+ boost::shared_ptr<SysEx> sysex = find_canvas_sys_ex (sysex_ptr);
- boost::shared_ptr<SysEx> sysex = boost::shared_ptr<SysEx>(
- new SysEx (*this, _note_group, text, height, x, 1.0));
+ if (!sysex) {
+ sysex = boost::shared_ptr<SysEx>(
+ new SysEx (*this, _note_group, text, height, x, 1.0, sysex_ptr));
+ _sys_exes.insert (make_pair (sysex_ptr, sysex));
+ } else {
+ sysex->set_height (height);
+ sysex->item().set_position (ArdourCanvas::Duple (x, 1.0));
+ }
// Show unless message is beyond the region bounds
if (time - _region->start() >= _region->length() || time < _region->start()) {
} else {
sysex->show();
}
-
- _sys_exes.push_back(sysex);
}
}
redisplay_model();
}
- for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) {
- if ((*x)->canvas_item()->width() >= _pixel_width) {
- (*x)->hide();
- } else {
- (*x)->show();
+ bool hide_all = false;
+ PatchChanges::iterator x = _patch_changes.begin();
+ if (x != _patch_changes.end()) {
+ hide_all = x->second->width() >= _pixel_width;
+ }
+
+ if (hide_all) {
+ for (; x != _patch_changes.end(); ++x) {
+ x->second->hide();
}
}
}
for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) {
- (*x)->set_height (midi_stream_view()->contents_height());
+ (*x).second->set_height (midi_stream_view()->contents_height());
}
if (_step_edit_cursor) {
ghost = new MidiGhostRegion (*this, tv, trackview, unit_position);
}
- for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- ghost->add_note(*i);
- }
-
ghost->set_colors ();
ghost->set_height ();
ghost->set_duration (_region->length() / samples_per_pixel);
- ghosts.push_back (ghost);
+ for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
+ ghost->add_note(i->second);
+ }
+
+ ghosts.push_back (ghost);
+ enable_display (true);
return ghost;
}
if (midi_view()->note_mode() == Sustained) {
- Note* ev_rect = new Note (*this, _note_group, note);
+ Note* ev_rect = new Note (*this, _note_group, note); // XXX may leak
update_sustained (ev_rect);
const double diamond_size = std::max(1., floor(note_height()) - 2.);
- Hit* ev_diamond = new Hit (*this, _note_group, diamond_size, note);
+ Hit* ev_diamond = new Hit (*this, _note_group, diamond_size, note); // XXX may leak
update_hit (ev_diamond);
}
event->on_channel_selection_change (get_selected_channels());
- _events.push_back(event);
+ _events.insert (make_pair (event->note(), event));
if (visible) {
event->show();
patch_change->hide ();
}
- _patch_changes.push_back (patch_change);
+ _patch_changes.insert (make_pair (patch, patch_change));
}
void
{
/* remove the canvas item */
for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) {
- if ((*x)->patch() == pc->patch()) {
+ if (x->second->patch() == pc->patch()) {
_patch_changes.erase (x);
break;
}
trackview.editor().commit_reversible_command ();
for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) {
- if ((*x)->patch() == old_change) {
+ if (x->second->patch() == old_change) {
_patch_changes.erase (x);
break;
}
void
MidiRegionView::add_patch_change (framecnt_t t, Evoral::PatchChange<Evoral::Beats> const & patch)
{
- MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
string name = _("add patch change");
trackview.editor().begin_reversible_command (name);
c->add (MidiModel::PatchChangePtr (
new Evoral::PatchChange<Evoral::Beats> (
absolute_frames_to_source_beats (_region->position() + t),
- mtv->get_channel_for_add(), patch.program(), patch.bank()
+ patch.channel(), patch.program(), patch.bank()
)
)
);
clear_editor_note_selection ();
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- add_to_selection (*i);
+ add_to_selection (i->second);
}
}
clear_editor_note_selection ();
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- framepos_t t = source_beats_to_absolute_frames((*i)->note()->time());
+ framepos_t t = source_beats_to_absolute_frames(i->first->time());
if (t >= start && t <= end) {
- add_to_selection (*i);
+ add_to_selection (i->second);
}
}
}
MidiRegionView::invert_selection ()
{
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->selected()) {
- remove_from_selection(*i);
+ if (i->second->selected()) {
+ remove_from_selection(i->second);
} else {
- add_to_selection (*i);
+ add_to_selection (i->second);
}
}
}
/* find notes entirely within OR spanning the earliest..latest range */
- if (((*i)->note()->time() >= earliest && (*i)->note()->end_time() <= latest) ||
- ((*i)->note()->time() <= earliest && (*i)->note()->end_time() >= latest)) {
- add_to_selection (*i);
+ if ((i->first->time() >= earliest && i->first->end_time() <= latest) ||
+ (i->first->time() <= earliest && i->first->end_time() >= latest)) {
+ add_to_selection (i->second);
}
-
}
}
}
// We probably need a tree to be able to find events in O(log(n)) time.
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->x0() < x1 && (*i)->x1() > x0 && (*i)->y0() < y1 && (*i)->y1() > y0) {
+ if (i->second->x0() < x1 && i->second->x1() > x0 && i->second->y0() < y1 && i->second->y1() > y0) {
// Rectangles intersect
- if (!(*i)->selected()) {
- add_to_selection (*i);
+ if (!i->second->selected()) {
+ add_to_selection (i->second);
}
- } else if ((*i)->selected() && !extend) {
+ } else if (i->second->selected() && !extend) {
// Rectangles do not intersect
- remove_from_selection (*i);
+ remove_from_selection (i->second);
}
}
// We probably need a tree to be able to find events in O(log(n)) time.
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if (((*i)->y1() >= y1 && (*i)->y1() <= y2)) {
+ if ((i->second->y1() >= y1 && i->second->y1() <= y2)) {
// within y- (note-) range
- if (!(*i)->selected()) {
- add_to_selection (*i);
+ if (!i->second->selected()) {
+ add_to_selection (i->second);
}
- } else if ((*i)->selected() && !extend) {
- remove_from_selection (*i);
+ } else if (i->second->selected() && !extend) {
+ remove_from_selection (i->second);
}
}
}
}
}
-void
-MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
+Evoral::Beats
+MidiRegionView::earliest_in_selection ()
{
- typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
- PossibleChord to_play;
Evoral::Beats earliest = Evoral::MaxBeats;
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
}
}
+ return earliest;
+}
+
+void
+MidiRegionView::move_selection(double dx_qn, double dy, double cumulative_dy)
+{
+ typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
+ Editor* editor = dynamic_cast<Editor*> (&trackview.editor());
+ TempoMap& tmap (editor->session()->tempo_map());
+ PossibleChord to_play;
+ Evoral::Beats earliest = earliest_in_selection();
+
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
- if ((*i)->note()->time() == earliest) {
- to_play.push_back ((*i)->note());
+ NoteBase* n = *i;
+ if (n->note()->time() == earliest) {
+ to_play.push_back (n->note());
}
+ double const note_time_qn = session_relative_qn (n->note()->time().to_double());
+ double dx = 0.0;
+ if (midi_view()->note_mode() == Sustained) {
+ dx = editor->sample_to_pixel_unrounded (tmap.frame_at_quarter_note (note_time_qn + dx_qn))
+ - n->item()->item_to_canvas (ArdourCanvas::Duple (n->x0(), 0)).x;
+ } else {
+ /* Hit::x0() is offset by _position.x, unlike Note::x0() */
+ Hit* hit = dynamic_cast<Hit*>(n);
+ if (hit) {
+ dx = editor->sample_to_pixel_unrounded (tmap.frame_at_quarter_note (note_time_qn + dx_qn))
+ - n->item()->item_to_canvas (ArdourCanvas::Duple (((hit->x0() + hit->x1()) / 2.0) - hit->position().x, 0)).x;
+ }
+ }
+
(*i)->move_event(dx, dy);
+
+ /* update length */
+ if (midi_view()->note_mode() == Sustained) {
+ Note* sus = dynamic_cast<Note*> (*i);
+ double const len_dx = editor->sample_to_pixel_unrounded (
+ tmap.frame_at_quarter_note (note_time_qn + dx_qn + n->note()->length().to_double()));
+
+ sus->set_x1 (n->item()->canvas_to_item (ArdourCanvas::Duple (len_dx, 0)).x);
+ }
}
if (dy && !_selection.empty() && !_no_sound_notes && UIConfiguration::instance().get_sound_midi_notes()) {
}
}
+NoteBase*
+MidiRegionView::copy_selection (NoteBase* primary)
+{
+ _copy_drag_events.clear ();
+
+ if (_selection.empty()) {
+ return 0;
+ }
+
+ NoteBase* note;
+ NoteBase* ret = 0;
+
+ for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ boost::shared_ptr<NoteType> g (new NoteType (*((*i)->note())));
+ if (midi_view()->note_mode() == Sustained) {
+ Note* n = new Note (*this, _note_group, g);
+ update_sustained (n, false);
+ note = n;
+ } else {
+ Hit* h = new Hit (*this, _note_group, 10, g);
+ update_hit (h, false);
+ note = h;
+ }
+
+ if ((*i) == primary) {
+ ret = note;
+ }
+
+ _copy_drag_events.push_back (note);
+ }
+
+ return ret;
+}
+
+void
+MidiRegionView::move_copies (double dx_qn, double dy, double cumulative_dy)
+{
+ typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
+ Editor* editor = dynamic_cast<Editor*> (&trackview.editor());
+ TempoMap& tmap (editor->session()->tempo_map());
+ PossibleChord to_play;
+ Evoral::Beats earliest = earliest_in_selection();
+
+ for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end(); ++i) {
+ NoteBase* n = *i;
+ if (n->note()->time() == earliest) {
+ to_play.push_back (n->note());
+ }
+ double const note_time_qn = session_relative_qn (n->note()->time().to_double());
+ double dx = 0.0;
+ if (midi_view()->note_mode() == Sustained) {
+ dx = editor->sample_to_pixel_unrounded (tmap.frame_at_quarter_note (note_time_qn + dx_qn))
+ - n->item()->item_to_canvas (ArdourCanvas::Duple (n->x0(), 0)).x;
+ } else {
+ Hit* hit = dynamic_cast<Hit*>(n);
+ if (hit) {
+ dx = editor->sample_to_pixel_unrounded (tmap.frame_at_quarter_note (note_time_qn + dx_qn))
+ - n->item()->item_to_canvas (ArdourCanvas::Duple (((hit->x0() + hit->x1()) / 2.0) - hit->position().x, 0)).x;
+ }
+ }
+
+ (*i)->move_event(dx, dy);
+
+ if (midi_view()->note_mode() == Sustained) {
+ Note* sus = dynamic_cast<Note*> (*i);
+ double const len_dx = editor->sample_to_pixel_unrounded (
+ tmap.frame_at_quarter_note (note_time_qn + dx_qn + n->note()->length().to_double()));
+
+ sus->set_x1 (n->item()->canvas_to_item (ArdourCanvas::Duple (len_dx, 0)).x);
+ }
+ }
+
+ if (dy && !_copy_drag_events.empty() && !_no_sound_notes && UIConfiguration::instance().get_sound_midi_notes()) {
+
+ if (to_play.size() > 1) {
+
+ PossibleChord shifted;
+
+ for (PossibleChord::iterator n = to_play.begin(); n != to_play.end(); ++n) {
+ boost::shared_ptr<NoteType> moved_note (new NoteType (**n));
+ moved_note->set_note (moved_note->note() + cumulative_dy);
+ shifted.push_back (moved_note);
+ }
+
+ start_playing_midi_chord (shifted);
+
+ } else if (!to_play.empty()) {
+
+ boost::shared_ptr<NoteType> moved_note (new NoteType (*to_play.front()));
+ moved_note->set_note (moved_note->note() + cumulative_dy);
+ start_playing_midi_note (moved_note);
+ }
+ }
+}
+
void
-MidiRegionView::note_dropped(NoteBase *, frameoffset_t dt, int8_t dnote)
+MidiRegionView::note_dropped(NoteBase *, double d_qn, int8_t dnote, bool copy)
{
uint8_t lowest_note_in_selection = 127;
uint8_t highest_note_in_selection = 0;
uint8_t highest_note_difference = 0;
- // find highest and lowest notes first
+ if (!copy) {
+ // find highest and lowest notes first
- for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
- uint8_t pitch = (*i)->note()->note();
- lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
- highest_note_in_selection = std::max(highest_note_in_selection, pitch);
- }
-
- /*
- cerr << "dnote: " << (int) dnote << endl;
- cerr << "lowest note (streamview): " << int(midi_stream_view()->lowest_note())
- << " highest note (streamview): " << int(midi_stream_view()->highest_note()) << endl;
- cerr << "lowest note (selection): " << int(lowest_note_in_selection) << " highest note(selection): "
- << int(highest_note_in_selection) << endl;
- cerr << "selection size: " << _selection.size() << endl;
- cerr << "Highest note in selection: " << (int) highest_note_in_selection << endl;
- */
+ for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ uint8_t pitch = (*i)->note()->note();
+ lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
+ highest_note_in_selection = std::max(highest_note_in_selection, pitch);
+ }
- // Make sure the note pitch does not exceed the MIDI standard range
- if (highest_note_in_selection + dnote > 127) {
- highest_note_difference = highest_note_in_selection - 127;
- }
- TempoMap& map (trackview.session()->tempo_map());
+ /*
+ cerr << "dnote: " << (int) dnote << endl;
+ cerr << "lowest note (streamview): " << int(midi_stream_view()->lowest_note())
+ << " highest note (streamview): " << int(midi_stream_view()->highest_note()) << endl;
+ cerr << "lowest note (selection): " << int(lowest_note_in_selection) << " highest note(selection): "
+ << int(highest_note_in_selection) << endl;
+ cerr << "selection size: " << _selection.size() << endl;
+ cerr << "Highest note in selection: " << (int) highest_note_in_selection << endl;
+ */
- start_note_diff_command (_("move notes"));
+ // Make sure the note pitch does not exceed the MIDI standard range
+ if (highest_note_in_selection + dnote > 127) {
+ highest_note_difference = highest_note_in_selection - 127;
+ }
- for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) {
+ start_note_diff_command (_("move notes"));
- double const start_qn = _region->quarter_note() - midi_region()->start_beats();
- framepos_t new_frames = map.frame_at_quarter_note (start_qn + (*i)->note()->time().to_double()) + dt;
- Evoral::Beats new_time = Evoral::Beats (map.quarter_note_at_frame (new_frames) - start_qn);
- if (new_time < 0) {
- continue;
+ for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) {
+
+ Evoral::Beats new_time = Evoral::Beats ((*i)->note()->time().to_double() + d_qn);
+
+ if (new_time < 0) {
+ continue;
+ }
+
+ note_diff_add_change (*i, MidiModel::NoteDiffCommand::StartTime, new_time);
+
+ uint8_t original_pitch = (*i)->note()->note();
+ uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
+
+ // keep notes in standard midi range
+ clamp_to_0_127(new_pitch);
+
+ lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
+ highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
+
+ note_diff_add_change (*i, MidiModel::NoteDiffCommand::NoteNumber, new_pitch);
+ }
+ } else {
+
+ clear_editor_note_selection ();
+
+ for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end(); ++i) {
+ uint8_t pitch = (*i)->note()->note();
+ lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
+ highest_note_in_selection = std::max(highest_note_in_selection, pitch);
}
- note_diff_add_change (*i, MidiModel::NoteDiffCommand::StartTime, new_time);
+ // Make sure the note pitch does not exceed the MIDI standard range
+ if (highest_note_in_selection + dnote > 127) {
+ highest_note_difference = highest_note_in_selection - 127;
+ }
+
+ start_note_diff_command (_("copy notes"));
- uint8_t original_pitch = (*i)->note()->note();
- uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
+ for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end() ; ++i) {
- // keep notes in standard midi range
- clamp_to_0_127(new_pitch);
+ /* update time */
+ Evoral::Beats new_time = Evoral::Beats ((*i)->note()->time().to_double() + d_qn);
- lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
- highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
+ if (new_time < 0) {
+ continue;
+ }
- note_diff_add_change (*i, MidiModel::NoteDiffCommand::NoteNumber, new_pitch);
+ (*i)->note()->set_time (new_time);
+
+ /* update pitch */
+
+ uint8_t original_pitch = (*i)->note()->note();
+ uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
+
+ (*i)->note()->set_note (new_pitch);
+
+ // keep notes in standard midi range
+ clamp_to_0_127(new_pitch);
+
+ lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
+ highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
+
+ note_diff_add_note ((*i)->note(), true);
+
+ delete *i;
+ }
+
+ _copy_drag_events.clear ();
}
- apply_diff();
+ apply_diff (false, copy);
// care about notes being moved beyond the upper/lower bounds on the canvas
if (lowest_note_in_selection < midi_stream_view()->lowest_note() ||
highest_note_in_selection > midi_stream_view()->highest_note()) {
- midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
+ midi_stream_view()->set_note_range (MidiStreamView::ContentsRange);
}
}
MidiRegionView::snap_pixel_to_sample(double x, bool ensure_snap)
{
PublicEditor& editor (trackview.editor());
- return snap_frame_to_frame (editor.pixel_to_sample (x), ensure_snap);
+ return snap_frame_to_frame (editor.pixel_to_sample (x), ensure_snap).frame;
}
/** @param x Pixel relative to the region position.
/* use grid */
- framepos_t next_pos = ref_point;
-
+ MusicFrame next_pos (ref_point, 0);
if (forward) {
- if (max_framepos - 1 < next_pos) {
- next_pos += 1;
+ if (max_framepos - 1 < next_pos.frame) {
+ next_pos.frame += 1;
}
} else {
- if (next_pos == 0) {
+ if (next_pos.frame == 0) {
return;
}
- next_pos -= 1;
+ next_pos.frame -= 1;
}
trackview.editor().snap_to (next_pos, (forward ? RoundUpAlways : RoundDownAlways), false);
- const framecnt_t distance = ref_point - next_pos;
+ const framecnt_t distance = ref_point - next_pos.frame;
delta = region_frames_to_region_beats (fabs ((double)distance));
}
// Update notes for selection
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- (*i)->on_channel_selection_change (mask);
+ i->second->on_channel_selection_change (mask);
}
_patch_changes.clear ();
}
};
-void
-MidiRegionView::time_sort_events ()
-{
- if (!_sort_needed) {
- return;
- }
-
- EventNoteTimeEarlyFirstComparator cmp;
- _events.sort (cmp);
-
- _sort_needed = false;
-}
-
void
MidiRegionView::goto_next_note (bool add_to_selection)
{
bool use_next = false;
- if (_events.back()->selected()) {
- return;
- }
-
- time_sort_events ();
-
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
uint16_t const channel_mask = mtv->midi_track()->get_playback_channel_mask();
+ NoteBase* first_note = 0;
- for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->selected()) {
- use_next = true;
- continue;
- } else if (use_next) {
- if (channel_mask & (1 << (*i)->note()->channel())) {
- if (!add_to_selection) {
- unique_select (*i);
- } else {
- note_selected (*i, true, false);
+ MidiModel::ReadLock lock(_model->read_lock());
+ MidiModel::Notes& notes (_model->notes());
+
+ for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) {
+ NoteBase* cne = 0;
+ if ((cne = find_canvas_note (*n))) {
+
+ if (!first_note && (channel_mask & (1 << (*n)->channel()))) {
+ first_note = cne;
+ }
+
+ if (cne->selected()) {
+ use_next = true;
+ continue;
+ } else if (use_next) {
+ if (channel_mask & (1 << (*n)->channel())) {
+ if (!add_to_selection) {
+ unique_select (cne);
+ } else {
+ note_selected (cne, true, false);
+ }
+
+ return;
}
- return;
}
}
}
/* use the first one */
- if (!_events.empty() && (channel_mask & (1 << _events.front()->note()->channel ()))) {
- unique_select (_events.front());
+ if (!_events.empty() && first_note) {
+ unique_select (first_note);
}
}
{
bool use_next = false;
- if (_events.front()->selected()) {
- return;
- }
-
- time_sort_events ();
-
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
uint16_t const channel_mask = mtv->midi_track()->get_playback_channel_mask ();
+ NoteBase* last_note = 0;
- for (Events::reverse_iterator i = _events.rbegin(); i != _events.rend(); ++i) {
- if ((*i)->selected()) {
- use_next = true;
- continue;
- } else if (use_next) {
- if (channel_mask & (1 << (*i)->note()->channel())) {
- if (!add_to_selection) {
- unique_select (*i);
- } else {
- note_selected (*i, true, false);
+ MidiModel::ReadLock lock(_model->read_lock());
+ MidiModel::Notes& notes (_model->notes());
+
+ for (MidiModel::Notes::reverse_iterator n = notes.rbegin(); n != notes.rend(); ++n) {
+ NoteBase* cne = 0;
+ if ((cne = find_canvas_note (*n))) {
+
+ if (!last_note && (channel_mask & (1 << (*n)->channel()))) {
+ last_note = cne;
+ }
+
+ if (cne->selected()) {
+ use_next = true;
+ continue;
+
+ } else if (use_next) {
+ if (channel_mask & (1 << (*n)->channel())) {
+ if (!add_to_selection) {
+ unique_select (cne);
+ } else {
+ note_selected (cne, true, false);
+ }
+
+ return;
}
- return;
}
}
}
/* use the last one */
- if (!_events.empty() && (channel_mask & (1 << (*_events.rbegin())->note()->channel ()))) {
- unique_select (*(_events.rbegin()));
+ if (!_events.empty() && last_note) {
+ unique_select (last_note);
}
}
{
bool had_selected = false;
- time_sort_events ();
+ /* we previously time sorted events here, but Notes is a multiset sorted by time */
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- if ((*i)->selected()) {
- selected.insert ((*i)->note());
+ if (i->second->selected()) {
+ selected.insert (i->first);
had_selected = true;
}
}
if (allow_all_if_none_selected && !had_selected) {
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- selected.insert ((*i)->note());
+ selected.insert (i->first);
}
}
}
}
for (Events::iterator i = e.begin(); i != e.end(); ++i) {
- if (_selection.insert (*i).second) {
- (*i)->set_selected (true);
+ if (_selection.insert (i->second).second) {
+ i->second->set_selected (true);
}
}
_patch_change_fill = UIConfiguration::instance().color_mod ("midi patch change fill", "midi patch change fill");
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- (*i)->set_selected ((*i)->selected()); // will change color
+ i->second->set_selected (i->second->selected()); // will change color
}
/* XXX probably more to do here */
{
return contents_height() - (note + 1 - _current_range_min) * note_height() + 1;
}
+
+double
+MidiRegionView::session_relative_qn (double qn) const
+{
+ return qn + (region()->quarter_note() - midi_region()->start_beats());
+}