slightly improved fixes for MIDI issues
[ardour.git] / libs / ardour / session_timefx.cc
index a200572584bd2bdb913a3d69ea151696c134d963..115d3eeeec5b8321c2d13e93d098b18caf108751 100644 (file)
@@ -15,7 +15,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id$
 */
 
 #include <cerrno>
 
 #include <ardour/session.h>
 #include <ardour/audioregion.h>
-#include <ardour/filesource.h>
 #include <ardour/sndfilesource.h>
+#include <ardour/region_factory.h>
+#include <ardour/source_factory.h>
 
 #include "i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
+using namespace PBD;
 using namespace soundtouch;
 
-AudioRegion*
+boost::shared_ptr<AudioRegion>
 Session::tempoize_region (TimeStretchRequest& tsr)
 {
-       AudioRegion::SourceList sources;
-       AudioRegion::SourceList::iterator it;
-       AudioRegion* r = 0;
+       SourceList sources;
+       SourceList::iterator it;
+       boost::shared_ptr<AudioRegion> r;
        SoundTouch st;
        string region_name;
        string ident = X_("-TIMEFX-");
        float percentage;
-       jack_nframes_t total_frames;
-       jack_nframes_t done;
+       nframes_t total_frames;
+       nframes_t done;
+       int c;
+       char buf[64];
+       string::size_type len;
 
        /* the soundtouch code wants a *tempo* change percentage, which is 
           of opposite sign to the length change.  
@@ -71,34 +75,52 @@ Session::tempoize_region (TimeStretchRequest& tsr)
        done = 0;
 
        for (uint32_t i = 0; i < tsr.region->n_channels(); ++i) {
-               string path = path_from_region_name (PBD::basename_nosuffix (names[i]), ident);
 
+               string rstr;
+               string::size_type existing_ident;
+               
+               if ((existing_ident = names[i].find (ident)) != string::npos) {
+                       rstr = names[i].substr (0, existing_ident);
+               } else {
+                       rstr = names[i];
+               }
+
+               string path = path_from_region_name (DataType::AUDIO, PBD::basename_nosuffix (rstr), ident);
+               
                if (path.length() == 0) {
-                       error << compose (_("tempoize: error creating name for new audio file based on %1"), tsr.region->name()) 
+                       error << string_compose (_("tempoize: error creating name for new audio file based on %1"), tsr.region->name()) 
                              << endmsg;
                        goto out;
                }
 
                try {
-                       sources.push_back(new FileSource (path, frame_rate()));
+                       sources.push_back (boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, *this, path, false, frame_rate())));
+
                } catch (failed_constructor& err) {
-                       error << compose (_("tempoize: error creating new audio file %1 (%2)"), path, strerror (errno)) << endmsg;
+                       error << string_compose (_("tempoize: error creating new audio file %1 (%2)"), path, strerror (errno)) << endmsg;
                        goto out;
                }
+
        }
        
        try {
-               const jack_nframes_t bufsize = 16384;
+               const nframes_t bufsize = 16384;
 
                for (uint32_t i = 0; i < sources.size(); ++i) {
                        gain_t gain_buffer[bufsize];
                        Sample buffer[bufsize];
-                       jack_nframes_t pos = 0;
-                       jack_nframes_t this_read = 0;
+                       nframes_t pos = 0;
+                       nframes_t this_read = 0;
+
+                       boost::shared_ptr<AudioSource> asrc = boost::dynamic_pointer_cast<AudioSource>(sources[i]);
+                       if (!asrc) {
+                               cerr << "FIXME: TimeFX for non-audio" << endl;
+                               continue;
+                       }
 
                        st.clear();
                        while (tsr.running && pos < tsr.region->length()) {
-                               jack_nframes_t this_time;
+                               nframes_t this_time;
                        
                                this_time = min (bufsize, tsr.region->length() - pos);
 
@@ -107,7 +129,7 @@ Session::tempoize_region (TimeStretchRequest& tsr)
                                   subject to timefx.  */
 
                                if ((this_read = tsr.region->master_read_at (buffer, buffer, gain_buffer, pos + tsr.region->position(), this_time)) != this_time) {
-                                       error << compose (_("tempoize: error reading data from %1"), sources[i]->name()) << endmsg;
+                                       error << string_compose (_("tempoize: error reading data from %1"), sources[i]->name()) << endmsg;
                                        goto out;
                                }
                        
@@ -119,8 +141,8 @@ Session::tempoize_region (TimeStretchRequest& tsr)
                                st.putSamples (buffer, this_read);
                        
                                while ((this_read = st.receiveSamples (buffer, bufsize)) > 0 && tsr.running) {
-                                       if (sources[i]->write (buffer, this_read) != this_read) {
-                                               error << compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg;
+                                       if (asrc->write (buffer, this_read) != this_read) {
+                                               error << string_compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg;
                                                goto out;
                                        }
                                }
@@ -131,8 +153,8 @@ Session::tempoize_region (TimeStretchRequest& tsr)
                        }
                
                        while (tsr.running && (this_read = st.receiveSamples (buffer, bufsize)) > 0) {
-                               if (sources[i]->write (buffer, this_read) != this_read) {
-                                       error << compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg;
+                               if (asrc->write (buffer, this_read) != this_read) {
+                                       error << string_compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg;
                                        goto out;
                                }
                        }
@@ -149,15 +171,44 @@ Session::tempoize_region (TimeStretchRequest& tsr)
        xnow = localtime (&now);
 
        for (it = sources.begin(); it != sources.end(); ++it) {
-               dynamic_cast<FileSource*>(*it)->update_header (0, *xnow, now);
+               boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*it);
+               if (afs) {
+                       afs->update_header (tsr.region->position(), *xnow, now);
+               }
+       }
+
+       len = tsr.region->name().length();
+
+       while (--len) {
+               if (!isdigit (tsr.region->name()[len])) {
+                       break;
+               }
        }
 
-       region_name = tsr.region->name() + X_(".t");
+       if (len == 0) {
+               
+               region_name = tsr.region->name() + ".t000";
+
+       } else {
+
+               if (tsr.region->name()[len] == 't') {
+                       c = atoi (tsr.region->name().substr(len+1).c_str());
 
-       r = new AudioRegion (sources, 0, sources.front()->length(), region_name,
-                       0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile));
+                       snprintf (buf, sizeof (buf), "t%03d", ++c);
+                       region_name = tsr.region->name().substr (0, len) + buf;
 
+               } else {
+                       
+                       /* not sure what this is, just tack the suffix on to it */
 
+                       region_name = tsr.region->name() + ".t000";
+               }
+                       
+       }
+
+       r = (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, 0, sources.front()->length(), region_name,
+                                                                             0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile))));
+            
   out:
 
        if (sources.size()) {
@@ -166,21 +217,19 @@ Session::tempoize_region (TimeStretchRequest& tsr)
                   for deletion.
                */
 
-               if ((r == 0 || !tsr.running)) {
+               if ((!r || !tsr.running)) {
                        for (it = sources.begin(); it != sources.end(); ++it) {
                                (*it)->mark_for_remove ();
-                               delete *it;
                        }
                }
+
+               sources.clear ();
        }
        
        /* if the process was cancelled, delete the region */
 
        if (!tsr.running) {
-               if (r) {
-                       delete r;
-                       r = 0;
-               } 
+               r.reset ();
        }
        
        return r;