ardour
session_export.cc
Go to the documentation of this file.
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 
21 #include "pbd/error.h"
22 #include <glibmm/threads.h>
23 
24 #include <midi++/mmc.h>
25 
26 #include "ardour/audioengine.h"
27 #include "ardour/butler.h"
28 #include "ardour/export_handler.h"
29 #include "ardour/export_status.h"
30 #include "ardour/process_thread.h"
31 #include "ardour/session.h"
32 #include "ardour/track.h"
33 
34 #include "i18n.h"
35 
36 using namespace std;
37 using namespace ARDOUR;
38 using namespace PBD;
39 
41 Session::get_export_handler ()
42 {
43  if (!export_handler) {
44  export_handler.reset (new ExportHandler (*this));
45  }
46 
47  return export_handler;
48 }
49 
51 Session::get_export_status ()
52 {
53  if (!export_status) {
54  export_status.reset (new ExportStatus ());
55  }
56 
57  return export_status;
58 }
59 
60 
61 int
62 Session::pre_export ()
63 {
64  get_export_status (); // Init export_status
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_sync = config.get_external_sync ();
85  post_export_position = _transport_frame;
86 
87  config.set_external_sync (false);
88 
89  _exporting = true;
90  export_status->running = true;
91  export_status->Finished.connect_same_thread (*this, boost::bind (&Session::finalize_audio_export, this));
92 
93  /* disable MMC output early */
94 
95  _pre_export_mmc_enabled = _mmc->send_enabled ();
96  _mmc->enable_send (false);
97 
98  return 0;
99 }
100 
102 int
103 Session::start_audio_export (framepos_t position)
104 {
105  if (!_exporting) {
106  pre_export ();
107  }
108  _export_started = false;
109 
110  /* We're about to call Track::seek, so the butler must have finished everything
111  up otherwise it could be doing do_refill in its thread while we are doing
112  it here.
113  */
114 
115  _butler->wait_until_finished ();
116 
117  /* get everyone to the right position */
118 
119  {
120  boost::shared_ptr<RouteList> rl = routes.reader();
121 
122  for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
124  if (tr && tr->seek (position, true)) {
125  error << string_compose (_("%1: cannot seek to %2 for export"),
126  (*i)->name(), position)
127  << endmsg;
128  return -1;
129  }
130  }
131  }
132 
133  /* we just did the core part of a locate() call above, but
134  for the sake of any GUI, put the _transport_frame in
135  the right place too.
136  */
137 
138  _transport_frame = position;
139  export_status->stop = false;
140 
141  /* get transport ready. note how this is calling butler functions
142  from a non-butler thread. we waited for the butler to stop
143  what it was doing earlier in Session::pre_export() and nothing
144  since then has re-awakened it.
145  */
146 
147  /* we are ready to go ... */
148 
149  if (!_engine.connected()) {
150  return -1;
151  }
152 
153  _engine.Freewheel.connect_same_thread (export_freewheel_connection, boost::bind (&Session::process_export_fw, this, _1));
154  _export_rolling = true;
155  return _engine.freewheel (true);
156 }
157 
158 int
159 Session::process_export (pframes_t nframes)
160 {
161  if (_export_rolling && export_status->stop) {
162  stop_audio_export ();
163  }
164 
165  if (_export_rolling) {
166  /* make sure we've caught up with disk i/o, since
167  we're running faster than realtime c/o JACK.
168  */
169  _butler->wait_until_finished ();
170 
171  /* do the usual stuff */
172 
173  process_without_events (nframes);
174  }
175 
176  try {
177  /* handle export - XXX what about error handling? */
178 
179  ProcessExport (nframes);
180 
181  } catch (std::exception & e) {
182  error << string_compose (_("Export ended unexpectedly: %1"), e.what()) << endmsg;
183  export_status->abort (true);
184  return -1;
185  }
186 
187  return 0;
188 }
189 
190 int
191 Session::process_export_fw (pframes_t nframes)
192 {
193  if (!_export_started) {
194  _export_started = true;
195  set_transport_speed (1.0, 0, false);
196  butler_transport_work ();
197  g_atomic_int_set (&_butler->should_do_transport_work, 0);
198  post_transport ();
199  return 0;
200  }
201 
202  _engine.main_thread()->get_buffers ();
203  process_export (nframes);
204  _engine.main_thread()->drop_buffers ();
205 
206  return 0;
207 }
208 
209 int
210 Session::stop_audio_export ()
211 {
212  /* can't use stop_transport() here because we need
213  an immediate halt and don't require all the declick
214  stuff that stop_transport() implements.
215  */
216 
217  realtime_stop (true, true);
218  _export_rolling = false;
219  _butler->schedule_transport_work ();
220 
221  return 0;
222 }
223 
224 void
225 Session::finalize_audio_export ()
226 {
227  _exporting = false;
228 
229  if (_export_rolling) {
230  stop_audio_export ();
231  }
232 
233  /* Clean up */
234 
235  _engine.freewheel (false);
236 
237  export_freewheel_connection.disconnect();
238 
239  _mmc->enable_send (_pre_export_mmc_enabled);
240 
241  /* maybe write CUE/TOC */
242 
243  export_handler.reset();
244  export_status.reset();
245 
246  /* restart slaving */
247 
248  if (post_export_sync) {
249  config.set_external_sync (true);
250  } else {
251  locate (post_export_position, false, false, false, false, false);
252  }
253 }
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
uint32_t pframes_t
Definition: types.h:61
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
#define _(Text)
Definition: i18n.h:11
int seek(framepos_t, bool complete_refill=false)
Definition: track.cc:668
Definition: amp.h:29
int64_t framepos_t
Definition: types.h:66
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
Definition: debug.h:30
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208