Stop bounce / freeze on tracks that have more outputs than inputs and so cannot recor...
[ardour.git] / gtk2_ardour / editor_export_audio.cc
1 /*
2     Copyright (C) 2001 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 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <inttypes.h>
23 #include <unistd.h>
24 #include <climits>
25
26 #include <gtkmm/messagedialog.h>
27
28 #include "gtkmm2ext/choice.h"
29
30 #include "export_dialog.h"
31 #include "editor.h"
32 #include "public_editor.h"
33 #include "selection.h"
34 #include "time_axis_view.h"
35 #include "audio_time_axis.h"
36 #include "audio_region_view.h"
37 #include "midi_region_view.h"
38
39 #include "pbd/pthread_utils.h"
40 #include "ardour/types.h"
41 #include "ardour/audio_track.h"
42 #include "ardour/audiofilesource.h"
43 #include "ardour/audio_diskstream.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/audioplaylist.h"
46 #include "ardour/chan_count.h"
47 #include "ardour/session_directory.h"
48 #include "ardour/source_factory.h"
49 #include "ardour/audiofilesource.h"
50 #include "ardour/session.h"
51
52 #include "i18n.h"
53
54 using namespace std;
55 using namespace ARDOUR;
56 using namespace PBD;
57 using namespace Gtk;
58
59 void
60 Editor::export_audio ()
61 {
62         ExportDialog dialog (*this, _("Export"));
63         dialog.set_session (_session);
64         dialog.run();
65 }
66
67 void
68 Editor::export_selection ()
69 {
70         ExportSelectionDialog dialog (*this);
71         dialog.set_session (_session);
72         dialog.run();
73 }
74
75 void
76 Editor::export_range ()
77 {
78         Marker* marker;
79
80         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
81                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
82                 /*NOTREACHED*/
83         }
84
85         Location* l;
86         bool is_start;
87
88         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
89                 ExportRangeDialog dialog (*this, l->id().to_s());
90                 dialog.set_session (_session);
91                 dialog.run();
92         }
93 }
94
95 /** Export the first selected region */
96 void
97 Editor::export_region ()
98 {
99         if (selection->regions.empty()) {
100                 return;
101         }
102
103         try {
104                 boost::shared_ptr<Region> r = selection->regions.front()->region();
105                 AudioRegion & region (dynamic_cast<AudioRegion &> (*r));
106
107                 RouteTimeAxisView & rtv (dynamic_cast<RouteTimeAxisView &> (selection->regions.front()->get_time_axis_view()));
108                 AudioTrack & track (dynamic_cast<AudioTrack &> (*rtv.route()));
109
110                 ExportRegionDialog dialog (*this, region, track);
111                 dialog.set_session (_session);
112                 dialog.run();
113
114         } catch (std::bad_cast & e) {
115                 error << "Exporting Region failed!" << endmsg;
116                 return;
117         }
118 }
119
120 int
121 Editor::write_region_selection (RegionSelection& regions)
122 {
123         for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
124                 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*i);
125                 if (arv) {
126                         if (write_region ("", arv->audio_region()) == false)
127                                 return -1;
128                 }
129
130                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
131                 if (mrv) {
132                         warning << "MIDI region export not implemented" << endmsg;
133                 }
134         }
135
136         return 0;
137 }
138
139 void
140 Editor::bounce_region_selection ()
141 {
142         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
143
144                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
145                 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (rtv->route());
146
147                 if (!track->bounceable()) {
148                         MessageDialog d (
149                                 _("One or more of the selected regions' tracks cannot be bounced because it has more outputs than inputs.  "
150                                   "You can fix this by increasing the number of inputs on that track.")
151                                 );
152                         d.set_title (_("Cannot bounce"));
153                         d.run ();
154                         return;
155                 }
156         }
157
158         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
159
160                 boost::shared_ptr<Region> region ((*i)->region());
161                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
162                 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (rtv->route());
163
164                 InterThreadInfo itt;
165
166                 boost::shared_ptr<Region> r = track->bounce_range (region->position(), region->position() + region->length(), itt);
167                 cerr << "Result of bounce of "
168                      << region->name() << " len = " << region->length()
169                      << " was "
170                      << r->name() << " len = " << r->length()
171                      << endl;
172         }
173 }
174
175 bool
176 Editor::write_region (string path, boost::shared_ptr<AudioRegion> region)
177 {
178         boost::shared_ptr<AudioFileSource> fs;
179         const framepos_t chunk_size = 4096;
180         framepos_t to_read;
181         Sample buf[chunk_size];
182         gain_t gain_buffer[chunk_size];
183         framepos_t pos;
184         char s[PATH_MAX+1];
185         uint32_t cnt;
186         vector<boost::shared_ptr<AudioFileSource> > sources;
187         uint32_t nchans;
188
189         const string sound_directory = _session->session_directory().sound_path().to_string();
190
191         nchans = region->n_channels();
192
193         /* don't do duplicate of the entire source if that's what is going on here */
194
195         if (region->start() == 0 && region->length() == region->source_length(0)) {
196                 /* XXX should link(2) to create a new inode with "path" */
197                 return true;
198         }
199
200         if (path.length() == 0) {
201
202                 for (uint32_t n=0; n < nchans; ++n) {
203
204                         for (cnt = 0; cnt < 999999; ++cnt) {
205                                 if (nchans == 1) {
206                                         snprintf (s, sizeof(s), "%s/%s_%" PRIu32 ".wav", sound_directory.c_str(),
207                                                   legalize_for_path(region->name()).c_str(), cnt);
208                                 }
209                                 else {
210                                         snprintf (s, sizeof(s), "%s/%s_%" PRIu32 "-%" PRId32 ".wav", sound_directory.c_str(),
211                                                   legalize_for_path(region->name()).c_str(), cnt, n);
212                                 }
213
214                                 path = s;
215
216                                 if (::access (path.c_str(), F_OK) != 0) {
217                                         break;
218                                 }
219                         }
220
221                         if (cnt == 999999) {
222                                 error << "" << endmsg;
223                                 goto error_out;
224                         }
225
226
227
228                         try {
229                                 fs = boost::dynamic_pointer_cast<AudioFileSource> (
230                                         SourceFactory::createWritable (DataType::AUDIO, *_session,
231                                                                        path, string(), true,
232                                                                        false, _session->frame_rate()));
233                         }
234
235                         catch (failed_constructor& err) {
236                                 goto error_out;
237                         }
238
239                         sources.push_back (fs);
240                 }
241         }
242         else {
243                 /* TODO: make filesources based on passed path */
244
245         }
246
247         to_read = region->length();
248         pos = region->position();
249
250         while (to_read) {
251                 framepos_t this_time;
252
253                 this_time = min (to_read, chunk_size);
254
255                 for (vector<boost::shared_ptr<AudioFileSource> >::iterator src=sources.begin(); src != sources.end(); ++src) {
256
257                         fs = (*src);
258
259                         if (region->read_at (buf, buf, gain_buffer, pos, this_time) != this_time) {
260                                 break;
261                         }
262
263                         if (fs->write (buf, this_time) != this_time) {
264                                 error << "" << endmsg;
265                                 goto error_out;
266                         }
267                 }
268
269                 to_read -= this_time;
270                 pos += this_time;
271         }
272
273         time_t tnow;
274         struct tm* now;
275         time (&tnow);
276         now = localtime (&tnow);
277
278         for (vector<boost::shared_ptr<AudioFileSource> >::iterator src = sources.begin(); src != sources.end(); ++src) {
279                 (*src)->update_header (0, *now, tnow);
280                 (*src)->mark_immutable ();
281         }
282
283         return true;
284
285 error_out:
286
287         for (vector<boost::shared_ptr<AudioFileSource> >::iterator i = sources.begin(); i != sources.end(); ++i) {
288                 (*i)->mark_for_remove ();
289         }
290
291         return 0;
292 }
293
294 int
295 Editor::write_audio_selection (TimeSelection& ts)
296 {
297         int ret = 0;
298
299         if (selection->tracks.empty()) {
300                 return 0;
301         }
302
303         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
304
305                 AudioTimeAxisView* atv;
306
307                 if ((atv = dynamic_cast<AudioTimeAxisView*>(*i)) == 0) {
308                         continue;
309                 }
310
311                 if (atv->is_audio_track()) {
312
313                         boost::shared_ptr<AudioPlaylist> playlist = boost::dynamic_pointer_cast<AudioPlaylist>(atv->track()->playlist());
314
315                         if (playlist && write_audio_range (*playlist, atv->track()->n_channels(), ts) == 0) {
316                                 ret = -1;
317                                 break;
318                         }
319                 }
320         }
321
322         return ret;
323 }
324
325 bool
326 Editor::write_audio_range (AudioPlaylist& playlist, const ChanCount& count, list<AudioRange>& range)
327 {
328         boost::shared_ptr<AudioFileSource> fs;
329         const framepos_t chunk_size = 4096;
330         framepos_t nframes;
331         Sample buf[chunk_size];
332         gain_t gain_buffer[chunk_size];
333         framepos_t pos;
334         char s[PATH_MAX+1];
335         uint32_t cnt;
336         string path;
337         vector<boost::shared_ptr<AudioFileSource> > sources;
338
339         const string sound_directory = _session->session_directory().sound_path().to_string();
340
341         uint32_t channels = count.n_audio();
342
343         for (uint32_t n=0; n < channels; ++n) {
344
345                 for (cnt = 0; cnt < 999999; ++cnt) {
346                         if (channels == 1) {
347                                 snprintf (s, sizeof(s), "%s/%s_%" PRIu32 ".wav", sound_directory.c_str(),
348                                           legalize_for_path(playlist.name()).c_str(), cnt);
349                         }
350                         else {
351                                 snprintf (s, sizeof(s), "%s/%s_%" PRIu32 "-%" PRId32 ".wav", sound_directory.c_str(),
352                                           legalize_for_path(playlist.name()).c_str(), cnt, n);
353                         }
354
355                         if (::access (s, F_OK) != 0) {
356                                 break;
357                         }
358                 }
359
360                 if (cnt == 999999) {
361                         error << "" << endmsg;
362                         goto error_out;
363                 }
364
365                 path = s;
366
367                 try {
368                         fs = boost::dynamic_pointer_cast<AudioFileSource> (
369                                 SourceFactory::createWritable (DataType::AUDIO, *_session,
370                                                                path, string(), true,
371                                                                false, _session->frame_rate()));
372                 }
373
374                 catch (failed_constructor& err) {
375                         goto error_out;
376                 }
377
378                 sources.push_back (fs);
379
380         }
381
382
383         for (list<AudioRange>::iterator i = range.begin(); i != range.end();) {
384
385                 nframes = (*i).length();
386                 pos = (*i).start;
387
388                 while (nframes) {
389                         framepos_t this_time;
390
391                         this_time = min (nframes, chunk_size);
392
393                         for (uint32_t n=0; n < channels; ++n) {
394
395                                 fs = sources[n];
396
397                                 if (playlist.read (buf, buf, gain_buffer, pos, this_time, n) != this_time) {
398                                         break;
399                                 }
400
401                                 if (fs->write (buf, this_time) != this_time) {
402                                         goto error_out;
403                                 }
404                         }
405
406                         nframes -= this_time;
407                         pos += this_time;
408                 }
409
410                 list<AudioRange>::iterator tmp = i;
411                 ++tmp;
412
413                 if (tmp != range.end()) {
414
415                         /* fill gaps with silence */
416
417                         nframes = (*tmp).start - (*i).end;
418
419                         while (nframes) {
420
421                                 framepos_t this_time = min (nframes, chunk_size);
422                                 memset (buf, 0, sizeof (Sample) * this_time);
423
424                                 for (uint32_t n=0; n < channels; ++n) {
425
426                                         fs = sources[n];
427                                         if (fs->write (buf, this_time) != this_time) {
428                                                 goto error_out;
429                                         }
430                                 }
431
432                                 nframes -= this_time;
433                         }
434                 }
435
436                 i = tmp;
437         }
438
439         time_t tnow;
440         struct tm* now;
441         time (&tnow);
442         now = localtime (&tnow);
443
444         for (vector<boost::shared_ptr<AudioFileSource> >::iterator s = sources.begin(); s != sources.end(); ++s) {
445                 (*s)->update_header (0, *now, tnow);
446                 (*s)->mark_immutable ();
447                 // do we need to ref it again?
448         }
449
450         return true;
451
452 error_out:
453         /* unref created files */
454
455         for (vector<boost::shared_ptr<AudioFileSource> >::iterator i = sources.begin(); i != sources.end(); ++i) {
456                 (*i)->mark_for_remove ();
457         }
458
459         return false;
460 }
461
462 void
463 Editor::write_selection ()
464 {
465         if (!selection->time.empty()) {
466                 write_audio_selection (selection->time);
467         } else if (!selection->regions.empty()) {
468                 write_region_selection (selection->regions);
469         }
470 }