2 Copyright (C) 2001 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 /* Note: public Editor methods are documented in public_editor.h */
22 #define __STDC_FORMAT_MACROS 1
27 #include <gtkmm/messagedialog.h>
29 #include "export_dialog.h"
31 #include "public_editor.h"
32 #include "selection.h"
33 #include "time_axis_view.h"
34 #include "audio_time_axis.h"
35 #include "audio_region_view.h"
36 #include "midi_region_view.h"
38 #include "pbd/pthread_utils.h"
39 #include "ardour/types.h"
40 #include "ardour/audio_track.h"
41 #include "ardour/audiofilesource.h"
42 #include "ardour/audio_diskstream.h"
43 #include "ardour/audioregion.h"
44 #include "ardour/audioplaylist.h"
45 #include "ardour/chan_count.h"
46 #include "ardour/session_directory.h"
47 #include "ardour/source_factory.h"
48 #include "ardour/audiofilesource.h"
49 #include "ardour/session.h"
54 using namespace ARDOUR
;
59 Editor::export_audio ()
61 ExportDialog
dialog (*this, _("Export"));
62 dialog
.set_session (_session
);
67 Editor::export_selection ()
69 ExportSelectionDialog
dialog (*this);
70 dialog
.set_session (_session
);
75 Editor::export_range ()
79 if ((marker
= reinterpret_cast<Marker
*> (marker_menu_item
->get_data ("marker"))) == 0) {
80 fatal
<< _("programming error: marker canvas item has no marker object pointer!") << endmsg
;
87 if (((l
= find_location_from_marker (marker
, is_start
)) != 0) && (l
->end() > l
->start())) {
88 ExportRangeDialog
dialog (*this, l
->id().to_s());
89 dialog
.set_session (_session
);
94 /** Export the first selected region */
96 Editor::export_region ()
98 if (selection
->regions
.empty()) {
103 boost::shared_ptr
<Region
> r
= selection
->regions
.front()->region();
104 AudioRegion
& region (dynamic_cast<AudioRegion
&> (*r
));
106 RouteTimeAxisView
& rtv (dynamic_cast<RouteTimeAxisView
&> (selection
->regions
.front()->get_time_axis_view()));
107 AudioTrack
& track (dynamic_cast<AudioTrack
&> (*rtv
.route()));
109 ExportRegionDialog
dialog (*this, region
, track
);
110 dialog
.set_session (_session
);
113 } catch (std::bad_cast
& e
) {
114 error
<< "Exporting Region failed!" << endmsg
;
120 Editor::write_region_selection (RegionSelection
& regions
)
122 for (RegionSelection::iterator i
= regions
.begin(); i
!= regions
.end(); ++i
) {
123 AudioRegionView
* arv
= dynamic_cast<AudioRegionView
*>(*i
);
125 if (write_region ("", arv
->audio_region()) == false)
129 MidiRegionView
* mrv
= dynamic_cast<MidiRegionView
*>(*i
);
131 warning
<< "MIDI region export not implemented" << endmsg
;
139 Editor::bounce_region_selection ()
141 for (RegionSelection::iterator i
= selection
->regions
.begin(); i
!= selection
->regions
.end(); ++i
) {
143 boost::shared_ptr
<Region
> region ((*i
)->region());
144 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*>(&(*i
)->get_time_axis_view());
145 Track
* track
= dynamic_cast<Track
*>(rtv
->route().get());
149 boost::shared_ptr
<Region
> r
= track
->bounce_range (region
->position(), region
->position() + region
->length(), itt
);
150 cerr
<< "Result of bounce of "
151 << region
->name() << " len = " << region
->length()
153 << r
->name() << " len = " << r
->length()
159 Editor::write_region (string path
, boost::shared_ptr
<AudioRegion
> region
)
161 boost::shared_ptr
<AudioFileSource
> fs
;
162 const nframes64_t chunk_size
= 4096;
164 Sample buf
[chunk_size
];
165 gain_t gain_buffer
[chunk_size
];
169 vector
<boost::shared_ptr
<AudioFileSource
> > sources
;
172 const string sound_directory
= _session
->session_directory().sound_path().to_string();
174 nchans
= region
->n_channels();
176 /* don't do duplicate of the entire source if that's what is going on here */
178 if (region
->start() == 0 && region
->length() == region
->source_length(0)) {
179 /* XXX should link(2) to create a new inode with "path" */
183 if (path
.length() == 0) {
185 for (uint32_t n
=0; n
< nchans
; ++n
) {
187 for (cnt
= 0; cnt
< 999999; ++cnt
) {
189 snprintf (s
, sizeof(s
), "%s/%s_%" PRIu32
".wav", sound_directory
.c_str(),
190 legalize_for_path(region
->name()).c_str(), cnt
);
193 snprintf (s
, sizeof(s
), "%s/%s_%" PRIu32
"-%" PRId32
".wav", sound_directory
.c_str(),
194 legalize_for_path(region
->name()).c_str(), cnt
, n
);
199 if (::access (path
.c_str(), F_OK
) != 0) {
205 error
<< "" << endmsg
;
212 fs
= boost::dynamic_pointer_cast
<AudioFileSource
> (
213 SourceFactory::createWritable (DataType::AUDIO
, *_session
,
215 false, _session
->frame_rate()));
218 catch (failed_constructor
& err
) {
222 sources
.push_back (fs
);
226 /* TODO: make filesources based on passed path */
230 to_read
= region
->length();
231 pos
= region
->position();
234 nframes64_t this_time
;
236 this_time
= min (to_read
, chunk_size
);
238 for (vector
<boost::shared_ptr
<AudioFileSource
> >::iterator src
=sources
.begin(); src
!= sources
.end(); ++src
) {
242 if (region
->read_at (buf
, buf
, gain_buffer
, pos
, this_time
) != this_time
) {
246 if (fs
->write (buf
, this_time
) != this_time
) {
247 error
<< "" << endmsg
;
252 to_read
-= this_time
;
259 now
= localtime (&tnow
);
261 for (vector
<boost::shared_ptr
<AudioFileSource
> >::iterator src
= sources
.begin(); src
!= sources
.end(); ++src
) {
262 (*src
)->update_header (0, *now
, tnow
);
263 (*src
)->mark_immutable ();
270 for (vector
<boost::shared_ptr
<AudioFileSource
> >::iterator i
= sources
.begin(); i
!= sources
.end(); ++i
) {
271 (*i
)->mark_for_remove ();
278 Editor::write_audio_selection (TimeSelection
& ts
)
282 if (selection
->tracks
.empty()) {
286 for (TrackSelection::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
288 AudioTimeAxisView
* atv
;
290 if ((atv
= dynamic_cast<AudioTimeAxisView
*>(*i
)) == 0) {
294 if (atv
->is_audio_track()) {
296 boost::shared_ptr
<AudioPlaylist
> playlist
= boost::dynamic_pointer_cast
<AudioPlaylist
>(atv
->track()->playlist());
298 if (playlist
&& write_audio_range (*playlist
, atv
->track()->n_channels(), ts
) == 0) {
309 Editor::write_audio_range (AudioPlaylist
& playlist
, const ChanCount
& count
, list
<AudioRange
>& range
)
311 boost::shared_ptr
<AudioFileSource
> fs
;
312 const nframes64_t chunk_size
= 4096;
314 Sample buf
[chunk_size
];
315 gain_t gain_buffer
[chunk_size
];
320 vector
<boost::shared_ptr
<AudioFileSource
> > sources
;
322 const string sound_directory
= _session
->session_directory().sound_path().to_string();
324 uint32_t channels
= count
.n_audio();
326 for (uint32_t n
=0; n
< channels
; ++n
) {
328 for (cnt
= 0; cnt
< 999999; ++cnt
) {
330 snprintf (s
, sizeof(s
), "%s/%s_%" PRIu32
".wav", sound_directory
.c_str(),
331 legalize_for_path(playlist
.name()).c_str(), cnt
);
334 snprintf (s
, sizeof(s
), "%s/%s_%" PRIu32
"-%" PRId32
".wav", sound_directory
.c_str(),
335 legalize_for_path(playlist
.name()).c_str(), cnt
, n
);
338 if (::access (s
, F_OK
) != 0) {
344 error
<< "" << endmsg
;
351 fs
= boost::dynamic_pointer_cast
<AudioFileSource
> (
352 SourceFactory::createWritable (DataType::AUDIO
, *_session
,
354 false, _session
->frame_rate()));
357 catch (failed_constructor
& err
) {
361 sources
.push_back (fs
);
366 for (list
<AudioRange
>::iterator i
= range
.begin(); i
!= range
.end();) {
368 nframes
= (*i
).length();
372 nframes64_t this_time
;
374 this_time
= min (nframes
, chunk_size
);
376 for (uint32_t n
=0; n
< channels
; ++n
) {
380 if (playlist
.read (buf
, buf
, gain_buffer
, pos
, this_time
, n
) != this_time
) {
384 if (fs
->write (buf
, this_time
) != this_time
) {
389 nframes
-= this_time
;
393 list
<AudioRange
>::iterator tmp
= i
;
396 if (tmp
!= range
.end()) {
398 /* fill gaps with silence */
400 nframes
= (*tmp
).start
- (*i
).end
;
404 nframes64_t this_time
= min (nframes
, chunk_size
);
405 memset (buf
, 0, sizeof (Sample
) * this_time
);
407 for (uint32_t n
=0; n
< channels
; ++n
) {
410 if (fs
->write (buf
, this_time
) != this_time
) {
415 nframes
-= this_time
;
425 now
= localtime (&tnow
);
427 for (vector
<boost::shared_ptr
<AudioFileSource
> >::iterator s
= sources
.begin(); s
!= sources
.end(); ++s
) {
428 (*s
)->update_header (0, *now
, tnow
);
429 (*s
)->mark_immutable ();
430 // do we need to ref it again?
436 /* unref created files */
438 for (vector
<boost::shared_ptr
<AudioFileSource
> >::iterator i
= sources
.begin(); i
!= sources
.end(); ++i
) {
439 (*i
)->mark_for_remove ();
446 Editor::write_selection ()
448 if (!selection
->time
.empty()) {
449 write_audio_selection (selection
->time
);
450 } else if (!selection
->regions
.empty()) {
451 write_region_selection (selection
->regions
);