2 Copyright (C) 2008 Paul Davis
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <ardour/export_processor.h>
23 #include <pbd/error.h>
24 #include <pbd/filesystem.h>
26 #include <ardour/session.h>
27 #include <ardour/audiofile_tagger.h>
28 #include <ardour/broadcast_info.h>
29 #include <ardour/export_failed.h>
30 #include <ardour/export_filename.h>
31 #include <ardour/export_status.h>
32 #include <ardour/export_format_specification.h>
33 #include <ardour/sndfile_helpers.h>
42 sigc::signal<void, Glib::ustring> ExportProcessor::WritingFile;
44 ExportProcessor::ExportProcessor (Session & session) :
46 status (session.export_status),
47 blocksize (session.get_block_size()),
48 frame_rate (session.frame_rate())
53 ExportProcessor::~ExportProcessor ()
59 ExportProcessor::reset ()
71 ExportProcessor::prepare (FormatPtr format, FilenamePtr fname, uint32_t chans, bool split, nframes_t start)
73 session.export_status.format++;
76 /* Reset just to be sure all references are dropped */
80 /* Get parameters needed later on */
86 broadcast_info = format->has_broadcast_info();
87 normalize = format->normalize();
88 trim_beginning = format->trim_beginning();
89 trim_end = format->trim_end();
90 silence_beginning = format->silence_beginning();
91 silence_end = format->silence_end();
95 src.reset (new SampleRateConverter (channels, frame_rate, format->sample_rate(), format->src_quality()));
97 /* Construct export pipe to temp file */
99 status.stage = export_PostProcess;
102 /* Normalizing => we need a normalizer, peak reader and tempfile */
104 normalizer.reset (new Normalizer (channels, format->normalize_target()));
106 peak_reader.reset (new PeakReader (channels));
107 temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
109 src->pipe_to (peak_reader);
110 peak_reader->pipe_to (temp_file);
112 } else if (trim_beginning || trim_end) {
113 /* Not normalizing, but silence will be trimmed => need for a tempfile */
115 temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
116 src->pipe_to (temp_file);
119 /* Due to complexity and time running out, a tempfile will be created for this also... */
121 temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
122 src->pipe_to (temp_file);
127 FloatSinkPtr (ExportProcessor::*prep_function) (FormatPtr, uint32_t, ustring const &);
129 switch (format->type()) {
130 case ExportFormatBase::T_Sndfile:
131 prep_function = &ExportProcessor::prepare_sndfile_writer;
135 throw ExportFailed (_("Export failed due to a programming error"), "Invalid format given for ExportProcessor::prepare!");
140 /* Ensure directory exists */
142 sys::path folder (filename->get_folder());
143 if (!sys::exists (folder)) {
144 if (!sys::create_directory (folder)) {
145 throw ExportFailed ("Export could not create the directory you requested for", "sys::create_directory failed for export dir");
149 /* prep file sinks */
152 filename->include_channel = true;
153 for (uint32_t chn = 1; chn <= channels; ++chn) {
154 filename->set_channel (chn);
155 file_sinks.push_back ((this->*prep_function) (format, 1, filename->get_path (format)));
156 WritingFile (filename->get_path (format));
160 file_sinks.push_back ((this->*prep_function) (format, channels, filename->get_path (format)));
161 WritingFile (filename->get_path (format));
164 /* Set position info */
166 nframes_t start_position = ((double) format->sample_rate() / frame_rate) * start + 0.5;
168 for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
169 (*it)->set_position (start_position);
172 /* set broadcast info if necessary */
174 if (broadcast_info) {
175 for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
178 bci.set_from_session (session, (*it)->position());
180 boost::shared_ptr<SndfileWriterBase> sndfile_ptr;
181 if ((sndfile_ptr = boost::dynamic_pointer_cast<SndfileWriterBase> (*it))) {
182 if (!bci.write_to_file (sndfile_ptr->get_sndfile())) {
183 std::cerr << bci.get_error() << std::endl;
186 if (!bci.write_to_file ((*it)->filename())) {
187 std::cerr << bci.get_error() << std::endl;
197 ExportProcessor::process (float * data, nframes_t frames)
199 nframes_t frames_written = src->write (data, frames);
200 temp_file_length += frames_written;
201 return frames_written;
205 ExportProcessor::prepare_post_processors ()
207 /* Set end of input and do last write */
209 src->set_end_of_input ();
210 src->write (&dummy, 0);
212 /* Trim and add silence */
214 temp_file->trim_beginning (trim_beginning);
215 temp_file->trim_end (trim_end);
217 temp_file->set_silence_beginning (silence_beginning);
218 temp_file->set_silence_end (silence_end);
220 /* Set up normalizer */
223 normalizer->set_peak (peak_reader->get_peak ());
228 ExportProcessor::write_files ()
232 status.stage = export_Write;
233 temp_file_position = 0;
235 uint32_t buffer_size = 4096; // TODO adjust buffer size?
236 float * buf = new float[channels * buffer_size];
239 FloatSinkPtr disk_sink;
242 disk_sink = boost::dynamic_pointer_cast<FloatSink> (normalizer);
243 normalizer->pipe_to (file_sinks[0]);
245 disk_sink = file_sinks[0];
250 /* Get buffers for each channel separately */
252 std::vector<float *> chan_bufs;
254 for (uint32_t i = 0; i < channels; ++i) {
255 chan_bufs.push_back(new float[buffer_size]);
258 /* de-interleave and write files */
260 while ((frames_read = temp_file->read (buf, buffer_size)) > 0) {
261 for (uint32_t channel = 0; channel < channels; ++channel) {
262 for (uint32_t i = 0; i < buffer_size; ++i) {
263 chan_bufs[channel][i] = buf[channel + (channels * i)];
266 normalizer->pipe_to (file_sinks[channel]);
268 disk_sink = file_sinks[channel];
270 disk_sink->write (chan_bufs[channel], frames_read);
273 if (status.aborted()) { break; }
274 temp_file_position += frames_read;
275 status.progress = (float) temp_file_position / temp_file_length;
280 for (std::vector<float *>::iterator it = chan_bufs.begin(); it != chan_bufs.end(); ++it) {
285 while ((frames_read = temp_file->read (buf, buffer_size)) > 0) {
286 disk_sink->write (buf, frames_read);
288 if (status.aborted()) { break; }
289 temp_file_position += frames_read;
290 status.progress = (float) temp_file_position / temp_file_length;
296 /* Tag files if necessary and send exported signal */
299 for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
301 AudiofileTagger::tag_file ((*it)->filename(), session.metadata());
303 session.Exported ((*it)->filename(), session.name());
307 ExportProcessor::FloatSinkPtr
308 ExportProcessor::prepare_sndfile_writer (FormatPtr format, uint32_t channels, ustring const & filename)
310 int real_format = format->format_id() | format->sample_format() | format->endianness();
312 uint32_t data_width = sndfile_data_width (real_format);
314 if (data_width == 8 || data_width == 16) {
316 ShortConverterPtr sfc = ShortConverterPtr (new SampleFormatConverter<short> (channels, format->dither_type(), data_width));
317 ShortWriterPtr sfw = ShortWriterPtr (new SndfileWriter<short> (channels, format->sample_rate(), real_format, filename));
319 writer_list.push_back (boost::static_pointer_cast<ExportFileWriter> (sfw));
322 return boost::static_pointer_cast<FloatSink> (sfc);
324 } else if (data_width == 24 || data_width == 32) {
326 IntConverterPtr sfc = IntConverterPtr (new SampleFormatConverter<int> (channels, format->dither_type(), data_width));
327 IntWriterPtr sfw = IntWriterPtr (new SndfileWriter<int> (channels, format->sample_rate(), real_format, filename));
329 writer_list.push_back (boost::static_pointer_cast<ExportFileWriter> (sfw));
332 return boost::static_pointer_cast<FloatSink> (sfc);
336 FloatConverterPtr sfc = FloatConverterPtr (new SampleFormatConverter<float> (channels, format->dither_type(), data_width));
337 FloatWriterPtr sfw = FloatWriterPtr (new SndfileWriter<float> (channels, format->sample_rate(), real_format, filename));
339 writer_list.push_back (boost::static_pointer_cast<ExportFileWriter> (sfw));
342 return boost::static_pointer_cast<FloatSink> (sfc);
347 }; // namespace ARDOUR