From: Paul Davis Date: Thu, 29 May 2008 14:45:13 +0000 (+0000) Subject: fix(es) from chris cannam for rb_effect mistakes X-Git-Tag: 2.8.16~1375 X-Git-Url: https://git.carlh.net/gitweb/?a=commitdiff_plain;h=5fc24b7f018f1855b3e497bdcc611889f3cf2b3f;p=ardour.git fix(es) from chris cannam for rb_effect mistakes git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@3424 d708f5d6-7413-0410-9779-e7cbd77b26cf --- diff --git a/libs/ardour/rb_effect.cc b/libs/ardour/rb_effect.cc index 35e7b1bb75..280eabda64 100644 --- a/libs/ardour/rb_effect.cc +++ b/libs/ardour/rb_effect.cc @@ -74,37 +74,102 @@ RBEffect::run (boost::shared_ptr region) nframes_t pos = 0; int avail = 0; - // note: this_time_fraction is a ratio of original length. 1.0 = no change, - // 0.5 is half as long, 2.0 is twice as long, etc. + cerr << "RBEffect: source region: position = " << region->position() + << ", start = " << region->start() + << ", length = " << region->length() + << ", ancestral_start = " << region->ancestral_start() + << ", ancestral_length = " << region->ancestral_length() + << ", stretch " << region->stretch() + << ", shift " << region->shift() << endl; + + /* + We have two cases to consider: + + 1. The region has not been stretched before. + + In this case, we just want to read region->length() frames + from region->start(). + + We will create a new region of region->length() * + tsr.time_fraction frames. The new region will have its + start set to 0 (because it has a new audio file that begins + at the start of the stretched area) and its ancestral_start + set to region->start() (so that we know where to begin + reading if we want to stretch it again). + + 2. The region has been stretched before. + + The region starts at region->start() frames into its + (possibly previously stretched) source file. But we don't + want to read from its source file; we want to read from the + file it was originally stretched from. + + The region's source begins at region->ancestral_start() + frames into its master source file. Thus, we need to start + reading at region->ancestral_start() + (region->start() / + region->stretch()) frames into the master source. This + value will also become the ancestral_start for the new + region. + + We cannot use region->ancestral_length() to establish how + many frames to read, because it won't be up to date if the + region has been trimmed since it was last stretched. We + must read region->length() / region->stretch() frames and + stretch them by tsr.time_fraction * region->stretch(), for + a new region of region->length() * tsr.time_fraction + frames. + + Case 1 is of course a special case of 2, where + region->ancestral_start() == 0 and region->stretch() == 1. + + When we ask to read from a region, we supply a position on + the global timeline. The read function calculates the + offset into the source as (position - region->position()) + + region->start(). This calculation is used regardless of + whether we are reading from a master or + previously-stretched region. In order to read from a point + n frames into the master source, we need to provide n - + region->start() + region->position() as our position + argument to master_read_at(). + + Note that region->ancestral_length() is not used. + + I hope this is clear. + */ + + double stretch = region->stretch() * tsr.time_fraction; + double shift = region->shift() * tsr.pitch_fraction; + + nframes_t read_start = region->ancestral_start() + + nframes_t(region->start() / (double)region->stretch()); - double this_time_fraction = tsr.time_fraction * region->stretch (); - double this_pitch_fraction = tsr.pitch_fraction * region->shift (); + nframes_t read_duration = + nframes_t(region->length() / (double)region->stretch()); - RubberBandStretcher stretcher (session.frame_rate(), region->n_channels(), - (RubberBandStretcher::Options) tsr.opts, - this_time_fraction, this_pitch_fraction); + uint32_t channels = region->n_channels(); + + RubberBandStretcher stretcher + (session.frame_rate(), channels, + (RubberBandStretcher::Options) tsr.opts, stretch, shift); tsr.progress = 0.0f; tsr.done = false; - uint32_t channels = region->n_channels(); - nframes_t duration = region->ancestral_length(); - - stretcher.setExpectedInputDuration(duration); + stretcher.setExpectedInputDuration(read_duration); stretcher.setDebugLevel(1); /* the name doesn't need to be super-precise, but allow for 2 fractional digits just to disambiguate close but not identical FX */ - if (this_time_fraction == 1.0) { - snprintf (suffix, sizeof (suffix), "@%d", (int) floor (this_pitch_fraction * 100.0f)); - } else if (this_pitch_fraction == 1.0) { - snprintf (suffix, sizeof (suffix), "@%d", (int) floor (this_time_fraction * 100.0f)); + if (stretch == 1.0) { + snprintf (suffix, sizeof (suffix), "@%d", (int) floor (shift * 100.0f)); + } else if (shift == 1.0) { + snprintf (suffix, sizeof (suffix), "@%d", (int) floor (stretch * 100.0f)); } else { snprintf (suffix, sizeof (suffix), "@%d-%d", - (int) floor (this_time_fraction * 100.0f), - (int) floor (this_pitch_fraction * 100.0f)); + (int) floor (stretch * 100.0f), + (int) floor (shift * 100.0f)); } /* create new sources */ @@ -131,22 +196,26 @@ RBEffect::run (boost::shared_ptr region) done = 0; try { - while (pos < duration && !tsr.cancel) { + while (pos < read_duration && !tsr.cancel) { nframes_t this_read = 0; for (uint32_t i = 0; i < channels; ++i) { this_read = 0; + nframes_t this_time; + this_time = min(bufsize, read_duration - pos); - this_time = min(bufsize, duration - pos); - + nframes_t this_position; + this_position = read_start + pos - + region->start() + region->position(); + this_read = region->master_read_at (buffers[i], buffers[i], gain_buffer, - pos + region->position(), + this_position, this_time, i); @@ -161,15 +230,15 @@ RBEffect::run (boost::shared_ptr region) pos += this_read; done += this_read; - tsr.progress = ((float) done / duration) * 0.25; + tsr.progress = ((float) done / read_duration) * 0.25; - stretcher.study(buffers, this_read, pos == duration); + stretcher.study(buffers, this_read, pos == read_duration); } done = 0; pos = 0; - while (pos < duration && !tsr.cancel) { + while (pos < read_duration && !tsr.cancel) { nframes_t this_read = 0; @@ -177,14 +246,17 @@ RBEffect::run (boost::shared_ptr region) this_read = 0; nframes_t this_time; - - this_time = min(bufsize, duration - pos); + this_time = min(bufsize, read_duration - pos); + + nframes_t this_position; + this_position = read_start + pos - + region->start() + region->position(); this_read = region->master_read_at (buffers[i], buffers[i], gain_buffer, - pos + region->position(), + this_position, this_time, i); @@ -199,9 +271,9 @@ RBEffect::run (boost::shared_ptr region) pos += this_read; done += this_read; - tsr.progress = 0.25 + ((float) done / duration) * 0.75; + tsr.progress = 0.25 + ((float) done / read_duration) * 0.75; - stretcher.process(buffers, this_read, pos == duration); + stretcher.process(buffers, this_read, pos == read_duration); int avail = 0; @@ -261,10 +333,10 @@ RBEffect::run (boost::shared_ptr region) for (vector >::iterator x = results.begin(); x != results.end(); ++x) { - (*x)->set_ancestral_data (region->ancestral_start(), - region->ancestral_length(), - this_time_fraction, - this_pitch_fraction ); + (*x)->set_ancestral_data (read_start, + read_duration, + stretch, + shift); (*x)->set_master_sources (region->get_master_sources()); } diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc index d999c59e97..e907770061 100644 --- a/libs/ardour/region.cc +++ b/libs/ardour/region.cc @@ -95,10 +95,10 @@ Region::Region (boost::shared_ptr other, nframes_t offset, nframes } _length = length; _last_length = length; - _ancestral_start = other->_ancestral_start + offset; - _ancestral_length = length; - _stretch = 1.0; - _shift = 1.0; + _ancestral_start = other->_ancestral_start; + _ancestral_length = other->_ancestral_length; + _stretch = other->_stretch; + _shift = other->_shift; _name = name; _last_position = 0; _position = 0; @@ -133,8 +133,8 @@ Region::Region (boost::shared_ptr other) _last_length = other->_length; _ancestral_start = _start; _ancestral_length = _length; - _stretch = 1.0; - _shift = 1.0; + _stretch = other->_stretch; + _shift = other->_shift; _name = other->_name; _last_position = other->_position; _position = other->_position;