Merge with 2.0-ongoing R3082.
[ardour.git] / libs / ardour / session_export.cc
index 0ccea59b81ccc66845bda18d4c342c3dcecc3882..49b6d9b1503851a941a787c06529ba7ddcf12bde 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$
 */
 
 /* see gdither.cc for why we have to do this */
@@ -37,7 +36,7 @@
 #include <sigc++/bind.h>
 
 #include <pbd/error.h>
-#include <pbd/lockmonitor.h>
+#include <glibmm/thread.h>
 
 #include <ardour/gdither.h>
 #include <ardour/timestamps.h>
 #include <ardour/export.h>
 #include <ardour/sndfile_helpers.h>
 #include <ardour/port.h>
+#include <ardour/audio_port.h>
 #include <ardour/audioengine.h>
-#include <ardour/diskstream.h>
+#include <ardour/audio_diskstream.h>
 #include <ardour/panner.h>
 
 #include "i18n.h"
 
 using namespace std;
 using namespace ARDOUR;
-//using namespace sigc;
+using namespace PBD;
 
 static int
-convert_spec_to_info (AudioExportSpecification& spec, SF_INFO& sfinfo)
+convert_spec_to_info (ExportSpecification& spec, SF_INFO& sfinfo)
 {
        if (spec.path.length() == 0) {
                error << _("Export: no output file specified") << endmsg;
@@ -76,18 +76,18 @@ convert_spec_to_info (AudioExportSpecification& spec, SF_INFO& sfinfo)
        return 0;
 }
 
-AudioExportSpecification::AudioExportSpecification ()
+ExportSpecification::ExportSpecification ()
 {
        init ();
 }
 
-AudioExportSpecification::~AudioExportSpecification ()
+ExportSpecification::~ExportSpecification ()
 {
        clear ();
 }
 
 void
-AudioExportSpecification::init ()
+ExportSpecification::init ()
 {
        src_state = 0;
        pos = 0;
@@ -113,7 +113,7 @@ AudioExportSpecification::init ()
 }
 
 void
-AudioExportSpecification::clear ()
+ExportSpecification::clear ()
 {
        if (out) {
                sf_close (out);
@@ -153,7 +153,7 @@ AudioExportSpecification::clear ()
 }
 
 int
-AudioExportSpecification::prepare (jack_nframes_t blocksize, jack_nframes_t frate)
+ExportSpecification::prepare (nframes_t blocksize, nframes_t frate)
 {
        char errbuf[256];
        GDitherSize dither_size;
@@ -161,7 +161,7 @@ AudioExportSpecification::prepare (jack_nframes_t blocksize, jack_nframes_t frat
        frame_rate = frate;
 
        if (channels == 0) {
-               error << _("illegal frame range in export specification") << endmsg;
+               error << _("illegal channel count in export specification") << endmsg;
                return -1;
        }
 
@@ -216,7 +216,7 @@ AudioExportSpecification::prepare (jack_nframes_t blocksize, jack_nframes_t frat
                }
                
                src_data.src_ratio = sample_rate / (double) frame_rate;
-               out_samples_max = (jack_nframes_t) ceil (blocksize * src_data.src_ratio * channels);
+               out_samples_max = (nframes_t) ceil (blocksize * src_data.src_ratio * channels);
                dataF2 = new float[out_samples_max];
 
                max_leftover_frames = 4 * blocksize;
@@ -258,7 +258,7 @@ AudioExportSpecification::prepare (jack_nframes_t blocksize, jack_nframes_t frat
 }
 
 int
-AudioExportSpecification::process (jack_nframes_t nframes)
+ExportSpecification::process (nframes_t nframes)
 {
        float* float_buffer = 0;
        uint32_t chn;
@@ -266,9 +266,9 @@ AudioExportSpecification::process (jack_nframes_t nframes)
        uint32_t i;
        sf_count_t written;
        char errbuf[256];
-       jack_nframes_t to_write = 0;
+       nframes_t to_write = 0;
        int cnt = 0;
-
+       
        do {
 
                /* now do sample rate conversion */
@@ -413,7 +413,7 @@ AudioExportSpecification::process (jack_nframes_t nframes)
                        break;
                }
        
-               if ((jack_nframes_t) written != to_write) {
+               if ((nframes_t) written != to_write) {
                        sf_error_str (out, errbuf, sizeof (errbuf) - 1);
                        error << string_compose(_("Export: could not write data to output file (%1)"), errbuf) << endmsg;
                        return -1;
@@ -426,9 +426,11 @@ AudioExportSpecification::process (jack_nframes_t nframes)
 }
 
 int
-Session::start_audio_export (AudioExportSpecification& spec)
+Session::start_export (ExportSpecification& spec)
 {
-       int ret;
+       if (!_engine.connected()) {
+               return -1;
+       }
 
        if (spec.prepare (current_block_size, frame_rate())) {
                return -1;
@@ -437,46 +439,27 @@ Session::start_audio_export (AudioExportSpecification& spec)
        spec.pos = spec.start_frame;
        spec.end_frame = spec.end_frame;
        spec.total_frames = spec.end_frame - spec.start_frame;
+       spec.running = true; 
+       spec.do_freewheel = false; /* force a call to ::prepare_to_export() before proceeding to normal operation */
 
        spec.freewheel_connection = _engine.Freewheel.connect (sigc::bind (mem_fun (*this, &Session::process_export), &spec));
 
-       if ((ret = _engine.freewheel (true)) == 0) {
-               spec.running = true; 
-               spec.do_freewheel = false;
-       }
-
-       return ret;
+       return _engine.freewheel (true);
 }
 
 int
-Session::stop_audio_export (AudioExportSpecification& spec)
+Session::stop_export (ExportSpecification& spec)
 {
-       /* can't use stop_transport() here because we need
-          an immediate halt and don't require all the declick
-          stuff that stop_transport() implements.
-       */
-
-       realtime_stop (true);
-       schedule_butler_transport_work ();
-
-       /* restart slaving */
-
-       if (post_export_slave != None) {
-               set_slave_source (post_export_slave, post_export_position);
-       } else {
-               locate (post_export_position, false, false, false);
-       }
-
-       spec.clear ();
-       _exporting = false;
+       /* don't stop freewheeling but do stop paying attention to it for now */
 
-       spec.running = false;
+       spec.freewheel_connection.disconnect ();
+       spec.clear (); /* resets running/stop etc */
 
        return 0;
 }
 
 int 
-Session::prepare_to_export (AudioExportSpecification& spec)
+Session::prepare_to_export (ExportSpecification& spec)
 {
        int ret = -1;
 
@@ -485,8 +468,9 @@ Session::prepare_to_export (AudioExportSpecification& spec)
        /* take everyone out of awrite to avoid disasters */
 
        {
-               RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
-               for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
+               boost::shared_ptr<RouteList> r = routes.reader ();
+
+               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                        (*i)->protect_automation ();
                }
        }
@@ -494,8 +478,9 @@ Session::prepare_to_export (AudioExportSpecification& spec)
        /* get everyone to the right position */
 
        {
-               RWLockMonitor lm (diskstream_lock, false, __LINE__, __FILE__);
-               for (DiskStreamList::iterator i = diskstreams.begin(); i != diskstreams.end(); ++i) {
+               boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
+
+               for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
                        if ((*i)-> seek (spec.start_frame, true)) {
                                error << string_compose (_("%1: cannot seek to %2 for export"),
                                                  (*i)->name(), spec.start_frame)
@@ -508,23 +493,23 @@ Session::prepare_to_export (AudioExportSpecification& spec)
        /* make sure we are actually rolling */
 
        if (get_record_enabled()) {
-               disable_record ();
+               disable_record (false);
        }
 
        _exporting = true;
        
        /* no slaving */
 
-       post_export_slave = _slave_type;
+       post_export_slave = Config->get_slave_source ();
        post_export_position = _transport_frame;
 
-       set_slave_source (None, 0);
+       Config->set_slave_source (None);
 
        /* get transport ready */
 
        set_transport_speed (1.0, false);
        butler_transport_work ();
-       atomic_set (&butler_should_do_transport_work, 0);
+       g_atomic_int_set (&butler_should_do_transport_work, 0);
        post_transport ();
 
        /* we are ready to go ... */
@@ -536,12 +521,12 @@ Session::prepare_to_export (AudioExportSpecification& spec)
 }
 
 int
-Session::process_export (jack_nframes_t nframes, AudioExportSpecification* spec)
+Session::process_export (nframes_t nframes, ExportSpecification* spec)
 {
        uint32_t chn;
        uint32_t x;
        int ret = -1;
-       jack_nframes_t this_nframes;
+       nframes_t this_nframes;
 
        /* This is not required to be RT-safe because we are running while freewheeling */
 
@@ -566,7 +551,7 @@ Session::process_export (jack_nframes_t nframes, AudioExportSpecification* spec)
                
        if (!spec->running || spec->stop || (this_nframes = min ((spec->end_frame - spec->pos), nframes)) == 0) {
                process_without_events (nframes);
-               return stop_audio_export (*spec);
+               return stop_export (*spec);
        }
 
        /* make sure we've caught up with disk i/o, since
@@ -589,7 +574,7 @@ Session::process_export (jack_nframes_t nframes, AudioExportSpecification* spec)
        
        for (chn = 0; chn < spec->channels; ++chn) {
                
-               AudioExportPortMap::iterator mi = spec->port_map.find (chn);
+               ExportPortMap::iterator mi = spec->port_map.find (chn);
                
                if (mi == spec->port_map.end()) {
                        /* no ports exported to this channel */
@@ -603,13 +588,18 @@ Session::process_export (jack_nframes_t nframes, AudioExportSpecification* spec)
                        /* OK, this port's output is supposed to appear on this channel 
                         */
 
-                       Port* port = (*t).first;
-                       Sample* port_buffer = port->get_buffer (nframes);
+                       AudioPort* const aport = dynamic_cast<AudioPort*>((*t).first);
+                       MidiPort* const mport = dynamic_cast<MidiPort*>((*t).first);
+                       if (aport != 0) {
+                               Sample* port_buffer = aport->get_audio_buffer().data();
 
-                       /* now interleave the data from the channel into the float buffer */
-                               
-                       for (x = 0; x < nframes; ++x) {
-                               spec->dataF[chn+(x*spec->channels)] += (float) port_buffer[x];
+                               /* now interleave the data from the channel into the float buffer */
+
+                               for (x = 0; x < nframes; ++x) {
+                                       spec->dataF[chn+(x*spec->channels)] += (float) port_buffer[x];
+                               }
+                       } else if (mport != 0) {
+                               cerr << "EXPORT MIDI PORT" << endl;
                        }
                }
        }
@@ -638,3 +628,25 @@ Session::process_export (jack_nframes_t nframes, AudioExportSpecification* spec)
        return ret;
 }
 
+void
+Session::finalize_audio_export ()
+{
+       _engine.freewheel (false);
+       _exporting = false;
+
+       /* can't use stop_transport() here because we need
+          an immediate halt and don't require all the declick
+          stuff that stop_transport() implements.
+       */
+
+       realtime_stop (true);
+       schedule_butler_transport_work ();
+
+       /* restart slaving */
+
+       if (post_export_slave != None) {
+               Config->set_slave_source (post_export_slave);
+       } else {
+               locate (post_export_position, false, false, false);
+       }
+}