X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=gtk2_ardour%2Fmidi_region_view.cc;h=79933b94d6cdb58afb0877c796720801733885c3;hb=b8f5306d5bf59ddb237fabcdbab91a7d1e6fd612;hp=3fbe2c83fc1d874a3e3f13af240692113620e4ae;hpb=4f7a4cd23331d64acfabc52e978dcb3dde2e82ec;p=ardour.git diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 3fbe2c83fc..79933b94d6 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -82,7 +82,7 @@ #include "sys_ex.h" #include "ui_config.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace ARDOUR; using namespace PBD; @@ -928,16 +928,24 @@ MidiRegionView::create_note_at (framepos_t t, double y, Evoral::Beats length, bo MidiTimeAxisView* const mtv = dynamic_cast(&trackview); MidiStreamView* const view = mtv->midi_view(); + boost::shared_ptr mr = boost::dynamic_pointer_cast (_region); + + if (!mr) { + return; + } // Start of note in frames relative to region start + uint32_t divisions = 0; + if (snap_t) { framecnt_t grid_frames; t = snap_frame_to_grid_underneath (t, grid_frames); + divisions = trackview.editor().get_grid_music_divisions (0); } - const MidiModel::TimeType beat_time = region_frames_to_region_beats( - t + _region->start()); + const MidiModel::TimeType beat_time = Evoral::Beats (trackview.session()->tempo_map().exact_beat_at_frame (_region->position() + t, divisions) + - (mr->beat() - mr->start_beats().to_double())); const double note = view->y_to_note(y); const uint8_t chan = mtv->get_channel_for_add(); const uint8_t velocity = get_velocity_for_add(beat_time); @@ -1180,21 +1188,20 @@ MidiRegionView::redisplay_model() _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); - NoteBase* cne; bool visible; if (note_in_region_range (note, visible)) { if (!empty_when_starting && (cne = find_canvas_note (note)) != 0) { - cne->validate (); - update_note (cne); - if (visible) { + cne->validate (); + update_note (cne); cne->show (); } else { cne->hide (); @@ -1407,12 +1414,18 @@ MidiRegionView::region_resized (const PropertyChange& what_changed) _region_relative_time_converter.set_origin_b(_region->position()); _region_relative_time_converter_double.set_origin_b(_region->position()); /* reset_width dependent_items() redisplays model */ + } if (what_changed.contains (ARDOUR::Properties::start) || what_changed.contains (ARDOUR::Properties::position)) { _source_relative_time_converter.set_origin_b (_region->position() - _region->start()); } + /* catch an end trim so we can live update */ + if (!what_changed.contains (ARDOUR::Properties::start) && + what_changed.contains (ARDOUR::Properties::length)) { + enable_display (true); + } } void @@ -1422,7 +1435,7 @@ MidiRegionView::reset_width_dependent_items (double pixel_width) if (_enable_display) { redisplay_model(); - } + } for (PatchChanges::iterator x = _patch_changes.begin(); x != _patch_changes.end(); ++x) { if ((*x)->canvas_item()->width() >= _pixel_width) { @@ -1667,12 +1680,9 @@ MidiRegionView::start_playing_midi_chord (vector > n bool MidiRegionView::note_in_region_range (const boost::shared_ptr note, bool& visible) const { - /* This is imprecise due to all the conversion conversion involved, so only - hide notes if they seem to start more than one tick before the start. */ - const framecnt_t tick_frames = Evoral::Beats::tick().to_ticks(trackview.session()->frame_rate()); - const framepos_t note_start_frames = source_beats_to_region_frames (note->time()); - const bool outside = ((note_start_frames <= -tick_frames) || - (note_start_frames >= _region->length())); + const boost::shared_ptr midi_reg = midi_region(); + const bool outside = (note->time() < midi_reg->start_beats() || + note->time() > midi_reg->start_beats() + midi_reg->length_beats()); visible = (note->note() >= midi_stream_view()->lowest_note()) && (note->note() <= midi_stream_view()->highest_note()); @@ -1699,16 +1709,27 @@ MidiRegionView::update_note (NoteBase* note, bool update_ghost_regions) void MidiRegionView::update_sustained (Note* ev, bool update_ghost_regions) { + TempoMap& map (trackview.session()->tempo_map()); + const boost::shared_ptr mr = midi_region(); boost::shared_ptr note = ev->note(); - const double x0 = trackview.editor().sample_to_pixel (source_beats_to_region_frames (note->time())); + const framepos_t note_start_frames = map.frame_at_beat (_region->beat() - mr->start_beats().to_double() + + note->time().to_double()) - _region->position(); + + const double x0 = trackview.editor().sample_to_pixel (note_start_frames); double x1; const double y0 = 1 + floor(midi_stream_view()->note_to_y(note->note())); - double y1; - - /* trim note display to not overlap the end of its region */ + double y1;/* trim note display to not overlap the end of its region */ if (note->length() > 0) { - const framepos_t note_end_frames = min (source_beats_to_region_frames (note->end_time()), _region->length()); + Evoral::Beats note_end_time = note->end_time(); + + if (note->end_time() > mr->start_beats() + mr->length_beats()) { + note_end_time = mr->start_beats() + mr->length_beats(); + } + + const framepos_t note_end_frames = map.frame_at_beat (_region->beat() - mr->start_beats().to_double() + + note_end_time.to_double()) - _region->position(); + x1 = std::max(1., trackview.editor().sample_to_pixel (note_end_frames)) - 1; } else { x1 = std::max(1., trackview.editor().sample_to_pixel (_region->length())) - 1; @@ -1716,10 +1737,8 @@ MidiRegionView::update_sustained (Note* ev, bool update_ghost_regions) y1 = y0 + std::max(1., floor(midi_stream_view()->note_height()) - 1); - ev->set_x0 (x0); - ev->set_x1 (x1); - ev->set_y0 (y0); - ev->set_y1 (y1); + ArdourCanvas::Rect rect (x0, y0, x1, y1); + ev->set (rect); if (!note->length()) { if (_active_notes && note->note() < 128) { @@ -1743,8 +1762,9 @@ MidiRegionView::update_sustained (Note* ev, bool update_ghost_regions) } // Update color in case velocity has changed - //ev->set_fill_color(ev->base_color()); - //ev->set_outline_color(ev->calculate_outline(ev->base_color(), ev->selected())); + //const uint32_t base_col = ev->base_color(); + //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) { @@ -1761,7 +1781,8 @@ MidiRegionView::update_hit (Hit* ev, bool update_ghost_regions) { boost::shared_ptr note = ev->note(); - const framepos_t note_start_frames = source_beats_to_region_frames(note->time()); + const framepos_t note_start_frames = trackview.session()->tempo_map().frame_at_beat (_region->beat() - midi_region()->start_beats().to_double() + + note->time().to_double()) - _region->position(); const double x = trackview.editor().sample_to_pixel(note_start_frames); const double diamond_size = std::max(1., floor(midi_stream_view()->note_height()) - 2.); const double y = 1.5 + floor(midi_stream_view()->note_to_y(note->note())) + diamond_size * .5; @@ -1869,7 +1890,8 @@ MidiRegionView::step_add_note (uint8_t channel, uint8_t number, uint8_t velocity framepos_t region_end = _region->last_frame(); if (end_frame > region_end) { - _region->set_length (end_frame - _region->position()); + /* XX sets length in beats from audio space. make musical */ + _region->set_length (end_frame - _region->position(), 0); } MidiTimeAxisView* const mtv = dynamic_cast(&trackview); @@ -2728,6 +2750,7 @@ MidiRegionView::begin_resizing (bool /*at_front*/) void MidiRegionView::update_resizing (NoteBase* primary, bool at_front, double delta_x, bool relative, double snap_delta, bool with_snap) { + TempoMap& tmap (trackview.session()->tempo_map()); bool cursor_set = false; bool const ensure_snap = trackview.editor().snap_mode () != SnapMagnetic; @@ -2789,9 +2812,19 @@ MidiRegionView::update_resizing (NoteBase* primary, bool at_front, double delta_ sign = -1; } - const double snapped_x = (with_snap ? snap_pixel_to_sample (current_x, ensure_snap) : trackview.editor ().pixel_to_sample (current_x)); - Evoral::Beats beats = region_frames_to_region_beats (snapped_x); - Evoral::Beats len = Evoral::Beats(); + double snapped_x; + uint32_t divisions = 0; + + if (with_snap) { + snapped_x = snap_pixel_to_sample (current_x, ensure_snap); + divisions = trackview.editor().get_grid_music_divisions (0); + } 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) + - midi_region()->beat()) + midi_region()->start_beats(); + + Evoral::Beats len = Evoral::Beats(); if (at_front) { if (beats < canvas_note->note()->end_time()) { @@ -2824,6 +2857,7 @@ void MidiRegionView::commit_resizing (NoteBase* primary, bool at_front, double delta_x, bool relative, double snap_delta, bool with_snap) { _note_diff_command = _model->new_note_diff_command (_("resize notes")); + TempoMap& tmap (trackview.session()->tempo_map()); /* XX why doesn't snap_pixel_to_sample() handle this properly? */ bool const ensure_snap = trackview.editor().snap_mode () != SnapMagnetic; @@ -2871,16 +2905,19 @@ MidiRegionView::commit_resizing (NoteBase* primary, bool at_front, double delta_ sign = -1; } + uint32_t divisions = 0; /* Convert the new x position to a frame within the source */ framepos_t current_fr; if (with_snap) { - current_fr = snap_pixel_to_sample (current_x, ensure_snap) + _region->start (); + current_fr = snap_pixel_to_sample (current_x, ensure_snap); + divisions = trackview.editor().get_grid_music_divisions (0); } else { - current_fr = trackview.editor().pixel_to_sample (current_x) + _region->start (); + current_fr = trackview.editor().pixel_to_sample (current_x); } /* and then to beats */ - const Evoral::Beats x_beats = region_frames_to_region_beats (current_fr); + const Evoral::Beats x_beats = Evoral::Beats (tmap.exact_beat_at_frame (current_fr + midi_region()->position(), divisions) + - midi_region()->beat()) + midi_region()->start_beats(); 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)); @@ -3229,7 +3266,7 @@ MidiRegionView::nudge_notes (bool forward, bool fine) if (!fine) { /* non-fine, move by 1 bar regardless of snap */ - delta = Evoral::Beats(trackview.session()->tempo_map().meter_at(ref_point).divisions_per_bar()); + delta = Evoral::Beats(trackview.session()->tempo_map().meter_at_frame (ref_point).divisions_per_bar()); } else if (trackview.editor().snap_mode() == Editing::SnapOff) { @@ -3332,9 +3369,8 @@ void MidiRegionView::patch_entered (PatchChange* p) { ostringstream s; - /* XXX should get patch name if we can */ s << _("Bank ") << (p->patch()->bank() + MIDI_BP_ZERO) << '\n' - << _("Program ") << ((int) p->patch()->program()) + MIDI_BP_ZERO << '\n' + << instrument_info().get_patch_name_without (p->patch()->bank(), p->patch()->program(), p->patch()->channel()) << '\n' << _("Channel ") << ((int) p->patch()->channel() + 1); show_verbose_cursor (s.str(), 10, 20); p->item().grab_focus(); @@ -3488,7 +3524,7 @@ MidiRegionView::selection_as_cut_buffer () const /** This method handles undo */ bool -MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx) +MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx, const int32_t sub_num) { bool commit = false; // Paste notes, if available @@ -3503,7 +3539,7 @@ MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContex typedef RouteTimeAxisView::AutomationTracks ATracks; const ATracks& atracks = midi_view()->automation_tracks(); for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) { - if (a->second->paste(pos, selection, ctx)) { + if (a->second->paste(pos, selection, ctx, sub_num)) { commit = true; } } @@ -3566,7 +3602,8 @@ MidiRegionView::paste_internal (framepos_t pos, unsigned paste_count, float time DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste extended region from %1 to %2\n", region_end, end_frame)); _region->clear_changes (); - _region->set_length (end_frame - _region->position()); + /* 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)); trackview.session()->add_command (new StatefulDiffCommand (_region)); } @@ -3828,9 +3865,6 @@ void MidiRegionView::enable_display (bool yn) { RegionView::enable_display (yn); - if (yn) { - redisplay_model (); - } } void @@ -3876,7 +3910,9 @@ MidiRegionView::set_step_edit_cursor_width (Evoral::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 (beats))); + _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))); } } @@ -3963,6 +3999,10 @@ MidiRegionView::trim_front_ending () /* Trim drag made start time -ve; fix this */ midi_region()->fix_negative_start (); } + /* until _start is modified on the fly during front trim, + we have to redisplay the model when a start trim has finished. + */ + enable_display (true); } void @@ -4021,7 +4061,7 @@ MidiRegionView::get_note_name (boost::shared_ptr n, uint8_t note_value char buf[128]; snprintf (buf, sizeof (buf), "%d %s\nCh %d Vel %d", (int) note_value, - name.empty() ? Evoral::midi_note_name (note_value).c_str() : name.c_str(), + name.empty() ? ParameterDescriptor::midi_note_name (note_value).c_str() : name.c_str(), (int) n->channel() + 1, (int) n->velocity()); @@ -4089,8 +4129,8 @@ framepos_t MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, framecnt_t& grid_frames) const { PublicEditor& editor = trackview.editor (); - const Evoral::Beats p_beat = region_frames_to_region_beats (p); const Evoral::Beats grid_beats = get_grid_beats(p); + const Evoral::Beats p_beat = max (Evoral::Beats(), region_frames_to_region_beats (p)); grid_frames = region_beats_to_region_frames (p_beat + grid_beats) - region_beats_to_region_frames (p_beat);