diff --git a/gtk2_ardour/midi_view_background.cc b/gtk2_ardour/midi_view_background.cc index 991c894b4b..39d244bf44 100644 --- a/gtk2_ardour/midi_view_background.cc +++ b/gtk2_ardour/midi_view_background.cc @@ -81,32 +81,6 @@ MidiViewBackground::color_handler () setup_note_lines (); } -void -MidiViewBackground::note_range_adjustment_changed() -{ - double sum = note_range_adjustment.get_value() + note_range_adjustment.get_page_size(); - int lowest = (int) floor(note_range_adjustment.get_value()); - int highest; - - if (sum == _range_sum_cache) { - //cerr << "cached" << endl; - highest = (int) floor(sum); - } else { - //cerr << "recalc" << endl; - highest = lowest + (int) floor(note_range_adjustment.get_page_size()); - _range_sum_cache = sum; - } - - if (lowest == _lowest_note && highest == _highest_note) { - return; - } - - //cerr << "note range adjustment changed: " << lowest << " " << highest << endl; - //cerr << " val=" << v_zoom_adjustment.get_value() << " page=" << v_zoom_adjustment.get_page_size() << " sum=" << v_zoom_adjustment.get_value() + v_zoom_adjustment.get_page_size() << endl; - - apply_note_range (lowest, highest, true); -} - uint8_t MidiViewBackground::y_to_note (int y) const { @@ -157,7 +131,7 @@ MidiViewBackground::setup_note_lines() ArdourCanvas::RectSet::ResetRAII lr (*_note_lines); - if (contents_height() < 10 || note_height() < 3) { + if (contents_height() < 10 || note_height() < 2) { /* context is too small for note lines, or there are too many */ return; } @@ -195,9 +169,21 @@ MidiViewBackground::setup_note_lines() break; } + /* There's no clipping region trivially available for the note + * lines, so make sure the last line doesn't draw "too tall" + */ + + if (y + h > contents_height()) { + h = contents_height() - y; + } + _note_lines->add_rect (i, ArdourCanvas::Rect (0., y, ArdourCanvas::COORD_MAX, y + h), color); y += h; + + if (y >= contents_height()) { + break; + } } } @@ -244,24 +230,26 @@ MidiViewBackground::maybe_extend_note_range (uint8_t note_num) } void -MidiViewBackground::maybe_apply_note_range (uint8_t lowest, uint8_t highest, bool to_children) +MidiViewBackground::maybe_apply_note_range (uint8_t lowest, uint8_t highest, bool to_children, RangeCanMove can_move) { if (note_range_set && _lowest_note <= lowest && _highest_note >= highest) { /* already large enough */ return; } - apply_note_range (lowest, highest, to_children); + apply_note_range (lowest, highest, to_children, can_move); } void -MidiViewBackground::apply_note_range (uint8_t lowest, uint8_t highest, bool to_children) +MidiViewBackground::apply_note_range (uint8_t lowest, uint8_t highest, bool to_children, RangeCanMove can_move) { if (contents_height() == 0) { return; } bool changed = false; + uint8_t ol = _lowest_note; + uint8_t oh = _highest_note; /* Enforce a 1 octave minimum */ @@ -281,40 +269,56 @@ MidiViewBackground::apply_note_range (uint8_t lowest, uint8_t highest, bool to_c _lowest_note = lowest; } + if (note_range_set && !changed) { return; } float uiscale = UIConfiguration::instance().get_ui_scale(); - uiscale = expf (uiscale) / expf (1.f); - const int mnh = UIConfiguration::instance().get_max_note_height(); - int const max_note_height = std::max (mnh, mnh * uiscale); int const range = _highest_note - _lowest_note; - int nh = contents_height() / range; + int nh = std::min ((int) (UIConfiguration::instance().get_max_note_height() * uiscale), (int) ceil ((double) contents_height() / range)); int additional_notes = 0; - if (nh > max_note_height) { - int const available_note_range = contents_height() / max_note_height; - additional_notes = available_note_range - range; - } else if (note_range_set) { - additional_notes = (contents_height() - (nh * range)) / nh; + if (nh < 5) { + _lowest_note = ol; + _highest_note = oh; + return; + } + + if (note_range_set) { + additional_notes = (int) ceil ((contents_height() - (nh * range)) / (double) nh); } /* distribute additional notes to higher and lower ranges, clamp at 0 and 127 */ - for (int i = 0; i < additional_notes; i++){ + if (additional_notes > 0) { + for (int i = 0; i < additional_notes; i++){ - if (i % 2 && _highest_note < 127){ - _highest_note++; + if ((can_move & CanMoveTop) || (i % 2 && _highest_note < 127)) { + _highest_note++; + } else if ((can_move & CanMoveBottom) && (i % 2)) { + _lowest_note--; + } else if ((can_move & CanMoveBottom) && (_lowest_note > 0)) { + _lowest_note--; + } else if (can_move & CanMoveTop) { + _highest_note++; + } } - else if (i % 2) { - _lowest_note--; - } - else if (_lowest_note > 0){ - _lowest_note--; - } - else { - _highest_note++; + } else if (additional_notes < 0) { + for (int i = 0; i < -additional_notes; i++){ + + if ((can_move & CanMoveTop) && (i % 2 && _highest_note < 127)) { + _highest_note--; + } + else if ((can_move & CanMoveBottom) && (i % 2)) { + _lowest_note++; + } + else if ((can_move & CanMoveBottom) && (_lowest_note > 0)) { + _lowest_note++; + } + else if ((can_move & CanMoveTop)) { + _highest_note--; + } } } @@ -332,6 +336,31 @@ MidiViewBackground::apply_note_range (uint8_t lowest, uint8_t highest, bool to_c NoteRangeChanged(); /* EMIT SIGNAL*/ } +void +MidiViewBackground::note_range_adjustment_changed() +{ + double sum = note_range_adjustment.get_value() + note_range_adjustment.get_page_size(); + int lowest = (int) floor(note_range_adjustment.get_value()); + int highest; + + if (sum == _range_sum_cache) { + //cerr << "cached" << endl; + highest = (int) floor(sum); + } else { + //cerr << "recalc" << endl; + highest = lowest + (int) floor(note_range_adjustment.get_page_size()); + _range_sum_cache = sum; + } + + if (lowest == _lowest_note && highest == _highest_note) { + return; + } + + // cerr << " val=" << v_zoom_adjustment.get_value() << " page=" << v_zoom_adjustment.get_page_size() << " sum=" << v_zoom_adjustment.get_value() + v_zoom_adjustment.get_page_size() << endl; + + apply_note_range (lowest, highest, true); +} + bool MidiViewBackground::update_data_note_range (uint8_t min, uint8_t max) { diff --git a/gtk2_ardour/midi_view_background.h b/gtk2_ardour/midi_view_background.h index 11423fd935..0d467871a6 100644 --- a/gtk2_ardour/midi_view_background.h +++ b/gtk2_ardour/midi_view_background.h @@ -96,8 +96,7 @@ class MidiViewBackground : public virtual ViewBackground void maybe_extend_note_range (uint8_t note_num); int note_height() const { - /* Note: this effectively rounds down (truncates) due to integer arithmetic */ - return contents_height() / contents_note_range(); + return (int) ceil ((double) contents_height() / contents_note_range()); } int note_to_y (uint8_t note) const { @@ -112,8 +111,14 @@ class MidiViewBackground : public virtual ViewBackground } sigc::signal NoteRangeChanged; - void apply_note_range (uint8_t lowest, uint8_t highest, bool to_children); - void maybe_apply_note_range (uint8_t lowest, uint8_t highest, bool to_children); + + enum RangeCanMove { + CanMoveTop = 0x1, + CanMoveBottom = 0x2 + }; + + void apply_note_range (uint8_t lowest, uint8_t highest, bool to_children, RangeCanMove = RangeCanMove (CanMoveTop|CanMoveBottom)); + void maybe_apply_note_range (uint8_t lowest, uint8_t highest, bool to_children, RangeCanMove = RangeCanMove (CanMoveTop|CanMoveBottom)); /** @return y position, or -1 if hidden */ virtual int y_position () const { return 0; } diff --git a/gtk2_ardour/prh_base.cc b/gtk2_ardour/prh_base.cc index abd49c6262..44fee1b8be 100644 --- a/gtk2_ardour/prh_base.cc +++ b/gtk2_ardour/prh_base.cc @@ -553,43 +553,45 @@ PianoRollHeaderBase::motion_handler (GdkEventMotion* ev) if (_scroomer_drag){ - double pixel2val = 127.0 / height(); + const double pixels_per_note = 127.0 / height(); double delta = _old_y - evy; - double val_at_pointer = (delta * pixel2val); - double real_val_at_pointer = 127.0 - (evy * pixel2val); + double val_at_pointer = (delta * pixels_per_note); + double real_val_at_pointer = 127.0 - (evy * pixels_per_note); double note_range = _adj.get_page_size (); switch (_scroomer_button_state){ - case MOVE: - _fract += val_at_pointer; - _fract = (_fract + note_range > 127.0)? 127.0 - note_range : _fract; - _fract = max(0.0, _fract); - _adj.set_value (min(_fract, 127.0 - note_range)); - break; - case TOP: - real_val_at_pointer = real_val_at_pointer <= _saved_top_val? _adj.get_value() + _adj.get_page_size() : real_val_at_pointer; - real_val_at_pointer = min(127.0, real_val_at_pointer); - if (_midi_context.note_height() >= UIConfiguration::instance().get_max_note_height()){ - _saved_top_val = min(_adj.get_value() + _adj.get_page_size (), 127.0); - } else { - _saved_top_val = 0.0; - } - //if we are at largest note size & the user is moving down don't do anything - //FIXME we are using a heuristic of 18.5 for max note size, but this changes when track size is small to 19.5? - _midi_context.apply_note_range (_adj.get_value (), real_val_at_pointer, true); - break; - case BOTTOM: - real_val_at_pointer = max(0.0, real_val_at_pointer); - real_val_at_pointer = real_val_at_pointer >= _saved_bottom_val? _adj.get_value() : real_val_at_pointer; - if (_midi_context.note_height() >= UIConfiguration::instance().get_max_note_height()){ - _saved_bottom_val = _adj.get_value(); - } else { - _saved_bottom_val = 127.0; - } - _midi_context.apply_note_range (real_val_at_pointer, _adj.get_value () + _adj.get_page_size (), true); - break; - default: - break; + case MOVE: + _fract += val_at_pointer; + _fract = (_fract + note_range > 127.0)? 127.0 - note_range : _fract; + _fract = max(0.0, _fract); + _adj.set_value (min(_fract, 127.0 - note_range)); + break; + + case TOP: + real_val_at_pointer = real_val_at_pointer <= _saved_top_val? _adj.get_value() + _adj.get_page_size() : real_val_at_pointer; + real_val_at_pointer = min (127.0, ceil (real_val_at_pointer)); + + if (_midi_context.note_height() >= UIConfiguration::instance().get_max_note_height()){ + _saved_top_val = min (_adj.get_value() + _adj.get_page_size (), 127.0); + } else { + _saved_top_val = 0.0; + _midi_context.apply_note_range (_adj.get_value (), real_val_at_pointer, true, MidiViewBackground::CanMoveTop); + } + break; + + case BOTTOM: + real_val_at_pointer = real_val_at_pointer >= _saved_bottom_val? _adj.get_value() : real_val_at_pointer; + real_val_at_pointer = max (0.0, floor (real_val_at_pointer)); + if (_midi_context.note_height() >= UIConfiguration::instance().get_max_note_height()){ + _saved_bottom_val = _adj.get_value(); + } else { + _saved_bottom_val = 127.0; + _midi_context.apply_note_range (real_val_at_pointer, _adj.get_value () + _adj.get_page_size (), true, MidiViewBackground::CanMoveBottom); + } + break; + + default: + break; } redraw ();