diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc index 64de0b39519..e9c0a25012e 100644 --- a/gtk2_ardour/midi_streamview.cc +++ b/gtk2_ardour/midi_streamview.cc @@ -270,18 +270,8 @@ MidiStreamView::redisplay_track () list::iterator i; - // Load models if necessary, and find note range of all our contents - _range_dirty = false; - _data_note_min = 127; - _data_note_max = 0; - _trackview.track()->playlist()->foreach_region( - sigc::mem_fun (*this, &StreamView::update_contents_metrics)); - - // No notes, use default range - if (!_range_dirty) { - _data_note_min = 60; - _data_note_max = 71; - } + // Load models if necessary, and find note range of all our contents; + read_data_note_range_from_regions(); // Flag region views as invalid and disable drawing for (i = region_views.begin(); i != region_views.end(); ++i) { @@ -301,6 +291,23 @@ MidiStreamView::redisplay_track () } +void +MidiStreamView::read_data_note_range_from_regions() +{ + // Load models if necessary, and find note range of all our contents + _range_dirty = false; + _data_note_min = 127; + _data_note_max = 0; + _trackview.track()->playlist()->foreach_region( + sigc::mem_fun (*this, &StreamView::update_contents_metrics)); + + // No notes, use default range + if (!_range_dirty) { + _data_note_min = 60; + _data_note_max = 71; + } +} + void MidiStreamView::update_contents_height () { @@ -376,12 +383,33 @@ MidiStreamView::draw_note_lines() void MidiStreamView::set_note_range(VisibleNoteRange r) { - if (r == FullRange) { + switch (r) { + case FullRange: _lowest_note = 0; _highest_note = 127; - } else { + break; + case OneNoteRange: + _lowest_note = _data_note_min; + _highest_note = _data_note_min; + break; + default: + /* range was one note so need read note data range again + * (if there was other notes range will be expanded) + */ + if (_lowest_note == _highest_note) + read_data_note_range_from_regions(); + /* the range read may still contain only one note, + * if so, we have to enlarge it manually + */ + if (_data_note_min == _data_note_max) { + if (_data_note_max < 117) + _data_note_max += 11; + else + _data_note_min -= 11; + } _lowest_note = _data_note_min; _highest_note = _data_note_max; + break; } apply_note_range(_lowest_note, _highest_note, true); @@ -394,11 +422,11 @@ MidiStreamView::apply_note_range(uint8_t lowest, uint8_t highest, bool to_region _lowest_note = lowest; int const max_note_height = 20; // This should probably be based on text size... - int const range = _highest_note - _lowest_note; + int const range = _highest_note == _lowest_note ? 1 : _highest_note - _lowest_note; int const pixels_per_note = floor (child_height () / range); - /* do not grow note height beyond 10 pixels */ - if (pixels_per_note > max_note_height) { + /* do not grow note height beyond 10 pixels (except when we want one note) */ + if (pixels_per_note > max_note_height && range > 1) { int const available_note_range = floor (child_height() / max_note_height); int additional_notes = available_note_range - range; diff --git a/gtk2_ardour/midi_streamview.h b/gtk2_ardour/midi_streamview.h index b333ff33e87..f237d0268f8 100644 --- a/gtk2_ardour/midi_streamview.h +++ b/gtk2_ardour/midi_streamview.h @@ -68,7 +68,8 @@ class MidiStreamView : public StreamView enum VisibleNoteRange { FullRange, - ContentsRange + ContentsRange, + OneNoteRange }; Gtk::Adjustment note_range_adjustment; @@ -133,6 +134,7 @@ class MidiStreamView : public StreamView void draw_note_lines(); bool update_data_note_range(uint8_t min, uint8_t max); void update_contents_metrics(boost::shared_ptr r); + void read_data_note_range_from_regions(); void color_handler (); diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index ae8c27a6324..06aeab2ef4e 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -628,6 +628,11 @@ MidiTimeAxisView::append_extra_display_menu_items () sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range), MidiStreamView::ContentsRange, true))); + range_items.push_back ( + MenuElem (_("One Note"), + sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range), + MidiStreamView::OneNoteRange, true))); + items.push_back (MenuElem (_("Note Range"), *range_menu)); items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu())); items.push_back (MenuElem (_("Channel Selector..."), diff --git a/gtk2_ardour/piano_roll_header.cc b/gtk2_ardour/piano_roll_header.cc index 5bf57fc6a8d..64d3d175b9b 100644 --- a/gtk2_ardour/piano_roll_header.cc +++ b/gtk2_ardour/piano_roll_header.cc @@ -22,6 +22,7 @@ #include #include "evoral/midi_events.h" #include "ardour/midi_track.h" +#include "ardour/parameter_descriptor.h" #include "gtkmm2ext/keyboard.h" @@ -34,6 +35,7 @@ using namespace std; using namespace Gtkmm2ext; +using namespace ARDOUR; PianoRollHeader::Color PianoRollHeader::white = PianoRollHeader::Color(0.77f, 0.78f, 0.76f); PianoRollHeader::Color PianoRollHeader::white_highlight = PianoRollHeader::Color(1.00f, 0.40f, 0.40f); @@ -302,6 +304,7 @@ PianoRollHeader::on_expose_event (GdkEventExpose* ev) int oct_rel; int y1 = max(rect.y, 0); int y2 = min(rect.y + rect.height, (int) floor(_view.contents_height() - 1.0f)); + bool is_white_key; //Cairo::TextExtents te; lowest = max(_view.lowest_note(), _view.y_to_note(y2)); @@ -313,7 +316,6 @@ PianoRollHeader::on_expose_event (GdkEventExpose* ev) cr->select_font_face ("Georgia", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_BOLD); font_size = min((double) 10.0f, _note_height - 4.0f); - cr->set_font_size(font_size); /* fill the entire rect with the color for non-highlighted white notes. * then we won't have to draw the background for those notes, @@ -348,6 +350,8 @@ PianoRollHeader::on_expose_event (GdkEventExpose* ev) case 8: case 10: /* black note */ + is_white_key = false; + if (i == _highlighted_note) { bg.set(black_highlight); } else { @@ -378,6 +382,8 @@ PianoRollHeader::on_expose_event (GdkEventExpose* ev) default: /* white note */ + is_white_key = true; + if (i == _highlighted_note) { bg.set(white_highlight); } else { @@ -443,25 +449,56 @@ PianoRollHeader::on_expose_event (GdkEventExpose* ev) } - /* render the name of which C this is */ - if (oct_rel == 0) { - std::stringstream s; + /* if only one note visible render note name vertical (because A#3 don't fit on key) */ + if (lowest == highest) { + string const note_name = ParameterDescriptor::midi_note_name(i); double y = floor(_view.note_to_y(i)) - 0.5f; double note_height = floor(_view.note_to_y(i - 1)) - y; - int cn = i / 12 - 1; - s << "C" << cn; + cr->set_font_size(font_size); + + Cairo::TextExtents te; + cr->get_text_extents(note_name, te); + + double r, g, b; - //cr->get_text_extents(s.str(), te); - cr->set_source_rgb(0.30f, 0.30f, 0.30f); + if (is_white_key) + note_name_color(white, r, g, b); + else + note_name_color(black, r, g, b); + + cr->set_source_rgb(r, g, b); + cr->move_to(2.0f + font_size , y + note_height - 1.0f - (note_height - te.width) / 2.0f); + cr->rotate(M_PI / -2.0); // -90 degrees + cr->show_text(note_name); + } + else if (oct_rel == 0) { + /* render the name of which C this is */ + double y = floor(_view.note_to_y(i)) - 0.5f; + double note_height = floor(_view.note_to_y(i - 1)) - y; + + double r, g, b; + note_name_color(white, r, g, b); + + cr->set_source_rgb(r, g, b); cr->move_to(2.0f, y + note_height - 1.0f - (note_height - font_size) / 2.0f); - cr->show_text(s.str()); + cr->show_text(ParameterDescriptor::midi_note_name(i)); } } return true; } +void +PianoRollHeader::note_name_color(const PianoRollHeader::Color& key_color, double& r, double& g, double& b) +{ + Gtkmm2ext::Color text_color = Gtkmm2ext::rgba_to_color(key_color.r, key_color.g, key_color.b, 1.0f); + text_color = Gtkmm2ext::contrasting_text_color(text_color); + + double a; + Gtkmm2ext::color_to_rgba(text_color, r, g, b, a); +} + bool PianoRollHeader::on_motion_notify_event (GdkEventMotion* ev) { diff --git a/gtk2_ardour/piano_roll_header.h b/gtk2_ardour/piano_roll_header.h index 04217c560a8..8378c70cf55 100644 --- a/gtk2_ardour/piano_roll_header.h +++ b/gtk2_ardour/piano_roll_header.h @@ -75,6 +75,8 @@ class PianoRollHeader : public Gtk::DrawingArea { static Color black_shade_light; static Color black_shade_dark; + static void note_name_color(const Color& key_color, double& r, double& g, double& b); + PianoRollHeader(const PianoRollHeader&); enum ItemType {