X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmidi_streamview.cc;h=301e9ddcb401f51eb959ccc6f9008eed3d0bff89;hb=29b80725559c8fd60ae51bf33270963e647d0c1c;hp=640c0263e14f8b66a6480b96c0b74438f5c5aaa9;hpb=b855e5f3220027502a3c88f189d511fe2a5a3c2b;p=ardour.git diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc index 640c0263e1..301e9ddcb4 100644 --- a/gtk2_ardour/midi_streamview.cc +++ b/gtk2_ardour/midi_streamview.cc @@ -34,8 +34,6 @@ #include "ardour/session.h" #include "ardour/smf_source.h" -#include "ardour_ui.h" -#include "global_signals.h" #include "gui_thread.h" #include "midi_region_view.h" #include "midi_streamview.h" @@ -46,12 +44,14 @@ #include "region_view.h" #include "rgb_macros.h" #include "selection.h" +#include "ui_config.h" #include "utils.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; +using namespace ARDOUR_UI_UTILS; using namespace PBD; using namespace Editing; @@ -68,13 +68,13 @@ MidiStreamView::MidiStreamView (MidiTimeAxisView& tv) , _updates_suspended (false) { /* use a group dedicated to MIDI underlays. Audio underlays are not in this group. */ - midi_underlay_group = new ArdourCanvas::Group (_canvas_group); + midi_underlay_group = new ArdourCanvas::Container (_canvas_group); midi_underlay_group->lower_to_bottom(); /* put the note lines in the timeaxisview's group, so it can be put below ghost regions from MIDI underlays */ - _note_lines = new ArdourCanvas::LineSet (_canvas_group); + _note_lines = new ArdourCanvas::LineSet (_canvas_group, ArdourCanvas::LineSet::Horizontal); _note_lines->Event.connect( sigc::bind(sigc::mem_fun(_trackview.editor(), @@ -85,7 +85,7 @@ MidiStreamView::MidiStreamView (MidiTimeAxisView& tv) color_handler (); - ColorsChanged.connect(sigc::mem_fun(*this, &MidiStreamView::color_handler)); + UIConfiguration::instance().ColorsChanged.connect(sigc::mem_fun(*this, &MidiStreamView::color_handler)); note_range_adjustment.set_page_size(_highest_note - _lowest_note); note_range_adjustment.set_value(_lowest_note); @@ -99,7 +99,7 @@ MidiStreamView::~MidiStreamView () } RegionView* -MidiStreamView::create_region_view (boost::shared_ptr r, bool /*wfd*/, bool) +MidiStreamView::create_region_view (boost::shared_ptr r, bool /*wfd*/, bool recording) { boost::shared_ptr region = boost::dynamic_pointer_cast (r); @@ -107,20 +107,28 @@ MidiStreamView::create_region_view (boost::shared_ptr r, bool /*wfd*/, b return 0; } - RegionView* region_view = new MidiRegionView (_canvas_group, _trackview, region, - _samples_per_pixel, region_color); + RegionView* region_view = NULL; + if (recording) { + region_view = new MidiRegionView ( + _canvas_group, _trackview, region, + _samples_per_pixel, region_color, recording, + TimeAxisViewItem::Visibility(TimeAxisViewItem::ShowFrame)); + } else { + region_view = new MidiRegionView (_canvas_group, _trackview, region, + _samples_per_pixel, region_color); + } - region_view->init (region_color, false); + region_view->init (false); return region_view; } RegionView* -MidiStreamView::add_region_view_internal (boost::shared_ptr r, bool wfd, bool recording) +MidiStreamView::add_region_view_internal (boost::shared_ptr r, bool wait_for_data, bool recording) { boost::shared_ptr region = boost::dynamic_pointer_cast (r); - if (region == 0) { + if (!region) { return 0; } @@ -131,27 +139,21 @@ MidiStreamView::add_region_view_internal (boost::shared_ptr r, bool wfd, (*i)->set_valid (true); - display_region(dynamic_cast(*i), wfd); + display_region(dynamic_cast(*i), wait_for_data); return 0; } } - MidiRegionView* region_view = dynamic_cast (create_region_view (r, wfd, recording)); + MidiRegionView* region_view = dynamic_cast (create_region_view (r, wait_for_data, recording)); if (region_view == 0) { return 0; } region_views.push_front (region_view); - if (_trackview.editor().internal_editing()) { - region_view->hide_rect (); - } else { - region_view->show_rect (); - } - /* display events and find note range */ - display_region (region_view, wfd); + display_region (region_view, wait_for_data); /* fit note range if we are importing */ if (_trackview.session()->operation_in_progress (Operations::insert_file)) { @@ -174,12 +176,23 @@ MidiStreamView::display_region(MidiRegionView* region_view, bool load_model) return; } - region_view->enable_display(true); + region_view->enable_display (true); + region_view->set_height (child_height()); boost::shared_ptr source(region_view->midi_region()->midi_source(0)); + if (!source) { + error << _("attempt to display MIDI region with no source") << endmsg; + return; + } if (load_model) { - source->load_model(); + Glib::Threads::Mutex::Lock lm(source->mutex()); + source->load_model(lm); + } + + if (!source->model()) { + error << _("attempt to display MIDI region with no model") << endmsg; + return; } _range_dirty = update_data_note_range( @@ -187,10 +200,10 @@ MidiStreamView::display_region(MidiRegionView* region_view, bool load_model) source->model()->highest_note()); // Display region contents - region_view->set_height (child_height()); region_view->display_model(source->model()); } + void MidiStreamView::display_track (boost::shared_ptr tr) { @@ -206,7 +219,8 @@ MidiStreamView::update_contents_metrics(boost::shared_ptr r) { boost::shared_ptr mr = boost::dynamic_pointer_cast(r); if (mr) { - mr->midi_source(0)->load_model(); + Glib::Threads::Mutex::Lock lm(mr->midi_source(0)->mutex()); + mr->midi_source(0)->load_model(lm); _range_dirty = update_data_note_range( mr->model()->lowest_note(), mr->model()->highest_note()); @@ -272,7 +286,8 @@ void MidiStreamView::update_contents_height () { StreamView::update_contents_height(); - _note_lines->set_height (child_height ()); + + _note_lines->set_extent (ArdourCanvas::COORD_MAX); apply_note_range (lowest_note(), highest_note(), true); } @@ -285,7 +300,7 @@ MidiStreamView::draw_note_lines() } double y; - double prev_y = contents_height(); + double prev_y = .5; uint32_t color; _note_lines->clear(); @@ -295,10 +310,25 @@ MidiStreamView::draw_note_lines() return; } - for (int i = lowest_note(); i <= highest_note(); ++i) { - y = floor(note_to_y(i)); + /* do this is order of highest ... lowest since that matches the + * coordinate system in which y=0 is at the top + */ + + for (int i = highest_note() + 1; i >= lowest_note(); --i) { + + y = floor(note_to_y (i)) + .5; - _note_lines->add (prev_y, 1.0, ARDOUR_UI::config()->get_canvasvar_PianoRollBlackOutline()); + /* this is the line actually corresponding to the division + * between notes + */ + + if (i <= highest_note()) { + _note_lines->add (y, 1.0, UIConfiguration::instance().color ("piano roll black outline")); + } + + /* now add a thicker line/bar which covers the entire vertical + * height of this note. + */ switch (i % 12) { case 1: @@ -306,17 +336,18 @@ MidiStreamView::draw_note_lines() case 6: case 8: case 10: - color = ARDOUR_UI::config()->get_canvasvar_PianoRollBlack(); + color = UIConfiguration::instance().color_mod ("piano roll black", "piano roll black"); break; default: - color = ARDOUR_UI::config()->get_canvasvar_PianoRollWhite(); + color = UIConfiguration::instance().color_mod ("piano roll white", "piano roll white"); break; } - if (i == highest_note()) { - _note_lines->add (y, prev_y - y, color); - } else { - _note_lines->add (y + 1.0, prev_y - y - 1.0, color); + double h = y - prev_y; + double mid = y + (h/2.0); + + if (height > 1.0) { // XXX ? should that not be h >= 1 ? + _note_lines->add (mid, h, color); } prev_y = y; @@ -409,9 +440,9 @@ MidiStreamView::setup_rec_box () if (!rec_active && _trackview.session()->record_status() == Session::Recording && - _trackview.track()->record_enabled()) { + _trackview.track()->rec_enable_control()->get_value()) { - if (Config->get_show_waveforms_while_recording() && rec_regions.size() == rec_rects.size()) { + if (UIConfiguration::instance().get_show_waveforms_while_recording() && rec_regions.size() == rec_rects.size()) { /* add a new region, but don't bother if they set show-waveforms-while-recording mid-record */ @@ -459,12 +490,12 @@ MidiStreamView::setup_rec_box () if (region) { region->set_start (_trackview.track()->current_capture_start() - _trackview.track()->get_capture_start_frame (0)); - region->set_position (_trackview.track()->current_capture_start()); - RegionView* rv = add_region_view_internal (region, false); + region->set_position (_trackview.session()->transport_frame()); + + RegionView* rv = add_region_view_internal (region, false, true); MidiRegionView* mrv = dynamic_cast (rv); mrv->begin_write (); - /* rec region will be destroyed in setup_rec_box */ rec_regions.push_back (make_pair (region, rv)); @@ -477,36 +508,11 @@ MidiStreamView::setup_rec_box () /* start a new rec box */ - boost::shared_ptr mt = _trackview.midi_track(); /* we know what it is already */ - framepos_t const frame_pos = mt->current_capture_start (); - gdouble const xstart = _trackview.editor().sample_to_pixel (frame_pos); - gdouble const xend = xstart; - uint32_t fill_color; - - fill_color = ARDOUR_UI::config()->get_canvasvar_RecordingRect(); - - ArdourCanvas::Rectangle * rec_rect = new ArdourCanvas::Rectangle (_canvas_group); - rec_rect->set (ArdourCanvas::Rect (xstart, 1, xend, _trackview.current_height() - 1)); - rec_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RecordingRect()); - rec_rect->set_fill_color (fill_color); - rec_rect->lower_to_bottom(); - - RecBoxInfo recbox; - recbox.rectangle = rec_rect; - recbox.start = _trackview.session()->transport_frame(); - recbox.length = 0; - - rec_rects.push_back (recbox); - - screen_update_connection.disconnect(); - screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect ( - sigc::mem_fun (*this, &MidiStreamView::update_rec_box)); - rec_updating = true; - rec_active = true; + create_rec_box(_trackview.midi_track()->current_capture_start(), 0); } else if (rec_active && (_trackview.session()->record_status() != Session::Recording || - !_trackview.track()->record_enabled())) { + !_trackview.track()->rec_enable_control()->get_value())) { screen_update_connection.disconnect(); rec_active = false; rec_updating = false; @@ -521,7 +527,6 @@ MidiStreamView::setup_rec_box () /* disconnect rapid update */ screen_update_connection.disconnect(); rec_data_ready_connections.drop_connections (); - rec_updating = false; rec_active = false; @@ -560,9 +565,9 @@ MidiStreamView::color_handler () draw_note_lines (); if (_trackview.is_midi_track()) { - canvas_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MidiTrackBase()); + canvas_rect->set_fill_color (UIConfiguration::instance().color_mod ("midi track base", "midi track base")); } else { - canvas_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_MidiBusBase()); + canvas_rect->set_fill_color (UIConfiguration::instance().color ("midi bus base")); } } @@ -605,7 +610,7 @@ MidiStreamView::update_rec_box () /* Update the region being recorded to reflect where we currently are */ boost::shared_ptr region = rec_regions.back().first; - region->set_length (_trackview.track()->current_capture_end () - _trackview.track()->current_capture_start()); + region->set_length (_trackview.track()->current_capture_end () - _trackview.track()->current_capture_start(), 0); MidiRegionView* mrv = dynamic_cast (rec_regions.back().second); mrv->extend_active_notes (); @@ -614,7 +619,7 @@ MidiStreamView::update_rec_box () uint8_t MidiStreamView::y_to_note (double y) const { - int const n = ((contents_height() - y - 1) / contents_height() * (double)contents_note_range()) + int const n = ((contents_height() - y) / contents_height() * (double)contents_note_range()) + lowest_note(); if (n < 0) { @@ -623,7 +628,8 @@ MidiStreamView::y_to_note (double y) const return 127; } - return n; + /* min due to rounding and/or off-by-one errors */ + return min ((uint8_t) n, highest_note()); } /** Suspend updates to the regions' note ranges and our @@ -645,16 +651,44 @@ MidiStreamView::resume_updates () draw_note_lines (); apply_note_range_to_regions (); + + _canvas_group->redraw (); } -void -MidiStreamView::leave_internal_edit_mode () +struct RegionPositionSorter { + bool operator() (RegionView* a, RegionView* b) { + return a->region()->position() < b->region()->position(); + } +}; + +bool +MidiStreamView::paste (ARDOUR::framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num) { - StreamView::leave_internal_edit_mode (); - for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { - MidiRegionView* mrv = dynamic_cast (*i); - if (mrv) { - mrv->clear_selection (); + /* Paste into the first region which starts on or before pos. Only called when + using an internal editing tool. */ + + if (region_views.empty()) { + return false; + } + + region_views.sort (RegionView::PositionOrder()); + + list::const_iterator prev = region_views.begin (); + + for (list::const_iterator i = region_views.begin(); i != region_views.end(); ++i) { + if ((*i)->region()->position() > pos) { + break; } + prev = i; } + + boost::shared_ptr r = (*prev)->region (); + + /* If *prev doesn't cover pos, it's no good */ + if (r->position() > pos || ((r->position() + r->length()) < pos)) { + return false; + } + + MidiRegionView* mrv = dynamic_cast (*prev); + return mrv ? mrv->paste(pos, selection, ctx, sub_num) : false; }