2 Copyright (C) 1999-2008 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <sigc++/bind.h>
22 #include "pbd/error.h"
23 #include <glibmm/thread.h>
25 #include "ardour/session.h"
26 #include "ardour/audio_diskstream.h"
27 #include "ardour/audioengine.h"
28 #include "ardour/export_failed.h"
29 #include "ardour/export_file_io.h"
30 #include "ardour/export_handler.h"
31 #include "ardour/export_status.h"
32 #include "ardour/export_utilities.h"
33 #include "ardour/route.h"
38 using namespace ARDOUR;
41 boost::shared_ptr<ExportHandler>
42 Session::get_export_handler ()
44 if (!export_handler) {
45 export_handler.reset (new ExportHandler (*this));
48 return export_handler;
51 boost::shared_ptr<ExportStatus>
52 Session::get_export_status ()
55 export_status.reset (new ExportStatus ());
63 Session::pre_export ()
65 get_export_status (); // Init export_status
67 wait_till_butler_finished ();
69 /* take everyone out of awrite to avoid disasters */
72 boost::shared_ptr<RouteList> r = routes.reader ();
74 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
75 (*i)->protect_automation ();
79 /* make sure we are actually rolling */
81 if (get_record_enabled()) {
82 disable_record (false);
87 post_export_slave = Config->get_slave_source ();
88 post_export_position = _transport_frame;
90 Config->set_slave_source (None);
93 export_status->running = true;
94 export_status->Aborting.connect (sigc::hide_return (sigc::mem_fun (*this, &Session::stop_audio_export)));
95 export_status->Finished.connect (sigc::hide_return (sigc::mem_fun (*this, &Session::finalize_audio_export)));
101 Session::start_audio_export (nframes_t position, bool realtime)
107 /* get everyone to the right position */
110 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
112 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
113 if ((*i)-> seek (position, true)) {
114 error << string_compose (_("%1: cannot seek to %2 for export"),
115 (*i)->name(), position)
122 /* we just did the core part of a locate() call above, but
123 for the sake of any GUI, put the _transport_frame in
127 _transport_frame = position;
129 _exporting_realtime = realtime;
130 export_status->stop = false;
132 /* get transport ready. note how this is calling butler functions
133 from a non-butler thread. we waited for the butler to stop
134 what it was doing earlier in Session::pre_export() and nothing
135 since then has re-awakened it.
138 set_transport_speed (1.0, false);
139 butler_transport_work ();
140 g_atomic_int_set (&butler_should_do_transport_work, 0);
143 /* we are ready to go ... */
145 if (!_engine.connected()) {
150 last_process_function = process_function;
151 process_function = &Session::process_export;
153 export_freewheel_connection = _engine.Freewheel.connect (sigc::mem_fun (*this, &Session::process_export_fw));
154 return _engine.freewheel (true);
161 Session::process_export (nframes_t nframes)
165 if (export_status->stop) {
166 stop_audio_export ();
170 if (!_exporting_realtime) {
171 /* make sure we've caught up with disk i/o, since
172 we're running faster than realtime c/o JACK.
175 wait_till_butler_finished ();
178 /* do the usual stuff */
180 process_without_events (nframes);
184 ProcessExport (nframes);
186 } catch (ExportFailed e) {
187 export_status->abort (true);
192 Session::process_export_fw (nframes_t nframes)
194 process_export (nframes);
199 Session::stop_audio_export ()
201 if (_exporting_realtime) {
202 process_function = last_process_function;
204 export_freewheel_connection.disconnect();
207 /* can't use stop_transport() here because we need
208 an immediate halt and don't require all the declick
209 stuff that stop_transport() implements.
212 realtime_stop (true);
213 schedule_butler_transport_work ();
215 if (!export_status->aborted()) {
216 ExportReadFinished ();
218 finalize_audio_export ();
226 Session::finalize_audio_export ()
229 export_status->running = false;
231 if (!_exporting_realtime) {
232 _engine.freewheel (false);
233 _exporting_realtime = false;
238 ProcessExport.clear();
239 ExportReadFinished.clear();
240 export_freewheel_connection.disconnect();
241 export_handler.reset();
242 export_status.reset();
244 /* restart slaving */
246 if (post_export_slave != None) {
247 Config->set_slave_source (post_export_slave);
249 locate (post_export_position, false, false, false);