First stage of options rework.
[ardour.git] / gtk2_ardour / editor_ops.cc
index 1b5067e2ac1d1ccdd684a745f414f9940140b1ec..a9cc7ae7d6d6b0de1c488bbcde9d02f4419cfaf2 100644 (file)
@@ -54,6 +54,7 @@
 #include "ardour/transient_detector.h"
 #include "ardour/dB.h"
 #include "ardour/quantize.h"
+#include "ardour/strip_silence.h"
 
 #include "ardour_ui.h"
 #include "editor.h"
@@ -73,6 +74,7 @@
 #include "gui_thread.h"
 #include "keyboard.h"
 #include "utils.h"
+#include "strip_silence_dialog.h"
 
 #include "i18n.h"
 
@@ -197,74 +199,6 @@ Editor::split_regions_at (nframes64_t where, RegionSelection& regions)
        _new_regionviews_show_envelope = false;
 }
 
-
-/** Remove `clicked_regionview' */
-void
-Editor::remove_clicked_region ()
-{
-       if (clicked_routeview == 0 || clicked_regionview == 0) {
-               return;
-       }
-
-       boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
-       
-       begin_reversible_command (_("remove region"));
-        XMLNode &before = playlist->get_state();
-       playlist->remove_region (clicked_regionview->region());
-        XMLNode &after = playlist->get_state();
-       session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
-       commit_reversible_command ();
-}
-
-
-/** Remove the selected regions */
-void
-Editor::remove_selected_regions ()
-{
-       RegionSelection rs; 
-       get_regions_for_action (rs);
-       
-       if (!session) {
-               return;
-       }
-
-       if (rs.empty()) {
-               return;
-       }
-
-       begin_reversible_command (_("remove region"));
-
-       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;
-               }
-
-               XMLNode &before = playlist->get_state();
-               playlist->remove_region (*rl);
-               XMLNode &after = playlist->get_state();
-               session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
-       }
-
-       commit_reversible_command ();
-}
-
 boost::shared_ptr<Region>
 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
 {
@@ -3476,6 +3410,49 @@ Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint poi
        session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
 }      
 
+void
+Editor::trim_region_front ()
+{
+       trim_region (true);
+}
+
+void
+Editor::trim_region_back ()
+{
+       trim_region (false);
+}
+
+void
+Editor::trim_region (bool front)
+{
+       nframes64_t where = get_preferred_edit_position();
+       RegionSelection rs;
+
+       get_regions_for_action (rs);
+
+       if (rs.empty()) {
+               return;
+       }
+
+       begin_reversible_command (front ? _("trim front") : _("trim back"));
+
+       for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
+               if (!(*i)->region()->locked()) {
+                       boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
+                       XMLNode &before = pl->get_state();
+                       if (front) {
+                               (*i)->region()->trim_front (where, this);       
+                       } else {
+                               (*i)->region()->trim_end (where, this); 
+                       }
+                       XMLNode &after = pl->get_state();
+                       session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
+               }
+       }
+
+       commit_reversible_command ();
+}
+
 /** Trim the end of the selected regions to the position of the edit cursor */
 void
 Editor::trim_region_to_loop ()
@@ -3622,6 +3599,85 @@ Editor::trim_region_from_edit_point ()
        commit_reversible_command ();
 }
 
+void
+Editor::trim_region_to_previous_region_end ()
+{
+       return trim_to_region(false);
+}
+
+void
+Editor::trim_region_to_next_region_start ()
+{
+       return trim_to_region(true);
+}
+
+void
+Editor::trim_to_region(bool forward)
+{
+       RegionSelection rs;
+
+       get_regions_for_action (rs);
+
+       begin_reversible_command (_("trim to region"));
+
+       boost::shared_ptr<Region> next_region;
+
+       for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
+
+               AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
+
+               if (!arv) {
+                       continue;
+               }
+
+               AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
+
+               if (!atav) {
+                       return;
+               }
+
+               float speed = 1.0;
+
+               if (atav->get_diskstream() != 0) {
+                       speed = atav->get_diskstream()->speed();
+               }
+
+               
+               boost::shared_ptr<Region> region = arv->region();
+               boost::shared_ptr<Playlist> playlist (region->playlist());
+               
+               XMLNode &before = playlist->get_state();
+
+               if(forward){
+
+                   next_region = playlist->find_next_region (region->first_frame(), Start, 1);
+
+                   if(!next_region){
+                       continue;
+                   }
+
+                   region->trim_end((nframes64_t) (next_region->first_frame() * speed), this);
+                   arv->region_changed (Change (LengthChanged));
+               }
+               else {
+
+                   next_region = playlist->find_next_region (region->first_frame(), Start, 0);
+
+                   if(!next_region){
+                       continue;
+                   }
+
+                   region->trim_front((nframes64_t) ((next_region->last_frame() + 1) * speed), this);              
+                   arv->region_changed (Change (LengthChanged|PositionChanged|StartChanged));
+               }
+
+               XMLNode &after = playlist->get_state();
+               session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+       }
+
+       commit_reversible_command ();
+}
+
 void
 Editor::unfreeze_route ()
 {
@@ -3952,13 +4008,106 @@ struct PlaylistMapping {
     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
 };
 
+/** Remove `clicked_regionview' */
+void
+Editor::remove_clicked_region ()
+{
+       if (clicked_routeview == 0 || clicked_regionview == 0) {
+               return;
+       }
+
+       boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
+       
+       begin_reversible_command (_("remove region"));
+        XMLNode &before = playlist->get_state();
+       playlist->remove_region (clicked_regionview->region());
+        XMLNode &after = playlist->get_state();
+       session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+       commit_reversible_command ();
+}
+
+
+/** Remove the selected regions */
+void
+Editor::remove_selected_regions ()
+{
+       RegionSelection rs; 
+       get_regions_for_action (rs);
+       
+       if (!session) {
+               return;
+       }
+
+       if (rs.empty()) {
+               return;
+       }
+
+       begin_reversible_command (_("remove region"));
+
+       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());
+       }
+
+       vector<PlaylistState> playlists;
+       
+       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);
+               }
+
+               playlist->remove_region (*rl);          
+       }
+
+       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 ();
+}
 
 /** Cut, copy or clear selected regions.
  * @param op Operation (Cut, Copy or Clear)
  */
 void
 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
-{      
+{
        /* we can't use a std::map here because the ordering is important, and we can't trivially sort
           a map when we want ordered access to both elements. i think.
        */
@@ -3982,15 +4131,21 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
                        boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
 
                        if (pl) {
+                               set<PlaylistState, lt_playlist>::iterator fl;
 
-                               PlaylistState before;
-                               before.playlist = pl;
-                               before.before = &pl->get_state();
-                               
-                               insert_result = freezelist.insert (before);
-                               
-                               if (insert_result.second) {
+                               //only take state if this is a new playlist.
+                               for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
+                                       if ((*fl).playlist == pl) {
+                                               break;
+                                       }
+                               }
+               
+                               if (fl == freezelist.end()) {
+                                       PlaylistState before;
+                                       before.playlist = pl;
+                                       before.before = &pl->get_state();
                                        pl->freeze ();
+                                       insert_result = freezelist.insert (before);
                                }
                        }
                }
@@ -4538,6 +4693,38 @@ Editor::reverse_region ()
        apply_filter (rev, _("reverse regions"));
 }
 
+void
+Editor::strip_region_silence ()
+{
+       if (!session) {
+               return;
+       }
+
+       RegionSelection rs;
+       get_regions_for_action (rs);
+
+       if (rs.empty()) {
+               return;
+       }
+
+       std::list<boost::shared_ptr<AudioRegion> > ar;
+       
+       for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
+               AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
+               if (arv) {
+                       ar.push_back (arv->audio_region ());
+               }
+       }
+       
+       StripSilenceDialog d (ar);
+       int const r = d.run ();
+
+       if (r == Gtk::RESPONSE_OK) {
+               StripSilence s (*session, d.threshold (), d.minimum_length (), d.fade_length ());
+               apply_filter (s, _("strip silence"));
+       }
+}
+
 
 void
 Editor::quantize_region ()
@@ -4585,7 +4772,28 @@ Editor::apply_filter (Filter& filter, string command)
                        if (arv->audio_region()->apply (filter) == 0) {
 
                                XMLNode &before = playlist->get_state();
-                               playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
+
+                               if (filter.results.empty ()) {
+
+                                       /* no regions returned; remove the old one */
+                                       playlist->remove_region (arv->region ());
+                                       
+                               } else {
+
+                                       std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
+
+                                       /* first region replaces the old one */
+                                       playlist->replace_region (arv->region(), *res, (*res)->position());
+                                       ++res;
+
+                                       /* add the rest */
+                                       while (res != filter.results.end()) {
+                                               playlist->add_region (*res, (*res)->position());
+                                               ++res;
+                                       }
+                                       
+                               }
+
                                XMLNode &after = playlist->get_state();
                                session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
                        } else {
@@ -5093,7 +5301,7 @@ Editor::toggle_selected_region_fades (int dir)
 void
 Editor::update_region_fade_visibility ()
 {
-       bool _fade_visibility = Config->get_show_region_fades ();
+       bool _fade_visibility = session->config.get_show_region_fades ();
 
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
@@ -5111,7 +5319,7 @@ Editor::update_region_fade_visibility ()
 void
 Editor::update_xfade_visibility ()
 {
-       _xfade_visibility = Config->get_xfades_visible ();
+       _xfade_visibility = session->config.get_xfades_visible ();
        
        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
@@ -5207,49 +5415,6 @@ Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_ar
        }
 }
 
-void
-Editor::trim_region_front ()
-{
-       trim_region (true);
-}
-
-void
-Editor::trim_region_back ()
-{
-       trim_region (false);
-}
-
-void
-Editor::trim_region (bool front)
-{
-       nframes64_t where = get_preferred_edit_position();
-       RegionSelection rs;
-
-       get_regions_for_action (rs);
-
-       if (rs.empty()) {
-               return;
-       }
-
-       begin_reversible_command (front ? _("trim front") : _("trim back"));
-
-       for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
-               if (!(*i)->region()->locked()) {
-                       boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
-                       XMLNode &before = pl->get_state();
-                       if (front) {
-                               (*i)->region()->trim_front (where, this);       
-                       } else {
-                               (*i)->region()->trim_end (where, this); 
-                       }
-                       XMLNode &after = pl->get_state();
-                       session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
-               }
-       }
-
-       commit_reversible_command ();
-}
-
 struct EditorOrderRouteSorter {
     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
            /* use of ">" forces the correct sort order */