Allow trim of midi regions to before the start of the source (better, this time)...
authorCarl Hetherington <carl@carlh.net>
Thu, 9 Dec 2010 21:34:46 +0000 (21:34 +0000)
committerCarl Hetherington <carl@carlh.net>
Thu, 9 Dec 2010 21:34:46 +0000 (21:34 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@8229 d708f5d6-7413-0410-9779-e7cbd77b26cf

15 files changed:
gtk2_ardour/edit_note_dialog.cc
gtk2_ardour/editor_drag.cc
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_region_view.h
libs/ardour/ardour/midi_model.h
libs/ardour/ardour/midi_region.h
libs/ardour/ardour/region.h
libs/ardour/enums.cc
libs/ardour/midi_model.cc
libs/ardour/midi_region.cc
libs/ardour/quantize.cc
libs/ardour/region.cc
libs/ardour/session_state.cc
libs/evoral/evoral/Event.hpp
libs/evoral/src/Event.cpp

index 0d22e0ae95a9e26368ed9f3a5bb747d3fec8ac7b..8466cdfa85a709dc3d1f7a8dd65ae70dc5b8b5f3 100644 (file)
@@ -111,7 +111,7 @@ EditNoteDialog::run ()
                return r;
        }
 
-       _region_view->start_diff_command (_("edit note"));
+       _region_view->start_note_diff_command (_("edit note"));
        
        bool had_change = false;
 
index fb3ef58802ee841b90be32cb0899302ea6f624af..ea71390ce6c507b416af1b36bf4de676b1eb6914 100644 (file)
@@ -1533,6 +1533,7 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
        framepos_t const pf = adjusted_current_frame (event);
 
        if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
+               /* Move the contents of the region around without changing the region bounds */
                _operation = ContentsTrim;
                Drag::start_grab (event, _editor->cursors()->trimmer);
        } else {
@@ -1691,6 +1692,16 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
        if (movement_occurred) {
                motion (event, false);
 
+               /* This must happen before the region's StatefulDiffCommand is created, as it may
+                  `correct' (ahem) the region's _start from being negative to being zero.  It
+                  needs to be zero in the undo record.
+               */
+               if (_operation == StartTrim) {
+                       for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+                               i->view->trim_front_ending ();
+                       }
+               }
+               
                if (!_editor->selection->selected (_primary)) {
                        _primary->thaw_after_trim ();
                } else {
@@ -1709,7 +1720,6 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
                }
 
                _editor->motion_frozen_playlists.clear ();
-
                if (_have_transaction) {
                        _editor->commit_reversible_command();
                }
@@ -1723,6 +1733,7 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
                if (_operation == StartTrim) {
                        i->view->trim_front_ending ();
                }
+               
                i->view->region()->resume_property_changes ();
        }
 }
index cdfc1cbc3a1eea5d8ce70a7c269a87b640e67594..048265474015794153b11e27d1f6d76b74328d62 100644 (file)
@@ -88,7 +88,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
        , _custom_device_mode(string())
        , _active_notes(0)
        , _note_group(new ArdourCanvas::Group(*group))
-       , _diff_command(0)
+       , _note_diff_command (0)
        , _ghost_note(0)
         , _drag_rect (0)
         , _step_edit_cursor (0)
@@ -121,7 +121,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
        , _custom_device_mode(string())
        , _active_notes(0)
        , _note_group(new ArdourCanvas::Group(*parent))
-       , _diff_command(0)
+       , _note_diff_command (0)
        , _ghost_note(0)
         , _drag_rect (0)
         , _step_edit_cursor (0)
@@ -152,7 +152,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
        , _custom_device_mode(string())
        , _active_notes(0)
        , _note_group(new ArdourCanvas::Group(*get_canvas_group()))
-       , _diff_command(0)
+       , _note_diff_command (0)
        , _ghost_note(0)
         , _drag_rect (0)
         , _step_edit_cursor (0)
@@ -185,7 +185,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<M
        , _custom_device_mode(string())
        , _active_notes(0)
        , _note_group(new ArdourCanvas::Group(*get_canvas_group()))
-       , _diff_command(0)
+       , _note_diff_command (0)
        , _ghost_note(0)
         , _drag_rect (0)
         , _step_edit_cursor (0)
@@ -774,8 +774,8 @@ MidiRegionView::create_note_at(double x, double y, double length, bool sh)
 
        view->update_note_range(new_note->note());
 
-       MidiModel::DiffCommand* cmd = _model->new_diff_command("add note");
-       cmd->add(new_note);
+       MidiModel::NoteDiffCommand* cmd = _model->new_note_diff_command("add note");
+       cmd->add (new_note);
        _model->apply_command(*trackview.session(), cmd);
 
        play_midi_note (new_note);
@@ -819,18 +819,18 @@ MidiRegionView::display_model(boost::shared_ptr<MidiModel> model)
 }
 
 void
-MidiRegionView::start_diff_command(string name)
+MidiRegionView::start_note_diff_command (string name)
 {
-       if (!_diff_command) {
-               _diff_command = _model->new_diff_command(name);
+       if (!_note_diff_command) {
+               _note_diff_command = _model->new_note_diff_command (name);
        }
 }
 
 void
-MidiRegionView::diff_add_note(const boost::shared_ptr<NoteType> note, bool selected, bool show_velocity)
+MidiRegionView::note_diff_add_note (const boost::shared_ptr<NoteType> note, bool selected, bool show_velocity)
 {
-       if (_diff_command) {
-               _diff_command->add(note);
+       if (_note_diff_command) {
+               _note_diff_command->add (note);
        }
        if (selected) {
                _marked_for_selection.insert(note);
@@ -841,30 +841,30 @@ MidiRegionView::diff_add_note(const boost::shared_ptr<NoteType> note, bool selec
 }
 
 void
-MidiRegionView::diff_remove_note(ArdourCanvas::CanvasNoteEvent* ev)
+MidiRegionView::note_diff_remove_note (ArdourCanvas::CanvasNoteEvent* ev)
 {
-       if (_diff_command && ev->note()) {
-               _diff_command->remove(ev->note());
+       if (_note_diff_command && ev->note()) {
+               _note_diff_command->remove(ev->note());
        }
 }
 
 void
-MidiRegionView::diff_add_change (ArdourCanvas::CanvasNoteEvent* ev,
-                                MidiModel::DiffCommand::Property property,
-                                uint8_t val)
+MidiRegionView::note_diff_add_change (ArdourCanvas::CanvasNoteEvent* ev,
+                                     MidiModel::NoteDiffCommand::Property property,
+                                     uint8_t val)
 {
-       if (_diff_command) {
-               _diff_command->change (ev->note(), property, val);
+       if (_note_diff_command) {
+               _note_diff_command->change (ev->note(), property, val);
        }
 }
 
 void
-MidiRegionView::diff_add_change (ArdourCanvas::CanvasNoteEvent* ev,
-                                MidiModel::DiffCommand::Property property,
-                                Evoral::MusicalTime val)
+MidiRegionView::note_diff_add_change (ArdourCanvas::CanvasNoteEvent* ev,
+                                     MidiModel::NoteDiffCommand::Property property,
+                                     Evoral::MusicalTime val)
 {
-       if (_diff_command) {
-               _diff_command->change (ev->note(), property, val);
+       if (_note_diff_command) {
+               _note_diff_command->change (ev->note(), property, val);
        }
 }
 
@@ -873,19 +873,19 @@ MidiRegionView::apply_diff ()
 {
         bool add_or_remove;
 
-       if (!_diff_command) {
+       if (!_note_diff_command) {
                return;
        }
 
-        if ((add_or_remove = _diff_command->adds_or_removes())) {
+        if ((add_or_remove = _note_diff_command->adds_or_removes())) {
                 // Mark all selected notes for selection when model reloads
                 for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
                         _marked_for_selection.insert((*i)->note());
                 }
         }
 
-       _model->apply_command(*trackview.session(), _diff_command);
-       _diff_command = 0;
+       _model->apply_command(*trackview.session(), _note_diff_command);
+       _note_diff_command = 0;
        midi_view()->midi_track()->playlist_modified();
         
         if (add_or_remove) {
@@ -896,23 +896,23 @@ MidiRegionView::apply_diff ()
 }
 
 void
-MidiRegionView::apply_diff_as_subcommand()
+MidiRegionView::apply_diff_as_subcommand ()
 {
         bool add_or_remove;
 
-       if (!_diff_command) {
+       if (!_note_diff_command) {
                return;
        }
 
-        if ((add_or_remove = _diff_command->adds_or_removes())) {
+        if ((add_or_remove = _note_diff_command->adds_or_removes())) {
                 // Mark all selected notes for selection when model reloads
                 for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
                         _marked_for_selection.insert((*i)->note());
                 }
         }
 
-       _model->apply_command_as_subcommand(*trackview.session(), _diff_command);
-       _diff_command = 0;
+       _model->apply_command_as_subcommand(*trackview.session(), _note_diff_command);
+       _note_diff_command = 0;
        midi_view()->midi_track()->playlist_modified();
 
         if (add_or_remove) {
@@ -925,8 +925,8 @@ MidiRegionView::apply_diff_as_subcommand()
 void
 MidiRegionView::abort_command()
 {
-       delete _diff_command;
-       _diff_command = 0;
+       delete _note_diff_command;
+       _note_diff_command = 0;
        clear_selection();
 }
 
@@ -1177,7 +1177,7 @@ MidiRegionView::~MidiRegionView ()
        clear_events();
 
        delete _note_group;
-       delete _diff_command;
+       delete _note_diff_command;
         delete _step_edit_cursor;
        delete _temporary_note_group;
 }
@@ -1569,8 +1569,8 @@ MidiRegionView::step_add_note (uint8_t channel, uint8_t number, uint8_t velocity
         _marked_for_selection.clear ();
         clear_selection ();
 
-       start_diff_command (_("step add"));
-       diff_add_note (new_note, true, false);
+       start_note_diff_command (_("step add"));
+       note_diff_add_note (new_note, true, false);
        apply_diff();
 
         // last_step_edit_note = new_note;
@@ -1720,11 +1720,11 @@ MidiRegionView::delete_selection()
                return;
        }
 
-       start_diff_command (_("delete selection"));
+       start_note_diff_command (_("delete selection"));
 
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
                if ((*i)->selected()) {
-                       _diff_command->remove((*i)->note());
+                       _note_diff_command->remove((*i)->note());
                }
        }
 
@@ -1736,8 +1736,8 @@ MidiRegionView::delete_selection()
 void
 MidiRegionView::delete_note (boost::shared_ptr<NoteType> n)
 {
-       start_diff_command (_("delete note"));
-       _diff_command->remove (n);
+       start_note_diff_command (_("delete note"));
+       _note_diff_command->remove (n);
        apply_diff ();
 
        trackview.editor().hide_verbose_canvas_cursor ();
@@ -2096,7 +2096,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent *, frameoffset_t dt, int8_t dnote)
                highest_note_difference = highest_note_in_selection - 127;
        }
 
-       start_diff_command(_("move notes"));
+       start_note_diff_command (_("move notes"));
 
        for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) {
 
@@ -2106,7 +2106,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent *, frameoffset_t dt, int8_t dnote)
                        continue;
                }
 
-               diff_add_change (*i, MidiModel::DiffCommand::StartTime, new_time);
+               note_diff_add_change (*i, MidiModel::NoteDiffCommand::StartTime, new_time);
 
                uint8_t original_pitch = (*i)->note()->note();
                uint8_t new_pitch      = original_pitch + dnote - highest_note_difference;
@@ -2123,7 +2123,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent *, frameoffset_t dt, int8_t dnote)
                lowest_note_in_selection  = std::min(lowest_note_in_selection,  new_pitch);
                highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
 
-               diff_add_change (*i, MidiModel::DiffCommand::NoteNumber, new_pitch);
+               note_diff_add_change (*i, MidiModel::NoteDiffCommand::NoteNumber, new_pitch);
        }
 
        apply_diff();
@@ -2308,7 +2308,7 @@ MidiRegionView::update_resizing (ArdourCanvas::CanvasNote* primary, bool at_fron
 void
 MidiRegionView::commit_resizing (ArdourCanvas::CanvasNote* primary, bool at_front, double delta_x, bool relative)
 {
-       start_diff_command(_("resize notes"));
+       start_note_diff_command (_("resize notes"));
 
        for (std::vector<NoteResizeData *>::iterator i = _resize_data.begin(); i != _resize_data.end(); ++i) {
                CanvasNote*  canvas_note = (*i)->canvas_note;
@@ -2333,14 +2333,14 @@ MidiRegionView::commit_resizing (ArdourCanvas::CanvasNote* primary, bool at_fron
                current_x = frames_to_beats (current_x);
 
                if (at_front && current_x < canvas_note->note()->end_time()) {
-                       diff_add_change (canvas_note, MidiModel::DiffCommand::StartTime, current_x);
+                       note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::StartTime, current_x);
 
                        double len = canvas_note->note()->time() - current_x;
                        len += canvas_note->note()->length();
 
                        if (len > 0) {
                                /* XXX convert to beats */
-                               diff_add_change (canvas_note, MidiModel::DiffCommand::Length, len);
+                               note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::Length, len);
                        }
                }
 
@@ -2349,7 +2349,7 @@ MidiRegionView::commit_resizing (ArdourCanvas::CanvasNote* primary, bool at_fron
 
                        if (len > 0) {
                                /* XXX convert to beats */
-                               diff_add_change (canvas_note, MidiModel::DiffCommand::Length, len);
+                               note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::Length, len);
                        }
                }
 
@@ -2364,7 +2364,7 @@ MidiRegionView::commit_resizing (ArdourCanvas::CanvasNote* primary, bool at_fron
 void
 MidiRegionView::change_note_channel (CanvasNoteEvent* event, int8_t channel)
 {
-       diff_add_change (event, MidiModel::DiffCommand::Channel, (uint8_t) channel);
+       note_diff_add_change (event, MidiModel::NoteDiffCommand::Channel, (uint8_t) channel);
 }
 
 void
@@ -2381,7 +2381,7 @@ MidiRegionView::change_note_velocity(CanvasNoteEvent* event, int8_t velocity, bo
 
         event->set_selected (event->selected()); // change color 
         
-       diff_add_change (event, MidiModel::DiffCommand::Velocity, new_velocity);
+       note_diff_add_change (event, MidiModel::NoteDiffCommand::Velocity, new_velocity);
 }
 
 void
@@ -2396,7 +2396,7 @@ MidiRegionView::change_note_note (CanvasNoteEvent* event, int8_t note, bool rela
        }
 
        clamp_to_0_127 (new_note);
-       diff_add_change (event, MidiModel::DiffCommand::NoteNumber, new_note);
+       note_diff_add_change (event, MidiModel::NoteDiffCommand::NoteNumber, new_note);
 }
 
 void
@@ -2463,11 +2463,11 @@ MidiRegionView::trim_note (CanvasNoteEvent* event, Evoral::MusicalTime front_del
        }
 
        if (change_start) {
-               diff_add_change (event, MidiModel::DiffCommand::StartTime, new_start);
+               note_diff_add_change (event, MidiModel::NoteDiffCommand::StartTime, new_start);
        }
 
        if (change_length) {
-               diff_add_change (event, MidiModel::DiffCommand::Length, new_length);
+               note_diff_add_change (event, MidiModel::NoteDiffCommand::Length, new_length);
        }
 }
 
@@ -2490,13 +2490,13 @@ MidiRegionView::change_note_time (CanvasNoteEvent* event, Evoral::MusicalTime de
                new_time = delta;
        }
 
-       diff_add_change (event, MidiModel::DiffCommand::StartTime, new_time);
+       note_diff_add_change (event, MidiModel::NoteDiffCommand::StartTime, new_time);
 }
 
 void
 MidiRegionView::change_note_length (CanvasNoteEvent* event, Evoral::MusicalTime t)
 {
-       diff_add_change (event, MidiModel::DiffCommand::Length, t);
+       note_diff_add_change (event, MidiModel::NoteDiffCommand::Length, t);
 }
 
 void
@@ -2526,7 +2526,7 @@ MidiRegionView::change_velocities (bool up, bool fine, bool allow_smush)
                }
        }
 
-       start_diff_command(_("change velocities"));
+       start_note_diff_command (_("change velocities"));
 
        for (Selection::iterator i = _selection.begin(); i != _selection.end();) {
                Selection::iterator next = i;
@@ -2579,7 +2579,7 @@ MidiRegionView::transpose (bool up, bool fine, bool allow_smush)
                }
        }
 
-       start_diff_command (_("transpose"));
+       start_note_diff_command (_("transpose"));
 
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
                Selection::iterator next = i;
@@ -2613,7 +2613,7 @@ MidiRegionView::change_note_lengths (bool fine, bool shorter, Evoral::MusicalTim
                delta = -delta;
        }
 
-       start_diff_command (_("change note lengths"));
+       start_note_diff_command (_("change note lengths"));
 
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
                Selection::iterator next = i;
@@ -2682,7 +2682,7 @@ MidiRegionView::nudge_notes (bool forward)
                delta = -delta;
        }
 
-       start_diff_command (_("nudge"));
+       start_note_diff_command (_("nudge"));
 
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ) {
                Selection::iterator next = i;
@@ -2697,9 +2697,9 @@ MidiRegionView::nudge_notes (bool forward)
 void
 MidiRegionView::change_channel(uint8_t channel)
 {
-       start_diff_command(_("change channel"));
+       start_note_diff_command(_("change channel"));
        for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
-               diff_add_change (*i, MidiModel::DiffCommand::Channel, channel);
+               note_diff_add_change (*i, MidiModel::NoteDiffCommand::Channel, channel);
        }
 
        apply_diff();
@@ -2814,7 +2814,7 @@ MidiRegionView::cut_copy_clear (Editing::CutCopyOp op)
 
         if (op != Copy) {
 
-                start_diff_command();
+                start_note_diff_command();
                 
                 for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
                         switch (op) {
@@ -2822,7 +2822,7 @@ MidiRegionView::cut_copy_clear (Editing::CutCopyOp op)
                                 break;
                         case Cut:
                         case Clear:
-                                diff_remove_note (*i);
+                                note_diff_remove_note (*i);
                                 break;
                         }
                 }
@@ -2854,7 +2854,7 @@ MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb)
                return;
        }
 
-       start_diff_command (_("paste"));
+       start_note_diff_command (_("paste"));
 
        Evoral::MusicalTime beat_delta;
        Evoral::MusicalTime paste_pos_beats;
@@ -2877,7 +2877,7 @@ MidiRegionView::paste (framepos_t pos, float times, const MidiCutBuffer& mcb)
 
                        /* make all newly added notes selected */
 
-                       diff_add_note (copied_note, true);
+                       note_diff_add_note (copied_note, true);
                        end_point = copied_note->end_time();
                }
 
@@ -3246,4 +3246,9 @@ MidiRegionView::trim_front_ending ()
        _note_group->reparent (*group);
        delete _temporary_note_group;
        _temporary_note_group = 0;
+
+       if (_region->start() < 0) {
+               /* Trim drag made start time -ve; fix this */
+               midi_region()->fix_negative_start ();
+       }
 }
index 88fb43180595a9fd9b02e4c904c8518438ea5df5..4d1252fab47e828d9e98e5eac1fbeb680d5e6fb3 100644 (file)
@@ -180,11 +180,11 @@ class MidiRegionView : public RegionView
 
        void display_model(boost::shared_ptr<ARDOUR::MidiModel> model);
 
-       void start_diff_command(std::string name = "midi edit");
-       void diff_add_change(ArdourCanvas::CanvasNoteEvent* ev, ARDOUR::MidiModel::DiffCommand::Property, uint8_t val);
-       void diff_add_change(ArdourCanvas::CanvasNoteEvent* ev, ARDOUR::MidiModel::DiffCommand::Property, Evoral::MusicalTime val);
-       void diff_add_note(const boost::shared_ptr<NoteType> note, bool selected, bool show_velocity=false);
-       void diff_remove_note(ArdourCanvas::CanvasNoteEvent* ev);
+       void start_note_diff_command (std::string name = "midi edit");
+       void note_diff_add_change (ArdourCanvas::CanvasNoteEvent* ev, ARDOUR::MidiModel::NoteDiffCommand::Property, uint8_t val);
+       void note_diff_add_change (ArdourCanvas::CanvasNoteEvent* ev, ARDOUR::MidiModel::NoteDiffCommand::Property, Evoral::MusicalTime val);
+       void note_diff_add_note (const boost::shared_ptr<NoteType> note, bool selected, bool show_velocity = false);
+       void note_diff_remove_note (ArdourCanvas::CanvasNoteEvent* ev);
 
        void apply_diff();
        void apply_diff_as_subcommand();
@@ -363,7 +363,7 @@ class MidiRegionView : public RegionView
        SysExes                              _sys_exes;
        ArdourCanvas::CanvasNote**           _active_notes;
        ArdourCanvas::Group*                 _note_group;
-       ARDOUR::MidiModel::DiffCommand*      _diff_command;
+       ARDOUR::MidiModel::NoteDiffCommand*  _note_diff_command;
        ArdourCanvas::CanvasNote*            _ghost_note;
        double                               _last_ghost_x;
        double                               _last_ghost_y;
index 27ffa4d8a2ed31f6e17beaaa4bf652796aacbb48..69dc452b622cb71957716cce6844970acb5227dd 100644 (file)
@@ -58,6 +58,31 @@ public:
 
        class DiffCommand : public Command {
        public:
+               
+               DiffCommand (boost::shared_ptr<MidiModel> m, const std::string& name);
+
+               const std::string& name () const { return _name; }
+
+               virtual void operator() () = 0;
+               virtual void undo () = 0;
+
+               virtual int set_state (const XMLNode&, int version) = 0;
+               virtual XMLNode & get_state () = 0;
+
+                boost::shared_ptr<MidiModel> model() const { return _model; }
+
+       protected:
+               boost::shared_ptr<MidiModel> _model;
+               const std::string            _name;
+
+       };
+
+       class NoteDiffCommand : public DiffCommand {
+       public:
+
+               NoteDiffCommand (boost::shared_ptr<MidiModel> m, const std::string& name) : DiffCommand (m, name) {}
+               NoteDiffCommand (boost::shared_ptr<MidiModel> m, const XMLNode& node);
+               
                enum Property {
                        NoteNumber,
                        Velocity,
@@ -66,17 +91,12 @@ public:
                        Channel
                };
 
-               DiffCommand (boost::shared_ptr<MidiModel> m, const std::string& name);
-               DiffCommand (boost::shared_ptr<MidiModel> m, const XMLNode& node);
-
-               const std::string& name() const { return _name; }
-
-               void operator()();
-               void undo();
+               void operator() ();
+               void undo ();
 
                int set_state (const XMLNode&, int version);
-               XMLNode& get_state ();
-
+               XMLNode & get_state ();
+               
                void add (const NotePtr note);
                void remove (const NotePtr note);
                 void side_effect_remove (const NotePtr note);
@@ -88,15 +108,11 @@ public:
                         return !_added_notes.empty() || !_removed_notes.empty();
                 }
 
-                DiffCommand& operator+= (const DiffCommand& other);
-                boost::shared_ptr<MidiModel> model() const { return _model; }
-
+                NoteDiffCommand& operator+= (const NoteDiffCommand& other);
+               
           private:
-               boost::shared_ptr<MidiModel> _model;
-               const std::string            _name;
-
                struct NoteChange {
-                       DiffCommand::Property property;
+                       NoteDiffCommand::Property property;
                        NotePtr note;
                        union {
                                uint8_t  old_value;
@@ -124,9 +140,9 @@ public:
                NotePtr unmarshal_note(XMLNode *xml_note);
        };
 
-       MidiModel::DiffCommand*  new_diff_command(const std::string name="midi edit");
-       void                     apply_command(Session& session, Command* cmd);
-       void                     apply_command_as_subcommand(Session& session, Command* cmd);
+       MidiModel::NoteDiffCommand* new_note_diff_command (const std::string name="midi edit");
+       void apply_command (Session& session, Command* cmd);
+       void apply_command_as_subcommand (Session& session, Command* cmd);
 
        bool sync_to_source ();
        bool write_to(boost::shared_ptr<MidiSource> source);
@@ -151,6 +167,8 @@ public:
 
        boost::shared_ptr<Evoral::Control> control_factory(const Evoral::Parameter& id);
 
+       void insert_silence_at_start (TimeType);
+
 protected:
         int resolve_overlaps_unlocked (const NotePtr, void* arg = 0);
 
index 853272d3499c309aa0c31e855377ff1f44e18340..dae984c33106df27a1270a788b9ffca4430f6b43 100644 (file)
@@ -107,13 +107,20 @@ class MidiRegion : public Region
        boost::shared_ptr<MidiModel> model()             { return midi_source()->model(); }
        boost::shared_ptr<const MidiModel> model() const { return midi_source()->model(); }
 
+       void fix_negative_start ();
+
+  protected:
+       
+       virtual bool can_trim_start_before_source_start () const {
+               return true;
+       }
+
   private:
        friend class RegionFactory;
 
        MidiRegion (const SourceList&);
        MidiRegion (boost::shared_ptr<const MidiRegion>, frameoffset_t offset = 0, bool offset_relative = true);
 
-  private:
        framecnt_t _read_at (const SourceList&, Evoral::EventSink<framepos_t>& dst,
                             framepos_t position,
                             framecnt_t dur,
index 3ad61919b1ee3f46c9ae1f3b6b270d992da1f3ca..ed4923bc40d54af5b40ad4b36ec4bb945bbc5045 100644 (file)
@@ -315,6 +315,10 @@ class Region
        /** Constructor for derived types only */
        Region (Session& s, framepos_t start, framecnt_t length, const std::string& name, DataType);
 
+       virtual bool can_trim_start_before_source_start () const {
+               return false;
+       }
+
   protected:
        void send_change (const PBD::PropertyChange&);
         void mid_thaw (const PBD::PropertyChange&);
index bde6d7a7fe8b8d6c4908ae6a463fea17b7580051..6f3dff17a9d00648967b4ed859d191ea28c55995 100644 (file)
@@ -112,7 +112,7 @@ setup_enum_writer ()
        Delivery::Role _Delivery_Role;
        IO::Direction _IO_Direction;
        MuteMaster::MutePoint _MuteMaster_MutePoint;
-       MidiModel::DiffCommand::Property _MidiModel_DiffCommand_Property;
+       MidiModel::NoteDiffCommand::Property _MidiModel_NoteDiffCommand_Property;
        WaveformScale _WaveformScale;
        WaveformShape _WaveformShape;
        QuantizeType _QuantizeType;
@@ -525,12 +525,12 @@ setup_enum_writer ()
        REGISTER_CLASS_ENUM (IO, Output);
        REGISTER (_IO_Direction);
 
-       REGISTER_CLASS_ENUM (MidiModel::DiffCommand, NoteNumber);
-       REGISTER_CLASS_ENUM (MidiModel::DiffCommand, Channel);
-       REGISTER_CLASS_ENUM (MidiModel::DiffCommand, Velocity);
-       REGISTER_CLASS_ENUM (MidiModel::DiffCommand, StartTime);
-       REGISTER_CLASS_ENUM (MidiModel::DiffCommand, Length);
-       REGISTER (_MidiModel_DiffCommand_Property);
+       REGISTER_CLASS_ENUM (MidiModel::NoteDiffCommand, NoteNumber);
+       REGISTER_CLASS_ENUM (MidiModel::NoteDiffCommand, Channel);
+       REGISTER_CLASS_ENUM (MidiModel::NoteDiffCommand, Velocity);
+       REGISTER_CLASS_ENUM (MidiModel::NoteDiffCommand, StartTime);
+       REGISTER_CLASS_ENUM (MidiModel::NoteDiffCommand, Length);
+       REGISTER (_MidiModel_NoteDiffCommand_Property);
 
        REGISTER_ENUM(Linear);
        REGISTER_ENUM(Logarithmic);
index 8fbfde0ee7bdb9728ba3651d363aaccff35b1f04..e3d31df58d5f87ca69841e85d628d1539d99820c 100644 (file)
@@ -33,6 +33,7 @@
 #include "ardour/smf_source.h"
 #include "ardour/types.h"
 #include "ardour/session.h"
+#include "ardour/midi_automation_list_binder.h"
 
 using namespace std;
 using namespace ARDOUR;
@@ -44,20 +45,19 @@ MidiModel::MidiModel (boost::shared_ptr<MidiSource> s)
        set_midi_source (s);
 }
 
-/** Start a new Diff command.
+/** Start a new NoteDiff command.
  *
  * This has no side-effects on the model or Session, the returned command
  * can be held on to for as long as the caller wishes, or discarded without
  * formality, until apply_command is called and ownership is taken.
  */
-MidiModel::DiffCommand*
-MidiModel::new_diff_command(const string name)
+MidiModel::NoteDiffCommand*
+MidiModel::new_note_diff_command (const string name)
 {
        boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
        assert (ms);
        
-       DiffCommand* cmd = new DiffCommand (ms->model(), name);
-       return cmd;
+       return new NoteDiffCommand (ms->model(), name);
 }
 
 /** Apply a command.
@@ -89,50 +89,50 @@ MidiModel::apply_command_as_subcommand(Session& session, Command* cmd)
 
 /************** DIFF COMMAND ********************/
 
-#define DIFF_COMMAND_ELEMENT "DiffCommand"
+#define NOTE_DIFF_COMMAND_ELEMENT "NoteDiffCommand"
 #define DIFF_NOTES_ELEMENT "ChangedNotes"
 #define ADDED_NOTES_ELEMENT "AddedNotes"
 #define REMOVED_NOTES_ELEMENT "RemovedNotes"
 #define SIDE_EFFECT_REMOVALS_ELEMENT "SideEffectRemovals"
 
 MidiModel::DiffCommand::DiffCommand(boost::shared_ptr<MidiModel> m, const std::string& name)
-       : Command(name)
-       , _model(m)
-       , _name(name)
+       : Command (name)
+       , _model (m)
+       , _name (name)
 {
        assert(_model);
 }
 
-MidiModel::DiffCommand::DiffCommand(boost::shared_ptr<MidiModel> m, const XMLNode& node)
-       : _model(m)
+MidiModel::NoteDiffCommand::NoteDiffCommand (boost::shared_ptr<MidiModel> m, const XMLNode& node)
+       : DiffCommand (m, "")
 {
-       assert(_model);
-       set_state(node, Stateful::loading_state_version);
+       assert (_model);
+       set_state (node, Stateful::loading_state_version);
 }
 
 void
-MidiModel::DiffCommand::add(const NotePtr note)
+MidiModel::NoteDiffCommand::add (const NotePtr note)
 {
        _removed_notes.remove(note);
        _added_notes.push_back(note);
 }
 
 void
-MidiModel::DiffCommand::remove(const NotePtr note)
+MidiModel::NoteDiffCommand::remove (const NotePtr note)
 {
        _added_notes.remove(note);
        _removed_notes.push_back(note);
 }
 
 void
-MidiModel::DiffCommand::side_effect_remove(const NotePtr note)
+MidiModel::NoteDiffCommand::side_effect_remove (const NotePtr note)
 {
        side_effect_removals.insert (note);
 }
 
 void
-MidiModel::DiffCommand::change(const NotePtr note, Property prop,
-                               uint8_t new_value)
+MidiModel::NoteDiffCommand::change (const NotePtr note, Property prop,
+                                   uint8_t new_value)
 {
         NoteChange change;
         
@@ -175,8 +175,8 @@ MidiModel::DiffCommand::change(const NotePtr note, Property prop,
 }
 
 void
-MidiModel::DiffCommand::change(const NotePtr note, Property prop,
-                               TimeType new_time)
+MidiModel::NoteDiffCommand::change (const NotePtr note, Property prop,
+                                   TimeType new_time)
 {
         NoteChange change;
 
@@ -184,7 +184,7 @@ MidiModel::DiffCommand::change(const NotePtr note, Property prop,
         case NoteNumber:
         case Channel:
         case Velocity:
-                fatal << "MidiModel::DiffCommand::change() with time argument called for note, channel or velocity" << endmsg;
+                fatal << "MidiModel::NoteDiffCommand::change() with time argument called for note, channel or velocity" << endmsg;
                 break;
 
         case StartTime:
@@ -208,8 +208,8 @@ MidiModel::DiffCommand::change(const NotePtr note, Property prop,
         _changes.push_back (change);
 }
 
-MidiModel::DiffCommand&
-MidiModel::DiffCommand::operator+= (const DiffCommand& other)
+MidiModel::NoteDiffCommand &
+MidiModel::NoteDiffCommand::operator+= (const NoteDiffCommand& other)
 {
         if (this == &other) {
                 return *this;
@@ -228,7 +228,7 @@ MidiModel::DiffCommand::operator+= (const DiffCommand& other)
 }
 
 void
-MidiModel::DiffCommand::operator()()
+MidiModel::NoteDiffCommand::operator() ()
 {
         {
                 MidiModel::WriteLock lock(_model->edit_lock());
@@ -293,7 +293,7 @@ MidiModel::DiffCommand::operator()()
 
 
                 for (set<NotePtr>::iterator i = temporary_removals.begin(); i != temporary_removals.end(); ++i) {
-                        DiffCommand side_effects (model(), "side effects");
+                        NoteDiffCommand side_effects (model(), "side effects");
                         _model->add_note_unlocked (*i, &side_effects);
                         *this += side_effects;
                 }
@@ -310,7 +310,7 @@ MidiModel::DiffCommand::operator()()
 }
 
 void
-MidiModel::DiffCommand::undo()
+MidiModel::NoteDiffCommand::undo ()
 {
         {
                 MidiModel::WriteLock lock(_model->edit_lock());
@@ -377,7 +377,7 @@ MidiModel::DiffCommand::undo()
 }
 
 XMLNode&
-MidiModel::DiffCommand::marshal_note(const NotePtr note)
+MidiModel::NoteDiffCommand::marshal_note(const NotePtr note)
 {
         XMLNode* xml_note = new XMLNode("note");
 
@@ -421,7 +421,7 @@ MidiModel::DiffCommand::marshal_note(const NotePtr note)
 }
 
 Evoral::Sequence<MidiModel::TimeType>::NotePtr
-MidiModel::DiffCommand::unmarshal_note(XMLNode *xml_note)
+MidiModel::NoteDiffCommand::unmarshal_note (XMLNode *xml_note)
 {
         unsigned int note;
         XMLProperty* prop;
@@ -486,7 +486,7 @@ MidiModel::DiffCommand::unmarshal_note(XMLNode *xml_note)
 }
 
 XMLNode&
-MidiModel::DiffCommand::marshal_change(const NoteChange& change)
+MidiModel::NoteDiffCommand::marshal_change (const NoteChange& change)
 {
         XMLNode* xml_change = new XMLNode("Change");
 
@@ -521,8 +521,8 @@ MidiModel::DiffCommand::marshal_change(const NoteChange& change)
         return *xml_change;
 }
 
-MidiModel::DiffCommand::NoteChange
-MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
+MidiModel::NoteDiffCommand::NoteChange
+MidiModel::NoteDiffCommand::unmarshal_change (XMLNode *xml_change)
 {
         XMLProperty* prop;
         NoteChange change;
@@ -584,9 +584,9 @@ MidiModel::DiffCommand::unmarshal_change(XMLNode *xml_change)
 }
 
 int
-MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int /*version*/)
+MidiModel::NoteDiffCommand::set_state (const XMLNode& diff_command, int /*version*/)
 {
-        if (diff_command.name() != string(DIFF_COMMAND_ELEMENT)) {
+        if (diff_command.name() != string (NOTE_DIFF_COMMAND_ELEMENT)) {
                 return 1;
         }
 
@@ -597,7 +597,7 @@ MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int /*version*/)
         if (added_notes) {
                 XMLNodeList notes = added_notes->children();
                 transform(notes.begin(), notes.end(), back_inserter(_added_notes),
-                          boost::bind (&DiffCommand::unmarshal_note, this, _1));
+                          boost::bind (&NoteDiffCommand::unmarshal_note, this, _1));
         }
 
 
@@ -608,7 +608,7 @@ MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int /*version*/)
         if (removed_notes) {
                 XMLNodeList notes = removed_notes->children();
                 transform(notes.begin(), notes.end(), back_inserter(_removed_notes),
-                          boost::bind (&DiffCommand::unmarshal_note, this, _1));
+                          boost::bind (&NoteDiffCommand::unmarshal_note, this, _1));
         }
 
 
@@ -621,7 +621,7 @@ MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int /*version*/)
         if (changed_notes) {
                 XMLNodeList notes = changed_notes->children();
                 transform (notes.begin(), notes.end(), back_inserter(_changes),
-                           boost::bind (&DiffCommand::unmarshal_change, this, _1));
+                           boost::bind (&NoteDiffCommand::unmarshal_change, this, _1));
 
         }
 
@@ -642,28 +642,28 @@ MidiModel::DiffCommand::set_state(const XMLNode& diff_command, int /*version*/)
 }
 
 XMLNode&
-MidiModel::DiffCommand::get_state ()
+MidiModel::NoteDiffCommand::get_state ()
 {
-        XMLNode* diff_command = new XMLNode(DIFF_COMMAND_ELEMENT);
+        XMLNode* diff_command = new XMLNode (NOTE_DIFF_COMMAND_ELEMENT);
         diff_command->add_property("midi-source", _model->midi_source()->id().to_s());
 
         XMLNode* changes = diff_command->add_child(DIFF_NOTES_ELEMENT);
         for_each(_changes.begin(), _changes.end(), 
                  boost::bind (
                          boost::bind (&XMLNode::add_child_nocopy, changes, _1),
-                         boost::bind (&DiffCommand::marshal_change, this, _1)));
+                         boost::bind (&NoteDiffCommand::marshal_change, this, _1)));
 
         XMLNode* added_notes = diff_command->add_child(ADDED_NOTES_ELEMENT);
         for_each(_added_notes.begin(), _added_notes.end(), 
                  boost::bind(
                          boost::bind (&XMLNode::add_child_nocopy, added_notes, _1),
-                         boost::bind (&DiffCommand::marshal_note, this, _1)));
+                         boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
 
         XMLNode* removed_notes = diff_command->add_child(REMOVED_NOTES_ELEMENT);
         for_each(_removed_notes.begin(), _removed_notes.end(), 
                  boost::bind (
                          boost::bind (&XMLNode::add_child_nocopy, removed_notes, _1),
-                         boost::bind (&DiffCommand::marshal_note, this, _1)));
+                         boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
 
         /* if this command had side-effects, store that state too 
          */
@@ -673,7 +673,7 @@ MidiModel::DiffCommand::get_state ()
                 for_each(side_effect_removals.begin(), side_effect_removals.end(), 
                          boost::bind (
                                  boost::bind (&XMLNode::add_child_nocopy, side_effect_notes, _1),
-                                 boost::bind (&DiffCommand::marshal_note, this, _1)));
+                                 boost::bind (&NoteDiffCommand::marshal_note, this, _1)));
         }
 
         return *diff_command;
@@ -910,7 +910,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
                 return 0;
         }
 
-        DiffCommand* cmd = static_cast<DiffCommand*>(arg);
+        NoteDiffCommand* cmd = static_cast<NoteDiffCommand*>(arg);
 
         TimeType sa = note->time();
         TimeType ea  = note->end_time();
@@ -964,7 +964,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
                                 break;
                         case InsertMergeTruncateExisting:
                                 if (cmd) {
-                                        cmd->change (*i, DiffCommand::Length, (note->time() - (*i)->time()));
+                                        cmd->change (*i, NoteDiffCommand::Length, (note->time() - (*i)->time()));
                                 }
                                 (*i)->set_length (note->time() - (*i)->time());
                                 break;
@@ -976,7 +976,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
                                 break;
                         case InsertMergeExtend:
                                 if (cmd) {
-                                        cmd->change ((*i), DiffCommand::Length, note->end_time() - (*i)->time());
+                                        cmd->change ((*i), NoteDiffCommand::Length, note->end_time() - (*i)->time());
                                 } 
                                 (*i)->set_length (note->end_time() - (*i)->time());
                                 return -1; /* do not add the new note */
@@ -1078,14 +1078,14 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
 
         if (set_note_time) {
                 if (cmd) {
-                        cmd->change (note, DiffCommand::StartTime, note_time);
+                        cmd->change (note, NoteDiffCommand::StartTime, note_time);
                 } 
                 note->set_time (note_time);
         }
 
         if (set_note_length) {
                 if (cmd) {
-                        cmd->change (note, DiffCommand::Length, note_length);
+                        cmd->change (note, NoteDiffCommand::Length, note_length);
                 } 
                 note->set_length (note_length);
         }
@@ -1097,7 +1097,6 @@ InsertMergePolicy
 MidiModel::insert_merge_policy () const 
 {
         /* XXX ultimately this should be a per-track or even per-model policy */
-
        boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
        assert (ms);
 
@@ -1165,7 +1164,6 @@ MidiModel::automation_list_automation_state_changed (Evoral::Parameter p, AutoSt
 {
        boost::shared_ptr<MidiSource> ms = _midi_source.lock ();
        assert (ms);
-
        ms->set_automation_state_of (p, s);
 }
 
@@ -1196,3 +1194,37 @@ MidiModel::midi_source ()
 {
        return _midi_source.lock ();
 }
+
+/** Moves notes, controllers and sys-ex to insert silence at the start of the model.
+ *  Adds commands to the session's current undo stack to reflect the movements.
+ */
+void
+MidiModel::insert_silence_at_start (TimeType t)
+{
+       /* Notes */
+       
+       NoteDiffCommand* c = new_note_diff_command ("insert silence");
+
+       for (Notes::const_iterator i = notes().begin(); i != notes().end(); ++i) {
+               c->change (*i, NoteDiffCommand::StartTime, (*i)->time() + t);
+       }
+
+       boost::shared_ptr<MidiSource> s = _midi_source.lock ();
+       assert (s);
+       
+       apply_command_as_subcommand (s->session(), c);
+
+       /* Controllers */
+
+       for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) {
+               boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second);
+               XMLNode& before = ac->alist()->get_state ();
+               i->second->list()->shift (0, t);
+               XMLNode& after = ac->alist()->get_state ();
+               s->session().add_command (new MementoCommand<AutomationList> (new MidiAutomationListBinder (s, i->first), &before, &after));
+       }
+
+       /* Sys-ex */
+
+       /* XXX */
+}
index f9fb791bad28717857cbd65b8aea578f6ae2eb64..26d43ba2a95519e7caeafc5acc10e25d32d9b23f 100644 (file)
@@ -121,7 +121,7 @@ MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
        BeatsFramesConverter old_converter(_session.tempo_map(), _position - _start);
        double length_beats = old_converter.from(_length);
 
-       Region::set_position_internal(pos, allow_bbt_recompute);
+       Region::set_position_internal (pos, allow_bbt_recompute);
 
        BeatsFramesConverter new_converter(_session.tempo_map(), pos - _start);
 
@@ -306,9 +306,21 @@ MidiRegion::model_automation_state_changed (Evoral::Parameter const & p)
        }
 
        /* the source will have an iterator into the model, and that iterator will have been set up
-          for a given set of filtered_paramters, so now that we've changed that list we must invalidate
+          for a given set of filtered_parameters, so now that we've changed that list we must invalidate
           the iterator.
        */
        Glib::Mutex::Lock lm (midi_source(0)->mutex());
        midi_source(0)->invalidate ();
 }
+
+/** This is called when a trim drag has resulted in a -ve _start time for this region.
+ *  Fix it up by adding some empty space to the source.
+ */
+void
+MidiRegion::fix_negative_start ()
+{
+        BeatsFramesConverter c (_session.tempo_map(), _position);
+
+       model()->insert_silence_at_start (c.from (-_start));
+       _start = 0;
+}
index 97be158badd853bdc5dfde5d07952b025988897a..db2cbb1d21f722ab0c50e6b61791c0fb5f239ef9 100644 (file)
@@ -63,7 +63,7 @@ Command*
 Quantize::operator () (boost::shared_ptr<MidiModel> model, std::vector<Evoral::Sequence<Evoral::MusicalTime>::Notes>& seqs)
 {
        bool even;
-       MidiModel::DiffCommand* cmd = new MidiModel::DiffCommand (model, "quantize");
+       MidiModel::NoteDiffCommand* cmd = new MidiModel::NoteDiffCommand (model, "quantize");
 
        for (std::vector<Evoral::Sequence<Evoral::MusicalTime>::Notes>::iterator s = seqs.begin(); s != seqs.end(); ++s) {
 
@@ -102,7 +102,7 @@ Quantize::operator () (boost::shared_ptr<MidiModel> model, std::vector<Evoral::S
                        if (fabs (delta) >= _threshold) {
                                if (_snap_start) {
                                        delta *= _strength;
-                                       cmd->change ((*i), MidiModel::DiffCommand::StartTime,
+                                       cmd->change ((*i), MidiModel::NoteDiffCommand::StartTime,
                                                     (*i)->time() + delta);
                                }
                        }
@@ -117,7 +117,7 @@ Quantize::operator () (boost::shared_ptr<MidiModel> model, std::vector<Evoral::S
                                                new_dur = _end_grid;
                                        }
 
-                                       cmd->change ((*i), MidiModel::DiffCommand::Length, new_dur);
+                                       cmd->change ((*i), MidiModel::NoteDiffCommand::Length, new_dur);
                                }
                        }
 
index 5c25d34c60cd866c9c46c6254b84b861ba598ddf..585689a656023386c379aea79b941000e00a4e33 100644 (file)
@@ -732,13 +732,7 @@ Region::trim_start (framepos_t new_position, void */*src*/)
                return;
        }
        framepos_t new_start;
-       frameoffset_t start_shift;
-
-       if (new_position > _position) {
-               start_shift = new_position - _position;
-       } else {
-               start_shift = -(_position - new_position);
-       }
+       frameoffset_t const start_shift = new_position - _position;
 
        if (start_shift > 0) {
 
@@ -759,6 +753,7 @@ Region::trim_start (framepos_t new_position, void */*src*/)
                } else {
                        new_start = _start + start_shift;
                }
+               
        } else {
                return;
        }
@@ -813,9 +808,10 @@ Region::modify_front (framepos_t new_position, bool reset_fade, void *src)
                framecnt_t newlen = 0;
                framepos_t delta = 0;
 
-               /* can't trim it back passed where source position zero is located */
-               
-               new_position = max (new_position, source_zero);
+               if (!can_trim_start_before_source_start ()) {
+                       /* can't trim it back past where source position zero is located */
+                       new_position = max (new_position, source_zero);
+               }
                
                if (new_position > _position) {
                        newlen = _length - (new_position - _position);
@@ -887,18 +883,13 @@ Region::trim_to (framepos_t position, framecnt_t length, void *src)
 void
 Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/)
 {
-       frameoffset_t start_shift;
        framepos_t new_start;
 
        if (locked()) {
                return;
        }
 
-       if (position > _position) {
-               start_shift = position - _position;
-       } else {
-               start_shift = -(_position - position);
-       }
+       frameoffset_t const start_shift = position - _position;
 
        if (start_shift > 0) {
 
@@ -910,7 +901,7 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, void */*src*/)
 
        } else if (start_shift < 0) {
 
-               if (_start < -start_shift) {
+               if (_start < -start_shift && !can_trim_start_before_source_start ()) {
                        new_start = 0;
                } else {
                        new_start = _start + start_shift;
@@ -1609,7 +1600,7 @@ Region::can_trim () const
 
         ct = CanTrim (ct | FrontTrimLater | EndTrimEarlier);
 
-        if (start() != 0) {
+        if (start() != 0 || can_trim_start_before_source_start ()) {
                 ct = CanTrim (ct | FrontTrimEarlier);
         }
 
index b67de14d07f629426468f357d3cfa6c1b7e2c700..93245d6d01737b95df1747478ede9405d64426dd 100644 (file)
@@ -3186,14 +3186,14 @@ Session::restore_history (string snapshot_name)
                                        ut->add_command(c);
                                }
 
-                       } else if (n->name() == "DiffCommand") {
-                               PBD::ID  id(n->property("midi-source")->value());
+                       } else if (n->name() == "NoteDiffCommand") {
+                               PBD::ID id (n->property("midi-source")->value());
                                boost::shared_ptr<MidiSource> midi_source =
                                        boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
                                if (midi_source) {
-                                       ut->add_command(new MidiModel::DiffCommand(midi_source->model(), *n));
+                                       ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
                                } else {
-                                       error << _("Failed to downcast MidiSource for DiffCommand") << endmsg;
+                                       error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
                                }
 
                        } else if (n->name() == "StatefulDiffCommand") {
index 2410b3684aa216517a044ba41c55ba62e9da7db2..873572e77c9918109774cc33f9341bcd35fffb06 100644 (file)
@@ -170,6 +170,9 @@ struct Event {
        inline const uint8_t* buffer()             const { return _buf; }
        inline uint8_t*&      buffer()                   { return _buf; }
 
+       void set_time (Time);
+       void set_original_time (Time);
+
         inline event_id_t id() const { return _id; }
         inline void set_id (event_id_t n) { _id = n; }
 
index 930a18e77b045e11fbdabb6bf4dae9b1421557ea..783634ff24e23f872a7b079cd8315c22946f2c5b 100644 (file)
@@ -90,6 +90,20 @@ Event<Timestamp>::~Event() {
        }
 }
 
+template<typename Timestamp>
+void
+Event<Timestamp>::set_time (Timestamp t)
+{
+       _nominal_time = t;
+}
+
+template<typename Timestamp>
+void
+Event<Timestamp>::set_original_time (Timestamp t)
+{
+       _original_time = t;
+}
+       
 #endif // EVORAL_EVENT_ALLOC
 
 template class Event<Evoral::MusicalTime>;