Use PLATFORM_WINDOWS (in preference to WIN32) for consistency with the other libraries
[ardour.git] / libs / ardour / session.cc
index 05fa883a9d3b02343d8cec6553ad1f1893021e8d..04c86dc979e896316135fe9cd703acece4b2b989 100644 (file)
@@ -125,6 +125,7 @@ PBD::Signal0<void> Session::FeedbackDetected;
 PBD::Signal0<void> Session::SuccessfulGraphSort;
 PBD::Signal2<void,std::string,std::string> Session::VersionMismatch;
 
+const framecnt_t Session::bounce_chunk_size = 65536;
 static void clean_up_session_event (SessionEvent* ev) { delete ev; }
 const SessionEvent::RTeventCallback Session::rt_cleanup (clean_up_session_event);
 
@@ -137,6 +138,7 @@ Session::Session (AudioEngine &eng,
        : playlists (new SessionPlaylists)
        , _engine (eng)
        , process_function (&Session::process_with_events)
+       , _bounce_processing_active (false)
        , waiting_for_sync_offset (false)
        , _base_frame_rate (0)
        , _current_frame_rate (0)
@@ -3881,7 +3883,7 @@ Session::update_locations_after_tempo_map_change (Locations::LocationList& loc)
 void
 Session::ensure_buffers (ChanCount howmany)
 {
-       BufferManager::ensure_buffers (howmany);
+       BufferManager::ensure_buffers (howmany, bounce_processing() ? bounce_chunk_size : 0);
 }
 
 void
@@ -4133,6 +4135,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
        framepos_t position;
        framecnt_t this_chunk;
        framepos_t to_do;
+       framepos_t latency_skip;
        BufferSet buffers;
        SessionDirectory sdir(get_best_session_directory_for_new_source ());
        const string sound_dir = sdir.sound_path();
@@ -4147,12 +4150,27 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
                return result;
        }
 
-       const framecnt_t chunk_size = (256 * 1024)/4;
+       diskstream_channels = track.bounce_get_output_streams (diskstream_channels, endpoint, include_endpoint, for_export);
+
+       if (diskstream_channels.n_audio() < 1) {
+               error << _("Cannot write a range with no audio.") << endmsg;
+               return result;
+       }
 
        // block all process callback handling
 
        block_processing ();
 
+       {
+               // synchronize with AudioEngine::process_callback()
+               // make sure processing is not currently running
+               // and processing_blocked() is honored before
+               // acquiring thread buffers
+               Glib::Threads::Mutex::Lock lm (_engine.process_lock());
+       }
+
+       _bounce_processing_active = true;
+
        /* call tree *MUST* hold route_lock */
 
        if ((playlist = track.playlist()) == 0) {
@@ -4194,13 +4212,17 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
         */
 
        need_block_size_reset = true;
-       track.set_block_size (chunk_size);
+       track.set_block_size (bounce_chunk_size);
+       _engine.main_thread()->get_buffers ();
 
        position = start;
        to_do = len;
+       latency_skip = track.bounce_get_latency (endpoint, include_endpoint, for_export);
 
        /* create a set of reasonably-sized buffers */
-       buffers.ensure_buffers (DataType::AUDIO, max_proc.n_audio(), chunk_size);
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               buffers.ensure_buffers(*t, max_proc.get(*t), bounce_chunk_size);
+       }
        buffers.set_count (max_proc);
 
        for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
@@ -4211,28 +4233,56 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
 
        while (to_do && !itt.cancel) {
 
-               this_chunk = min (to_do, chunk_size);
+               this_chunk = min (to_do, bounce_chunk_size);
 
                if (track.export_stuff (buffers, start, this_chunk, endpoint, include_endpoint, for_export)) {
                        goto out;
                }
 
+               start += this_chunk;
+               to_do -= this_chunk;
+               itt.progress = (float) (1.0 - ((double) to_do / len));
+
+               if (latency_skip >= bounce_chunk_size) {
+                       latency_skip -= bounce_chunk_size;
+                       continue;
+               }
+
+               const framecnt_t current_chunk = this_chunk - latency_skip;
+
                uint32_t n = 0;
                for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
                        boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
 
                        if (afs) {
-                               if (afs->write (buffers.get_audio(n).data(), this_chunk) != this_chunk) {
+                               if (afs->write (buffers.get_audio(n).data(latency_skip), current_chunk) != current_chunk) {
                                        goto out;
                                }
                        }
                }
+               latency_skip = 0;
+       }
 
-               start += this_chunk;
-               to_do -= this_chunk;
+       /* post-roll, pick up delayed processor output */
+       latency_skip = track.bounce_get_latency (endpoint, include_endpoint, for_export);
 
-               itt.progress = (float) (1.0 - ((double) to_do / len));
+       while (latency_skip && !itt.cancel) {
+               this_chunk = min (latency_skip, bounce_chunk_size);
+               latency_skip -= this_chunk;
+
+               buffers.silence (this_chunk, 0);
+               track.bounce_process (buffers, start, this_chunk, endpoint, include_endpoint, for_export);
+
+               uint32_t n = 0;
+               for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
+                       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
 
+                       if (afs) {
+                               if (afs->write (buffers.get_audio(n).data(), this_chunk) != this_chunk) {
+                                       goto out;
+                               }
+                       }
+               }
        }
 
        if (!itt.cancel) {
@@ -4284,8 +4334,10 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
                }
        }
 
+       _bounce_processing_active = false;
 
        if (need_block_size_reset) {
+               _engine.main_thread()->drop_buffers ();
                track.set_block_size (get_block_size());
        }