Exact beat - provide audio->music mapping for region split.

- 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.
This commit is contained in:
nick_m 2016-06-16 00:18:27 +10:00
parent 2d5238d875
commit 94e0a15325
25 changed files with 115 additions and 102 deletions

View 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) {

View 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);

View 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

View 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 {

View 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);

View 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));
}

View 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 ();

View 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()));

View 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;

View 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);

View 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 ();

View 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 &);

View 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 &);

View 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;

View 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 ();

View 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);

View 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;

View 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.

View 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);

View 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",

View 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;
}

View 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());

View 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 */

View 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);
}
}

View 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")