merge Sakari's (sbergen) branch back into 3.0, removing libsndfile and adding taglib
[ardour.git] / libs / ardour / session_export.cc
1 /*
2     Copyright (C) 1999-2008 Paul Davis 
3
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.
8
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.
13
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.
17
18 */
19
20 #include <sigc++/bind.h>
21
22 #include <pbd/error.h>
23 #include <glibmm/thread.h>
24
25 #include <ardour/export_failed.h>
26 #include <ardour/export_file_io.h>
27 #include <ardour/export_utilities.h>
28 #include <ardour/export_handler.h>
29 #include <ardour/timestamps.h>
30 #include <ardour/ardour.h>
31 #include <ardour/session.h>
32 #include <ardour/audioengine.h>
33 #include <ardour/audio_diskstream.h>
34 #include <ardour/panner.h>
35
36 #include "i18n.h"
37
38 using namespace std;
39 using namespace ARDOUR;
40 using namespace PBD;
41
42 boost::shared_ptr<ExportHandler>
43 Session::get_export_handler ()
44 {
45         if (!export_handler) {
46                 export_handler.reset (new ExportHandler (*this));
47         }
48         
49         return export_handler;
50 }
51
52 void
53 Session::release_export_handler ()
54 {
55         if (!_exporting) {
56                 export_handler.reset();
57         }
58 }
59
60 int
61 Session::pre_export ()
62 {
63
64         wait_till_butler_finished ();
65
66         /* take everyone out of awrite to avoid disasters */
67
68         {
69                 boost::shared_ptr<RouteList> r = routes.reader ();
70
71                 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
72                         (*i)->protect_automation ();
73                 }
74         }
75
76         /* make sure we are actually rolling */
77
78         if (get_record_enabled()) {
79                 disable_record (false);
80         }
81
82         /* no slaving */
83
84         post_export_slave = Config->get_slave_source ();
85         post_export_position = _transport_frame;
86
87         Config->set_slave_source (None);
88         
89         _exporting = true;
90         export_status.running = true;
91         export_abort_connection = export_status.Aborting.connect (sigc::mem_fun (*this, &Session::abort_audio_export));
92
93         return 0;
94 }
95
96 int
97 Session::start_audio_export (nframes_t position, bool realtime)
98 {
99         /* get everyone to the right position */
100
101         {
102                 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
103
104                 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
105                         if ((*i)-> seek (position, true)) {
106                                 error << string_compose (_("%1: cannot seek to %2 for export"),
107                                                   (*i)->name(), position)
108                                       << endmsg;
109                                 return -1;
110                         }
111                 }
112         }
113
114         /* we just did the core part of a locate() call above, but
115            for the sake of any GUI, put the _transport_frame in
116            the right place too.
117         */
118
119         _transport_frame = position;
120         
121         _exporting_realtime = realtime;
122         export_status.stop = false;
123
124         /* get transport ready. note how this is calling butler functions
125            from a non-butler thread. we waited for the butler to stop
126            what it was doing earlier in Session::pre_export() and nothing
127            since then has re-awakened it.
128          */
129
130         set_transport_speed (1.0, false);
131         butler_transport_work ();
132         g_atomic_int_set (&butler_should_do_transport_work, 0);
133         post_transport ();
134
135         /* we are ready to go ... */
136         
137         if (!_engine.connected()) {
138                 return -1;
139         }
140
141         if (realtime) {
142                 last_process_function = process_function;
143                 process_function = &Session::process_export;
144         } else {
145                 export_freewheel_connection = _engine.Freewheel.connect (sigc::mem_fun (*this, &Session::process_export_fw));
146                 return _engine.freewheel (true);
147         }
148
149         return 0;
150 }
151
152 void
153 Session::process_export (nframes_t nframes)
154 {
155         try {
156
157                 if (export_status.stop) {
158                         stop_audio_export ();
159                         return;
160                 }
161         
162                 if (!_exporting_realtime) {
163                         /* make sure we've caught up with disk i/o, since
164                         we're running faster than realtime c/o JACK.
165                         */
166                         
167                         wait_till_butler_finished ();
168                 }
169         
170                 /* do the usual stuff */
171         
172                 process_without_events (nframes);
173         
174                 /* handle export */
175         
176                 ProcessExport (nframes);
177
178         } catch (ExportFailed e) {
179
180                 std::cerr << e.what() << std::endl;
181                 stop_audio_export();
182                 finalize_audio_export();
183
184         }
185 }
186
187 int
188 Session::process_export_fw (nframes_t nframes)
189 {
190         process_export (nframes);       
191         return 0;
192 }
193
194 int
195 Session::stop_audio_export ()
196 {
197         if (_exporting_realtime) {
198                 process_function = last_process_function;
199         } else {
200                 export_freewheel_connection.disconnect();
201         }
202
203         /* can't use stop_transport() here because we need
204            an immediate halt and don't require all the declick
205            stuff that stop_transport() implements.
206         */
207
208         realtime_stop (true);
209         schedule_butler_transport_work ();
210
211         if (!export_status.aborted()) {
212                 ExportFinished ();
213         }
214         
215         return 0;
216
217 }
218
219 void
220 Session::finalize_audio_export ()
221 {
222         _exporting = false;
223         export_status.running = false;
224
225         if (!_exporting_realtime) {
226                 _engine.freewheel (false);
227                 _exporting_realtime = false;
228         }
229
230         /* Clean up */
231         
232         ProcessExport.clear();
233         ExportFinished.clear();
234         export_freewheel_connection.disconnect();
235         export_abort_connection.disconnect();
236         export_handler.reset();
237
238         /* restart slaving */
239
240         if (post_export_slave != None) {
241                 Config->set_slave_source (post_export_slave);
242         } else {
243                 locate (post_export_position, false, false, false);
244         }
245 }
246
247 void
248 Session::abort_audio_export ()
249 {
250         stop_audio_export ();
251         finalize_audio_export ();
252 }