X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmidi_region_view.cc;h=bf0595de75485dc18878bf9f44f390609933f0e1;hb=abf1f286d49482ade939da7e49863a3d63048b42;hp=c8de0162167a33633c9de06658c85240f8864b3e;hpb=176625d9e0dbe53c9f5628d172ee6f5488be8202;p=ardour.git diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index c8de016216..bf0595de75 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -113,7 +113,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent, , _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) @@ -134,6 +133,8 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent, PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys)); 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 (); } @@ -160,7 +161,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent, , _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) @@ -191,6 +191,10 @@ MidiRegionView::parameter_changed (std::string const & p) if (_enable_display) { redisplay_model(); } + } else if (p == "color-regions-using-track-color") { + set_colors (); + } else if (p == "use-note-color-for-velocity") { + color_handler (); } } @@ -212,7 +216,6 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other) , _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) @@ -244,7 +247,6 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptrParameterChanged.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 (); } @@ -348,6 +351,9 @@ MidiRegionView::canvas_group_event(GdkEvent* ev) return RegionView::canvas_group_event (ev); } + //For now, move the snapped cursor aside so it doesn't bother you during internal editing + //trackview.editor().set_snapped_cursor_position(_region->position()); + bool r; switch (ev->type) { @@ -417,8 +423,8 @@ MidiRegionView::leave_notify (GdkEventCrossing*) void MidiRegionView::mouse_mode_changed () { - // Adjust frame colour (become more transparent for internal tools) - set_frame_color(); + // Adjust sample colour (become more transparent for internal tools) + set_sample_color(); if (_entered) { if (!trackview.editor().internal_editing()) { @@ -458,12 +464,12 @@ MidiRegionView::enter_internal (uint32_t state) _grabbed_keyboard = true; } - // Lower frame handles below notes so they don't steal events - if (frame_handle_start) { - frame_handle_start->lower_to_bottom(); + // Lower sample handles below notes so they don't steal events + if (sample_handle_start) { + sample_handle_start->lower_to_bottom(); } - if (frame_handle_end) { - frame_handle_end->lower_to_bottom(); + if (sample_handle_end) { + sample_handle_end->lower_to_bottom(); } } @@ -479,12 +485,12 @@ MidiRegionView::leave_internal() _grabbed_keyboard = false; } - // Raise frame handles above notes so they catch events - if (frame_handle_start) { - frame_handle_start->raise_to_top(); + // Raise sample handles above notes so they catch events + if (sample_handle_start) { + sample_handle_start->raise_to_top(); } - if (frame_handle_end) { - frame_handle_end->raise_to_top(); + if (sample_handle_end) { + sample_handle_end->raise_to_top(); } } @@ -681,16 +687,17 @@ MidiRegionView::motion (GdkEventMotion* ev) } - /* we may be dragging some non-note object (eg. patch-change, sysex) - */ - - return editor.drags()->motion_handler ((GdkEvent *) ev, false); + //let RegionView do it's thing. drags are handled in here + return RegionView::canvas_group_event ((GdkEvent *) ev); } bool MidiRegionView::scroll (GdkEventScroll* ev) { + if (trackview.editor().drags()->active()) { + return false; + } if (_selection.empty()) { return false; } @@ -749,7 +756,7 @@ MidiRegionView::key_press (GdkEventKey* ev) bool shorter = Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier); bool fine = Keyboard::modifier_state_contains (ev->state, Keyboard::SecondaryModifier); - change_note_lengths (fine, shorter, Evoral::Beats(), start, end); + change_note_lengths (fine, shorter, Temporal::Beats(), start, end); return true; @@ -918,13 +925,13 @@ MidiRegionView::show_list_editor () } /** Add a note to the model, and the view, at a canvas (click) coordinate. - * \param t time in frames relative to the position of the region + * \param t time in samples relative to the position of the region * \param y vertical position in pixels * \param length duration of the note in beats * \param snap_t true to snap t to the grid, otherwise false. */ void -MidiRegionView::create_note_at (framepos_t t, double y, Evoral::Beats length, uint32_t state, bool shift_snap) +MidiRegionView::create_note_at (samplepos_t t, double y, Temporal::Beats length, uint32_t state, bool shift_snap) { if (length < 2 * DBL_EPSILON) { return; @@ -938,9 +945,9 @@ MidiRegionView::create_note_at (framepos_t t, double y, Evoral::Beats length, ui return; } - // Start of note in frames relative to region start + // Start of note in samples relative to region start const int32_t divisions = trackview.editor().get_grid_music_divisions (state); - Evoral::Beats beat_time = snap_frame_to_grid_underneath (t, divisions, shift_snap); + Temporal::Beats beat_time = snap_sample_to_grid_underneath (t, divisions, shift_snap); const double note = view->y_to_note(y); const uint8_t chan = mtv->get_channel_for_add(); @@ -957,7 +964,6 @@ MidiRegionView::create_note_at (framepos_t t, double y, Evoral::Beats length, ui start_note_diff_command(_("add note")); - clear_editor_note_selection (); note_diff_add_note (new_note, true, false); apply_diff(); @@ -978,10 +984,8 @@ MidiRegionView::clear_events () } } - for (Events::iterator i = _events.begin(); i != _events.end(); ++i) { - delete *i; - } + _note_group->clear (true); _events.clear(); _patch_changes.clear(); _sys_exes.clear(); @@ -996,7 +1000,7 @@ MidiRegionView::display_model(boost::shared_ptr model) 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(); @@ -1047,7 +1051,7 @@ MidiRegionView::note_diff_add_change (NoteBase* ev, void MidiRegionView::note_diff_add_change (NoteBase* ev, MidiModel::NoteDiffCommand::Property property, - Evoral::Beats val) + Temporal::Beats val) { if (_note_diff_command) { _note_diff_command->change (ev->note(), property, val); @@ -1055,24 +1059,24 @@ MidiRegionView::note_diff_add_change (NoteBase* ev, } void -MidiRegionView::apply_diff (bool as_subcommand) +MidiRegionView::apply_diff (bool as_subcommand, bool was_copy) { - bool add_or_remove; bool commit = false; if (!_note_diff_command) { return; } - if ((add_or_remove = _note_diff_command->adds_or_removes())) { + bool add_or_remove = _note_diff_command->adds_or_removes(); + + if (!was_copy && add_or_remove) { // 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); @@ -1098,24 +1102,25 @@ MidiRegionView::abort_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 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; @@ -1128,16 +1133,40 @@ MidiRegionView::find_canvas_note (Evoral::event_id_t id) 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; } } return 0; } +boost::shared_ptr +MidiRegionView::find_canvas_patch_change (MidiModel::PatchChangePtr p) +{ + PatchChanges::const_iterator f = _patch_changes.find (p); + + if (f != _patch_changes.end()) { + return f->second; + } + + return boost::shared_ptr(); +} + +boost::shared_ptr +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(); +} + void -MidiRegionView::get_events (Events& e, Evoral::Sequence::NoteOperator op, uint8_t val, int chan_mask) +MidiRegionView::get_events (Events& e, Evoral::Sequence::NoteOperator op, uint8_t val, int chan_mask) { MidiModel::Notes notes; _model->get_notes (notes, op, val, chan_mask); @@ -1145,7 +1174,7 @@ MidiRegionView::get_events (Events& e, Evoral::Sequence::NoteOper 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)); } } } @@ -1155,14 +1184,14 @@ MidiRegionView::redisplay_model() { if (_active_notes) { // Currently recording - const framecnt_t zoom = trackview.editor().get_current_zoom(); + const samplecnt_t zoom = trackview.editor().get_current_zoom(); if (zoom != _last_display_zoom) { /* Update resolved canvas notes to reflect changes in zoom without 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; @@ -1174,80 +1203,107 @@ MidiRegionView::redisplay_model() return; } - for (Events::iterator i = _events.begin(); i != _events.end(); ++i) { - (*i)->invalidate (); + for (_optimization_iterator = _events.begin(); _optimization_iterator != _events.end(); ++_optimization_iterator) { + _optimization_iterator->second->invalidate(); } - MidiModel::ReadLock lock(_model->read_lock()); + bool empty_when_starting = _events.empty(); + _optimization_iterator = _events.begin(); + MidiModel::Notes missing_notes; + Note* sus = NULL; + Hit* hit = NULL; + MidiModel::ReadLock lock(_model->read_lock()); MidiModel::Notes& notes (_model->notes()); - _optimization_iterator = _events.begin(); - bool empty_when_starting = _events.empty(); NoteBase* cne; - for (MidiModel::Notes::iterator n = notes.begin(); n != notes.end(); ++n) { boost::shared_ptr 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->validate (); - update_note (cne); cne->show (); } else { cne->hide (); } - } else { - - cne = add_note (note, visible); - } - - set::iterator it; - for (it = _pending_note_selection.begin(); it != _pending_note_selection.end(); ++it) { - if ((*it) == note->id()) { - add_to_selection (cne); - } - } - - } else { - - if (!empty_when_starting && (cne = find_canvas_note (note)) != 0) { - cne->validate (); - cne->hide (); + missing_notes.insert (note); } } } - /* remove note items that are no longer valid */ - if (!empty_when_starting) { + MidiModel::Notes::iterator f; for (Events::iterator i = _events.begin(); i != _events.end(); ) { - if (!(*i)->valid ()) { + + NoteBase* cne = i->second; + + /* remove note items that are no longer valid */ + if (!cne->valid()) { for (vector::iterator j = ghosts.begin(); j != ghosts.end(); ++j) { MidiGhostRegion* gr = dynamic_cast (*j); if (gr) { - gr->remove_note (*i); + gr->remove_note (cne); } } - delete *i; + delete cne; i = _events.erase (i); } else { + bool visible = cne->item()->visible(); + + if ((sus = dynamic_cast(cne))) { + + if (visible) { + update_sustained (sus); + } + + } else if ((hit = dynamic_cast(cne))) { + + if (visible) { + update_hit (hit); + } + + } ++i; } } } - _patch_changes.clear(); - _sys_exes.clear(); + for (MidiModel::Notes::iterator n = missing_notes.begin(); n != missing_notes.end(); ++n) { + boost::shared_ptr note (*n); + 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::iterator it = _pending_note_selection.begin(); it != _pending_note_selection.end(); ++it) { + if ((*it) == note->id()) { + add_to_selection (cne); + } + } + } + + for (vector::iterator j = ghosts.begin(); j != ghosts.end(); ++j) { + MidiGhostRegion* gr = dynamic_cast (*j); + if (gr && !gr->trackview.hidden()) { + gr->redisplay_model (); + } + } display_sysexes(); display_patch_changes (); @@ -1256,12 +1312,6 @@ MidiRegionView::redisplay_model() _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 @@ -1282,13 +1332,31 @@ void MidiRegionView::display_patch_changes_on_channel (uint8_t channel, bool active_channel) { for (MidiModel::PatchChanges::const_iterator i = _model->patch_changes().begin(); i != _model->patch_changes().end(); ++i) { + boost::shared_ptr p; if ((*i)->channel() != channel) { continue; } - const string patch_name = instrument_info().get_patch_name ((*i)->bank(), (*i)->program(), channel); - add_canvas_patch_change (*i, patch_name, active_channel); + if ((p = find_canvas_patch_change (*i)) != 0) { + + const samplecnt_t region_samples = source_beats_to_region_samples ((*i)->time()); + + if (region_samples < 0 || region_samples >= _region->length()) { + p->hide(); + } else { + const double x = trackview.editor().sample_to_pixel (region_samples); + 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); + } } } @@ -1308,14 +1376,14 @@ MidiRegionView::display_sysexes() } if (have_periodic_system_messages) { - double zoom = trackview.editor().get_current_zoom (); // frames per pixel + double zoom = trackview.editor().get_current_zoom (); // samples per pixel /* get an approximate value for the number of samples per video frame */ - double video_frame = trackview.session()->frame_rate() * (1.0/30); + double video_frame = trackview.session()->sample_rate() * (1.0/30); /* if we are zoomed out beyond than the cutoff (i.e. more - * frames per pixel than frames per 4 video frames), don't + * samples per pixel than samples per 4 video frames), don't * show periodic sysex messages. */ @@ -1328,7 +1396,8 @@ MidiRegionView::display_sysexes() } for (MidiModel::SysExes::const_iterator i = _model->sysexes().begin(); i != _model->sysexes().end(); ++i) { - Evoral::Beats time = (*i)->time(); + MidiModel::SysExPtr sysex_ptr = *i; + Temporal::Beats time = sysex_ptr->time(); if ((*i)->is_spp() || (*i)->is_mtc_quarter() || (*i)->is_mtc_full()) { if (!display_periodic_messages) { @@ -1346,24 +1415,31 @@ MidiRegionView::display_sysexes() } string text = str.str(); - const double x = trackview.editor().sample_to_pixel(source_beats_to_region_frames(time)); + const double x = trackview.editor().sample_to_pixel(source_beats_to_region_samples(time)); double height = midi_stream_view()->contents_height(); // CAIROCANVAS: no longer passing *i (the sysex event) to the // SysEx canvas object!!! + boost::shared_ptr sysex = find_canvas_sys_ex (sysex_ptr); - boost::shared_ptr sysex = boost::shared_ptr( - new SysEx (*this, _note_group, text, height, x, 1.0)); - - // Show unless message is beyond the region bounds - if (time - _region->start() >= _region->length() || time < _region->start()) { - sysex->hide(); + if (!sysex) { + sysex = boost::shared_ptr( + new SysEx (*this, _note_group, text, height, x, 1.0, sysex_ptr)); + _sys_exes.insert (make_pair (sysex_ptr, sysex)); } else { - sysex->show(); + sysex->set_height (height); + sysex->item().set_position (ArdourCanvas::Duple (x, 1.0)); } - _sys_exes.push_back(sysex); + // Show unless message is beyond the region bounds +// XXX REQUIRES APPROPRIATE OPERATORS FOR Temporal::Beats and samplepos? say what? +#warning paul fix this +// if (time - _region->start() >= _region->length() || time < _region->start()) { +// sysex->hide(); +// } else { +// sysex->show(); +// } } } @@ -1423,11 +1499,15 @@ MidiRegionView::reset_width_dependent_items (double pixel_width) 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(); } } @@ -1450,7 +1530,7 @@ MidiRegionView::set_height (double height) } 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) { @@ -1495,15 +1575,16 @@ MidiRegionView::add_ghost (TimeAxisView& tv) 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; } @@ -1538,7 +1619,7 @@ MidiRegionView::end_write() /** Resolve an active MIDI note (while recording). */ void -MidiRegionView::resolve_note(uint8_t note, Evoral::Beats end_time) +MidiRegionView::resolve_note(uint8_t note, Temporal::Beats end_time) { if (midi_view()->note_mode() != Sustained) { return; @@ -1551,9 +1632,9 @@ MidiRegionView::resolve_note(uint8_t note, Evoral::Beats end_time) end_time - _active_notes[note]->note()->time()); /* End time is relative to the region being recorded. */ - const framepos_t end_time_frames = region_beats_to_region_frames(end_time); + const samplepos_t end_time_samples = region_beats_to_region_samples(end_time); - _active_notes[note]->set_x1 (trackview.editor().sample_to_pixel(end_time_frames)); + _active_notes[note]->set_x1 (trackview.editor().sample_to_pixel(end_time_samples)); _active_notes[note]->set_outline_all (); _active_notes[note] = 0; } @@ -1666,9 +1747,9 @@ MidiRegionView::update_sustained (Note* ev, bool update_ghost_regions) boost::shared_ptr note = ev->note(); const double session_source_start = _region->quarter_note() - mr->start_beats(); - const framepos_t note_start_frames = map.frame_at_quarter_note (note->time().to_double() + session_source_start) - _region->position(); + const samplepos_t note_start_samples = map.sample_at_quarter_note (note->time().to_double() + session_source_start) - _region->position(); - const double x0 = trackview.editor().sample_to_pixel (note_start_frames); + const double x0 = trackview.editor().sample_to_pixel (note_start_samples); double x1; const double y0 = 1 + floor(note_to_y(note->note())); double y1; @@ -1681,9 +1762,9 @@ MidiRegionView::update_sustained (Note* ev, bool update_ghost_regions) note_end_time = mr->start_beats() + mr->length_beats(); } - const framepos_t note_end_frames = map.frame_at_quarter_note (session_source_start + note_end_time) - _region->position(); + const samplepos_t note_end_samples = map.sample_at_quarter_note (session_source_start + note_end_time) - _region->position(); - x1 = std::max(1., trackview.editor().sample_to_pixel (note_end_frames)) - 1; + x1 = std::max(1., trackview.editor().sample_to_pixel (note_end_samples)) - 1; } else { x1 = std::max(1., trackview.editor().sample_to_pixel (_region->length())) - 1; } @@ -1691,6 +1772,7 @@ MidiRegionView::update_sustained (Note* ev, bool update_ghost_regions) y1 = y0 + std::max(1., floor(note_height()) - 1); ev->set (ArdourCanvas::Rect (x0, y0, x1, y1)); + ev->set_velocity (note->velocity()/127.0); if (!note->length()) { if (_active_notes && note->note() < 128) { @@ -1718,14 +1800,6 @@ MidiRegionView::update_sustained (Note* ev, bool update_ghost_regions) ev->set_fill_color(base_col); ev->set_outline_color(ev->calculate_outline(base_col, ev->selected())); - if (update_ghost_regions) { - for (std::vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { - MidiGhostRegion* gr = dynamic_cast (*i); - if (gr) { - gr->update_note (ev); - } - } - } } void @@ -1734,9 +1808,9 @@ MidiRegionView::update_hit (Hit* ev, bool update_ghost_regions) boost::shared_ptr note = ev->note(); const double note_time_qn = note->time().to_double() + (_region->quarter_note() - midi_region()->start_beats()); - const framepos_t note_start_frames = trackview.session()->tempo_map().frame_at_quarter_note (note_time_qn) - _region->position(); + const samplepos_t note_start_samples = trackview.session()->tempo_map().sample_at_quarter_note (note_time_qn) - _region->position(); - const double x = trackview.editor().sample_to_pixel(note_start_frames); + const double x = trackview.editor().sample_to_pixel(note_start_samples); const double diamond_size = std::max(1., floor(note_height()) - 2.); const double y = 1.5 + floor(note_to_y(note->note())) + diamond_size * .5; @@ -1755,14 +1829,6 @@ MidiRegionView::update_hit (Hit* ev, bool update_ghost_regions) ev->set_fill_color(base_col); ev->set_outline_color(ev->calculate_outline(base_col, ev->selected())); - if (update_ghost_regions) { - for (std::vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { - MidiGhostRegion* gr = dynamic_cast (*i); - if (gr) { - gr->update_hit (ev); - } - } - } } /** Add a MIDI note to the view (with length). @@ -1778,7 +1844,7 @@ MidiRegionView::add_note(const boost::shared_ptr note, bool visible) 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); @@ -1788,7 +1854,7 @@ MidiRegionView::add_note(const boost::shared_ptr note, bool visible) 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); @@ -1816,7 +1882,7 @@ MidiRegionView::add_note(const boost::shared_ptr note, bool visible) } event->on_channel_selection_change (get_selected_channels()); - _events.push_back(event); + _events.insert (make_pair (event->note(), event)); if (visible) { event->show(); @@ -1834,18 +1900,18 @@ MidiRegionView::add_note(const boost::shared_ptr note, bool visible) void MidiRegionView::step_add_note (uint8_t channel, uint8_t number, uint8_t velocity, - Evoral::Beats pos, Evoral::Beats len) + Temporal::Beats pos, Temporal::Beats len) { boost::shared_ptr new_note (new NoteType (channel, pos, len, number, velocity)); /* potentially extend region to hold new note */ - framepos_t end_frame = source_beats_to_absolute_frames (new_note->end_time()); - framepos_t region_end = _region->last_frame(); + samplepos_t end_sample = source_beats_to_absolute_samples (new_note->end_time()); + samplepos_t region_end = _region->last_sample(); - if (end_frame > region_end) { + if (end_sample > region_end) { /* XX sets length in beats from audio space. make musical */ - _region->set_length (end_frame - _region->position(), 0); + _region->set_length (end_sample - _region->position(), 0); } MidiTimeAxisView* const mtv = dynamic_cast(&trackview); @@ -1866,7 +1932,7 @@ MidiRegionView::step_add_note (uint8_t channel, uint8_t number, uint8_t velocity } void -MidiRegionView::step_sustain (Evoral::Beats beats) +MidiRegionView::step_sustain (Temporal::Beats beats) { change_note_lengths (false, false, beats, false, true); } @@ -1879,8 +1945,8 @@ MidiRegionView::step_sustain (Evoral::Beats beats) void MidiRegionView::add_canvas_patch_change (MidiModel::PatchChangePtr patch, const string& displaytext, bool /*active_channel*/) { - framecnt_t region_frames = source_beats_to_region_frames (patch->time()); - const double x = trackview.editor().sample_to_pixel (region_frames); + samplecnt_t region_samples = source_beats_to_region_samples (patch->time()); + const double x = trackview.editor().sample_to_pixel (region_samples); double const height = midi_stream_view()->contents_height(); @@ -1901,7 +1967,7 @@ MidiRegionView::add_canvas_patch_change (MidiModel::PatchChangePtr patch, const if (patch_change->item().width() < _pixel_width) { // Show unless patch change is beyond the region bounds - if (region_frames < 0 || region_frames >= _region->length()) { + if (region_samples < 0 || region_samples >= _region->length()) { patch_change->hide(); } else { patch_change->show(); @@ -1910,7 +1976,19 @@ MidiRegionView::add_canvas_patch_change (MidiModel::PatchChangePtr patch, const patch_change->hide (); } - _patch_changes.push_back (patch_change); + _patch_changes.insert (make_pair (patch, patch_change)); +} + +void +MidiRegionView::remove_canvas_patch_change (PatchChange* pc) +{ + /* remove the canvas item */ + for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) { + if (x->second->patch() == pc->patch()) { + _patch_changes.erase (x); + break; + } + } } MIDI::Name::PatchPrimaryKey @@ -1921,13 +1999,13 @@ MidiRegionView::patch_change_to_patch_key (MidiModel::PatchChangePtr p) /// Return true iff @p pc applies to the given time on the given channel. static bool -patch_applies (const ARDOUR::MidiModel::constPatchChangePtr pc, Evoral::Beats time, uint8_t channel) +patch_applies (const ARDOUR::MidiModel::constPatchChangePtr pc, Temporal::Beats time, uint8_t channel) { return pc->time() <= time && pc->channel() == channel; } void -MidiRegionView::get_patch_key_at (Evoral::Beats time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const +MidiRegionView::get_patch_key_at (Temporal::Beats time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const { // The earliest event not before time MidiModel::PatchChanges::iterator i = _model->patch_change_lower_bound (time); @@ -1953,6 +2031,7 @@ MidiRegionView::change_patch_change (PatchChange& pc, const MIDI::Name::PatchPri { string name = _("alter patch change"); trackview.editor().begin_reversible_command (name); + MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (name); if (pc.patch()->program() != new_patch.program()) { @@ -1967,12 +2046,12 @@ MidiRegionView::change_patch_change (PatchChange& pc, const MIDI::Name::PatchPri _model->apply_command (*trackview.session(), c); trackview.editor().commit_reversible_command (); - _patch_changes.clear (); + remove_canvas_patch_change (&pc); display_patch_changes (); } void -MidiRegionView::change_patch_change (MidiModel::PatchChangePtr old_change, const Evoral::PatchChange & new_change) +MidiRegionView::change_patch_change (MidiModel::PatchChangePtr old_change, const Evoral::PatchChange & new_change) { string name = _("alter patch change"); trackview.editor().begin_reversible_command (name); @@ -1997,27 +2076,32 @@ MidiRegionView::change_patch_change (MidiModel::PatchChangePtr old_change, const _model->apply_command (*trackview.session(), c); trackview.editor().commit_reversible_command (); - _patch_changes.clear (); + for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) { + if (x->second->patch() == old_change) { + _patch_changes.erase (x); + break; + } + } + display_patch_changes (); } /** Add a patch change to the region. - * @param t Time in frames relative to region position + * @param t Time in samples relative to region position * @param patch Patch to add; time and channel are ignored (time is converted from t, and channel comes from * MidiTimeAxisView::get_channel_for_add()) */ void -MidiRegionView::add_patch_change (framecnt_t t, Evoral::PatchChange const & patch) +MidiRegionView::add_patch_change (samplecnt_t t, Evoral::PatchChange const & patch) { - MidiTimeAxisView* const mtv = dynamic_cast(&trackview); string name = _("add patch change"); trackview.editor().begin_reversible_command (name); MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (name); c->add (MidiModel::PatchChangePtr ( - new Evoral::PatchChange ( - absolute_frames_to_source_beats (_region->position() + t), - mtv->get_channel_for_add(), patch.program(), patch.bank() + new Evoral::PatchChange ( + absolute_samples_to_source_beats (_region->position() + t), + patch.channel(), patch.program(), patch.bank() ) ) ); @@ -2025,12 +2109,11 @@ MidiRegionView::add_patch_change (framecnt_t t, Evoral::PatchChangeapply_command (*trackview.session(), c); trackview.editor().commit_reversible_command (); - _patch_changes.clear (); display_patch_changes (); } void -MidiRegionView::move_patch_change (PatchChange& pc, Evoral::Beats t) +MidiRegionView::move_patch_change (PatchChange& pc, Temporal::Beats t) { trackview.editor().begin_reversible_command (_("move patch change")); MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("move patch change")); @@ -2038,7 +2121,6 @@ MidiRegionView::move_patch_change (PatchChange& pc, Evoral::Beats t) _model->apply_command (*trackview.session(), c); trackview.editor().commit_reversible_command (); - _patch_changes.clear (); display_patch_changes (); } @@ -2046,12 +2128,13 @@ void MidiRegionView::delete_patch_change (PatchChange* pc) { trackview.editor().begin_reversible_command (_("delete patch change")); + MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("delete patch change")); c->remove (pc->patch ()); _model->apply_command (*trackview.session(), c); trackview.editor().commit_reversible_command (); - _patch_changes.clear (); + remove_canvas_patch_change (pc); display_patch_changes (); } @@ -2164,19 +2247,19 @@ MidiRegionView::select_all_notes () clear_editor_note_selection (); for (Events::iterator i = _events.begin(); i != _events.end(); ++i) { - add_to_selection (*i); + add_to_selection (i->second); } } void -MidiRegionView::select_range (framepos_t start, framepos_t end) +MidiRegionView::select_range (samplepos_t start, samplepos_t end) { 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()); + samplepos_t t = source_beats_to_absolute_samples(i->first->time()); if (t >= start && t <= end) { - add_to_selection (*i); + add_to_selection (i->second); } } } @@ -2185,10 +2268,10 @@ void 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); } } } @@ -2324,8 +2407,8 @@ MidiRegionView::note_selected (NoteBase* ev, bool add, bool extend) } else { /* find end of latest note selected, select all between that and the start of "ev" */ - Evoral::Beats earliest = Evoral::MaxBeats; - Evoral::Beats latest = Evoral::Beats(); + Temporal::Beats earliest = std::numeric_limits::max(); + Temporal::Beats latest = Temporal::Beats(); for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { if ((*i)->note()->end_time() > latest) { @@ -2348,11 +2431,10 @@ MidiRegionView::note_selected (NoteBase* ev, bool add, bool extend) /* 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); } - } } } @@ -2364,15 +2446,15 @@ MidiRegionView::note_deselected(NoteBase* ev) } void -MidiRegionView::update_drag_selection(framepos_t start, framepos_t end, double gy0, double gy1, bool extend) +MidiRegionView::update_drag_selection(samplepos_t start, samplepos_t end, double gy0, double gy1, bool extend) { PublicEditor& editor = trackview.editor(); // Convert to local coordinates - const framepos_t p = _region->position(); + const samplepos_t p = _region->position(); const double y = midi_view()->y_position(); - const double x0 = editor.sample_to_pixel(max((framepos_t)0, start - p)); - const double x1 = editor.sample_to_pixel(max((framepos_t)0, end - p)); + const double x0 = editor.sample_to_pixel(max((samplepos_t)0, start - p)); + const double x1 = editor.sample_to_pixel(max((samplepos_t)0, end - p)); const double y0 = max(0.0, gy0 - y); const double y1 = max(0.0, gy1 - y); @@ -2381,14 +2463,14 @@ MidiRegionView::update_drag_selection(framepos_t start, framepos_t end, double g // 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); } } @@ -2423,13 +2505,13 @@ MidiRegionView::update_vertical_drag_selection (double y1, double y2, bool exten // 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); } } } @@ -2478,12 +2560,10 @@ MidiRegionView::add_to_selection (NoteBase* ev) } } -void -MidiRegionView::move_selection(double dx, double dy, double cumulative_dy) +Temporal::Beats +MidiRegionView::earliest_in_selection () { - typedef vector > PossibleChord; - PossibleChord to_play; - Evoral::Beats earliest = Evoral::MaxBeats; + Temporal::Beats earliest = std::numeric_limits::max(); for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { if ((*i)->note()->time() < earliest) { @@ -2491,11 +2571,47 @@ MidiRegionView::move_selection(double dx, double dy, double cumulative_dy) } } + return earliest; +} + +void +MidiRegionView::move_selection(double dx_qn, double dy, double cumulative_dy) +{ + typedef vector > PossibleChord; + Editor* editor = dynamic_cast (&trackview.editor()); + TempoMap& tmap (editor->session()->tempo_map()); + PossibleChord to_play; + Temporal::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.sample_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(n); + if (hit) { + dx = editor->sample_to_pixel_unrounded (tmap.sample_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 (*i); + double const len_dx = editor->sample_to_pixel_unrounded ( + tmap.sample_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()) { @@ -2521,81 +2637,223 @@ MidiRegionView::move_selection(double dx, double dy, double cumulative_dy) } } +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 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 > PossibleChord; + Editor* editor = dynamic_cast (&trackview.editor()); + TempoMap& tmap (editor->session()->tempo_map()); + PossibleChord to_play; + Temporal::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.sample_at_quarter_note (note_time_qn + dx_qn)) + - n->item()->item_to_canvas (ArdourCanvas::Duple (n->x0(), 0)).x; + } else { + Hit* hit = dynamic_cast(n); + if (hit) { + dx = editor->sample_to_pixel_unrounded (tmap.sample_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 (*i); + double const len_dx = editor->sample_to_pixel_unrounded ( + tmap.sample_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 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 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) { + + Temporal::Beats new_time = Temporal::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); + } + + // 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; } - note_diff_add_change (*i, MidiModel::NoteDiffCommand::StartTime, new_time); + 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 */ + Temporal::Beats new_time = Temporal::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; + } + + (*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; + } - note_diff_add_change (*i, MidiModel::NoteDiffCommand::NoteNumber, new_pitch); + _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); } } /** @param x Pixel relative to the region position. * @param ensure_snap defaults to false. true = snap always, ignoring snap mode and magnetic snap. * Used for inverting the snap logic with key modifiers and snap delta calculation. - * @return Snapped frame relative to the region position. + * @return Snapped sample relative to the region position. */ -framepos_t +samplepos_t 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_sample_to_sample (editor.pixel_to_sample (x), ensure_snap).sample; } /** @param x Pixel relative to the region position. @@ -2611,55 +2869,55 @@ MidiRegionView::snap_to_pixel(double x, bool ensure_snap) double MidiRegionView::get_position_pixels() { - framepos_t region_frame = get_position(); - return trackview.editor().sample_to_pixel(region_frame); + samplepos_t region_sample = get_position(); + return trackview.editor().sample_to_pixel(region_sample); } double MidiRegionView::get_end_position_pixels() { - framepos_t frame = get_position() + get_duration (); - return trackview.editor().sample_to_pixel(frame); + samplepos_t sample = get_position() + get_duration (); + return trackview.editor().sample_to_pixel(sample); } -framepos_t -MidiRegionView::source_beats_to_absolute_frames(Evoral::Beats beats) const +samplepos_t +MidiRegionView::source_beats_to_absolute_samples(Temporal::Beats beats) const { - /* the time converter will return the frame corresponding to `beats' + /* the time converter will return the sample corresponding to `beats' relative to the start of the source. The start of the source is an implied position given by region->position - region->start */ - const framepos_t source_start = _region->position() - _region->start(); + const samplepos_t source_start = _region->position() - _region->start(); return source_start + _source_relative_time_converter.to (beats); } -Evoral::Beats -MidiRegionView::absolute_frames_to_source_beats(framepos_t frames) const +Temporal::Beats +MidiRegionView::absolute_samples_to_source_beats(samplepos_t samples) const { - /* the `frames' argument needs to be converted into a frame count + /* the `samples' argument needs to be converted into a sample count relative to the start of the source before being passed in to the converter. */ - const framepos_t source_start = _region->position() - _region->start(); - return _source_relative_time_converter.from (frames - source_start); + const samplepos_t source_start = _region->position() - _region->start(); + return _source_relative_time_converter.from (samples - source_start); } -framepos_t -MidiRegionView::region_beats_to_region_frames(Evoral::Beats beats) const +samplepos_t +MidiRegionView::region_beats_to_region_samples(Temporal::Beats beats) const { return _region_relative_time_converter.to(beats); } -Evoral::Beats -MidiRegionView::region_frames_to_region_beats(framepos_t frames) const +Temporal::Beats +MidiRegionView::region_samples_to_region_beats(samplepos_t samples) const { - return _region_relative_time_converter.from(frames); + return _region_relative_time_converter.from(samples); } double -MidiRegionView::region_frames_to_region_beats_double (framepos_t frames) const +MidiRegionView::region_samples_to_region_beats_double (samplepos_t samples) const { - return _region_relative_time_converter_double.from(frames); + return _region_relative_time_converter_double.from(samples); } void @@ -2680,9 +2938,7 @@ MidiRegionView::begin_resizing (bool /*at_front*/) ArdourCanvas::Rect (note->x0(), note->y0(), note->x0(), note->y1())); // calculate the colors: get the color settings - uint32_t fill_color = UINT_RGBA_CHANGE_A( - UIConfiguration::instance().color ("midi note selected"), - 128); + uint32_t fill_color = NoteBase::meter_style_fill_color (note->note()->velocity(), true); // make the resize preview notes more transparent and bright fill_color = UINT_INTERPOLATE(fill_color, 0xFFFFFF40, 0.5); @@ -2694,7 +2950,7 @@ MidiRegionView::begin_resizing (bool /*at_front*/) 0.85)); resize_rect->set_outline_color (NoteBase::calculate_outline ( - UIConfiguration::instance().color ("midi note selected"))); + UIConfiguration::instance().color ("midi note selected outline"))); resize_data->resize_rect = resize_rect; _resize_data.push_back(resize_data); @@ -2740,7 +2996,7 @@ MidiRegionView::update_resizing (NoteBase* primary, bool at_front, double delta_ } if (current_x < 0) { - // This works even with snapping because RegionView::snap_frame_to_frame() + // This works even with snapping because RegionView::snap_sample_to_sample() // snaps forward if the snapped sample is before the beginning of the region current_x = 0; } @@ -2766,15 +3022,15 @@ MidiRegionView::update_resizing (NoteBase* primary, bool at_front, double delta_ if (!cursor_set) { /* Convert snap delta from pixels to beats. */ - framepos_t snap_delta_samps = trackview.editor().pixel_to_sample (snap_delta); + samplepos_t snap_delta_samps = trackview.editor().pixel_to_sample (snap_delta); double snap_delta_beats = 0.0; int sign = 1; /* negative beat offsets aren't allowed */ if (snap_delta_samps > 0) { - snap_delta_beats = region_frames_to_region_beats_double (snap_delta_samps); + snap_delta_beats = region_samples_to_region_beats_double (snap_delta_samps); } else if (snap_delta_samps < 0) { - snap_delta_beats = region_frames_to_region_beats_double ( - snap_delta_samps); + snap_delta_beats = region_samples_to_region_beats_double ( - snap_delta_samps); sign = -1; } @@ -2787,10 +3043,11 @@ MidiRegionView::update_resizing (NoteBase* primary, bool at_front, double delta_ } else { snapped_x = trackview.editor ().pixel_to_sample (current_x); } - const Evoral::Beats beats = Evoral::Beats (tmap.exact_beat_at_frame (snapped_x + midi_region()->position(), divisions) + + const Temporal::Beats beats = Temporal::Beats (tmap.exact_beat_at_sample (snapped_x + midi_region()->position(), divisions) - midi_region()->beat()) + midi_region()->start_beats(); - Evoral::Beats len = Evoral::Beats(); + Temporal::Beats len = Temporal::Beats(); if (at_front) { if (beats < canvas_note->note()->end_time()) { @@ -2803,13 +3060,15 @@ MidiRegionView::update_resizing (NoteBase* primary, bool at_front, double delta_ } } - len = std::max(Evoral::Beats(1 / 512.0), len); + len = std::max(Temporal::Beats(1 / 512.0), len); char buf[16]; snprintf (buf, sizeof (buf), "%.3g beats", len.to_double()); show_verbose_cursor (buf, 0, 0); cursor_set = true; + + trackview.editor().set_snapped_cursor_position ( snapped_x + midi_region()->position() ); } } @@ -2860,20 +3119,20 @@ MidiRegionView::commit_resizing (NoteBase* primary, bool at_front, double delta_ } /* Convert snap delta from pixels to beats with sign. */ - framepos_t snap_delta_samps = trackview.editor().pixel_to_sample (snap_delta); + samplepos_t snap_delta_samps = trackview.editor().pixel_to_sample (snap_delta); double snap_delta_beats = 0.0; int sign = 1; if (snap_delta_samps > 0) { - snap_delta_beats = region_frames_to_region_beats_double (snap_delta_samps); + snap_delta_beats = region_samples_to_region_beats_double (snap_delta_samps); } else if (snap_delta_samps < 0) { - snap_delta_beats = region_frames_to_region_beats_double ( - snap_delta_samps); + snap_delta_beats = region_samples_to_region_beats_double ( - snap_delta_samps); sign = -1; } uint32_t divisions = 0; - /* Convert the new x position to a frame within the source */ - framepos_t current_fr; + /* Convert the new x position to a sample within the source */ + samplepos_t current_fr; if (with_snap) { current_fr = snap_pixel_to_sample (current_x, ensure_snap); divisions = trackview.editor().get_grid_music_divisions (0); @@ -2882,13 +3141,13 @@ MidiRegionView::commit_resizing (NoteBase* primary, bool at_front, double delta_ } /* and then to beats */ - const double e_qaf = tmap.exact_qn_at_frame (current_fr + midi_region()->position(), divisions); + const double e_qaf = tmap.exact_qn_at_sample (current_fr + midi_region()->position(), divisions); const double quarter_note_start = _region->quarter_note() - midi_region()->start_beats(); - const Evoral::Beats x_beats = Evoral::Beats (e_qaf - quarter_note_start); + const Temporal::Beats x_beats = Temporal::Beats (e_qaf - quarter_note_start); if (at_front && x_beats < canvas_note->note()->end_time()) { note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::StartTime, x_beats - (sign * snap_delta_beats)); - Evoral::Beats len = canvas_note->note()->time() - x_beats + (sign * snap_delta_beats); + Temporal::Beats len = canvas_note->note()->time() - x_beats + (sign * snap_delta_beats); len += canvas_note->note()->length(); if (!!len) { @@ -2897,7 +3156,7 @@ MidiRegionView::commit_resizing (NoteBase* primary, bool at_front, double delta_ } if (!at_front) { - Evoral::Beats len = std::max(Evoral::Beats(1 / 512.0), + Temporal::Beats len = std::max(Temporal::Beats(1 / 512.0), x_beats - canvas_note->note()->time() - (sign * snap_delta_beats)); note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::Length, len); } @@ -2954,12 +3213,12 @@ MidiRegionView::change_note_note (NoteBase* event, int8_t note, bool relative) } void -MidiRegionView::trim_note (NoteBase* event, Evoral::Beats front_delta, Evoral::Beats end_delta) +MidiRegionView::trim_note (NoteBase* event, Temporal::Beats front_delta, Temporal::Beats end_delta) { bool change_start = false; bool change_length = false; - Evoral::Beats new_start; - Evoral::Beats new_length; + Temporal::Beats new_start; + Temporal::Beats new_length; /* NOTE: the semantics of the two delta arguments are slightly subtle: @@ -2974,7 +3233,7 @@ MidiRegionView::trim_note (NoteBase* event, Evoral::Beats front_delta, Evoral::B if (front_delta < 0) { if (event->note()->time() < -front_delta) { - new_start = Evoral::Beats(); + new_start = Temporal::Beats(); } else { new_start = event->note()->time() + front_delta; // moves earlier } @@ -2989,7 +3248,7 @@ MidiRegionView::trim_note (NoteBase* event, Evoral::Beats front_delta, Evoral::B } else { - Evoral::Beats new_pos = event->note()->time() + front_delta; + Temporal::Beats new_pos = event->note()->time() + front_delta; if (new_pos < event->note()->end_time()) { new_start = event->note()->time() + front_delta; @@ -3048,14 +3307,14 @@ MidiRegionView::change_note_channel (NoteBase* event, int8_t chn, bool relative) } void -MidiRegionView::change_note_time (NoteBase* event, Evoral::Beats delta, bool relative) +MidiRegionView::change_note_time (NoteBase* event, Temporal::Beats delta, bool relative) { - Evoral::Beats new_time; + Temporal::Beats new_time; if (relative) { if (delta < 0.0) { if (event->note()->time() < -delta) { - new_time = Evoral::Beats(); + new_time = Temporal::Beats(); } else { new_time = event->note()->time() + delta; } @@ -3070,7 +3329,7 @@ MidiRegionView::change_note_time (NoteBase* event, Evoral::Beats delta, bool rel } void -MidiRegionView::change_note_length (NoteBase* event, Evoral::Beats t) +MidiRegionView::change_note_length (NoteBase* event, Temporal::Beats t) { note_diff_add_change (event, MidiModel::NoteDiffCommand::Length, t); } @@ -3182,11 +3441,11 @@ MidiRegionView::transpose (bool up, bool fine, bool allow_smush) } void -MidiRegionView::change_note_lengths (bool fine, bool shorter, Evoral::Beats delta, bool start, bool end) +MidiRegionView::change_note_lengths (bool fine, bool shorter, Temporal::Beats delta, bool start, bool end) { if (!delta) { if (fine) { - delta = Evoral::Beats(1.0/128.0); + delta = Temporal::Beats(1.0/128.0); } else { /* grab the current grid distance */ delta = get_grid_beats(_region->position()); @@ -3206,8 +3465,8 @@ MidiRegionView::change_note_lengths (bool fine, bool shorter, Evoral::Beats delt /* note the negation of the delta for start */ trim_note (*i, - (start ? -delta : Evoral::Beats()), - (end ? delta : Evoral::Beats())); + (start ? -delta : Temporal::Beats()), + (end ? delta : Temporal::Beats())); i = next; } @@ -3227,42 +3486,41 @@ MidiRegionView::nudge_notes (bool forward, bool fine) into a vector and sort before using the first one. */ - const framepos_t ref_point = source_beats_to_absolute_frames ((*(_selection.begin()))->note()->time()); - Evoral::Beats delta; + const samplepos_t ref_point = source_beats_to_absolute_samples ((*(_selection.begin()))->note()->time()); + Temporal::Beats delta; if (!fine) { /* non-fine, move by 1 bar regardless of snap */ - delta = Evoral::Beats(trackview.session()->tempo_map().meter_at_frame (ref_point).divisions_per_bar()); + delta = Temporal::Beats(trackview.session()->tempo_map().meter_at_sample (ref_point).divisions_per_bar()); } else if (trackview.editor().snap_mode() == Editing::SnapOff) { /* grid is off - use nudge distance */ - framepos_t unused; - const framecnt_t distance = trackview.editor().get_nudge_distance (ref_point, unused); - delta = region_frames_to_region_beats (fabs ((double)distance)); + samplepos_t unused; + const samplecnt_t distance = trackview.editor().get_nudge_distance (ref_point, unused); + delta = region_samples_to_region_beats (fabs ((double)distance)); } else { /* use grid */ - framepos_t next_pos = ref_point; - + MusicSample next_pos (ref_point, 0); if (forward) { - if (max_framepos - 1 < next_pos) { - next_pos += 1; + if (max_samplepos - 1 < next_pos.sample) { + next_pos.sample += 1; } } else { - if (next_pos == 0) { + if (next_pos.sample == 0) { return; } - next_pos -= 1; + next_pos.sample -= 1; } - trackview.editor().snap_to (next_pos, (forward ? RoundUpAlways : RoundDownAlways), false); - const framecnt_t distance = ref_point - next_pos; - delta = region_frames_to_region_beats (fabs ((double)distance)); + trackview.editor().snap_to (next_pos, (forward ? RoundUpAlways : RoundDownAlways), SnapToGrid_Unscaled, false); + const samplecnt_t distance = ref_point - next_pos.sample; + delta = region_samples_to_region_beats (fabs ((double)distance)); } if (!delta) { @@ -3419,7 +3677,7 @@ MidiRegionView::midi_channel_mode_changed () // 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 (); @@ -3491,7 +3749,7 @@ MidiRegionView::selection_as_cut_buffer () const /** This method handles undo */ bool -MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx, const int32_t sub_num) +MidiRegionView::paste (samplepos_t pos, const ::Selection& selection, PasteContext& ctx, const int32_t sub_num) { bool commit = false; // Paste notes, if available @@ -3524,7 +3782,7 @@ MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContex /** This method handles undo */ void -MidiRegionView::paste_internal (framepos_t pos, unsigned paste_count, float times, const MidiCutBuffer& mcb) +MidiRegionView::paste_internal (samplepos_t pos, unsigned paste_count, float times, const MidiCutBuffer& mcb) { if (mcb.empty()) { return; @@ -3532,14 +3790,14 @@ MidiRegionView::paste_internal (framepos_t pos, unsigned paste_count, float time start_note_diff_command (_("paste")); - const Evoral::Beats snap_beats = get_grid_beats(pos); - const Evoral::Beats first_time = (*mcb.notes().begin())->time(); - const Evoral::Beats last_time = (*mcb.notes().rbegin())->end_time(); - const Evoral::Beats duration = last_time - first_time; - const Evoral::Beats snap_duration = duration.snap_to(snap_beats); - const Evoral::Beats paste_offset = snap_duration * paste_count; - const Evoral::Beats quarter_note = absolute_frames_to_source_beats(pos) + paste_offset; - Evoral::Beats end_point = Evoral::Beats(); + const Temporal::Beats snap_beats = get_grid_beats(pos); + const Temporal::Beats first_time = (*mcb.notes().begin())->time(); + const Temporal::Beats last_time = (*mcb.notes().rbegin())->end_time(); + const Temporal::Beats duration = last_time - first_time; + const Temporal::Beats snap_duration = duration.snap_to(snap_beats); + const Temporal::Beats paste_offset = snap_duration * paste_count; + const Temporal::Beats quarter_note = absolute_samples_to_source_beats(pos) + paste_offset; + Temporal::Beats end_point = Temporal::Beats(); DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste data spans from %1 to %2 (%3) ; paste pos beats = %4 (based on %5 - %6)\n", first_time, @@ -3566,16 +3824,16 @@ MidiRegionView::paste_internal (framepos_t pos, unsigned paste_count, float time /* if we pasted past the current end of the region, extend the region */ - framepos_t end_frame = source_beats_to_absolute_frames (end_point); - framepos_t region_end = _region->position() + _region->length() - 1; + samplepos_t end_sample = source_beats_to_absolute_samples (end_point); + samplepos_t region_end = _region->position() + _region->length() - 1; - if (end_frame > region_end) { + if (end_sample > region_end) { - DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste extended region from %1 to %2\n", region_end, end_frame)); + DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste extended region from %1 to %2\n", region_end, end_sample)); _region->clear_changes (); /* we probably need to get the snap modifier somehow to make this correct for non-musical use */ - _region->set_length (end_frame - _region->position(), trackview.editor().get_grid_music_divisions (0)); + _region->set_length (end_sample - _region->position(), trackview.editor().get_grid_music_divisions (0)); trackview.session()->add_command (new StatefulDiffCommand (_region)); } @@ -3588,53 +3846,47 @@ struct EventNoteTimeEarlyFirstComparator { } }; -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(&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); } } @@ -3643,35 +3895,43 @@ MidiRegionView::goto_previous_note (bool add_to_selection) { bool use_next = false; - if (_events.front()->selected()) { - return; - } - - time_sort_events (); - MidiTimeAxisView* const mtv = dynamic_cast(&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); } } @@ -3680,18 +3940,18 @@ MidiRegionView::selection_as_notelist (Notes& selected, bool allow_all_if_none_s { 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); } } } @@ -3710,11 +3970,11 @@ MidiRegionView::update_ghost_note (double x, double y, uint32_t state) PublicEditor& editor = trackview.editor (); - framepos_t const unsnapped_frame = editor.pixel_to_sample (x); + samplepos_t const unsnapped_sample = editor.pixel_to_sample (x); const int32_t divisions = editor.get_grid_music_divisions (state); const bool shift_snap = midi_view()->note_mode() != Percussive; - const Evoral::Beats snapped_beats = snap_frame_to_grid_underneath (unsnapped_frame, divisions, shift_snap); + const Temporal::Beats snapped_beats = snap_sample_to_grid_underneath (unsnapped_sample, divisions, shift_snap); /* prevent Percussive mode from displaying a ghost hit at region end */ if (!shift_snap && snapped_beats >= midi_region()->start_beats() + midi_region()->length_beats()) { @@ -3733,7 +3993,7 @@ MidiRegionView::update_ghost_note (double x, double y, uint32_t state) } /* calculate time in beats relative to start of source */ - const Evoral::Beats length = get_grid_beats(unsnapped_frame + _region->position()); + const Temporal::Beats length = get_grid_beats(unsnapped_sample + _region->position()); _ghost_note->note()->set_time (snapped_beats); _ghost_note->note()->set_length (length); @@ -3810,9 +4070,9 @@ MidiRegionView::maybe_select_by_position (GdkEventButton* ev, double /*x*/, doub uint16_t chn_mask = mtv->midi_track()->get_playback_channel_mask(); if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) { - get_events (e, Evoral::Sequence::PitchGreaterThanOrEqual, (uint8_t) floor (note), chn_mask); + get_events (e, Evoral::Sequence::PitchGreaterThanOrEqual, (uint8_t) floor (note), chn_mask); } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { - get_events (e, Evoral::Sequence::PitchLessThanOrEqual, (uint8_t) floor (note), chn_mask); + get_events (e, Evoral::Sequence::PitchLessThanOrEqual, (uint8_t) floor (note), chn_mask); } else { return; } @@ -3824,8 +4084,8 @@ MidiRegionView::maybe_select_by_position (GdkEventButton* ev, double /*x*/, doub } 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); } } @@ -3844,7 +4104,7 @@ MidiRegionView::color_handler () _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 */ @@ -3857,7 +4117,7 @@ MidiRegionView::enable_display (bool yn) } void -MidiRegionView::show_step_edit_cursor (Evoral::Beats pos) +MidiRegionView::show_step_edit_cursor (Temporal::Beats pos) { if (_step_edit_cursor == 0) { ArdourCanvas::Item* const group = get_canvas_group(); @@ -3874,12 +4134,12 @@ MidiRegionView::show_step_edit_cursor (Evoral::Beats pos) } void -MidiRegionView::move_step_edit_cursor (Evoral::Beats pos) +MidiRegionView::move_step_edit_cursor (Temporal::Beats pos) { _step_edit_cursor_position = pos; if (_step_edit_cursor) { - double pixel = trackview.editor().sample_to_pixel (region_beats_to_region_frames (pos)); + double pixel = trackview.editor().sample_to_pixel (region_beats_to_region_samples (pos)); _step_edit_cursor->set_x0 (pixel); set_step_edit_cursor_width (_step_edit_cursor_width); } @@ -3894,14 +4154,14 @@ MidiRegionView::hide_step_edit_cursor () } void -MidiRegionView::set_step_edit_cursor_width (Evoral::Beats beats) +MidiRegionView::set_step_edit_cursor_width (Temporal::Beats beats) { _step_edit_cursor_width = beats; if (_step_edit_cursor) { _step_edit_cursor->set_x1 (_step_edit_cursor->x0() + trackview.editor().sample_to_pixel ( - region_beats_to_region_frames (_step_edit_cursor_position + beats) - - region_beats_to_region_frames (_step_edit_cursor_position))); + region_beats_to_region_samples (_step_edit_cursor_position + beats) + - region_beats_to_region_samples (_step_edit_cursor_position))); } } @@ -3926,7 +4186,7 @@ MidiRegionView::data_recorded (boost::weak_ptr w) boost::shared_ptr buf = mtv->midi_track()->get_gui_feed_buffer (); - framepos_t back = max_framepos; + samplepos_t back = max_samplepos; for (MidiBuffer::iterator i = buf->begin(); i != buf->end(); ++i) { const Evoral::Event& ev = *i; @@ -3939,13 +4199,13 @@ MidiRegionView::data_recorded (boost::weak_ptr w) } } - /* convert from session frames to source beats */ - Evoral::Beats const time_beats = _source_relative_time_converter.from( + /* convert from session samples to source beats */ + Temporal::Beats const time_beats = _source_relative_time_converter.from( ev.time() - src->timeline_position() + _region->start()); if (ev.type() == MIDI_CMD_NOTE_ON) { boost::shared_ptr note ( - new NoteType (ev.channel(), time_beats, Evoral::Beats(), ev.note(), ev.velocity())); + new NoteType (ev.channel(), time_beats, Temporal::Beats(), ev.note(), ev.velocity())); add_note (note, true); @@ -4099,23 +4359,23 @@ MidiRegionView::get_velocity_for_add (MidiModel::TimeType time) const return (*n)->velocity() + (frac * ((*m)->velocity() - (*n)->velocity())); } -/** @param p A session framepos. +/** @param p A session samplepos. * @param divisions beat division to snap given by Editor::get_grid_music_divisions() where * bar is -1, 0 is audio samples and a positive integer is beat subdivisions. * @return beat duration of p snapped to the grid subdivision underneath it. */ -Evoral::Beats -MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, int32_t divisions, bool shift_snap) const +Temporal::Beats +MidiRegionView::snap_sample_to_grid_underneath (samplepos_t p, int32_t divisions, bool shift_snap) const { TempoMap& map (trackview.session()->tempo_map()); - double eqaf = map.exact_qn_at_frame (p + _region->position(), divisions); + double eqaf = map.exact_qn_at_sample (p + _region->position(), divisions); if (divisions != 0 && shift_snap) { - const double qaf = map.quarter_note_at_frame (p + _region->position()); + const double qaf = map.quarter_note_at_sample (p + _region->position()); /* Hack so that we always snap to the note that we are over, instead of snapping to the next one if we're more than halfway through the one we're over. */ - const Evoral::Beats grid_beats = get_grid_beats (p + _region->position()); + const Temporal::Beats grid_beats = get_grid_beats (p + _region->position()); const double rem = eqaf - qaf; if (rem >= 0.0) { eqaf -= grid_beats.to_double(); @@ -4123,7 +4383,7 @@ MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, int32_t divisions, } const double session_start_off = _region->quarter_note() - midi_region()->start_beats(); - return Evoral::Beats (eqaf - session_start_off); + return Temporal::Beats (eqaf - session_start_off); } ChannelMode @@ -4141,14 +4401,14 @@ MidiRegionView::get_selected_channels () const } -Evoral::Beats -MidiRegionView::get_grid_beats(framepos_t pos) const +Temporal::Beats +MidiRegionView::get_grid_beats(samplepos_t pos) const { PublicEditor& editor = trackview.editor(); bool success = false; - Evoral::Beats beats = editor.get_grid_type_as_beats (success, pos); + Temporal::Beats beats = editor.get_grid_type_as_beats (success, pos); if (!success) { - beats = Evoral::Beats(1); + beats = Temporal::Beats(1); } return beats; } @@ -4173,3 +4433,9 @@ MidiRegionView::note_to_y(uint8_t note) const { 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()); +}