From f3fc6195bc6136a31b08ffe8c260a64efe77f9dc Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 7 Dec 2010 19:16:23 +0000 Subject: [PATCH] Allow trim of midi regions to before the start of the source. Fixes #3156. git-svn-id: svn://localhost/ardour2/branches/3.0@8212 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/editor_drag.cc | 2 ++ gtk2_ardour/midi_region_view.cc | 5 +++++ libs/ardour/ardour/midi_region.h | 9 ++++++++- libs/ardour/ardour/region.h | 4 ++++ libs/ardour/midi_region.cc | 17 +++++++++++++++-- libs/ardour/region.cc | 27 +++++++++------------------ libs/evoral/evoral/Event.hpp | 3 +++ libs/evoral/evoral/Sequence.hpp | 2 ++ libs/evoral/src/Event.cpp | 14 ++++++++++++++ libs/evoral/src/Sequence.cpp | 20 ++++++++++++++++++++ 10 files changed, 82 insertions(+), 21 deletions(-) diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index fb3ef58802..daebea1cfe 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -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 { @@ -1723,6 +1724,7 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) if (_operation == StartTrim) { i->view->trim_front_ending (); } + i->view->region()->resume_property_changes (); } } diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index cdfc1cbc3a..40dbd15037 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -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 (); + } } diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index 853272d349..dae984c331 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -107,13 +107,20 @@ class MidiRegion : public Region boost::shared_ptr model() { return midi_source()->model(); } boost::shared_ptr 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, frameoffset_t offset = 0, bool offset_relative = true); - private: framecnt_t _read_at (const SourceList&, Evoral::EventSink& dst, framepos_t position, framecnt_t dur, diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h index 3ad61919b1..ed4923bc40 100644 --- a/libs/ardour/ardour/region.h +++ b/libs/ardour/ardour/region.h @@ -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&); diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index f9fb791bad..74276ff5b6 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -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,22 @@ 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); + + MidiModel::WriteLock lock (model()->edit_lock ()); + model()->insert_silence_at_start (c.from (-_start)); + _start = 0; +} diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index 5c25d34c60..585689a656 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -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); } diff --git a/libs/evoral/evoral/Event.hpp b/libs/evoral/evoral/Event.hpp index 2410b3684a..873572e77c 100644 --- a/libs/evoral/evoral/Event.hpp +++ b/libs/evoral/evoral/Event.hpp @@ -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; } diff --git a/libs/evoral/evoral/Sequence.hpp b/libs/evoral/evoral/Sequence.hpp index 7675aeeb4e..56903f582b 100644 --- a/libs/evoral/evoral/Sequence.hpp +++ b/libs/evoral/evoral/Sequence.hpp @@ -173,6 +173,8 @@ public: void set_notes (const Sequence