8d7b4da6c5b0c2470891e82ec9013fd8b41f3f31
[ardour.git] / libs / ardour / session_export.cc
1 /*
2  * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
4  * Copyright (C) 2008-2013 Sakari Bergen <sakari.bergen@beatwaves.net>
5  * Copyright (C) 2010-2012 Carl Hetherington <carl@carlh.net>
6  * Copyright (C) 2015-2018 Robin Gareus <robin@gareus.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23
24 #include "pbd/error.h"
25 #include <glibmm/threads.h>
26
27 #include <midi++/mmc.h>
28
29 #include "ardour/audioengine.h"
30 #include "ardour/butler.h"
31 #include "ardour/export_handler.h"
32 #include "ardour/export_status.h"
33 #include "ardour/process_thread.h"
34 #include "ardour/session.h"
35 #include "ardour/track.h"
36
37 #include "pbd/i18n.h"
38
39 using namespace std;
40 using namespace ARDOUR;
41 using namespace PBD;
42
43 boost::shared_ptr<ExportHandler>
44 Session::get_export_handler ()
45 {
46         if (!export_handler) {
47                 export_handler.reset (new ExportHandler (*this));
48         }
49
50         return export_handler;
51 }
52
53 boost::shared_ptr<ExportStatus>
54 Session::get_export_status ()
55 {
56         if (!export_status) {
57                 export_status.reset (new ExportStatus ());
58         }
59
60         return export_status;
61 }
62
63
64 int
65 Session::pre_export ()
66 {
67         get_export_status (); // Init export_status
68
69         /* take everyone out of awrite to avoid disasters */
70
71         {
72                 boost::shared_ptr<RouteList> r = routes.reader ();
73
74                 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
75                         (*i)->protect_automation ();
76                 }
77         }
78
79         /* prepare transport */
80
81         realtime_stop (true, true);
82
83         if (get_record_enabled()) {
84                 disable_record (false);
85         }
86
87         unset_play_loop ();
88
89         /* no slaving */
90
91         post_export_sync = config.get_external_sync ();
92         post_export_position = _transport_sample;
93
94         config.set_external_sync (false);
95
96         _exporting = true;
97         export_status->set_running (true);
98         export_status->Finished.connect_same_thread (*this, boost::bind (&Session::finalize_audio_export, this));
99
100         /* disable MMC output early */
101
102         _pre_export_mmc_enabled = _mmc->send_enabled ();
103         _mmc->enable_send (false);
104
105         return 0;
106 }
107
108 /** Called for each range that is being exported */
109 int
110 Session::start_audio_export (samplepos_t position, bool realtime, bool region_export)
111 {
112         if (!_exporting) {
113                 pre_export ();
114         }
115
116         _realtime_export = realtime;
117         _region_export = region_export;
118
119         if (region_export) {
120                 _export_preroll = 0;
121         }
122         else if (realtime) {
123                 _export_preroll = nominal_sample_rate ();
124         } else {
125                 _export_preroll = Config->get_export_preroll() * nominal_sample_rate ();
126         }
127
128         if (_export_preroll == 0) {
129                 // must be > 0 so that transport is started in sync.
130                 _export_preroll = 1;
131         }
132
133         /* We're about to call Track::seek, so the butler must have finished everything
134            up otherwise it could be doing do_refill in its thread while we are doing
135            it here.
136         */
137
138         _butler->wait_until_finished ();
139
140         /* get everyone to the right position */
141
142         {
143                 boost::shared_ptr<RouteList> rl = routes.reader();
144
145                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
146                         boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
147                         if (tr && tr->seek (position, true)) {
148                                 error << string_compose (_("%1: cannot seek to %2 for export"),
149                                                   (*i)->name(), position)
150                                       << endmsg;
151                                 return -1;
152                         }
153                 }
154         }
155
156         /* we just did the core part of a locate() call above, but
157            for the sake of any GUI, put the _transport_sample in
158            the right place too.
159         */
160
161         _transport_sample = position;
162
163         if (!region_export) {
164                 _remaining_latency_preroll = worst_latency_preroll ();
165         } else {
166                 _remaining_latency_preroll = 0;
167         }
168         export_status->stop = false;
169
170         /* get transport ready. note how this is calling butler functions
171            from a non-butler thread. we waited for the butler to stop
172            what it was doing earlier in Session::pre_export() and nothing
173            since then has re-awakened it.
174          */
175
176         /* we are ready to go ... */
177
178         if (!_engine.running()) {
179                 return -1;
180         }
181
182         _engine.Freewheel.connect_same_thread (export_freewheel_connection, boost::bind (&Session::process_export_fw, this, _1));
183
184         if (_realtime_export) {
185                 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
186                 _export_rolling = true;
187                 process_function = &Session::process_export_fw;
188                 return 0;
189         } else {
190                 _export_rolling = true;
191                 return _engine.freewheel (true);
192         }
193 }
194
195 void
196 Session::process_export (pframes_t nframes)
197 {
198         if (_export_rolling && export_status->stop) {
199                 stop_audio_export ();
200         }
201
202         /* for Region Raw or Fades, we can skip this
203          * RegionExportChannelFactory::update_buffers() does not care
204          * about anything done here
205          */
206         if (!_region_export) {
207                 if (_export_rolling) {
208                         if (!_realtime_export)  {
209                                 /* make sure we've caught up with disk i/o, since
210                                  * we're running faster than realtime c/o JACK.
211                                  */
212                                 _butler->wait_until_finished ();
213                         }
214
215                         /* do the usual stuff */
216
217                         process_without_events (nframes);
218
219                 } else if (_realtime_export) {
220                         fail_roll (nframes); // somehow we need to silence _ALL_ output buffers
221                 }
222         }
223
224         try {
225                 /* handle export - XXX what about error handling? */
226
227                 ProcessExport (nframes);
228
229         } catch (std::exception & e) {
230                 error << string_compose (_("Export ended unexpectedly: %1"), e.what()) << endmsg;
231                 export_status->abort (true);
232         }
233 }
234
235 void
236 Session::process_export_fw (pframes_t nframes)
237 {
238         const bool need_buffers = _engine.freewheeling ();
239         if (_export_preroll > 0) {
240
241                 if (need_buffers) {
242                         _engine.main_thread()->get_buffers ();
243                 }
244                 fail_roll (nframes);
245                 if (need_buffers) {
246                         _engine.main_thread()->drop_buffers ();
247                 }
248
249                 _export_preroll -= std::min ((samplepos_t)nframes, _export_preroll);
250
251                 if (_export_preroll > 0) {
252                         // clear out buffers (reverb tails etc).
253                         return;
254                 }
255
256                 set_transport_speed (1.0, 0, false);
257                 butler_transport_work ();
258                 g_atomic_int_set (&_butler->should_do_transport_work, 0);
259                 post_transport ();
260
261                 return;
262         }
263
264         if (_remaining_latency_preroll > 0) {
265                 samplepos_t remain = std::min ((samplepos_t)nframes, _remaining_latency_preroll);
266
267                 if (need_buffers) {
268                         _engine.main_thread()->get_buffers ();
269                 }
270
271                 process_without_events (remain);
272
273                 if (need_buffers) {
274                         _engine.main_thread()->drop_buffers ();
275                 }
276
277                 _remaining_latency_preroll -= remain;
278                 _transport_sample -= remain;
279                 nframes -= remain;
280
281                 if (nframes == 0) {
282                         return;
283                 }
284                 _engine.split_cycle (remain);
285         }
286
287         if (need_buffers) {
288                 _engine.main_thread()->get_buffers ();
289         }
290         process_export (nframes);
291         if (need_buffers) {
292                 _engine.main_thread()->drop_buffers ();
293         }
294
295         return;
296 }
297
298 int
299 Session::stop_audio_export ()
300 {
301         /* can't use stop_transport() here because we need
302            an immediate halt and don't require all the declick
303            stuff that stop_transport() implements.
304         */
305
306         realtime_stop (true, true);
307         _export_rolling = false;
308         _butler->schedule_transport_work ();
309
310         return 0;
311 }
312
313 void
314 Session::finalize_audio_export ()
315 {
316         _exporting = false;
317
318         if (_export_rolling) {
319                 stop_audio_export ();
320         }
321
322         /* Clean up */
323
324         if (_realtime_export) {
325                 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
326                 process_function = &Session::process_with_events;
327         }
328         _engine.freewheel (false);
329         export_freewheel_connection.disconnect();
330
331         _mmc->enable_send (_pre_export_mmc_enabled);
332
333         /* maybe write CUE/TOC */
334
335         export_handler.reset();
336         export_status.reset();
337
338         /* restart slaving */
339
340         if (post_export_sync) {
341                 config.set_external_sync (true);
342         } else {
343                 locate (post_export_position, false, false, false, false, false);
344         }
345 }