From 2f9184d65395da75a43ea21ffb5f11b8d577d27a Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 6 Jul 2010 11:33:27 +0000 Subject: [PATCH] beat slicing patch #1 from lincoln spiteri git-svn-id: svn://localhost/ardour2/branches/3.0@7381 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/ardour.menus.in | 9 +- gtk2_ardour/audio_region_view.cc | 111 ++++++++- gtk2_ardour/audio_region_view.h | 8 + gtk2_ardour/editor.h | 14 +- gtk2_ardour/editor_actions.cc | 17 ++ gtk2_ardour/editor_canvas_events.cc | 39 +++ gtk2_ardour/editor_drag.cc | 70 ++++++ gtk2_ardour/editor_drag.h | 27 ++ gtk2_ardour/editor_items.h | 1 + gtk2_ardour/editor_mouse.cc | 28 ++- gtk2_ardour/editor_ops.cc | 365 ++++++++++++++++++++++++---- gtk2_ardour/midi_streamview.cc | 15 +- gtk2_ardour/mnemonic-us.bindings.in | 3 + gtk2_ardour/public_editor.h | 1 + gtk2_ardour/rhythm_ferret.cc | 61 +++-- gtk2_ardour/rhythm_ferret.h | 6 +- gtk2_ardour/time_axis_view.cc | 56 ----- gtk2_ardour/time_axis_view.h | 7 - libs/ardour/ardour/audioregion.h | 6 + libs/ardour/ardour/region.h | 30 ++- libs/ardour/audioregion.cc | 62 ++++- libs/ardour/playlist.cc | 14 +- libs/ardour/region.cc | 27 +- libs/ardour/session.cc | 44 ++-- 24 files changed, 828 insertions(+), 193 deletions(-) diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in index e6ae76a74e..85df23ab14 100644 --- a/gtk2_ardour/ardour.menus.in +++ b/gtk2_ardour/ardour.menus.in @@ -172,12 +172,13 @@ + + - @@ -272,8 +273,14 @@ + + + + + + diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index 802d9230fb..06621a20e2 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -254,6 +254,10 @@ AudioRegionView::~AudioRegionView () delete *i; } + for (list >::iterator i = feature_lines.begin(); i != feature_lines.end(); ++i) { + delete ((*i).second); + } + /* all waveviews etc will be destroyed when the group is destroyed */ delete gain_line; @@ -292,6 +296,9 @@ AudioRegionView::region_changed (const PropertyChange& what_changed) if (what_changed.contains (ARDOUR::Properties::envelope_active)) { envelope_active_changed (); } + if (what_changed.contains (ARDOUR::Properties::valid_transients)) { + transients_changed (); + } } void @@ -388,13 +395,26 @@ AudioRegionView::region_resized (const PropertyChange& what_changed) } for (vector::iterator i = ghosts.begin(); i != ghosts.end(); ++i) { - if((agr = dynamic_cast(*i)) != 0) { + if ((agr = dynamic_cast(*i)) != 0) { for (vector::iterator w = agr->waves.begin(); w != agr->waves.end(); ++w) { (*w)->property_region_start() = _region->start(); } } } + + /* hide transient lines that extend beyond the region end */ + + list >::iterator l; + + for (l = feature_lines.begin(); l != feature_lines.end(); ++l) { + if ((*l).first > _region->length()- 1){ + (*l).second->hide(); + } + else { + (*l).second->show(); + } + } } } @@ -425,6 +445,15 @@ AudioRegionView::reset_width_dependent_items (double pixel_width) } } + AnalysisFeatureList analysis_features = _region->transients(); + AnalysisFeatureList::const_iterator i; + list >::iterator l; + + for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) { + (*l).second->property_x1() = trackview.editor().frame_to_pixel (*i); + (*l).second->property_x2() = trackview.editor().frame_to_pixel (*i); + } + reset_fade_shapes (); } @@ -501,6 +530,13 @@ AudioRegionView::set_height (gdouble height) manage_zero_line (); reset_fade_shapes (); + + /* Update hights for any active feature lines */ + list >::iterator l; + + for (l = feature_lines.begin(); l != feature_lines.end(); ++l) { + (*l).second->property_y2() = _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1; + } if (name_pixbuf) { name_pixbuf->raise_to_top(); @@ -583,7 +619,7 @@ AudioRegionView::reset_fade_in_shape_width (nframes_t width) float curve[npoints]; audio_region()->fade_in()->curve().get_vector (0, audio_region()->fade_in()->back()->when, curve, npoints); - points = get_canvas_points ("fade in shape", npoints+3); + points = get_canvas_points ("fade in shape", npoints + 3); if (_height >= NAME_HIGHLIGHT_THRESH) { h = _height - NAME_HIGHLIGHT_SIZE; @@ -682,7 +718,7 @@ AudioRegionView::reset_fade_out_shape_width (nframes_t width) /* points *MUST* be in anti-clockwise order */ - points = get_canvas_points ("fade out shape", npoints+3); + points = get_canvas_points ("fade out shape", npoints + 3); uint32_t pi, pc; double xdelta = pwidth/npoints; @@ -1380,3 +1416,72 @@ AudioRegionView::show_region_editor () editor->present (); editor->show_all(); } + +void +AudioRegionView::transients_changed () +{ + AnalysisFeatureList analysis_features = _region->transients(); + + while (feature_lines.size() < analysis_features.size()) { + ArdourCanvas::SimpleLine* l = new ArdourCanvas::SimpleLine (*group); + l->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get(); + feature_lines.push_back (make_pair(0, l)); + } + + while (feature_lines.size() > analysis_features.size()) { + ArdourCanvas::SimpleLine *line = feature_lines.back().second; + feature_lines.pop_back (); + delete line; + } + + AnalysisFeatureList::const_iterator i; + list >::iterator l; + + for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) { + (*l).first = *i; + (*l).second->property_x1() = trackview.editor().frame_to_pixel (*i); + (*l).second->property_x2() = trackview.editor().frame_to_pixel (*i); + (*l).second->property_y1() = 2; + (*l).second->property_y2() = _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1; + (*l).second->set_data("regionview", this); + (*l).second->show (); + (*l).second->raise_to_top (); + + (*l).second->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_feature_line_event), (*l).second, this)); + } +} + +void +AudioRegionView::update_transient(float old_pos, float new_pos) +{ + /* Find frame at old pos, calulate new frame then update region transients*/ + list >::iterator l; + + for (l = feature_lines.begin(); l != feature_lines.end(); ++l) { + /* Simple line x1 has been updated in drag so we compare to new_pos */ + if (rint(new_pos) == rint((*l).second->property_x1())) { + + nframes64_t old_frame = (*l).first; + nframes64_t new_frame = trackview.editor().pixel_to_frame (new_pos); + + _region->update_transient (old_frame, new_frame); + + break; + } + } +} + +void +AudioRegionView::remove_transient(float pos) +{ + /* Find frame at old pos, calulate new frame then update region transients*/ + list >::iterator l; + + for (l = feature_lines.begin(); l != feature_lines.end(); ++l) { + /* Simple line x1 has been updated in drag so we compare to new_pos */ + if (rint(pos) == rint((*l).second->property_x1())) { + _region->remove_transient ((*l).first); + break; + } + } +} \ No newline at end of file diff --git a/gtk2_ardour/audio_region_view.h b/gtk2_ardour/audio_region_view.h index b00fb583fa..0e2b54130c 100644 --- a/gtk2_ardour/audio_region_view.h +++ b/gtk2_ardour/audio_region_view.h @@ -105,6 +105,9 @@ class AudioRegionView : public RegionView void set_fade_visibility (bool); void update_coverage_frames (LayerDisplay); + + void update_transient(float old_pos, float new_pos); + void remove_transient(float pos); void show_region_editor (); @@ -127,6 +130,9 @@ class AudioRegionView : public RegionView std::vector waves; std::vector tmp_waves; ///< see ::create_waves() + + std::list > feature_lines; + ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position ArdourCanvas::SimpleLine* zero_line; ArdourCanvas::Polygon* fade_in_shape; @@ -169,6 +175,8 @@ class AudioRegionView : public RegionView void color_handler (); std::vector wave_caches; + + void transients_changed(); private: diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 2300fe7c20..44e7289f6d 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -228,6 +228,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void new_region_from_selection (); void separate_regions_between (const TimeSelection&); void separate_region_from_selection (); + void separate_under_selected_regions (); void separate_region_from_punch (); void separate_region_from_loop (); void separate_regions_using_location (ARDOUR::Location&); @@ -921,10 +922,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void select_all_selectables_between (bool within); void select_range_between (); - boost::shared_ptr find_next_region (nframes64_t, ARDOUR::RegionPoint, int32_t dir, TrackViewList&, TimeAxisView ** = 0); - nframes64_t find_next_region_boundary (nframes64_t, int32_t dir, const TrackViewList&); + boost::shared_ptr find_next_region (ARDOUR::framepos_t, ARDOUR::RegionPoint, int32_t dir, TrackViewList&, TimeAxisView ** = 0); + ARDOUR::framepos_t find_next_region_boundary (ARDOUR::framepos_t, int32_t dir, const TrackViewList&); - std::vector region_boundary_cache; + std::vector region_boundary_cache; void build_region_boundary_cache (); Gtk::HBox top_hbox; @@ -1124,6 +1125,11 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void cut (); void copy (); void paste (float times); + + void place_transient (); + void remove_transient (ArdourCanvas::Item* item); + void snap_regions_to_grid (); + void close_region_gaps (); int get_prefix (float&, bool&); @@ -1364,6 +1370,7 @@ public: bool canvas_frame_handle_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); + bool canvas_feature_line_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*); bool canvas_stream_view_event (GdkEvent* event,ArdourCanvas::Item*, RouteTimeAxisView*); bool canvas_marker_event (GdkEvent* event,ArdourCanvas::Item*, Marker*); bool canvas_zoom_rect_event (GdkEvent* event,ArdourCanvas::Item*); @@ -2064,6 +2071,7 @@ public: friend class EditorGroupTabs; friend class EditorRoutes; + friend class RhythmFerret; }; #endif /* __ardour_editor_h__ */ diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index eeb604c2e5..f1d20fbed7 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -476,6 +476,15 @@ Editor::register_actions () act = ActionManager::register_action (editor_actions, "mute-unmute-region", _("Mute/Unmute Region"), sigc::mem_fun(*this, &Editor::kbd_mute_unmute_region)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::region_selection_sensitive_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "snap-regions-to-grid", _("Snap Regions to Grid"), sigc::mem_fun(*this, &Editor::snap_regions_to_grid)); + ActionManager::session_sensitive_actions.push_back (act); + ActionManager::region_selection_sensitive_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "close-region-gaps", _("Close Region Gaps"), sigc::mem_fun(*this, &Editor::close_region_gaps)); + ActionManager::session_sensitive_actions.push_back (act); + ActionManager::region_selection_sensitive_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "place-transient", _("Place Transient"), sigc::mem_fun(*this, &Editor::place_transient)); + ActionManager::session_sensitive_actions.push_back (act); + ActionManager::region_selection_sensitive_actions.push_back (act); undo_action = act = ActionManager::register_action (editor_actions, "undo", _("Undo"), sigc::bind (sigc::mem_fun(*this, &Editor::undo), 1U)); ActionManager::session_sensitive_actions.push_back (act); @@ -487,20 +496,28 @@ Editor::register_actions () act = ActionManager::register_action (editor_actions, "export-range", _("Export Range"), sigc::mem_fun(*this, &Editor::export_range)); ActionManager::session_sensitive_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "separate-under-region", _("Separate Under Selected Regions"), sigc::mem_fun(*this, &Editor::separate_under_selected_regions)); + ActionManager::session_sensitive_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "editor-separate", _("Separate"), sigc::mem_fun(*this, &Editor::separate_region_from_selection)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::mouse_edit_point_requires_canvas_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "separate-from-punch", _("Separate Using Punch Range"), sigc::mem_fun(*this, &Editor::separate_region_from_punch)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::mouse_edit_point_requires_canvas_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "separate-from-loop", _("Separate Using Loop Range"), sigc::mem_fun(*this, &Editor::separate_region_from_loop)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::mouse_edit_point_requires_canvas_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "editor-crop", _("Crop"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)); ActionManager::session_sensitive_actions.push_back (act); ActionManager::mouse_edit_point_requires_canvas_actions.push_back (act); + act = ActionManager::register_action (editor_actions, "editor-cut", _("Cut"), sigc::mem_fun(*this, &Editor::cut)); ActionManager::session_sensitive_actions.push_back (act); + /* Note: for now, editor-delete does the exact same thing as editor-cut */ act = ActionManager::register_action (editor_actions, "editor-delete", _("Delete"), sigc::mem_fun(*this, &Editor::cut)); ActionManager::session_sensitive_actions.push_back (act); diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index 0b9d8a3793..34a73d318c 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -899,6 +899,45 @@ Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item return ret; } +bool +Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv) +{ + bool ret = false; + + switch (event->type) { + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + clicked_regionview = 0; + clicked_control_point = 0; + clicked_axisview = 0; + clicked_routeview = 0; //dynamic_cast(clicked_axisview); + ret = button_press_handler (item, event, FeatureLineItem); + break; + + case GDK_BUTTON_RELEASE: + ret = button_release_handler (item, event, FeatureLineItem); + break; + + case GDK_MOTION_NOTIFY: + ret = motion_handler (item, event); + break; + + case GDK_ENTER_NOTIFY: + ret = enter_handler (item, event, FeatureLineItem); + break; + + case GDK_LEAVE_NOTIFY: + ret = leave_handler (item, event, FeatureLineItem); + break; + + default: + break; + } + + return ret; +} + bool Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, Marker* /*marker*/) { diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index b01c79ad91..2aaeaa1038 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -2935,6 +2935,76 @@ LineDrag::aborted () _line->reset (); } +FeatureLineDrag::FeatureLineDrag (Editor* e, ArdourCanvas::Item* i) + : Drag (e, i), + _line (0), + _cumulative_x_drag (0) +{ + +} +void +FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) +{ + + Drag::start_grab (event); + + _line = reinterpret_cast (_item); + assert (_line); + + /* need to get x coordinate in terms of parent (AudioRegionView) origin. */ + + double cx = event->button.x; + double cy = event->button.y; + + _item->property_parent().get_value()->w2i(cx, cy); + + /* store grab start in parent frame */ + _region_view_grab_x = cx; + + _before = _line->property_x1(); + + _arv = reinterpret_cast (_item->get_data ("regionview")); + + _max_x = _editor->frame_to_pixel(_arv->get_duration()); +} + +void +FeatureLineDrag::motion (GdkEvent* event, bool) +{ + double dx = _drags->current_pointer_x() - last_pointer_x(); + + double cx = _region_view_grab_x + _cumulative_x_drag + dx; + + _cumulative_x_drag += dx; + + /* Clamp the min and max extent of the drag to keep it within the region view bounds */ + + if (cx > _max_x){ + cx = _max_x; + } + else if(cx < 0){ + cx = 0; + } + + _line->property_x1() = cx; + _line->property_x2() = cx; + + _before = _line->property_x1(); +} + +void +FeatureLineDrag::finished (GdkEvent* event, bool) +{ + _arv = reinterpret_cast (_item->get_data ("regionview")); + _arv->update_transient(_before, _line->property_x1()); +} + +void +FeatureLineDrag::aborted () +{ + //_line->reset (); +} + void RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *) { diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index f1634ffb64..9e206cfebf 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -604,6 +604,33 @@ private: double _cumulative_y_drag; }; +/** Transient feature line drags*/ +class FeatureLineDrag : public Drag +{ +public: + FeatureLineDrag (Editor *e, ArdourCanvas::Item *i); + + void start_grab (GdkEvent *, Gdk::Cursor* c = 0); + void motion (GdkEvent *, bool); + void finished (GdkEvent *, bool); + void aborted (); + + bool active (Editing::MouseMode) { + return true; + } + +private: + + ArdourCanvas::SimpleLine* _line; + AudioRegionView* _arv; + + double _region_view_grab_x; + double _cumulative_x_drag; + + uint32_t _before; + uint32_t _max_x; +}; + /** Dragging of a rubberband rectangle for selecting things */ class RubberbandSelectDrag : public Drag { diff --git a/gtk2_ardour/editor_items.h b/gtk2_ardour/editor_items.h index 08013e30ab..36a5a9e36f 100644 --- a/gtk2_ardour/editor_items.h +++ b/gtk2_ardour/editor_items.h @@ -47,6 +47,7 @@ enum ItemType { FadeOutItem, FadeOutHandleItem, NoteItem, + FeatureLineItem, LeftFrameHandle, RightFrameHandle, diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 55a7e6887f..68d9230028 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -735,10 +735,23 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; } + case FeatureLineItem: + { + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier)) { + remove_transient(item); + return true; + } + + _drags->set (new FeatureLineDrag (this, item), event); + return true; + break; + } + case RegionItem: if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) { add_region_copy_drag (item, event, clicked_regionview); - } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) { + } + else if (Keyboard::the_keyboard().key_is_down (GDK_b)) { add_region_brush_drag (item, event, clicked_regionview); } else { add_region_drag (item, event, clicked_regionview); @@ -1616,7 +1629,12 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ track_canvas->get_window()->set_cursor (*fade_out_cursor); } break; - + case FeatureLineItem: + { + ArdourCanvas::SimpleLine *line = dynamic_cast (item); + line->property_color_rgba() = 0xFF0000FF; + } + break; default: break; } @@ -1761,6 +1779,12 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ Glib::signal_idle().connect (sigc::mem_fun(*this, &Editor::left_automation_track)); } break; + case FeatureLineItem: + { + ArdourCanvas::SimpleLine *line = dynamic_cast (item); + line->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();; + } + break; default: break; diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 9bf09557ee..adc9078fba 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -552,7 +552,7 @@ Editor::move_to_end () void Editor::build_region_boundary_cache () { - nframes64_t pos = 0; + framepos_t pos = 0; vector interesting_points; boost::shared_ptr r; TrackViewList tracks; @@ -595,8 +595,8 @@ Editor::build_region_boundary_cache () while (pos < _session->current_end_frame() && !at_end) { - nframes64_t rpos; - nframes64_t lpos = max_frames; + framepos_t rpos; + framepos_t lpos = max_frames; for (vector::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) { @@ -645,7 +645,7 @@ Editor::build_region_boundary_cache () to sort later. */ - vector::iterator ri; + vector::iterator ri; for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) { if (*ri == rpos) { @@ -664,23 +664,29 @@ Editor::build_region_boundary_cache () /* finally sort to be sure that the order is correct */ sort (region_boundary_cache.begin(), region_boundary_cache.end()); + + cerr << "RBC contains " << region_boundary_cache.size() << endl; + + for (vector::iterator x = region_boundary_cache.begin(); x != region_boundary_cache.end(); ++x) { + cerr << "Region boundary @ " << *x << endl; + } } boost::shared_ptr -Editor::find_next_region (nframes64_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack) +Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack) { TrackViewList::iterator i; nframes64_t closest = max_frames; boost::shared_ptr ret; - nframes64_t rpos = 0; + framepos_t rpos = 0; float track_speed; - nframes64_t track_frame; + framepos_t track_frame; RouteTimeAxisView *rtav; for (i = tracks.begin(); i != tracks.end(); ++i) { - nframes64_t distance; + framecnt_t distance; boost::shared_ptr r; track_speed = 1.0f; @@ -730,17 +736,16 @@ Editor::find_next_region (nframes64_t frame, RegionPoint point, int32_t dir, Tra return ret; } -nframes64_t -Editor::find_next_region_boundary (nframes64_t pos, int32_t dir, const TrackViewList& tracks) +framepos_t +Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks) { - nframes64_t distance = max_frames; - nframes64_t current_nearest = -1; - + framecnt_t distance = max_frames; + framepos_t current_nearest = -1; for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) { - nframes64_t contender; - nframes64_t d; - + framepos_t contender; + framecnt_t d; + RouteTimeAxisView* rtv = dynamic_cast (*i); if (!rtv) { @@ -762,10 +767,10 @@ Editor::find_next_region_boundary (nframes64_t pos, int32_t dir, const TrackView return current_nearest; } -nframes64_t -Editor::get_region_boundary (nframes64_t pos, int32_t dir, bool with_selection, bool only_onscreen) +framepos_t +Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen) { - nframes64_t target; + framepos_t target; TrackViewList tvl; if (with_selection && Config->get_region_boundaries_from_selected_tracks()) { @@ -2793,6 +2798,7 @@ Editor::separate_regions_between (const TimeSelection& ts) sigc::connection c = rtv->view()->RegionViewAdded.connect ( sigc::mem_fun(*this, &Editor::collect_new_region_view)); + latest_regionviews.clear (); playlist->partition ((nframes64_t)((*t).start * speed), @@ -2838,6 +2844,11 @@ Editor::separate_regions_between (const TimeSelection& ts) } } +struct PlaylistState { + boost::shared_ptr playlist; + XMLNode* before; +}; + /** Take tracks from get_tracks_for_range_action and cut any regions * on those tracks so that the tracks are empty over the time * selection. @@ -2903,6 +2914,85 @@ Editor::separate_regions_using_location (Location& loc) separate_regions_between (ts); } +/** Separate regions under the selected region */ +void +Editor::separate_under_selected_regions () +{ + RegionSelection rs; + get_regions_for_action (rs); + + vector playlists; + + if (!_session) { + return; + } + + if (rs.empty()) { + return; + } + + begin_reversible_command (_("separate region under")); + + list > regions_to_remove; + + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { + // we can't just remove the region(s) in this loop because + // this removes them from the RegionSelection, and they thus + // disappear from underneath the iterator, and the ++i above + // SEGVs in a puzzling fashion. + + // so, first iterate over the regions to be removed from rs and + // add them to the regions_to_remove list, and then + // iterate over the list to actually remove them. + + regions_to_remove.push_back ((*i)->region()); + } + + for (list >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) { + + boost::shared_ptr playlist = (*rl)->playlist(); + + if (!playlist) { + // is this check necessary? + continue; + } + + vector::iterator i; + + //only take state if this is a new playlist. + for (i = playlists.begin(); i != playlists.end(); ++i) { + if ((*i).playlist == playlist) { + break; + } + } + + if (i == playlists.end()) { + + PlaylistState before; + before.playlist = playlist; + before.before = &playlist->get_state(); + + playlist->freeze (); + playlists.push_back(before); + } + + //Partition on the region bounds + playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true); + + //Re-add region that was just removed due to the partition operation + playlist->add_region( (*rl), (*rl)->first_frame() ); + } + + vector::iterator pl; + + for (pl = playlists.begin(); pl != playlists.end(); ++pl) { + (*pl).playlist->thaw (); + _session->add_command(new MementoCommand(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state())); + } + + commit_reversible_command (); +} + void Editor::crop_region_to_selection () { @@ -3354,12 +3444,15 @@ Editor::trim_region (bool front) for (list::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) { if (!(*i)->region()->locked()) { - (*i)->region()->clear_history (); + + (*i)->region()->clear_history (); + if (front) { (*i)->region()->trim_front (where, this); } else { (*i)->region()->trim_end (where, this); } + _session->add_command (new StatefulDiffCommand ((*i)->region())); } } @@ -3564,7 +3657,7 @@ Editor::trim_to_region(bool forward) continue; } - region->trim_end((nframes64_t) (next_region->first_frame() * speed), this); + region->trim_end((nframes64_t) ( (next_region->first_frame() - 1) * speed), this); arv->region_changed (PropertyChange (ARDOUR::Properties::length)); } else { @@ -3892,6 +3985,14 @@ Editor::cut_copy_midi (CutCopyOp op) } } + + +struct lt_playlist { + bool operator () (const PlaylistState& a, const PlaylistState& b) { + return a.playlist < b.playlist; + } +}; + struct PlaylistMapping { TimeAxisView* tv; boost::shared_ptr pl; @@ -4263,7 +4364,7 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times) playlist = (*i)->region()->playlist(); playlist->clear_history (); - playlist->duplicate (r, end_frame + (r->first_frame() - start_frame) + 1, times); + playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times); _session->add_command(new StatefulDiffCommand (playlist)); c.disconnect (); @@ -5872,6 +5973,7 @@ Editor::split_region_at_points (boost::shared_ptr r, AnalysisFeatureList int response = msg.run(); msg.hide (); + switch (response) { case RESPONSE_OK: break; @@ -5890,19 +5992,10 @@ Editor::split_region_at_points (boost::shared_ptr r, AnalysisFeatureList AnalysisFeatureList::const_iterator x; - nframes64_t pos = r->position(); - pl->clear_history (); x = positions.begin(); - while (x != positions.end()) { - if ((*x) > pos) { - break; - } - ++x; - } - if (x == positions.end()) { return; } @@ -5910,18 +6003,26 @@ Editor::split_region_at_points (boost::shared_ptr r, AnalysisFeatureList pl->freeze (); pl->remove_region (r); + nframes64_t pos = 0; + while (x != positions.end()) { + + /* deal with positons that are out of scope of present region bounds */ + if (*x <= 0 || *x > r->length()){ + ++x; + continue; + } /* file start = original start + how far we from the initial position ? */ - nframes64_t file_start = r->start() + (pos - r->position()); + nframes64_t file_start = r->start() + pos; /* length = next position - current position */ nframes64_t len = (*x) - pos; - + /* XXX we do we really want to allow even single-sample regions? shouldn't we have some kind of lower limit on region size? */ @@ -5946,37 +6047,192 @@ Editor::split_region_at_points (boost::shared_ptr r, AnalysisFeatureList plist.add (ARDOUR::Properties::layer, 0); boost::shared_ptr nr = RegionFactory::create (r->sources(), plist, false); - pl->add_region (nr, pos); + pl->add_region (nr, r->position() + pos); pos += len; ++x; - - if (*x > r->last_frame()) { - - /* add final fragment */ - - file_start = r->start() + (pos - r->position()); - len = r->last_frame() - pos; - - PropertyList plist2; - - plist2.add (ARDOUR::Properties::start, file_start); - plist2.add (ARDOUR::Properties::length, len); - plist2.add (ARDOUR::Properties::name, new_name); - plist2.add (ARDOUR::Properties::layer, 0); - - nr = RegionFactory::create (r->sources(), plist2); - pl->add_region (nr, pos); - - break; - } } + string new_name; + + RegionFactory::region_name (new_name, r->name()); + + /* Add the final region */ + PropertyList plist; + + plist.add (ARDOUR::Properties::start, r->start() + pos); + plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1); + plist.add (ARDOUR::Properties::name, new_name); + plist.add (ARDOUR::Properties::layer, 0); + + boost::shared_ptr nr = RegionFactory::create (r->sources(), plist, false); + pl->add_region (nr, r->position() + pos); + + pl->thaw (); _session->add_command (new StatefulDiffCommand (pl)); } +void +Editor::place_transient() +{ + if (!_session) { + return; + } + + RegionSelection rs; + + get_regions_for_action (rs); + + if (rs.empty()) { + return; + } + + nframes64_t where = get_preferred_edit_position(); + + _session->begin_reversible_command (_("place transient")); + + for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) { + framepos_t position = (*r)->region()->position(); + (*r)->region()->add_transient(where - position); + } + + _session->commit_reversible_command (); +} + +void +Editor::remove_transient(ArdourCanvas::Item* item) +{ + if (!_session) { + return; + } + + ArdourCanvas::SimpleLine* _line = reinterpret_cast (item); + assert (_line); + + AudioRegionView* _arv = reinterpret_cast (item->get_data ("regionview")); + _arv->remove_transient(_line->property_x1()); +} + +void +Editor::snap_regions_to_grid() +{ + if (!_session) { + return; + } + + RegionSelection rs; + + get_regions_for_action (rs); + + if (rs.empty()) { + return; + } + + _session->begin_reversible_command (_("snap regions to grid")); + + for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) { + framepos_t start_frame = (*r)->region()->first_frame (); + snap_to (start_frame); + (*r)->region()->set_position (start_frame, this); + } + + _session->commit_reversible_command (); +} + +void +Editor::close_region_gaps() +{ + if (!_session) { + return; + } + + RegionSelection rs; + + get_regions_for_action (rs); + + if (rs.empty()) { + return; + } + + Dialog dialog (rs.size() > 1 ? _("Conform regions") : _("Conform region")); + + HBox hbox_crossfade; + hbox_crossfade.set_spacing (10); + //hbox_crossfade.set_border_width (3); + hbox_crossfade.pack_start (*manage (new Label (_("Crossfade length:")))); + + SpinButton spin_crossfade (1, 0); + spin_crossfade.set_range (0, 15); + spin_crossfade.set_increments (1, 1); + spin_crossfade.set_value (3); + + hbox_crossfade.pack_start (spin_crossfade); + hbox_crossfade.pack_start (*manage (new Label (_("ms")))); + hbox_crossfade.show_all (); + + HBox hbox_pullback; + + hbox_pullback.set_spacing (10); + //hbox_pullback.set_border_width (3); + hbox_pullback.pack_start (*manage (new Label (_("Pull-back length:")))); + + SpinButton spin_pullback (1, 0); + spin_pullback.set_range (0, 15); + spin_pullback.set_increments (1, 1); + spin_pullback.set_value (5); + + hbox_pullback.pack_start (spin_pullback); + hbox_pullback.pack_start (*manage (new Label (_("ms")))); + hbox_pullback.show_all (); + + dialog.get_vbox()->set_spacing (6); + dialog.get_vbox()->pack_start (hbox_crossfade); + dialog.get_vbox()->pack_start (hbox_pullback); + dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL); + dialog.add_button (_("Ok"), RESPONSE_ACCEPT); + + if (dialog.run () == RESPONSE_CANCEL) { + return; + } + + nframes64_t crossfade_len = spin_crossfade.get_value(); + nframes64_t pull_back_frames = spin_pullback.get_value(); + + crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000); + pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000); + + /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */ + + _session->begin_reversible_command (_("close region gaps")); + + int idx = 0; + boost::shared_ptr last_region; + + rs.sort_by_position_and_track(); + + for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) { + + nframes64_t position = (*r)->region()->position(); + + if (idx == 0 || position < last_region->position()){ + last_region = (*r)->region(); + idx++; + continue; + } + + (*r)->region()->trim_front( (position - pull_back_frames), this ); + last_region->trim_end( (position - pull_back_frames + crossfade_len), this ); + + last_region = (*r)->region(); + + idx++; + } + + _session->commit_reversible_command (); +} + void Editor::tab_to_transient (bool forward) { @@ -6053,6 +6309,7 @@ Editor::tab_to_transient (bool forward) } } } + void Editor::playhead_forward_to_grid () { diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc index 96d331ba01..cf58224766 100644 --- a/gtk2_ardour/midi_streamview.cc +++ b/gtk2_ardour/midi_streamview.cc @@ -63,6 +63,7 @@ MidiStreamView::MidiStreamView (MidiTimeAxisView& tv) , _highest_note(71) , _data_note_min(60) , _data_note_max(71) + , _note_lines (0) { /* use a group dedicated to MIDI underlays. Audio underlays are not in this group. */ midi_underlay_group = new ArdourCanvas::Group (*_canvas_group); @@ -617,11 +618,23 @@ MidiStreamView::update_rec_regions (boost::shared_ptr data, nframes_t const boost::shared_ptr& note = *i; + cerr << "New note arrived, length = " << note->length() + << " num " << note->note() + << endl; + + if (note->length() == 0) { + /* we got NoteOn but not NoteOff (yet) + */ + continue; + } + nframes_t note_start_frames = tconv.to(note->time()); nframes_t note_end_frames = tconv.to(note->end_time()); - if (note->length() > 0 && note_end_frames + region->position() > start) + + if (note->length() > 0 && note_end_frames + region->position() > start) { mrv->resolve_note(note->note(), note_end_frames); + } if (note_start_frames + region->position() < start) { continue; diff --git a/gtk2_ardour/mnemonic-us.bindings.in b/gtk2_ardour/mnemonic-us.bindings.in index 3056b2e3e5..3754591015 100644 --- a/gtk2_ardour/mnemonic-us.bindings.in +++ b/gtk2_ardour/mnemonic-us.bindings.in @@ -115,6 +115,9 @@ This mode provides many different operations on both regions and control points, @eep|Editor/trim-from-start|<@TERTIARY@>braceleft|trim region start to edit point @eep|Editor/trim-to-end|<@TERTIARY@>braceright|trim region end to edit point +@eep|Editor/trim-to-previous-region|<@PRIMARY@>j|trim region to end of previous region +@eep|Editor/trim-to-next-region|<@PRIMARY@>k|trim region to start of next region + @ranges|Editor/set-loop-from-edit-range|bracketright|set loop range from edit range @ranges|Editor/set-loop-from-region|<@SECONDARY@>bracketright|set loop range from region(s) diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 52fb601f8d..ea9ef9dfad 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -304,6 +304,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible { virtual bool canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0; virtual bool canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0; virtual bool canvas_region_view_name_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0; + virtual bool canvas_feature_line_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0; virtual bool canvas_stream_view_event (GdkEvent* event, ArdourCanvas::Item*, RouteTimeAxisView*) = 0; virtual bool canvas_marker_event (GdkEvent* event, ArdourCanvas::Item*, Marker*) = 0; virtual bool canvas_zoom_rect_event (GdkEvent* event, ArdourCanvas::Item*) = 0; diff --git a/gtk2_ardour/rhythm_ferret.cc b/gtk2_ardour/rhythm_ferret.cc index 8c67ceae21..cba0042cfe 100644 --- a/gtk2_ardour/rhythm_ferret.cc +++ b/gtk2_ardour/rhythm_ferret.cc @@ -14,7 +14,7 @@ #include "rhythm_ferret.h" #include "audio_region_view.h" -#include "public_editor.h" +#include "editor.h" #include "utils.h" #include "time_axis_view.h" @@ -53,7 +53,7 @@ static const gchar * _operation_strings[] = { 0 }; -RhythmFerret::RhythmFerret (PublicEditor& e) +RhythmFerret::RhythmFerret (Editor& e) : ArdourDialog (_("Rhythm Ferret")) , editor (e) , detection_threshold_adjustment (3, 0, 20, 1, 4) @@ -205,13 +205,10 @@ RhythmFerret::run_analysis () default: break; } - + + (*i)->region()->set_transients (current_results); + current_results.clear(); } - - for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { - (*i)->get_time_axis_view().show_feature_lines (current_results); - } - } int @@ -233,9 +230,9 @@ RhythmFerret::run_percussion_onset_analysis (boost::shared_ptr readabl /* translate all transients to give absolute position */ - for (AnalysisFeatureList::iterator x = these_results.begin(); x != these_results.end(); ++x) { - (*x) += offset; - } + //for (AnalysisFeatureList::iterator x = these_results.begin(); x != these_results.end(); ++x) { + // (*x) += offset; + //} /* merge */ @@ -289,9 +286,9 @@ RhythmFerret::run_note_onset_analysis (boost::shared_ptr readable, nfr /* translate all transients to give absolute position */ - for (AnalysisFeatureList::iterator x = these_results.begin(); x != these_results.end(); ++x) { - (*x) += offset; - } + //for (AnalysisFeatureList::iterator x = these_results.begin(); x != these_results.end(); ++x) { + // (*x) += offset; + //} /* merge */ @@ -314,7 +311,7 @@ RhythmFerret::run_note_onset_analysis (boost::shared_ptr readable, nfr void RhythmFerret::do_action () { - if (!_session || current_results.empty()) { + if (!_session) { return; } @@ -322,7 +319,9 @@ RhythmFerret::do_action () case SplitRegion: do_split_action (); break; - + case ConformRegion: + editor.close_region_gaps(); + break; default: break; } @@ -333,13 +332,29 @@ RhythmFerret::do_split_action () { /* this can/will change the current selection, so work with a copy */ - RegionSelection& regions (editor.get_selection().regions); + //RegionSelection& regions (editor.get_selection().regions); + RegionSelection regions; + editor.get_regions_for_action(regions); if (regions.empty()) { return; } _session->begin_reversible_command (_("split regions (rhythm ferret)")); + + /* Merge the transient positions for regions in consideration */ + AnalysisFeatureList merged_features; + + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + + AnalysisFeatureList features; + features = (*i)->region()->transients(); + + merged_features.insert (merged_features.end(), features.begin(), features.end()); + } + + merged_features.sort(); + merged_features.unique(); for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ) { @@ -348,9 +363,9 @@ RhythmFerret::do_split_action () tmp = i; ++tmp; - (*i)->get_time_axis_view().hide_feature_lines (); - - editor.split_region_at_points ((*i)->region(), current_results, false); + AnalysisFeatureList features; + features = (*i)->region()->transients(); + editor.split_region_at_points ((*i)->region(), merged_features, false); /* i is invalid at this point */ @@ -367,15 +382,9 @@ RhythmFerret::set_session (Session* s) current_results.clear (); } -static void hide_time_axis_features (TimeAxisView& tav) -{ - tav.hide_feature_lines (); -} - void RhythmFerret::on_hide () { - editor.foreach_time_axis_view (sigc::ptr_fun (hide_time_axis_features)); ArdourDialog::on_hide (); } diff --git a/gtk2_ardour/rhythm_ferret.h b/gtk2_ardour/rhythm_ferret.h index b18a86377c..043b9fe8a7 100644 --- a/gtk2_ardour/rhythm_ferret.h +++ b/gtk2_ardour/rhythm_ferret.h @@ -17,7 +17,7 @@ namespace ARDOUR { class Readable; } -class PublicEditor; +class Editor; class RegionView; class RhythmFerret : public ArdourDialog { @@ -36,7 +36,7 @@ class RhythmFerret : public ArdourDialog { ConformRegion }; - RhythmFerret (PublicEditor&); + RhythmFerret (Editor&); void set_session (ARDOUR::Session*); @@ -44,7 +44,7 @@ class RhythmFerret : public ArdourDialog { void on_hide (); private: - PublicEditor& editor; + Editor& editor; Gtk::ComboBoxText operation_selector; diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc index 58dbd595bf..803053b8c7 100644 --- a/gtk2_ardour/time_axis_view.cc +++ b/gtk2_ardour/time_axis_view.cc @@ -203,10 +203,6 @@ TimeAxisView::~TimeAxisView() delete (*i)->end_trim; } - for (list::iterator i = feature_lines.begin(); i != feature_lines.end(); ++i) { - delete (*i); - } - delete selection_group; selection_group = 0; @@ -426,8 +422,6 @@ TimeAxisView::set_height(uint32_t h) /* resize the selection rect */ show_selection (_editor.get_selection().time); } - - reshow_feature_lines (); } bool @@ -652,11 +646,6 @@ TimeAxisView::set_samples_per_unit (double spu) AnalysisFeatureList::const_iterator i; list::iterator l; - - for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) { - (*l)->property_x1() = _editor.frame_to_pixel (*i); - (*l)->property_x2() = _editor.frame_to_pixel (*i); - } } void @@ -1188,51 +1177,6 @@ TimeAxisView::covers_y_position (double y) return std::make_pair ( (TimeAxisView *) 0, 0); } -void -TimeAxisView::show_feature_lines (const AnalysisFeatureList& pos) -{ - analysis_features = pos; - reshow_feature_lines (); -} - - -void -TimeAxisView::hide_feature_lines () -{ - list::iterator l; - - for (l = feature_lines.begin(); l != feature_lines.end(); ++l) { - (*l)->hide(); - } -} - -void -TimeAxisView::reshow_feature_lines () -{ - while (feature_lines.size()< analysis_features.size()) { - ArdourCanvas::SimpleLine* l = new ArdourCanvas::SimpleLine (*_canvas_display); - l->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get(); - feature_lines.push_back (l); - } - - while (feature_lines.size() > analysis_features.size()) { - ArdourCanvas::SimpleLine *line = feature_lines.back(); - feature_lines.pop_back (); - delete line; - } - - AnalysisFeatureList::const_iterator i; - list::iterator l; - - for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) { - (*l)->property_x1() = _editor.frame_to_pixel (*i); - (*l)->property_x2() = _editor.frame_to_pixel (*i); - (*l)->property_y1() = 0; - (*l)->property_y2() = current_height(); - (*l)->show (); - } -} - bool TimeAxisView::resizer_button_press (GdkEventButton* event) { diff --git a/gtk2_ardour/time_axis_view.h b/gtk2_ardour/time_axis_view.h index 4e91b15336..93cb7eced3 100644 --- a/gtk2_ardour/time_axis_view.h +++ b/gtk2_ardour/time_axis_view.h @@ -165,9 +165,6 @@ class TimeAxisView : public virtual AxisView, public PBD::Stateful virtual ARDOUR::RouteGroup* route_group() const { return 0; } virtual boost::shared_ptr playlist() const { return boost::shared_ptr (); } - virtual void show_feature_lines (const ARDOUR::AnalysisFeatureList&); - virtual void hide_feature_lines (); - virtual void set_samples_per_unit (double); virtual void show_selection (TimeSelection&); virtual void hide_selection (); @@ -310,10 +307,6 @@ class TimeAxisView : public virtual AxisView, public PBD::Stateful void set_heights (uint32_t h); void color_handler (); - std::list feature_lines; - ARDOUR::AnalysisFeatureList analysis_features; - void reshow_feature_lines (); - void conditionally_add_to_selection (); ArdourCanvas::Group* _canvas_display; diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h index 0a3e53039e..5843d6f753 100644 --- a/libs/ardour/ardour/audioregion.h +++ b/libs/ardour/ardour/audioregion.h @@ -176,7 +176,13 @@ class AudioRegion : public Region void resume_fade_in (); void resume_fade_out (); + void add_transient (nframes64_t where); + void remove_transient (nframes64_t where); + int set_transients (AnalysisFeatureList&); int get_transients (AnalysisFeatureList&, bool force_new = false); + int update_transient (nframes64_t old_position, nframes64_t new_position); + int adjust_transients (nframes64_t delta); + std::list > find_silence (Sample, framecnt_t, InterThreadInfo&) const; private: diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index 8bc1612fbc..3dab0f46de 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -52,6 +52,7 @@ namespace Properties { extern PBD::PropertyDescriptor right_of_split; extern PBD::PropertyDescriptor hidden; extern PBD::PropertyDescriptor position_locked; + extern PBD::PropertyDescriptor valid_transients; extern PBD::PropertyDescriptor start; extern PBD::PropertyDescriptor length; extern PBD::PropertyDescriptor position; @@ -95,6 +96,8 @@ class Region bool set_name (const std::string& str); const DataType& data_type() const { return _type; } + + AnalysisFeatureList transients () { return _transients; }; /** How the region parameters play together: * @@ -137,6 +140,7 @@ class Region bool opaque () const { return _opaque; } bool locked() const { return _locked; } bool position_locked() const { return _position_locked; } + bool valid_transients() const { return _valid_transients; } bool automatic() const { return _automatic; } bool whole_file() const { return _whole_file; } bool captured() const { return !(_import || _external); } @@ -245,12 +249,35 @@ class Region virtual int exportme (ARDOUR::Session&, ARDOUR::ExportSpecification&) = 0; + virtual void add_transient (nframes64_t where) { + // no transients, but its OK + } + + virtual int update_transient (nframes64_t old_position, nframes64_t new_position) { + // no transients, but its OK + return 0; + } + + virtual void remove_transient (nframes64_t where) { + // no transients, but its OK + } + + virtual int set_transients (AnalysisFeatureList&) { + // no transients, but its OK + return 0; + } + virtual int get_transients (AnalysisFeatureList&, bool force_new = false) { (void) force_new; // no transients, but its OK return 0; } + virtual int adjust_transients (nframes64_t delta) { + // no transients, but its OK + return 0; + } + virtual int separate_by_channel (ARDOUR::Session&, std::vector< boost::shared_ptr >&) const { return 0; @@ -317,6 +344,7 @@ class Region PBD::Property _right_of_split; PBD::Property _hidden; PBD::Property _position_locked; + PBD::Property _valid_transients; PBD::Property _start; PBD::Property _length; PBD::Property _position; @@ -333,7 +361,7 @@ class Region mutable RegionEditState _first_edit; BBT_Time _bbt_time; AnalysisFeatureList _transients; - bool _valid_transients; + mutable uint64_t _read_data_count; ///< modified in read() uint64_t _last_layer_op; ///< timestamp SourceList _sources; diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index 80f8baef0e..5f8b35256b 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -101,15 +101,14 @@ AudioRegion::register_properties () , _fade_in_active (Properties::fade_in_active, true) \ , _fade_out_active (Properties::fade_out_active, true) \ , _scale_amplitude (Properties::scale_amplitude, 1.0) - + #define AUDIOREGION_COPY_STATE(other) \ _envelope_active (other->_envelope_active) \ , _default_fade_in (other->_default_fade_in) \ , _default_fade_out (other->_default_fade_out) \ , _fade_in_active (other->_fade_in_active) \ , _fade_out_active (other->_fade_out_active) \ - , _scale_amplitude (other->_scale_amplitude) - + , _scale_amplitude (other->_scale_amplitude) /* a Session will reset these to its chosen defaults by calling AudioRegion::set_default_fade() */ void @@ -1265,6 +1264,63 @@ AudioRegion::audio_source (uint32_t n) const return boost::dynamic_pointer_cast(source(n)); } +int +AudioRegion::adjust_transients (nframes64_t delta) +{ + for (AnalysisFeatureList::iterator x = _transients.begin(); x != _transients.end(); ++x) { + (*x) = (*x) + delta; + } + + send_change (PropertyChange (Properties::valid_transients)); + + return 0; +} + +int +AudioRegion::update_transient (nframes64_t old_position, nframes64_t new_position) +{ + for (AnalysisFeatureList::iterator x = _transients.begin(); x != _transients.end(); ++x) { + if ((*x) == old_position) { + (*x) = new_position; + send_change (PropertyChange (Properties::valid_transients)); + + break; + } + } + + return 0; +} + +void +AudioRegion::add_transient (nframes64_t where) +{ + _transients.push_back(where); + _valid_transients = true; + + send_change (PropertyChange (Properties::valid_transients)); +} + +void +AudioRegion::remove_transient (nframes64_t where) +{ + _transients.remove(where); + _valid_transients = true; + + send_change (PropertyChange (Properties::valid_transients)); +} + +int +AudioRegion::set_transients (AnalysisFeatureList& results) +{ + _transients.clear(); + _transients = results; + _valid_transients = true; + + send_change (PropertyChange (Properties::valid_transients)); + + return 0; +} + int AudioRegion::get_transients (AnalysisFeatureList& results, bool force_new) { diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index cc9dc62ec7..20d771c692 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -696,7 +696,7 @@ Playlist::add_region (boost::shared_ptr region, framepos_t position, flo framepos_t pos = position; if (times == 1 && auto_partition){ - partition(pos, (pos + region->length()), true); + partition((nframes_t) pos - 1, (nframes_t) (pos + region->length()), true); } if (itimes >= 1) { @@ -869,9 +869,7 @@ Playlist::remove_region_internal (boost::shared_ptr region) } } - /* XXX and thaw ... */ - - return ret; + return -1; } void @@ -1284,7 +1282,7 @@ Playlist::duplicate (boost::shared_ptr region, framepos_t position, floa RegionLock rl (this); int itimes = (int) floor (times); - framepos_t pos = position; + nframes_t pos = position + 1; while (itimes--) { boost::shared_ptr copy = RegionFactory::create (region); @@ -2094,6 +2092,7 @@ Playlist::find_next_region_boundary (framepos_t frame, int dir) return ret; } + /***********************************************************************/ @@ -2257,7 +2256,7 @@ Playlist::set_state (const XMLNode& node, int version) error << _("Playlist: cannot create region from XML") << endmsg; continue; } - + add_region (region, region->position(), 1.0); // So that layer_op ordering doesn't get screwed up @@ -2300,7 +2299,7 @@ XMLNode& Playlist::state (bool full_state) { XMLNode *node = new XMLNode (X_("Playlist")); - char buf[64]; + char buf[64] = ""; node->add_property (X_("id"), id().to_s()); node->add_property (X_("name"), _name); @@ -2312,6 +2311,7 @@ Playlist::state (bool full_state) if (full_state) { RegionLock rlock (this, false); + for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { node->add_child_nocopy ((*i)->get_state()); } diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 64c7d8c66a..9d8e4e8ca0 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -59,6 +59,7 @@ namespace ARDOUR { PBD::PropertyDescriptor right_of_split; PBD::PropertyDescriptor hidden; PBD::PropertyDescriptor position_locked; + PBD::PropertyDescriptor valid_transients; PBD::PropertyDescriptor start; PBD::PropertyDescriptor length; PBD::PropertyDescriptor position; @@ -101,6 +102,8 @@ Region::make_property_quarks () DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n", Properties::hidden.property_id)); Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked")); DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n", Properties::position_locked.property_id)); + Properties::valid_transients.property_id = g_quark_from_static_string (X_("valid-transients")); + DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n", Properties::valid_transients.property_id)); Properties::start.property_id = g_quark_from_static_string (X_("start")); DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n", Properties::start.property_id)); Properties::length.property_id = g_quark_from_static_string (X_("length")); @@ -140,6 +143,7 @@ Region::register_properties () add_property (_right_of_split); add_property (_hidden); add_property (_position_locked); + add_property (_valid_transients); add_property (_start); add_property (_length); add_property (_position); @@ -165,6 +169,7 @@ Region::register_properties () , _right_of_split (Properties::right_of_split, false) \ , _hidden (Properties::hidden, false) \ , _position_locked (Properties::position_locked, false) \ + , _valid_transients (Properties::valid_transients, false) \ , _start (Properties::start, (s)) \ , _length (Properties::length, (l)) \ , _position (Properties::position, 0) \ @@ -189,6 +194,7 @@ Region::register_properties () , _right_of_split (other->_right_of_split) \ , _hidden (other->_hidden) \ , _position_locked (other->_position_locked) \ + , _valid_transients (other->_valid_transients) \ , _start(other->_start) \ , _length(other->_length) \ , _position(other->_position) \ @@ -225,7 +231,6 @@ Region::Region (const SourceList& srcs) , _last_length (0) , _last_position (0) , _first_edit (EditChangesNothing) - , _valid_transients(false) , _read_data_count(0) , _last_layer_op (0) , _pending_explicit_relayer (false) @@ -254,7 +259,6 @@ Region::Region (boost::shared_ptr other, frameoffset_t offset, boo , _last_length (other->_last_length) , _last_position(other->_last_position) \ , _first_edit (EditChangesNothing) - , _valid_transients(false) , _read_data_count(0) , _last_layer_op (0) , _pending_explicit_relayer (false) @@ -360,7 +364,6 @@ Region::Region (boost::shared_ptr other, const SourceList& srcs) , _last_length (other->_last_length) , _last_position (other->_last_position) , _first_edit (EditChangesID) - , _valid_transients (false) , _read_data_count (0) , _last_layer_op (other->_last_layer_op) , _pending_explicit_relayer (false) @@ -390,7 +393,6 @@ Region::Region (boost::shared_ptr other) , _last_length (other->_last_length) , _last_position (other->_last_position) , _first_edit (EditChangesID) - , _valid_transients(false) , _read_data_count(0) , _last_layer_op(other->_last_layer_op) , _pending_explicit_relayer (false) @@ -609,13 +611,12 @@ Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute) recompute_position_from_lock_style (); } - invalidate_transients (); + //invalidate_transients (); } /* do this even if the position is the same. this helps out a GUI that has moved its representation already. */ - send_change (Properties::position); } @@ -802,7 +803,8 @@ Region::modify_front (nframes_t new_position, bool reset_fade, void *src) if (new_position < end) { /* can't trim it zero or negative length */ - nframes_t newlen; + nframes_t newlen = 0; + nframes64_t delta = 0; /* can't trim it back passed where source position zero is located */ @@ -810,11 +812,14 @@ Region::modify_front (nframes_t new_position, bool reset_fade, void *src) if (new_position > _position) { newlen = _length - (new_position - _position); + delta = -1 * (new_position - _position); } else { newlen = _length + (_position - new_position); + delta = _position - new_position; } trim_to_internal (new_position, newlen, src); + if (reset_fade) { _right_of_split = true; } @@ -822,6 +827,10 @@ Region::modify_front (nframes_t new_position, bool reset_fade, void *src) if (!property_changes_suspended()) { recompute_at_start (); } + + if (_transients.size() > 0){ + adjust_transients(delta); + } } } @@ -892,7 +901,6 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/) new_start = _start + start_shift; } - } else if (start_shift < 0) { if (_start < -start_shift) { @@ -900,6 +908,7 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/) } else { new_start = _start + start_shift; } + } else { new_start = _start; } @@ -1528,6 +1537,8 @@ Region::invalidate_transients () { _valid_transients = false; _transients.clear (); + + send_change (PropertyChange (Properties::valid_transients)); } void diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index dd6a453080..5e56b82e68 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -957,25 +957,33 @@ Session::handle_locations_changed (Locations::LocationList& locations) void Session::enable_record () { - /* XXX really atomic compare+swap here */ - if (g_atomic_int_get (&_record_status) != Recording) { - g_atomic_int_set (&_record_status, Recording); - _last_record_location = _transport_frame; - _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordStrobe)); + while (1) { + RecordState rs = (RecordState) g_atomic_int_get (&_record_status); + + if (rs == Recording) { + break; + } - if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) { - - boost::shared_ptr rl = routes.reader (); - for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { - boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); - if (tr && tr->record_enabled ()) { - tr->monitor_input (true); - } - } - } - - RecordStateChanged (); - } + if (g_atomic_int_compare_and_exchange (&_record_status, rs, Recording)) { + + _last_record_location = _transport_frame; + _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordStrobe)); + + if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) { + + boost::shared_ptr rl = routes.reader (); + for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { + boost::shared_ptr tr = boost::dynamic_pointer_cast (*i); + if (tr && tr->record_enabled ()) { + tr->monitor_input (true); + } + } + } + + RecordStateChanged (); + break; + } + } } void