Exact beat - provide audio->music mapping for region split.
authornick_m <mainsbridge@gmail.com>
Wed, 15 Jun 2016 14:18:27 +0000 (00:18 +1000)
committernick_m <mainsbridge@gmail.com>
Sat, 9 Jul 2016 16:18:36 +0000 (02:18 +1000)
- for those not in the know, this series provides a way to
  remove the temporal distortion introduced when using an
  audio frame-based gui for music-locked objects.

  In short, the gui uses an audio frame representation to move
  objects. It displays the object using frame_at_beat(), quantizing
  the time value to audio frames. This is fine until the user selects
  that frame but expects it to be interpreted as a beat.
  Thus beat_at_frame() would not produce the user-expected beat
  (temporal quantization error of up to 0.5 audio samples).
  This is one method of mapping audio time to music time accurately.

25 files changed:
gtk2_ardour/audio_streamview.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_mouse.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_streamview.cc
gtk2_ardour/midi_time_axis.cc
gtk2_ardour/public_editor.h
gtk2_ardour/region_view.cc
gtk2_ardour/region_view.h
libs/ardour/ardour/audioregion.h
libs/ardour/ardour/midi_region.h
libs/ardour/ardour/playlist.h
libs/ardour/ardour/region.h
libs/ardour/ardour/region_factory.h
libs/ardour/audio_diskstream.cc
libs/ardour/audioregion.cc
libs/ardour/midi_region.cc
libs/ardour/midi_state_tracker.cc
libs/ardour/midi_stretch.cc
libs/ardour/playlist.cc
libs/ardour/rb_effect.cc
libs/ardour/region.cc
libs/ardour/region_factory.cc

index ed9ec23b028d5d30fa88b15f6812678168e8c6c8..511b4296ebcaa24ffbed7d33d47c74fd56784e12 100644 (file)
@@ -353,8 +353,9 @@ AudioStreamView::update_rec_regions (framepos_t start, framecnt_t cnt)
                                if (nlen != region->length()) {
 
                                        region->suspend_property_changes ();
+                                       /* set non-musical position / length */
                                        region->set_position (_trackview.track()->get_capture_start_frame(n));
-                                       region->set_length (nlen);
+                                       region->set_length (nlen, 0);
                                        region->resume_property_changes ();
 
                                        if (origlen == 1) {
@@ -381,7 +382,7 @@ AudioStreamView::update_rec_regions (framepos_t start, framecnt_t cnt)
 
                                                region->suspend_property_changes ();
                                                region->set_position (_trackview.track()->get_capture_start_frame(n));
-                                               region->set_length (nlen);
+                                               region->set_length (nlen, 0);
                                                region->resume_property_changes ();
 
                                                if (origlen == 1) {
index 8bbc7fee2b263b374dfdf9d233a5e099d15dd384..af781f019c7d1ff94f81cda3c3ae21dfe5cac9cf 100644 (file)
@@ -534,7 +534,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
 
        /* editing operations that need to be public */
        void mouse_add_new_marker (framepos_t where, bool is_cd=false);
-       void split_regions_at (framepos_t, RegionSelection&);
+       void split_regions_at (framepos_t, RegionSelection&, const int32_t& sub_num);
        void split_region_at_points (boost::shared_ptr<ARDOUR::Region>, ARDOUR::AnalysisFeatureList&, bool can_ferret, bool select_new = false);
        RegionSelection get_regions_from_selection_and_mouse (framepos_t);
 
index d87388e888a96cabeff3dd86f010399578b21999..11809af788730dc9141b7abb471aa7b6dc648e65 100644 (file)
@@ -2323,7 +2323,7 @@ RegionCreateDrag::motion (GdkEvent* event, bool first_move)
                        */
 
                        framecnt_t const len = (framecnt_t) fabs ((double)(f - grab_frame () - 1));
-                       _region->set_length (len < 1 ? 1 : len);
+                       _region->set_length (len < 1 ? 1 : len, _editor->get_grid_music_divisions (event->button.state));
                }
        }
 }
@@ -2934,7 +2934,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
 
        case EndTrim:
                for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
-                       bool changed = i->view->trim_end (i->initial_end + dt, non_overlap_trim);
+                       bool changed = i->view->trim_end (i->initial_end + dt, non_overlap_trim, _editor->get_grid_music_divisions (event->button.state));
                        if (changed && _preserve_fade_anchor) {
                                AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
                                if (arv) {
@@ -6333,7 +6333,7 @@ RegionCutDrag::motion (GdkEvent*, bool)
 }
 
 void
-RegionCutDrag::finished (GdkEvent*, bool)
+RegionCutDrag::finished (GdkEvent* event, bool)
 {
        _editor->get_track_canvas()->canvas()->re_enter();
 
@@ -6347,7 +6347,7 @@ RegionCutDrag::finished (GdkEvent*, bool)
                return;
        }
 
-       _editor->split_regions_at (pos, rs);
+       _editor->split_regions_at (pos, rs, _editor->get_grid_music_divisions (event->button.state));
 }
 
 void
index dfdd7d995f87875d8bb10ab4f8cff5ddb8a91189..86386c21fb9175d03185b7fbdbc3a407dac0ebcb 100644 (file)
@@ -1037,7 +1037,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                                if (!prev) {
                                                        _drags->set (new RegionCreateDrag (this, item, parent), event);
                                                } else {
-                                                       prev->set_length (t - prev->position ());
+                                                       prev->set_length (t - prev->position (), get_grid_music_divisions (event->button.state));
                                                }
                                        }
                                } else {
index d22df0a0bf3928ff01c9729fac31d5d8daaa37b2..80a5ee399ea9bba7981303ed1b84284193376759 100644 (file)
@@ -151,7 +151,7 @@ Editor::redo (uint32_t n)
 }
 
 void
-Editor::split_regions_at (framepos_t where, RegionSelection& regions)
+Editor::split_regions_at (framepos_t where, RegionSelection& regions, const int32_t& sub_num)
 {
        bool frozen = false;
 
@@ -226,7 +226,7 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions)
 
                if (pl) {
                        pl->clear_changes ();
-                       pl->split_region ((*a)->region(), where);
+                       pl->split_region ((*a)->region(), where, sub_num);
                        _session->add_command (new StatefulDiffCommand (pl));
                }
 
@@ -6151,7 +6151,11 @@ Editor::split_region ()
                        return;
                }
 
-               split_regions_at (where, rs);
+               if (snap_musical()) {
+                       split_regions_at (where, rs, get_grid_music_divisions (0));
+               } else {
+                       split_regions_at (where, rs, 0);
+               }
        }
 }
 
@@ -7294,7 +7298,8 @@ Editor::insert_time (
                        (*i)->clear_owned_changes ();
 
                        if (opt == SplitIntersected) {
-                               (*i)->split (pos);
+                               /* non musical split */
+                               (*i)->split (pos, 0);
                        }
 
                        (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
index 9e271cc3987af4b2925263ceeb903473ce19f45c..6ffba154f4c8fe9e0e7f2adb48572273afd25220 100644 (file)
@@ -1872,7 +1872,8 @@ MidiRegionView::step_add_note (uint8_t channel, uint8_t number, uint8_t velocity
        framepos_t region_end = _region->last_frame();
 
        if (end_frame > region_end) {
-               _region->set_length (end_frame - _region->position());
+               /* XX sets length in beats from audio space. make musical */
+               _region->set_length (end_frame - _region->position(), 0);
        }
 
        MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
@@ -2877,13 +2878,13 @@ MidiRegionView::commit_resizing (NoteBase* primary, bool at_front, double delta_
                /* Convert the new x position to a frame within the source */
                framepos_t current_fr;
                if (with_snap) {
-                       current_fr = snap_pixel_to_sample (current_x, ensure_snap) + _region->start ();
+                       current_fr = snap_pixel_to_sample (current_x, ensure_snap);
                } else {
-                       current_fr = trackview.editor().pixel_to_sample (current_x) + _region->start ();
+                       current_fr = trackview.editor().pixel_to_sample (current_x);
                }
 
                /* and then to beats */
-               const Evoral::Beats x_beats = region_frames_to_region_beats (current_fr);
+               const Evoral::Beats x_beats = region_frames_to_region_beats (current_fr + _region->start());
 
                if (at_front && x_beats < canvas_note->note()->end_time()) {
                        note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::StartTime, x_beats - (sign * snap_delta_beats));
@@ -3568,7 +3569,8 @@ MidiRegionView::paste_internal (framepos_t pos, unsigned paste_count, float time
                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("Paste extended region from %1 to %2\n", region_end, end_frame));
 
                _region->clear_changes ();
-               _region->set_length (end_frame - _region->position());
+               /* we probably need to get the snap modifier somehow to make this correct for non-musical use */
+               _region->set_length (end_frame - _region->position(), trackview.editor().get_grid_music_divisions (0));
                trackview.session()->add_command (new StatefulDiffCommand (_region));
        }
 
index e369c5842dfadd46cc68ae7f8be11143ea2ca5ce..88947e7e3d56b215b1a6477c502fc9132c10169b 100644 (file)
@@ -610,7 +610,7 @@ MidiStreamView::update_rec_box ()
 
        /* Update the region being recorded to reflect where we currently are */
        boost::shared_ptr<ARDOUR::Region> region = rec_regions.back().first;
-       region->set_length (_trackview.track()->current_capture_end () - _trackview.track()->current_capture_start());
+       region->set_length (_trackview.track()->current_capture_end () - _trackview.track()->current_capture_start(), 0);
 
        MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rec_regions.back().second);
        mrv->extend_active_notes ();
index 074f2a115b4248eee99d8375343c7c4bb81084c2..4b709c4e5ca57b74c9cc0eed3c28de94e81aa4ad 100644 (file)
@@ -1526,6 +1526,7 @@ MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit, co
        plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
 
        boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
+       /* sets beat position */
        region->set_position (pos, sub_num);
        playlist()->add_region (region, pos);
        _session->add_command (new StatefulDiffCommand (playlist()));
index e562e1cb37454abe5191794092ac72bc453919a9..a86169b4dbac61c57a1170c5b4d189cac61c6649 100644 (file)
@@ -289,7 +289,7 @@ class PublicEditor : public Gtkmm2ext::Tabbable {
        virtual void restore_editing_space () = 0;
        virtual framepos_t get_preferred_edit_position (Editing::EditIgnoreOption = Editing::EDIT_IGNORE_NONE, bool from_context_menu = false, bool from_outside_canvas = false) = 0;
        virtual void toggle_meter_updating() = 0;
-       virtual void split_regions_at (framepos_t, RegionSelection&) = 0;
+       virtual void split_regions_at (framepos_t, RegionSelection&, const int32_t& sub_num) = 0;
        virtual void split_region_at_points (boost::shared_ptr<ARDOUR::Region>, ARDOUR::AnalysisFeatureList&, bool can_ferret, bool select_new = false) = 0;
        virtual void mouse_add_new_marker (framepos_t where, bool is_cd=false) = 0;
        virtual void foreach_time_axis_view (sigc::slot<void,TimeAxisView&>) = 0;
index b9648bbbc3868751d0cd6275395c881d78ee882b..4f904d9f2b3b62b6f96b94c27ff42054b5aa09db 100644 (file)
@@ -861,7 +861,7 @@ RegionView::trim_front (framepos_t new_bound, bool no_overlap, const int32_t& su
 }
 
 bool
-RegionView::trim_end (framepos_t new_bound, bool no_overlap)
+RegionView::trim_end (framepos_t new_bound, bool no_overlap, const int32_t& sub_num)
 {
        if (_region->locked()) {
                return false;
@@ -872,7 +872,7 @@ RegionView::trim_end (framepos_t new_bound, bool no_overlap)
 
        framepos_t const pre_trim_last_frame = _region->last_frame();
 
-       _region->trim_end ((framepos_t) (new_bound * speed));
+       _region->trim_end ((framepos_t) (new_bound * speed), sub_num);
 
        if (no_overlap) {
                // Get the next region on the right of this region and shrink/expand it.
@@ -887,7 +887,7 @@ RegionView::trim_end (framepos_t new_bound, bool no_overlap)
 
                // Only trim region on the right if the last frame has gone beyond the right region's first frame.
                if (region_right != 0 && (region_right->first_frame() < _region->last_frame() || regions_touching)) {
-                       region_right->trim_front (_region->last_frame() + 1);
+                       region_right->trim_front (_region->last_frame() + 1, sub_num);
                }
 
                region_changed (ARDOUR::bounds_change);
index 43608c31d14c4ae25b7447b534727055809b7df5..40485f93cfebc77b44d80a6cbb46715551f9919f 100644 (file)
@@ -107,7 +107,7 @@ class RegionView : public TimeAxisViewItem
        /** Called when a start trim has finished */
        virtual void trim_front_ending () {}
 
-       bool trim_end (framepos_t, bool);
+       bool trim_end (framepos_t, bool, const int32_t& sub_num);
         void move_contents (ARDOUR::frameoffset_t);
        virtual void thaw_after_trim ();
 
index 2d74d91482a14a3a499b5c111ab1cecae260fcb0..bed64615b5d3b0cd2a3f3e644f9a6f129015dea2 100644 (file)
@@ -180,7 +180,7 @@ class LIBARDOUR_API AudioRegion : public Region
        AudioRegion (boost::shared_ptr<AudioSource>);
        AudioRegion (const SourceList &);
        AudioRegion (boost::shared_ptr<const AudioRegion>);
-       AudioRegion (boost::shared_ptr<const AudioRegion>, frameoffset_t offset);
+       AudioRegion (boost::shared_ptr<const AudioRegion>, frameoffset_t offset, const int32_t& sub_num);
        AudioRegion (boost::shared_ptr<const AudioRegion>, const SourceList&);
        AudioRegion (SourceList &);
 
index 3a097c907e37cfa6ed70e70e2e51f16e6f0b7d25..9de79a9513e3b40c11a38dccb684295f5ac7fc21 100644 (file)
@@ -115,7 +115,7 @@ class LIBARDOUR_API MidiRegion : public Region
 
        MidiRegion (const SourceList&);
        MidiRegion (boost::shared_ptr<const MidiRegion>);
-       MidiRegion (boost::shared_ptr<const MidiRegion>, frameoffset_t offset);
+       MidiRegion (boost::shared_ptr<const MidiRegion>, frameoffset_t offset, const int32_t& sub_num = 0);
 
        framecnt_t _read_at (const SourceList&, Evoral::EventSink<framepos_t>& dst,
                             framepos_t position,
@@ -131,11 +131,11 @@ class LIBARDOUR_API MidiRegion : public Region
        void recompute_at_start ();
        void recompute_at_end ();
 
-       void set_position_internal (framepos_t pos, bool allow_bbt_recompute);
-       void set_length_internal (framecnt_t len);
+       void set_position_internal (framepos_t pos, bool allow_bbt_recompute, const int32_t& sub_num);
+       void set_length_internal (framecnt_t len, const int32_t& sub_num);
        void set_start_internal (framecnt_t, const int32_t& sub_num);
        void trim_to_internal (framepos_t position, framecnt_t length, const int32_t& sub_num);
-       void update_length_beats ();
+       void update_length_beats (const int32_t& sub_num);
 
        void model_changed ();
        void model_automation_state_changed (Evoral::Parameter const &);
index 7b19a08f6ac2cb2805034ffa5d53743ddd1d37db..0a5f5e4ddc5c015050d410cc7fc0cc1643ea0f89 100644 (file)
@@ -134,8 +134,8 @@ public:
        void get_region_list_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
        void get_source_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
        void replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, framepos_t pos);
-       void split_region (boost::shared_ptr<Region>, framepos_t position);
-       void split (framepos_t at);
+       void split_region (boost::shared_ptr<Region>, framepos_t position, const int32_t& sub_num);
+       void split (framepos_t at, const int32_t& sub_num);
        void shift (framepos_t at, frameoffset_t distance, bool move_intersected, bool ignore_music_glue);
        void partition (framepos_t start, framepos_t end, bool cut = false);
        void duplicate (boost::shared_ptr<Region>, framepos_t position, float times);
@@ -380,7 +380,7 @@ public:
        void begin_undo ();
        void end_undo ();
 
-       void _split_region (boost::shared_ptr<Region>, framepos_t position);
+       void _split_region (boost::shared_ptr<Region>, framepos_t position, const int32_t& sub_num);
 
        typedef std::pair<boost::shared_ptr<Region>, boost::shared_ptr<Region> > TwoRegions;
 
index e0dd159ce5939d146d49e62495ba6c77e3d02e69..ec4f559a87e78563b4704a0f053dd25a6d4e139e 100644 (file)
@@ -171,9 +171,9 @@ class LIBARDOUR_API Region
        Trimmable::CanTrim can_trim () const;
 
        PositionLockStyle position_lock_style () const { return _position_lock_style; }
-       double beat () { return _beat; }
+       double beat () const { return _beat; }
        void set_position_lock_style (PositionLockStyle ps);
-       void recompute_position_from_lock_style ();
+       void recompute_position_from_lock_style (const int32_t& sub_num);
 
        void suspend_property_changes ();
 
@@ -205,7 +205,7 @@ class LIBARDOUR_API Region
 
        /* EDITING OPERATIONS */
 
-       void set_length (framecnt_t);
+       void set_length (framecnt_t, const int32_t& sub_num);
        void set_start (framepos_t);
        void set_position (framepos_t, int32_t sub_num = 0);
        void set_initial_position (framepos_t);
@@ -339,7 +339,7 @@ class LIBARDOUR_API Region
        Region (boost::shared_ptr<const Region>);
 
        /** Construct a region from another region, at an offset within that region */
-       Region (boost::shared_ptr<const Region>, frameoffset_t start_offset);
+       Region (boost::shared_ptr<const Region>, frameoffset_t start_offset, const int32_t& sub_num);
 
        /** Construct a region as a copy of another region, but with different sources */
        Region (boost::shared_ptr<const Region>, const SourceList&);
@@ -356,8 +356,8 @@ class LIBARDOUR_API Region
        void send_change (const PBD::PropertyChange&);
        virtual int _set_state (const XMLNode&, int version, PBD::PropertyChange& what_changed, bool send_signal);
        void post_set (const PBD::PropertyChange&);
-       virtual void set_position_internal (framepos_t pos, bool allow_bbt_recompute);
-       virtual void set_length_internal (framecnt_t);
+       virtual void set_position_internal (framepos_t pos, bool allow_bbt_recompute, const int32_t& sub_num);
+       virtual void set_length_internal (framecnt_t, const int32_t& sub_num);
        virtual void set_start_internal (framecnt_t, const int32_t& sub_num = 0);
        bool verify_start_and_length (framepos_t, framecnt_t&);
        void first_edit ();
index 08d9affc91e6502e0e03e6862ead0c405ca5262a..e331de2b006bfe4811152c2f69f374333d49d883 100644 (file)
@@ -59,7 +59,7 @@ public:
        static PBD::Signal1<void,boost::shared_ptr<Region> >  CheckNewRegion;
 
        /** create a "pure copy" of Region @param other */
-       static boost::shared_ptr<Region> create (boost::shared_ptr<const Region> other, bool announce = false);
+       static boost::shared_ptr<Region> create (boost::shared_ptr<const Region> other, bool announce = false, const int32_t& sub_num = 0);
 
        /** create a region from a single Source */
        static boost::shared_ptr<Region> create (boost::shared_ptr<Source>,
@@ -73,7 +73,7 @@ public:
                                                 const PBD::PropertyList&, bool announce = true);
        /** create a copy of @param other starting at @param offset within @param other */
        static boost::shared_ptr<Region> create (boost::shared_ptr<Region> other, frameoffset_t offset,
-                                                const PBD::PropertyList&, bool announce = true);
+                                                const PBD::PropertyList&, bool announce = true, const int32_t& sub_num = 0);
        /** create a "copy" of @param other but using a different set of sources @param srcs */
        static boost::shared_ptr<Region> create (boost::shared_ptr<Region> other, const SourceList& srcs,
                                                 const PBD::PropertyList&, bool announce = true);
index cab7f5faf8eab71957c936d16aba6eef18727ec2..e5ba4e8dcdd0e632b834914b8264e0573460a94a 100644 (file)
@@ -377,9 +377,9 @@ AudioDiskstream::use_destructive_playlist ()
                throw failed_constructor();
        }
 
-       /* be sure to stretch the region out to the maximum length */
+       /* be sure to stretch the region out to the maximum length (non-musical)*/
 
-       region->set_length (max_framepos - region->position());
+       region->set_length (max_framepos - region->position(), 0);
 
        uint32_t n;
        ChannelList::iterator chan;
index 60a6282181cf3a8814895f3ffb1fc5ba26b46f14..dff261a9dfe2f87a405a65ebb01f8bb1031b5d92 100644 (file)
@@ -279,8 +279,8 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
        assert (_sources.size() == _master_sources.size());
 }
 
-AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, framecnt_t offset)
-       : Region (other, offset)
+AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, framecnt_t offset, const int32_t& sub_num)
+       : Region (other, offset, sub_num)
        , AUDIOREGION_COPY_STATE (other)
          /* As far as I can see, the _envelope's times are relative to region position, and have nothing
             to do with sources (and hence _start).  So when we copy the envelope, we just use the supplied offset.
index 26a8509aca61a4c7199ea5d2726c0b9cbb0f9f1e..4d4c081c245219afb251bf71ab58684fcf5bec1c 100644 (file)
@@ -102,15 +102,14 @@ MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other)
 }
 
 /** Create a new MidiRegion that is part of an existing one */
-MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t offset)
-       : Region (other, offset)
+MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t offset, const int32_t& sub_num)
+       : Region (other, offset, sub_num)
        , _start_beats (Properties::start_beats, Evoral::Beats())
        , _length_beats (Properties::length_beats, other->_length_beats)
 {
-       BeatsFramesConverter bfc (_session.tempo_map(), other->_position);
-       Evoral::Beats const offset_beats = bfc.from (offset);
-
-       _start_beats = other->_start_beats.val() + offset_beats;
+       const double offset_beat = _session.tempo_map().exact_beat_at_frame (other->_position + offset, sub_num) - other->beat();
+       _start_beats = Evoral::Beats (other->_start_beats.val().to_double() + offset_beat);
+       update_length_beats (sub_num);
        register_properties ();
 
        assert(_name.val().find("/") == string::npos);
@@ -173,7 +172,8 @@ MidiRegion::post_set (const PropertyChange& pc)
        Region::post_set (pc);
 
        if (pc.contains (Properties::length) && !pc.contains (Properties::length_beats)) {
-               update_length_beats ();
+               /* update non-musically */
+               update_length_beats (0);
        } else if (pc.contains (Properties::start) && !pc.contains (Properties::start_beats)) {
                set_start_beats_from_start_frames ();
        }
@@ -186,10 +186,10 @@ MidiRegion::set_start_beats_from_start_frames ()
 }
 
 void
-MidiRegion::set_length_internal (framecnt_t len)
+MidiRegion::set_length_internal (framecnt_t len, const int32_t& sub_num)
 {
-       Region::set_length_internal (len);
-       update_length_beats ();
+       Region::set_length_internal (len, sub_num);
+       update_length_beats (sub_num);
 }
 
 void
@@ -198,26 +198,27 @@ MidiRegion::update_after_tempo_map_change (bool /* send */)
        Region::update_after_tempo_map_change (false);
 
        /* _start has now been updated. */
-       _length = _session.tempo_map().framepos_plus_beats (_position, _length_beats) - _position;
+       _length = _session.tempo_map().frame_at_beat (beat() + _length_beats.val().to_double()) - _position;
 
        PropertyChange s_and_l;
        s_and_l.add (Properties::start);
        s_and_l.add (Properties::length);
+       s_and_l.add (Properties::length_beats);
        s_and_l.add (Properties::position);
 
        send_change (s_and_l);
 }
 
 void
-MidiRegion::update_length_beats ()
+MidiRegion::update_length_beats (const int32_t& sub_num)
 {
-       _length_beats = Evoral::Beats (_session.tempo_map().beat_at_frame (_position + _length) - beat());
+       _length_beats = Evoral::Beats (_session.tempo_map().exact_beat_at_frame (_position + _length, sub_num) - beat());
 }
 
 void
-MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
+MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute, const int32_t& sub_num)
 {
-       Region::set_position_internal (pos, allow_bbt_recompute);
+       Region::set_position_internal (pos, allow_bbt_recompute, sub_num);
 
        /* set _start to new position in tempo map */
        _start = _position - _session.tempo_map().frame_at_beat (beat() - _start_beats.val().to_double());
@@ -225,7 +226,7 @@ MidiRegion::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
        /* leave _length_beats alone, and change _length to reflect the state of things
           at the new position (tempo map may dictate a different number of frames).
        */
-       Region::set_length_internal (_session.tempo_map().frame_at_beat (beat() + _length_beats.val().to_double()) - _position);
+       Region::set_length_internal (_session.tempo_map().frame_at_beat (beat() + _length_beats.val().to_double()) - _position, sub_num);
 }
 
 framecnt_t
@@ -328,7 +329,10 @@ MidiRegion::set_state (const XMLNode& node, int version)
        int ret = Region::set_state (node, version);
 
        if (ret == 0) {
-               update_length_beats ();
+               /* set length beats to the frame (non-musical) */
+               if (position_lock_style() == AudioTime) {
+                       update_length_beats (0);
+               }
        }
 
        return ret;
@@ -490,11 +494,11 @@ MidiRegion::trim_to_internal (framepos_t position, framecnt_t length, const int3
         */
 
        if (_position != position) {
-               set_position_internal (position, true);
+               set_position_internal (position, true, sub_num);
                what_changed.add (Properties::position);
        }
 
-       const double new_beat = _session.tempo_map().beat_at_frame (position);
+       const double new_beat = _session.tempo_map().exact_beat_at_frame (position, sub_num);
        const double new_start_beat = _start_beats.val().to_double() + beat_delta;
 
        new_start = _position - _session.tempo_map().frame_at_beat (new_beat - new_start_beat);
@@ -511,11 +515,10 @@ MidiRegion::trim_to_internal (framepos_t position, framecnt_t length, const int3
                what_changed.add (Properties::start);
        }
 
-
-
        if (_length != length) {
-               set_length_internal (length);
+               set_length_internal (length, sub_num);
                what_changed.add (Properties::length);
+               what_changed.add (Properties::length_beats);
        }
 
        set_whole_file (false);
index 0403461c73914102288b7bb2afc5c7207c215e2a..884d1e16f07e63e59ecac1ad0e22a974ad1b9224 100644 (file)
@@ -55,7 +55,7 @@ MidiStateTracker::add (uint8_t note, uint8_t chn)
        ++_active_notes[note + 128 * chn];
 
        if (_active_notes[note+128 * chn] > 1) {
-               cerr << this << " note " << (int) note << '/' << (int) chn << " was already on, now at " << (int) _active_notes[note+128*chn] << endl;
+               //cerr << this << " note " << (int) note << '/' << (int) chn << " was already on, now at " << (int) _active_notes[note+128*chn] << endl;
        }
 
        DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 ON %2/%3 voices %5 total on %4\n",
index 71ffcc21e111319f34f747a5c09b9eeeecd5579d..7258f49a1ccdab471f65f15f1c7e79810fb7fa23 100644 (file)
@@ -114,8 +114,8 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
        new_src->copy_interpolation_from (src);
 
        const int ret = finish (region, nsrcs, new_name);
-
-       results[0]->set_length((framecnt_t) floor (r->length() * _request.time_fraction));
+       /* non-musical */
+       results[0]->set_length((framecnt_t) floor (r->length() * _request.time_fraction), 0);
 
        return ret;
 }
index 58405e4755747be9c7b188a305413fd64162f1ba..3797f2f0c1118d19ec7e204d3d1a84dce5ce1241 100644 (file)
@@ -1384,12 +1384,12 @@ Playlist::duplicate_ranges (std::list<AudioRange>& ranges, float /* times */)
 
         /* XXX: may not be necessary; Region::post_set should do this, I think */
         for (RegionList::iterator r = fixup.begin(); r != fixup.end(); ++r) {
-                (*r)->recompute_position_from_lock_style ();
+                (*r)->recompute_position_from_lock_style (0);
         }
  }
 
  void
- Playlist::split (framepos_t at)
+ Playlist::split (framepos_t at, const int32_t& sub_num)
  {
         RegionWriteLock rlock (this);
         RegionList copy (regions.rlist());
@@ -1398,19 +1398,19 @@ Playlist::duplicate_ranges (std::list<AudioRange>& ranges, float /* times */)
          */
 
         for (RegionList::iterator r = copy.begin(); r != copy.end(); ++r) {
-                _split_region (*r, at);
+                _split_region (*r, at, sub_num);
         }
  }
 
  void
- Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
+ Playlist::split_region (boost::shared_ptr<Region> region, framepos_t playlist_position, const int32_t& sub_num)
  {
         RegionWriteLock rl (this);
-        _split_region (region, playlist_position);
+        _split_region (region, playlist_position, sub_num);
  }
 
  void
- Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position)
+ Playlist::_split_region (boost::shared_ptr<Region> region, framepos_t playlist_position, const int32_t& sub_num)
  {
         if (!region->covers (playlist_position)) {
                 return;
@@ -1451,7 +1451,7 @@ Playlist::duplicate_ranges (std::list<AudioRange>& ranges, float /* times */)
                    since it supplies that offset to the Region constructor, which
                    is necessary to get audio region gain envelopes right.
                 */
-                left = RegionFactory::create (region, 0, plist);
+                left = RegionFactory::create (region, 0, plist, true, sub_num);
         }
 
         RegionFactory::region_name (after_name, region->name(), false);
@@ -1466,7 +1466,7 @@ Playlist::duplicate_ranges (std::list<AudioRange>& ranges, float /* times */)
                 plist.add (Properties::layer, region->layer ());
 
                 /* same note as above */
-                right = RegionFactory::create (region, before, plist);
+                right = RegionFactory::create (region, before, plist, true, sub_num);
         }
 
         add_region_internal (left, region->position());
index 03ce918f3142817ffd72508b2d18074a7cb8c457..9ae909780ae005f5fb553f233df15bbbff4a0a8c 100644 (file)
@@ -352,9 +352,9 @@ RBEffect::run (boost::shared_ptr<Region> r, Progress* progress)
                                          shift);
                (*x)->set_master_sources (region->master_sources());
                /* multiply the old (possibly previously stretched) region length by the extra
-                  stretch this time around to get its new length
+                  stretch this time around to get its new length. this is a non-music based edit atm.
                */
-               (*x)->set_length ((*x)->length() * tsr.time_fraction);
+               (*x)->set_length ((*x)->length() * tsr.time_fraction, 0);
        }
 
        /* stretch region gain envelope */
index 5fb5b30014add2474a2f8ea6919c7c720f36688a..d308ea7797ef4d3faebb3b13956c321bf50e16d0 100644 (file)
@@ -320,7 +320,7 @@ Region::Region (boost::shared_ptr<const Region> other)
     the start within \a other is given by \a offset
     (i.e. relative to the start of \a other's sources, the start is \a offset + \a other.start()
 */
-Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset)
+Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset, const int32_t& sub_num)
        : SessionObject(other->session(), other->name())
        , _type (other->data_type())
        , REGION_COPY_STATE (other)
@@ -344,7 +344,7 @@ Region::Region (boost::shared_ptr<const Region> other, frameoffset_t offset)
        set_master_sources (other->_master_sources);
 
        _start = other->_start + offset;
-       _beat = _session.tempo_map().beat_at_frame (_position);
+       _beat = _session.tempo_map().exact_beat_at_frame (_position, sub_num);
 
        /* if the other region had a distinct sync point
           set, then continue to use it as best we can.
@@ -419,7 +419,7 @@ Region::set_name (const std::string& str)
 }
 
 void
-Region::set_length (framecnt_t len)
+Region::set_length (framecnt_t len, const int32_t& sub_num)
 {
        //cerr << "Region::set_length() len = " << len << endl;
        if (locked()) {
@@ -441,7 +441,7 @@ Region::set_length (framecnt_t len)
                }
 
 
-               set_length_internal (len);
+               set_length_internal (len, sub_num);
                _whole_file = false;
                first_edit ();
                maybe_uncopy ();
@@ -456,7 +456,7 @@ Region::set_length (framecnt_t len)
 }
 
 void
-Region::set_length_internal (framecnt_t len)
+Region::set_length_internal (framecnt_t len, const int32_t& sub_num)
 {
        _last_length = _length;
        _length = len;
@@ -558,7 +558,8 @@ Region::update_after_tempo_map_change (bool send)
        }
 
        const framepos_t pos = _session.tempo_map().frame_at_beat (_beat);
-       set_position_internal (pos, false);
+       /* we have _beat. update frame position non-musically */
+       set_position_internal (pos, false, 0);
 
        /* do this even if the position is the same. this helps out
           a GUI that has moved its representation already.
@@ -577,11 +578,11 @@ Region::set_position (framepos_t pos, int32_t sub_num)
        }
 
        if (sub_num == 0) {
-               set_position_internal (pos, true);
+               set_position_internal (pos, true, 0);
        } else {
                double beat = _session.tempo_map().exact_beat_at_frame (pos, sub_num);
                _beat = beat;
-               set_position_internal (pos, false);
+               set_position_internal (pos, false, sub_num);
        }
 
        /* do this even if the position is the same. this helps out
@@ -629,7 +630,7 @@ Region::set_initial_position (framepos_t pos)
                        _length = max_framepos - _position;
                }
 
-               recompute_position_from_lock_style ();
+               recompute_position_from_lock_style (0);
                /* ensure that this move doesn't cause a range move */
                _last_position = _position;
        }
@@ -642,7 +643,7 @@ Region::set_initial_position (framepos_t pos)
 }
 
 void
-Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
+Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute, const int32_t& sub_num)
 {
        /* We emit a change of Properties::position even if the position hasn't changed
           (see Region::set_position), so we must always set this up so that
@@ -654,7 +655,7 @@ Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
                _position = pos;
 
                if (allow_bbt_recompute) {
-                       recompute_position_from_lock_style ();
+                       recompute_position_from_lock_style (sub_num);
                }
                /* check that the new _position wouldn't make the current
                   length impossible - if so, change the length.
@@ -669,10 +670,10 @@ Region::set_position_internal (framepos_t pos, bool allow_bbt_recompute)
 }
 
 void
-Region::recompute_position_from_lock_style ()
+Region::recompute_position_from_lock_style (const int32_t& sub_num)
 {
        if (_position_lock_style == MusicTime) {
-               _beat = _session.tempo_map().beat_at_frame (_position);
+               _beat = _session.tempo_map().exact_beat_at_frame (_position, sub_num);
        }
 }
 
@@ -702,8 +703,8 @@ Region::nudge_position (frameoffset_t n)
                        new_position += n;
                }
        }
-
-       set_position_internal (new_position, true);
+       /* assumes non-musical nudge */
+       set_position_internal (new_position, true, 0);
 
        send_change (Properties::position);
 }
@@ -949,7 +950,7 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, const int32_t&
                if (!property_changes_suspended()) {
                        _last_position = _position;
                }
-               set_position_internal (position, true);
+               set_position_internal (position, true, sub_num);
                what_changed.add (Properties::position);
        }
 
@@ -957,7 +958,7 @@ Region::trim_to_internal (framepos_t position, framecnt_t length, const int32_t&
                if (!property_changes_suspended()) {
                        _last_length = _length;
                }
-               set_length_internal (length);
+               set_length_internal (length, sub_num);
                what_changed.add (Properties::length);
        }
 
@@ -1846,7 +1847,7 @@ void
 Region::post_set (const PropertyChange& pc)
 {
        if (pc.contains (Properties::position)) {
-               recompute_position_from_lock_style ();
+               recompute_position_from_lock_style (0);
        }
 }
 
index 549d0a252e59249654bdb5224193efacd65c7d61..fab9d8aaa83adf6ee933860206a31c4bc85fbbbb 100644 (file)
@@ -46,7 +46,7 @@ std::map<std::string, PBD::ID>                RegionFactory::region_name_map;
 RegionFactory::CompoundAssociations           RegionFactory::_compound_associations;
 
 boost::shared_ptr<Region>
-RegionFactory::create (boost::shared_ptr<const Region> region, bool announce)
+RegionFactory::create (boost::shared_ptr<const Region> region, bool announce, const int32_t& sub_num)
 {
        boost::shared_ptr<Region> ret;
        boost::shared_ptr<const AudioRegion> ar;
@@ -54,7 +54,7 @@ RegionFactory::create (boost::shared_ptr<const Region> region, bool announce)
 
        if ((ar = boost::dynamic_pointer_cast<const AudioRegion>(region)) != 0) {
 
-               ret = boost::shared_ptr<Region> (new AudioRegion (ar, 0));
+               ret = boost::shared_ptr<Region> (new AudioRegion (ar, 0, sub_num));
 
        } else if ((mr = boost::dynamic_pointer_cast<const MidiRegion>(region)) != 0) {
 
@@ -71,7 +71,7 @@ RegionFactory::create (boost::shared_ptr<const Region> region, bool announce)
                        source->set_ancestor_name(mr->sources().front()->name());
                        ret = mr->clone(source);
                } else {
-                       ret = boost::shared_ptr<Region> (new MidiRegion (mr, 0));
+                       ret = boost::shared_ptr<Region> (new MidiRegion (mr, 0, sub_num));
                }
 
        } else {
@@ -144,7 +144,7 @@ RegionFactory::create (boost::shared_ptr<Region> region, const PropertyList& pli
 }
 
 boost::shared_ptr<Region>
-RegionFactory::create (boost::shared_ptr<Region> region, frameoffset_t offset, const PropertyList& plist, bool announce)
+RegionFactory::create (boost::shared_ptr<Region> region, frameoffset_t offset, const PropertyList& plist, bool announce, const int32_t& sub_num)
 {
        boost::shared_ptr<Region> ret;
        boost::shared_ptr<const AudioRegion> other_a;
@@ -152,11 +152,11 @@ RegionFactory::create (boost::shared_ptr<Region> region, frameoffset_t offset, c
 
        if ((other_a = boost::dynamic_pointer_cast<AudioRegion>(region)) != 0) {
 
-               ret = boost::shared_ptr<Region> (new AudioRegion (other_a, offset));
+               ret = boost::shared_ptr<Region> (new AudioRegion (other_a, offset, sub_num));
 
        } else if ((other_m = boost::dynamic_pointer_cast<MidiRegion>(region)) != 0) {
 
-               ret = boost::shared_ptr<Region> (new MidiRegion (other_m, offset));
+               ret = boost::shared_ptr<Region> (new MidiRegion (other_m, offset, sub_num));
 
        } else {
                fatal << _("programming error: RegionFactory::create() called with unknown Region type")