X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmidi_streamview.cc;h=5e2f05558297e484f92c70cb57dfe904f77aae64;hb=78f749ef65e725eee82938df76f24c2b6811a519;hp=a1e1269468ada724f5c7b2829b42bcc66293ac67;hpb=2ba58dfe65bb0c5ba7d5eb18a1566fa79eeb6993;p=ardour.git diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc index a1e1269468..5e2f055582 100644 --- a/gtk2_ardour/midi_streamview.cc +++ b/gtk2_ardour/midi_streamview.cc @@ -33,9 +33,8 @@ #include "ardour/region_factory.h" #include "ardour/session.h" #include "ardour/smf_source.h" +#include "ardour/evoral_types_convert.h" -#include "ardour_ui.h" -#include "global_signals.h" #include "gui_thread.h" #include "midi_region_view.h" #include "midi_streamview.h" @@ -46,12 +45,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 +69,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 +86,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 +100,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,10 +108,18 @@ 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; } @@ -144,12 +153,6 @@ MidiStreamView::add_region_view_internal (boost::shared_ptr r, bool wait 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, wait_for_data); @@ -175,11 +178,22 @@ MidiStreamView::display_region(MidiRegionView* region_view, bool load_model) } 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,7 +201,6 @@ 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()); } @@ -207,7 +220,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()); @@ -229,6 +243,18 @@ MidiStreamView::update_data_note_range(uint8_t min, uint8_t max) return dirty; } +void +MidiStreamView::set_layer_display (LayerDisplay d) +{ + +//revert this change for now. Although stacked view is weirdly implemented wrt the "scroomer", it is still necessary to manage layered midi regions. +// if (d != Overlaid) { +// return; +// } + + StreamView::set_layer_display (d); +} + void MidiStreamView::redisplay_track () { @@ -273,7 +299,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); } @@ -286,7 +313,7 @@ MidiStreamView::draw_note_lines() } double y; - double prev_y = 0; + double prev_y = .5; uint32_t color; _note_lines->clear(); @@ -300,15 +327,17 @@ MidiStreamView::draw_note_lines() * coordinate system in which y=0 is at the top */ - for (int i = highest_note(); i >= lowest_note(); --i) { + for (int i = highest_note() + 1; i >= lowest_note(); --i) { - y = note_to_y (i); + y = floor(note_to_y (i)) + .5; /* this is the line actually corresponding to the division * between notes */ - _note_lines->add (y, 1.0, ARDOUR_UI::config()->get_canvasvar_PianoRollBlackOutline()); + 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. @@ -320,17 +349,17 @@ 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; } double h = y - prev_y; double mid = y + (h/2.0); - - if (height > 1.0) { + + if (mid >= 0 && h > 1.0) { _note_lines->add (mid, h, color); } @@ -420,13 +449,13 @@ MidiStreamView::setup_rec_box () { // cerr << _trackview.name() << " streamview SRB\n"; - if (_trackview.session()->transport_rolling()) { + if (!_trackview.session()->transport_stopped()) { 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 */ @@ -438,10 +467,10 @@ MidiStreamView::setup_rec_box () // handle multi - framepos_t start = 0; + samplepos_t start = 0; if (rec_regions.size() > 0) { start = rec_regions.back().first->start() - + _trackview.track()->get_captured_frames(rec_regions.size()-1); + + _trackview.track()->get_captured_samples(rec_regions.size()-1); } if (!rec_regions.empty()) { @@ -457,10 +486,10 @@ MidiStreamView::setup_rec_box () is so that the RegionView gets created with a non-zero width, as apparently creating a RegionView with a zero width causes it never to be displayed (there is a warning in TimeAxisViewItem::init about this). However, we - must also set length_beats to something non-zero, otherwise the frame length + must also set length_beats to something non-zero, otherwise the sample length of 1 causes length_beats to be set to some small quantity << 1. Then when the position is set up below, this length_beats is used to recompute - length using BeatsFramesConverter::to, which is slightly innacurate for small + length using BeatsSamplesConverter::to, which is slightly innacurate for small beats values because it converts floating point beats to bars, beats and integer ticks. The upshot of which being that length gets set back to 0, meaning no region view is ever seen, meaning no MIDI notes during record (#3820). @@ -473,13 +502,13 @@ MidiStreamView::setup_rec_box () (RegionFactory::create (sources, plist, false))); 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); + - _trackview.track()->get_capture_start_sample (0)); + region->set_position (_trackview.session()->transport_sample()); + + 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)); @@ -492,36 +521,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; @@ -536,7 +540,6 @@ MidiStreamView::setup_rec_box () /* disconnect rapid update */ screen_update_connection.disconnect(); rec_data_ready_connections.drop_connections (); - rec_updating = false; rec_active = false; @@ -575,9 +578,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")); } } @@ -620,7 +623,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 (); @@ -629,7 +632,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) { @@ -638,7 +641,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 @@ -657,21 +661,47 @@ void MidiStreamView::resume_updates () { _updates_suspended = false; - + 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::samplepos_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; }