Do not constrain vertical size without need
[ardour.git] / gtk2_ardour / editor_ops.cc
index cdb0b5bd6a2cb86031e7a292f761e5ef94bd6e64..f7bbf2a16666d68d05b06d67d4fee6196156ad79 100644 (file)
 #include "transform_dialog.h"
 #include "ui_config.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
@@ -119,6 +119,13 @@ using Gtkmm2ext::Keyboard;
 void
 Editor::undo (uint32_t n)
 {
+       if (_session && _session->actively_recording()) {
+               /* no undo allowed while recording. Session will check also,
+                  but we don't even want to get to that.
+               */
+               return;
+       }
+
        if (_drags->active ()) {
                _drags->abort ();
        }
@@ -136,12 +143,19 @@ Editor::undo (uint32_t n)
 void
 Editor::redo (uint32_t n)
 {
+       if (_session && _session->actively_recording()) {
+               /* no redo allowed while recording. Session will check also,
+                  but we don't even want to get to that.
+               */
+               return;
+       }
+
        if (_drags->active ()) {
                _drags->abort ();
        }
 
        if (_session) {
-               _session->redo (n);
+       _session->redo (n);
                if (_session->redo_depth() == 0) {
                        redo_action->set_sensitive(false);
                }
@@ -2243,19 +2257,29 @@ Editor::set_session_end_from_playhead ()
        _session->set_end_is_free (false);
 }
 
+
+void
+Editor::toggle_location_at_playhead_cursor ()
+{
+       if (!do_remove_location_at_playhead_cursor())
+       {
+               add_location_from_playhead_cursor();
+       }
+}
+
 void
 Editor::add_location_from_playhead_cursor ()
 {
        add_location_mark (_session->audible_frame());
 }
 
-void
-Editor::remove_location_at_playhead_cursor ()
+bool
+Editor::do_remove_location_at_playhead_cursor ()
 {
+       bool removed = false;
        if (_session) {
                //set up for undo
                XMLNode &before = _session->locations()->get_state();
-               bool removed = false;
 
                //find location(s) at this time
                Locations::LocationList locs;
@@ -2275,6 +2299,13 @@ Editor::remove_location_at_playhead_cursor ()
                        commit_reversible_command ();
                }
        }
+       return removed;
+}
+
+void
+Editor::remove_location_at_playhead_cursor ()
+{
+       do_remove_location_at_playhead_cursor ();
 }
 
 /** Add a range marker around each selected region */
@@ -4178,6 +4209,7 @@ Editor::cut_copy (CutCopyOp op)
        }
 }
 
+
 struct AutomationRecord {
        AutomationRecord () : state (0) , line(NULL) {}
        AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
@@ -4186,7 +4218,11 @@ struct AutomationRecord {
        const AutomationLine* line; ///< line this came from
        boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
 };
-
+struct PointsSelectionPositionSorter {
+       bool operator() (ControlPoint* a, ControlPoint* b) {
+               return (*(a->model()))->when < (*(b->model()))->when;
+       }
+};
 /** Cut, copy or clear selected automation points.
  *  @param op Operation (Cut, Copy or Clear)
  */
@@ -4204,9 +4240,12 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid
        typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
        Lists lists;
 
+       /* user could select points in any order */
+       selection->points.sort(PointsSelectionPositionSorter ());
+       
        /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
-       for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
-               const AutomationLine&                   line = (*i)->line();
+       for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
+               const AutomationLine&                   line = (*sel_point)->line();
                const boost::shared_ptr<AutomationList> al   = line.the_list();
                if (lists.find (al) == lists.end ()) {
                        /* We haven't seen this list yet, so make a record for it.  This includes
@@ -4226,17 +4265,17 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid
 
                /* Add all selected points to the relevant copy ControlLists */
                framepos_t start = std::numeric_limits<framepos_t>::max();
-               for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
-                       boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
-                       AutomationList::const_iterator    j  = (*i)->model();
+               for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
+                       boost::shared_ptr<AutomationList>    al = (*sel_point)->line().the_list();
+                       AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
 
-                       lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
+                       lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
                        if (midi) {
                                /* Update earliest MIDI start time in beats */
-                               earliest = std::min(earliest, Evoral::Beats((*j)->when));
+                               earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
                        } else {
                                /* Update earliest session start time in frames */
-                               start = std::min(start, (*i)->line().session_position(j));
+                               start = std::min(start, (*sel_point)->line().session_position(ctrl_evt));
                        }
                }
 
@@ -4259,12 +4298,13 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid
                           start time, so relative ordering between points is preserved
                           when copying from several lists and the paste starts at the
                           earliest copied piece of data. */
-                       for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
-                               (*j)->when -= line_offset;
+                       boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
+                       for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
+                               (*ctrl_evt)->when -= line_offset;
                        }
 
                        /* And add it to the cut buffer */
-                       cut_buffer->add (i->second.copy);
+                       cut_buffer->add (al_cpy);
                }
        }
 
@@ -4276,9 +4316,22 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid
                }
 
                /* Remove each selected point from its AutomationList */
-               for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
-                       boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
-                       al->erase ((*i)->model ());
+               for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
+                       AutomationLine& line = (*sel_point)->line ();
+                       boost::shared_ptr<AutomationList> al = line.the_list();
+
+                       bool erase = true;
+                       
+                       if (dynamic_cast<AudioRegionGainLine*> (&line)) {
+                               /* removing of first and last gain point in region gain lines is prohibited*/
+                               if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
+                                       erase = false;
+                               }
+                       }
+
+                       if(erase) {
+                               al->erase ((*sel_point)->model ());
+                       }
                }
 
                /* Thaw the lists and add undo records for them */
@@ -5010,25 +5063,36 @@ Editor::normalize_region ()
           obtain the maximum amplitude of them all.
        */
        list<double> max_amps;
+       list<double> rms_vals;
        double max_amp = 0;
+       double max_rms = 0;
+       bool use_rms = dialog.constrain_rms ();
+
        for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
                AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
-               if (arv) {
-                       dialog.descend (1.0 / regions);
-                       double const a = arv->audio_region()->maximum_amplitude (&dialog);
-
-                       if (a == -1) {
-                               /* the user cancelled the operation */
-                               return;
-                       }
+               if (!arv) {
+                       continue;
+               }
+               dialog.descend (1.0 / regions);
+               double const a = arv->audio_region()->maximum_amplitude (&dialog);
+               if (use_rms) {
+                       double r = arv->audio_region()->rms (&dialog);
+                       max_rms = max (max_rms, r);
+                       rms_vals.push_back (r);
+               }
 
-                       max_amps.push_back (a);
-                       max_amp = max (max_amp, a);
-                       dialog.ascend ();
+               if (a == -1) {
+                       /* the user cancelled the operation */
+                       return;
                }
+
+               max_amps.push_back (a);
+               max_amp = max (max_amp, a);
+               dialog.ascend ();
        }
 
        list<double>::const_iterator a = max_amps.begin ();
+       list<double>::const_iterator l = rms_vals.begin ();
        bool in_command = false;
 
        for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
@@ -5039,9 +5103,21 @@ Editor::normalize_region ()
 
                arv->region()->clear_changes ();
 
-               double const amp = dialog.normalize_individually() ? *a : max_amp;
+               double amp = dialog.normalize_individually() ? *a : max_amp;
+               double target = dialog.target_peak (); // dB
+
+               if (use_rms) {
+                       double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
+                       const double t_rms = dialog.target_rms ();
+                       const gain_t c_peak = dB_to_coefficient (target);
+                       const gain_t c_rms  = dB_to_coefficient (t_rms);
+                       if ((amp_rms / c_rms) > (amp / c_peak)) {
+                               amp = amp_rms;
+                               target = t_rms;
+                       }
+               }
 
-               arv->audio_region()->normalize (amp, dialog.target ());
+               arv->audio_region()->normalize (amp, target);
 
                if (!in_command) {
                        begin_reversible_command (_("normalize"));
@@ -5050,6 +5126,7 @@ Editor::normalize_region ()
                _session->add_command (new StatefulDiffCommand (arv->region()));
 
                ++a;
+               ++l;
        }
 
        if (in_command) {
@@ -5192,8 +5269,7 @@ Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv
        vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
        v.push_back (selected);
 
-       framepos_t    pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
-       Evoral::Beats pos_beats  = _session->tempo_map().framewalk_to_beats(0, pos_frames);
+       Evoral::Beats pos_beats  = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
 
        return op (mrv.midi_region()->model(), pos_beats, v);
 }
@@ -7909,7 +7985,7 @@ Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total,
 {
        Timers::TimerSuspender t;
        label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
-       Gtkmm2ext::UI::instance()->flush_pending ();
+       Gtkmm2ext::UI::instance()->flush_pending (1);
 }
 
 void
@@ -7929,7 +8005,7 @@ Editor::bring_all_sources_into_session ()
         */
 
        Timers::TimerSuspender t;
-       Gtkmm2ext::UI::instance()->flush_pending ();
+       Gtkmm2ext::UI::instance()->flush_pending (3);
 
        cerr << " Do it\n";