beat slicing patch #1 from lincoln spiteri
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 6 Jul 2010 11:33:27 +0000 (11:33 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 6 Jul 2010 11:33:27 +0000 (11:33 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@7381 d708f5d6-7413-0410-9779-e7cbd77b26cf

24 files changed:
gtk2_ardour/ardour.menus.in
gtk2_ardour/audio_region_view.cc
gtk2_ardour/audio_region_view.h
gtk2_ardour/editor.h
gtk2_ardour/editor_actions.cc
gtk2_ardour/editor_canvas_events.cc
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_drag.h
gtk2_ardour/editor_items.h
gtk2_ardour/editor_mouse.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/midi_streamview.cc
gtk2_ardour/mnemonic-us.bindings.in
gtk2_ardour/public_editor.h
gtk2_ardour/rhythm_ferret.cc
gtk2_ardour/rhythm_ferret.h
gtk2_ardour/time_axis_view.cc
gtk2_ardour/time_axis_view.h
libs/ardour/ardour/audioregion.h
libs/ardour/ardour/region.h
libs/ardour/audioregion.cc
libs/ardour/playlist.cc
libs/ardour/region.cc
libs/ardour/session.cc

index e6ae76a74eaa6b621100578f5b4310d4282749c9..85df23ab14bba717873747aedc3f65df7fd517eb 100644 (file)
                <menuitem action='editor-delete'/>
                <menuitem action='editor-crop'/>
                <menuitem action='split-region'/>
+              <menuitem action='split-region-at-transients'/>
               <menu action="SeparateMenu">
+                   <menuitem action='separate-under-region'/>
                    <menuitem action='editor-separate'/>
                    <menuitem action='separate-from-loop'/>
                    <menuitem action='separate-from-punch'/>
                    <separator/>
-                   <menuitem action='split-region-at-transients'/>
                </menu>
               <menu action="AlignMenu">
                   <menuitem action='align-regions-start'/>
              <menuitem action='set-punch-from-region'/>
              <menuitem action='add-range-marker-from-region'/>
              <menuitem action='add-range-markers-from-region'/>
+
+             <separator/>
+             <menuitem action='snap-regions-to-grid'/>
+             <menuitem action='close-region-gaps'/>
              <separator/>
+             <menuitem action='place-transient' />
              <menuitem action='toggle-rhythm-ferret'/>
+             
        </menu>
 
         <menu action='TrackMenu'>
index 802d9230fbb7ba272f7dabef5506c676feba0d8d..06621a20e2caae0e097890fa0ac01d459893e69f 100644 (file)
@@ -254,6 +254,10 @@ AudioRegionView::~AudioRegionView ()
                delete *i;
        }
 
+       for (list<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::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<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
-                       if((agr = dynamic_cast<AudioGhostRegion*>(*i)) != 0) {
+                       if ((agr = dynamic_cast<AudioGhostRegion*>(*i)) != 0) {
 
                                for (vector<WaveView*>::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<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::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<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::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<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::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<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::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<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::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<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::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
index b00fb583fa848ce88c185b172e3fe23e0adcee90..0e2b54130c10c2cb1eaf3ee7ee74c0f46271c2c4 100644 (file)
@@ -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<ArdourCanvas::WaveView *> waves;
     std::vector<ArdourCanvas::WaveView *> tmp_waves; ///< see ::create_waves()
+    
+    std::list<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> > 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<GnomeCanvasWaveViewCache*> wave_caches;
+    
+    void transients_changed();
 
   private:
 
index 2300fe7c205658ca5cf232a340419108db93e3ac..44e7289f6de4010ada37a1c68b5d9c2c9e8d6111 100644 (file)
@@ -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<ARDOUR::Region> 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<ARDOUR::Region> 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<nframes64_t> region_boundary_cache;
+       std::vector<ARDOUR::framepos_t> 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__ */
index eeb604c2e51652ec2794e067aa6b932d765bba32..f1d20fbed7a85e0b32ee323fc9498a62392e204b 100644 (file)
@@ -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);
index 0b9d8a3793824677914742214d647de271f1877d..34a73d318c029f79d4a1489e7cfef7274130b1d6 100644 (file)
@@ -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<RouteTimeAxisView*>(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*/)
 {
index b01c79ad916cee972b5b0bdfdaad176859857c9a..2aaeaa1038ad54804ff8f612e63653cc0d909b9f 100644 (file)
@@ -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<SimpleLine*> (_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<AudioRegionView*> (_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<AudioRegionView*> (_item->get_data ("regionview"));
+       _arv->update_transient(_before, _line->property_x1());
+}
+
+void
+FeatureLineDrag::aborted ()
+{
+       //_line->reset ();
+}
+
 void
 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
 {
index f1634ffb646e11e447d7314db8d7d915bca57326..9e206cfebf712ad24bbb422e1fcada9b1b6befaa 100644 (file)
@@ -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
 {
index 08013e30ab547f5eb7497de091d9f5dfb72fd64b..36a5a9e36fb1f796bea9710995f035c7f22056d9 100644 (file)
@@ -47,6 +47,7 @@ enum ItemType {
        FadeOutItem,
        FadeOutHandleItem,
        NoteItem,
+       FeatureLineItem,
         LeftFrameHandle,
         RightFrameHandle,
 
index 55a7e6887fa7d0b34a508378d79d2db4490a956b..68d92300281d80ea762ea34c693daa832191014f 100644 (file)
@@ -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<ArdourCanvas::SimpleLine *> (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<ArdourCanvas::SimpleLine *> (item);
+                       line->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();;
+               }
+               break;
 
        default:
                break;
index 9bf09557eeff164bfb9c7d8a34a8f1cb8abe5a2f..adc9078fba04fe48720120de00f86d50a88a826d 100644 (file)
@@ -552,7 +552,7 @@ Editor::move_to_end ()
 void
 Editor::build_region_boundary_cache ()
 {
-       nframes64_t pos = 0;
+       framepos_t pos = 0;
        vector<RegionPoint> interesting_points;
        boost::shared_ptr<Region> 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<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
 
@@ -645,7 +645,7 @@ Editor::build_region_boundary_cache ()
                           to sort later.
                        */
 
-                       vector<nframes64_t>::iterator ri;
+                       vector<framepos_t>::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<framepos_t>::iterator x = region_boundary_cache.begin(); x != region_boundary_cache.end(); ++x) {
+                cerr << "Region boundary @ " << *x << endl;
+        }
 }
 
 boost::shared_ptr<Region>
-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<Region> 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<Region> 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<RouteTimeAxisView*> (*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> 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<PlaylistState> playlists;
+
+       if (!_session) {
+               return;
+       }
+
+       if (rs.empty()) {
+               return;
+       }
+
+       begin_reversible_command (_("separate region under"));
+
+       list<boost::shared_ptr<Region> > 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<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
+
+               boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
+
+               if (!playlist) {
+                       // is this check necessary?
+                       continue;
+               }
+
+               vector<PlaylistState>::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<PlaylistState>::iterator pl;
+
+       for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
+               (*pl).playlist->thaw ();
+               _session->add_command(new MementoCommand<Playlist>(*(*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<RegionView*>::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<Playlist> 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<Region> 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<Region> 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<Region> 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,35 +6047,190 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
                plist.add (ARDOUR::Properties::layer, 0);
 
                boost::shared_ptr<Region> 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()) {
+       string new_name;
 
-                       /* add final fragment */
+       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);
 
-                       file_start = r->start() + (pos - r->position());
-                       len = r->last_frame() - pos;
+       boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
+       pl->add_region (nr, r->position() + 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);
+       
+       pl->thaw ();
 
-                       nr = RegionFactory::create (r->sources(), plist2); 
-                       pl->add_region (nr, pos);
+       _session->add_command (new StatefulDiffCommand (pl));
+}
 
-                       break;
-               }
+void
+Editor::place_transient()
+{
+       if (!_session) {
+               return;
        }
 
-       pl->thaw ();
+       RegionSelection rs;
 
-       _session->add_command (new StatefulDiffCommand (pl));
+       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<ArdourCanvas::SimpleLine*> (item);
+       assert (_line);
+
+       AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (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<Region> 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
@@ -6053,6 +6309,7 @@ Editor::tab_to_transient (bool forward)
                }
        }
 }
+
 void
 Editor::playhead_forward_to_grid ()
 {
index 96d331ba0146a8d21539dab0bcfa352367d682b4..cf5822476623e57669d3ab63490853bb8087dda2 100644 (file)
@@ -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<MidiModel> data, nframes_t
 
                                                        const boost::shared_ptr<MidiRegionView::NoteType>& 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;
index 3056b2e3e539dd0c2b1130316ad1c02ab647a86c..37545910151b41f5d654a5f5f0598fd3ba29aab6 100644 (file)
@@ -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)
 
index 52fb601f8dae68a32f2567d33200effcc457e1e5..ea9ef9dfad8cb71b10e0229e711903d0e3ade581 100644 (file)
@@ -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;
index 8c67ceae21afd7c52033d5edfd0e78c45239a765..cba0042cfea6a9c0d5e115d5ae6f36fdee3c52a1 100644 (file)
@@ -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<Readable> 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> 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> 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 ();
 }
 
index b18a86377ca0dc516dbca2dc1060589652c26080..043b9fe8a71ac716dd581822c8ad81ed6f37c962 100644 (file)
@@ -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;
 
index 58dbd595bfca32a74d49cb969147341e4eaf004b..803053b8c7fa3d33d2ec39669b19adef4be714f0 100644 (file)
@@ -203,10 +203,6 @@ TimeAxisView::~TimeAxisView()
                delete (*i)->end_trim;
        }
 
-       for (list<SimpleLine*>::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<ArdourCanvas::SimpleLine*>::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<ArdourCanvas::SimpleLine*>::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<ArdourCanvas::SimpleLine*>::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)
 {
index 4e91b15336a590b55bdff477598623207b657092..93cb7eced3a4355072b1a1b100e7348e7d02df7a 100644 (file)
@@ -165,9 +165,6 @@ class TimeAxisView : public virtual AxisView, public PBD::Stateful
        virtual ARDOUR::RouteGroup* route_group() const { return 0; }
        virtual boost::shared_ptr<ARDOUR::Playlist> playlist() const { return boost::shared_ptr<ARDOUR::Playlist> (); }
 
-       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<ArdourCanvas::SimpleLine*> feature_lines;
-       ARDOUR::AnalysisFeatureList analysis_features;
-       void reshow_feature_lines ();
-
        void conditionally_add_to_selection ();
 
        ArdourCanvas::Group* _canvas_display;
index 0a3e53039e13f126e4b80d7bd861e229e8d81b06..5843d6f753f0e9e118e3e3748748de98f5be0031 100644 (file)
@@ -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<std::pair<frameoffset_t, framecnt_t> > find_silence (Sample, framecnt_t, InterThreadInfo&) const;
 
   private:
index 8bc1612fbc2b397693f7711a2c359b430f20f48a..3dab0f46def994e0b20e081dbc1c9a13786ef87b 100644 (file)
@@ -52,6 +52,7 @@ namespace Properties {
        extern PBD::PropertyDescriptor<bool> right_of_split;
        extern PBD::PropertyDescriptor<bool> hidden;
        extern PBD::PropertyDescriptor<bool> position_locked;
+       extern PBD::PropertyDescriptor<bool> valid_transients;
        extern PBD::PropertyDescriptor<framepos_t> start;
        extern PBD::PropertyDescriptor<framecnt_t> length;
        extern PBD::PropertyDescriptor<framepos_t> 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<Region> >&) const {
                return 0;
@@ -317,6 +344,7 @@ class Region
        PBD::Property<bool>        _right_of_split;
        PBD::Property<bool>        _hidden;
        PBD::Property<bool>        _position_locked;
+       PBD::Property<bool>        _valid_transients;
        PBD::Property<framepos_t>  _start;
        PBD::Property<framecnt_t>  _length;
        PBD::Property<framepos_t>  _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;
index 80f8baef0e52f691b1b277b05ae8d8b2bc308b06..5f8b35256b7593c423d11e3ac3efcc3dd5d9591b 100644 (file)
@@ -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<AudioSource>(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)
 {
index cc9dc62ec79c027fcc3f8417c11ab7821bb5d190..20d771c692809dc0ffa9f439f4a3a5a97c3805e9 100644 (file)
@@ -696,7 +696,7 @@ Playlist::add_region (boost::shared_ptr<Region> 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> region)
                }
        }
 
-       /* XXX and thaw ... */
-
-       return ret;
+       return -1;
 }
 
 void
@@ -1284,7 +1282,7 @@ Playlist::duplicate (boost::shared_ptr<Region> 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<Region> 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());
                }
index 64c7d8c66a861a496a08dd5b31f5558c1f1deff3..9d8e4e8ca01613d96cea0a3ebacae7acbd8277bc 100644 (file)
@@ -59,6 +59,7 @@ namespace ARDOUR {
                PBD::PropertyDescriptor<bool> right_of_split;
                PBD::PropertyDescriptor<bool> hidden;
                PBD::PropertyDescriptor<bool> position_locked;
+               PBD::PropertyDescriptor<bool> valid_transients;
                PBD::PropertyDescriptor<framepos_t> start;
                PBD::PropertyDescriptor<framecnt_t> length;
                PBD::PropertyDescriptor<framepos_t> 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<const Region> 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<const Region> 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<const Region> 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
index dd6a4530800eac7c93b9d2f0e27e5938d72bd820..5e56b82e689b7dfa8990d2f1871009516421152b 100644 (file)
@@ -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));
-
-               if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
-                       
-                       boost::shared_ptr<RouteList> rl = routes.reader ();
-                       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-                               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-                               if (tr && tr->record_enabled ()) {
-                                       tr->monitor_input (true);
-                               }
-                       }
-               }
+        while (1) {
+                RecordState rs = (RecordState) g_atomic_int_get (&_record_status);
+                
+                if (rs == Recording) {
+                        break;
+                }
 
-               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<RouteList> rl = routes.reader ();
+                                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+                                        boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+                                        if (tr && tr->record_enabled ()) {
+                                                tr->monitor_input (true);
+                                        }
+                                }
+                        }
+                        
+                        RecordStateChanged ();
+                        break;
+                }
+        }
 }
 
 void