First part of consolidating ::roll(), ::no_roll()
[ardour.git] / libs / ardour / rb_effect.cc
index b61170da096b48c734e2783d287de6c22c0f6f72..23ffa944608ae03b458e25b92befb778b1993d1a 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
-    Copyright (C) 2004-2007 Paul Davis 
+    Copyright (C) 2004-2007 Paul Davis
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #include <algorithm>
 #include <cmath>
 
 #include <algorithm>
 #include <cmath>
 
+#include <rubberband/RubberBandStretcher.h>
+
 #include "pbd/error.h"
 #include "pbd/error.h"
-#include "rubberband/RubberBandStretcher.h"
 
 
-#include "ardour/types.h"
-#include "ardour/stretch.h"
+#include "ardour/audioregion.h"
+#include "ardour/audiosource.h"
 #include "ardour/pitch.h"
 #include "ardour/pitch.h"
-#include "ardour/audiofilesource.h"
+#include "ardour/progress.h"
 #include "ardour/session.h"
 #include "ardour/session.h"
-#include "ardour/audioregion.h"
+#include "ardour/stretch.h"
+#include "ardour/types.h"
 
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
 
 using namespace std;
 using namespace ARDOUR;
@@ -52,7 +54,7 @@ RBEffect::RBEffect (Session& s, TimeFXRequest& req)
        , tsr (req)
 
 {
        , tsr (req)
 
 {
-       tsr.progress = 0.0f;
+
 }
 
 RBEffect::~RBEffect ()
 }
 
 RBEffect::~RBEffect ()
@@ -60,7 +62,7 @@ RBEffect::~RBEffect ()
 }
 
 int
 }
 
 int
-RBEffect::run (boost::shared_ptr<Region> r)
+RBEffect::run (boost::shared_ptr<Region> r, Progress* progress)
 {
        boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
 
 {
        boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
 
@@ -70,20 +72,18 @@ RBEffect::run (boost::shared_ptr<Region> r)
        }
 
        SourceList nsrcs;
        }
 
        SourceList nsrcs;
-       nframes_t done;
        int ret = -1;
        int ret = -1;
-       const nframes_t bufsize = 256;
+       const samplecnt_t bufsize = 256;
        gain_t* gain_buffer = 0;
        Sample** buffers = 0;
        char suffix[32];
        string new_name;
        string::size_type at;
        gain_t* gain_buffer = 0;
        Sample** buffers = 0;
        char suffix[32];
        string new_name;
        string::size_type at;
-       nframes_t pos = 0;
-       int avail = 0;
+       boost::shared_ptr<AudioRegion> result;
 
        cerr << "RBEffect: source region: position = " << region->position()
             << ", start = " << region->start()
 
        cerr << "RBEffect: source region: position = " << region->position()
             << ", start = " << region->start()
-            << ", length = " << region->length() 
+            << ", length = " << region->length()
             << ", ancestral_start = " << region->ancestral_start()
             << ", ancestral_length = " << region->ancestral_length()
             << ", stretch " << region->stretch()
             << ", ancestral_start = " << region->ancestral_start()
             << ", ancestral_length = " << region->ancestral_length()
             << ", stretch " << region->stretch()
@@ -91,75 +91,75 @@ RBEffect::run (boost::shared_ptr<Region> r)
 
        /*
           We have two cases to consider:
 
        /*
           We have two cases to consider:
-         
+
           1. The region has not been stretched before.
           1. The region has not been stretched before.
-         
-          In this case, we just want to read region->length() frames
+
+          In this case, we just want to read region->length() samples
           from region->start().
           from region->start().
-         
+
           We will create a new region of region->length() *
           We will create a new region of region->length() *
-          tsr.time_fraction frames.  The new region will have its
+          tsr.time_fraction samples.  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).
           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.
           2. The region has been stretched before.
-         
-          The region starts at region->start() frames into its
+
+          The region starts at region->start() samples 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.
           (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()
           The region's source begins at region->ancestral_start()
-          frames into its master source file.  Thus, we need to start
+          samples into its master source file.  Thus, we need to start
           reading at region->ancestral_start() + (region->start() /
           reading at region->ancestral_start() + (region->start() /
-          region->stretch()) frames into the master source.  This
+          region->stretch()) samples into the master source.  This
           value will also become the ancestral_start for the new
           region.
           value will also become the ancestral_start for the new
           region.
-          
+
           We cannot use region->ancestral_length() to establish how
           We cannot use region->ancestral_length() to establish how
-          many frames to read, because it won't be up to date if the
+          many samples to read, because it won't be up to date if the
           region has been trimmed since it was last stretched.  We
           region has been trimmed since it was last stretched.  We
-          must read region->length() / region->stretch() frames and
+          must read region->length() / region->stretch() samples and
           stretch them by tsr.time_fraction * region->stretch(), for
           a new region of region->length() * tsr.time_fraction
           stretch them by tsr.time_fraction * region->stretch(), for
           a new region of region->length() * tsr.time_fraction
-          frames.
-         
+          samples.
+
           Case 1 is of course a special case of 2, where
           region->ancestral_start() == 0 and region->stretch() == 1.
           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
           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 -
+          n samples into the master source, we need to provide n -
           region->start() + region->position() as our position
           argument to master_read_at().
           region->start() + region->position() as our position
           argument to master_read_at().
-         
+
           Note that region->ancestral_length() is not used.
           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;
 
           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());
+       samplecnt_t read_start = region->ancestral_start() +
+               samplecnt_t(region->start() / (double)region->stretch());
 
 
-       nframes_t read_duration =
-               nframes_t(region->length() / (double)region->stretch());
+       samplecnt_t read_duration =
+               samplecnt_t(region->length() / (double)region->stretch());
 
        uint32_t channels = region->n_channels();
 
        RubberBandStretcher stretcher
 
        uint32_t channels = region->n_channels();
 
        RubberBandStretcher stretcher
-               (session.frame_rate(), channels,
+               (session.sample_rate(), channels,
                 (RubberBandStretcher::Options) tsr.opts, stretch, shift);
                 (RubberBandStretcher::Options) tsr.opts, stretch, shift);
-       
-       tsr.progress = 0.0f;
+
+       progress->set_progress (0);
        tsr.done = false;
 
        stretcher.setExpectedInputDuration(read_duration);
        tsr.done = false;
 
        stretcher.setExpectedInputDuration(read_duration);
@@ -174,13 +174,17 @@ RBEffect::run (boost::shared_ptr<Region> r)
        } else if (shift == 1.0) {
                snprintf (suffix, sizeof (suffix), "@%d", (int) floor (stretch * 100.0f));
        } else {
        } else if (shift == 1.0) {
                snprintf (suffix, sizeof (suffix), "@%d", (int) floor (stretch * 100.0f));
        } else {
-               snprintf (suffix, sizeof (suffix), "@%d-%d", 
+               snprintf (suffix, sizeof (suffix), "@%d-%d",
                          (int) floor (stretch * 100.0f),
                          (int) floor (shift * 100.0f));
        }
 
        /* create new sources */
 
                          (int) floor (stretch * 100.0f),
                          (int) floor (shift * 100.0f));
        }
 
        /* create new sources */
 
+       samplepos_t pos   = 0;
+       samplecnt_t avail = 0;
+       samplecnt_t done  = 0;
+
        if (make_new_sources (region, nsrcs, suffix)) {
                goto out;
        }
        if (make_new_sources (region, nsrcs, suffix)) {
                goto out;
        }
@@ -198,23 +202,17 @@ RBEffect::run (boost::shared_ptr<Region> r)
 
        /* study first, process afterwards. */
 
 
        /* study first, process afterwards. */
 
-       pos = 0;
-       avail = 0;
-       done = 0;
-
-       try { 
+       try {
                while (pos < read_duration && !tsr.cancel) {
                while (pos < read_duration && !tsr.cancel) {
-                       
-                       nframes_t this_read = 0;
+
+                       samplecnt_t this_read = 0;
 
                        for (uint32_t i = 0; i < channels; ++i) {
 
                        for (uint32_t i = 0; i < channels; ++i) {
-                               
-                               this_read = 0;
 
 
-                               nframes_t this_time;
+                               samplepos_t this_time;
                                this_time = min(bufsize, read_duration - pos);
                                this_time = min(bufsize, read_duration - pos);
-                               
-                               nframes_t this_position;
+
+                               samplepos_t this_position;
                                this_position = read_start + pos -
                                        region->start() + region->position();
 
                                this_position = read_start + pos -
                                        region->start() + region->position();
 
@@ -225,7 +223,7 @@ RBEffect::run (boost::shared_ptr<Region> r)
                                         this_position,
                                         this_time,
                                         i);
                                         this_position,
                                         this_time,
                                         i);
-                               
+
                                if (this_read != this_time) {
                                        error << string_compose
                                                (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
                                if (this_read != this_time) {
                                        error << string_compose
                                                (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
@@ -233,32 +231,31 @@ RBEffect::run (boost::shared_ptr<Region> r)
                                        goto out;
                                }
                        }
                                        goto out;
                                }
                        }
-                       
+
                        pos += this_read;
                        done += this_read;
 
                        pos += this_read;
                        done += this_read;
 
-                       tsr.progress = ((float) done / read_duration) * 0.25;
+                       progress->set_progress (((float) done / read_duration) * 0.25);
 
                        stretcher.study(buffers, this_read, pos == read_duration);
                }
 
                        stretcher.study(buffers, this_read, pos == read_duration);
                }
-               
+
                done = 0;
                pos = 0;
 
                while (pos < read_duration && !tsr.cancel) {
                done = 0;
                pos = 0;
 
                while (pos < read_duration && !tsr.cancel) {
-                       
-                       nframes_t this_read = 0;
-                       
+
+                       samplecnt_t this_read = 0;
+
                        for (uint32_t i = 0; i < channels; ++i) {
                        for (uint32_t i = 0; i < channels; ++i) {
-                               
-                               this_read = 0;
-                               nframes_t this_time;
+
+                               samplepos_t this_time;
                                this_time = min(bufsize, read_duration - pos);
 
                                this_time = min(bufsize, read_duration - pos);
 
-                               nframes_t this_position;
+                               samplepos_t this_position;
                                this_position = read_start + pos -
                                        region->start() + region->position();
                                this_position = read_start + pos -
                                        region->start() + region->position();
-                               
+
                                this_read = region->master_read_at
                                        (buffers[i],
                                         buffers[i],
                                this_read = region->master_read_at
                                        (buffers[i],
                                         buffers[i],
@@ -266,7 +263,7 @@ RBEffect::run (boost::shared_ptr<Region> r)
                                         this_position,
                                         this_time,
                                         i);
                                         this_position,
                                         this_time,
                                         i);
-                               
+
                                if (this_read != this_time) {
                                        error << string_compose
                                                (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
                                if (this_read != this_time) {
                                        error << string_compose
                                                (_("tempoize: error reading data from %1 at %2 (wanted %3, got %4)"),
@@ -278,18 +275,18 @@ RBEffect::run (boost::shared_ptr<Region> r)
                        pos += this_read;
                        done += this_read;
 
                        pos += this_read;
                        done += this_read;
 
-                       tsr.progress = 0.25 + ((float) done / read_duration) * 0.75;
+                       progress->set_progress (0.25 + ((float) done / read_duration) * 0.75);
 
                        stretcher.process(buffers, this_read, pos == read_duration);
 
 
                        stretcher.process(buffers, this_read, pos == read_duration);
 
-                       int avail = 0;
+                       samplecnt_t avail = 0;
 
                        while ((avail = stretcher.available()) > 0) {
 
 
                        while ((avail = stretcher.available()) > 0) {
 
-                               this_read = min(bufsize, uint32_t(avail));
+                               this_read = min (bufsize, avail);
 
                                stretcher.retrieve(buffers, this_read);
 
                                stretcher.retrieve(buffers, this_read);
-                       
+
                                for (uint32_t i = 0; i < nsrcs.size(); ++i) {
 
                                        boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
                                for (uint32_t i = 0; i < nsrcs.size(); ++i) {
 
                                        boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(nsrcs[i]);
@@ -307,7 +304,7 @@ RBEffect::run (boost::shared_ptr<Region> r)
 
                while ((avail = stretcher.available()) >= 0) {
 
 
                while ((avail = stretcher.available()) >= 0) {
 
-                       uint32_t this_read = min(bufsize, uint32_t(avail));
+                       samplecnt_t this_read = min (bufsize, avail);
 
                        stretcher.retrieve(buffers, this_read);
 
 
                        stretcher.retrieve(buffers, this_read);
 
@@ -317,7 +314,7 @@ RBEffect::run (boost::shared_ptr<Region> r)
                                if (!asrc) {
                                        continue;
                                }
                                if (!asrc) {
                                        continue;
                                }
-                               
+
                                if (asrc->write(buffers[i], this_read) !=
                                    this_read) {
                                        error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
                                if (asrc->write(buffers[i], this_read) !=
                                    this_read) {
                                        error << string_compose (_("error writing tempo-adjusted data to %1"), nsrcs[i]->name()) << endmsg;
@@ -327,7 +324,7 @@ RBEffect::run (boost::shared_ptr<Region> r)
                }
 
        } catch (runtime_error& err) {
                }
 
        } catch (runtime_error& err) {
-               error << _("timefx code failure. please notify ardour-developers.") << endmsg;
+               error << string_compose (_("programming error: %1"), X_("timefx code failure")) << endmsg;
                error << err.what() << endmsg;
                goto out;
        }
                error << err.what() << endmsg;
                goto out;
        }
@@ -354,6 +351,19 @@ RBEffect::run (boost::shared_ptr<Region> r)
                                          stretch,
                                          shift);
                (*x)->set_master_sources (region->master_sources());
                                          stretch,
                                          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. this is a non-music based edit atm.
+               */
+               (*x)->set_length ((*x)->length() * tsr.time_fraction, 0);
+       }
+
+       /* stretch region gain envelope */
+       /* XXX: assuming we've only processed one input region into one result here */
+
+       if (tsr.time_fraction != 1) {
+               result = boost::dynamic_pointer_cast<AudioRegion> (results.front());
+               assert (result);
+               result->envelope()->x_scale (tsr.time_fraction);
        }
 
   out:
        }
 
   out:
@@ -362,7 +372,7 @@ RBEffect::run (boost::shared_ptr<Region> r)
 
        if (buffers) {
                for (uint32_t i = 0; i < channels; ++i) {
 
        if (buffers) {
                for (uint32_t i = 0; i < channels; ++i) {
-                       delete buffers[i];
+                       delete [] buffers[i];
                }
                delete [] buffers;
        }
                }
                delete [] buffers;
        }
@@ -372,8 +382,6 @@ RBEffect::run (boost::shared_ptr<Region> r)
                        (*si)->mark_for_remove ();
                }
        }
                        (*si)->mark_for_remove ();
                }
        }
-       
-       tsr.done = true;
 
        return ret;
 }
 
        return ret;
 }
@@ -381,4 +389,4 @@ RBEffect::run (boost::shared_ptr<Region> r)
 
 
 
 
 
 
-    
+