Fix angle bracket project-local include paths.
[ardour2.git] / libs / ardour / export_processor.cc
blobd36ef9f18ab6994bb788e12733cfd034169e3e87
1 /*
2 Copyright (C) 2008 Paul Davis
3 Author: Sakari Bergen
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"
34 #include "i18n.h"
36 using namespace PBD;
38 namespace ARDOUR
41 sigc::signal<void, Glib::ustring> ExportProcessor::WritingFile;
43 ExportProcessor::ExportProcessor (Session & session) :
44 session (session),
45 status (session.get_export_status()),
46 blocksize (session.get_block_size()),
47 frame_rate (session.frame_rate())
49 reset ();
52 ExportProcessor::~ExportProcessor ()
57 void
58 ExportProcessor::reset ()
60 file_sinks.clear();
61 writer_list.clear();
62 filename.reset();
63 normalizer.reset();
64 src.reset();
65 peak_reader.reset();
66 temp_file.reset();
69 int
70 ExportProcessor::prepare (FormatPtr format, FilenamePtr fname, uint32_t chans, bool split, nframes_t start)
72 status->format++;
73 temp_file_length = 0;
75 /* Reset just to be sure all references are dropped */
77 reset();
79 /* Get parameters needed later on */
81 channels = chans;
82 split_files = split;
83 filename = fname;
84 tag = format->tag();
85 broadcast_info = format->has_broadcast_info();
86 normalize = format->normalize();
87 trim_beginning = format->trim_beginning();
88 trim_end = format->trim_end();
89 silence_beginning = format->silence_beginning();
90 silence_end = format->silence_end();
92 /* SRC */
94 src.reset (new SampleRateConverter (channels, frame_rate, format->sample_rate(), format->src_quality()));
96 /* Construct export pipe to temp file */
98 status->stage = export_PostProcess;
100 if (normalize) {
101 /* Normalizing => we need a normalizer, peak reader and tempfile */
103 normalizer.reset (new Normalizer (channels, format->normalize_target()));
105 peak_reader.reset (new PeakReader (channels));
106 temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
108 src->pipe_to (peak_reader);
109 peak_reader->pipe_to (temp_file);
111 } else if (trim_beginning || trim_end) {
112 /* Not normalizing, but silence will be trimmed => need for a tempfile */
114 temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
115 src->pipe_to (temp_file);
117 } else {
118 /* Due to complexity and time running out, a tempfile will be created for this also... */
120 temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
121 src->pipe_to (temp_file);
124 /* Ensure directory exists */
126 sys::path folder (filename->get_folder());
127 if (!sys::exists (folder)) {
128 if (!sys::create_directory (folder)) {
129 throw ExportFailed (X_("sys::create_directory failed for export dir"));
133 /* prep file sinks */
135 if (split) {
136 filename->include_channel = true;
137 for (uint32_t chn = 1; chn <= channels; ++chn) {
138 filename->set_channel (chn);
139 ExportFileFactory::FilePair pair = ExportFileFactory::create (format, 1, filename->get_path (format));
140 file_sinks.push_back (pair.first);
141 writer_list.push_back (pair.second);
142 WritingFile (filename->get_path (format));
145 } else {
146 ExportFileFactory::FilePair pair = ExportFileFactory::create (format, channels, filename->get_path (format));
147 file_sinks.push_back (pair.first);
148 writer_list.push_back (pair.second);
149 WritingFile (filename->get_path (format));
152 /* Set position info */
154 nframes_t start_position = ((double) format->sample_rate() / frame_rate) * start + 0.5;
156 for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
157 (*it)->set_position (start_position);
160 /* set broadcast info if necessary */
162 if (broadcast_info) {
163 for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
165 BroadcastInfo bci;
166 bci.set_from_session (session, (*it)->position());
168 boost::shared_ptr<SndfileWriterBase> sndfile_ptr;
169 if ((sndfile_ptr = boost::dynamic_pointer_cast<SndfileWriterBase> (*it))) {
170 if (!bci.write_to_file (sndfile_ptr->get_sndfile())) {
171 std::cerr << bci.get_error() << std::endl;
173 } else {
174 if (!bci.write_to_file ((*it)->filename())) {
175 std::cerr << bci.get_error() << std::endl;
181 return 0;
184 nframes_t
185 ExportProcessor::process (float * data, nframes_t frames)
187 nframes_t frames_written = src->write (data, frames);
188 temp_file_length += frames_written;
189 return frames_written;
192 void
193 ExportProcessor::prepare_post_processors ()
195 /* Set end of input and do last write */
196 float dummy;
197 src->set_end_of_input ();
198 src->write (&dummy, 0);
200 /* Trim and add silence */
202 temp_file->trim_beginning (trim_beginning);
203 temp_file->trim_end (trim_end);
205 temp_file->set_silence_beginning (silence_beginning);
206 temp_file->set_silence_end (silence_end);
208 /* Set up normalizer */
210 if (normalize) {
211 normalizer->set_peak (peak_reader->get_peak ());
215 void
216 ExportProcessor::write_files ()
218 /* Write to disk */
220 status->stage = export_Write;
221 temp_file_position = 0;
223 uint32_t buffer_size = 4096; // TODO adjust buffer size?
224 float * buf = new float[channels * buffer_size];
225 int frames_read;
227 FloatSinkPtr disk_sink;
229 if (normalize) {
230 disk_sink = boost::dynamic_pointer_cast<FloatSink> (normalizer);
231 normalizer->pipe_to (file_sinks[0]);
232 } else {
233 disk_sink = file_sinks[0];
236 if (split_files) {
238 /* Get buffers for each channel separately */
240 std::vector<float *> chan_bufs;
242 for (uint32_t i = 0; i < channels; ++i) {
243 chan_bufs.push_back(new float[buffer_size]);
246 /* de-interleave and write files */
248 while ((frames_read = temp_file->read (buf, buffer_size)) > 0) {
249 for (uint32_t channel = 0; channel < channels; ++channel) {
250 for (uint32_t i = 0; i < buffer_size; ++i) {
251 chan_bufs[channel][i] = buf[channel + (channels * i)];
253 if (normalize) {
254 normalizer->pipe_to (file_sinks[channel]);
255 } else {
256 disk_sink = file_sinks[channel];
258 disk_sink->write (chan_bufs[channel], frames_read);
261 if (status->aborted()) { break; }
262 temp_file_position += frames_read;
263 status->progress = (float) temp_file_position / temp_file_length;
266 /* Clean up */
268 for (std::vector<float *>::iterator it = chan_bufs.begin(); it != chan_bufs.end(); ++it) {
269 delete[] *it;
272 } else {
273 while ((frames_read = temp_file->read (buf, buffer_size)) > 0) {
274 disk_sink->write (buf, frames_read);
276 if (status->aborted()) { break; }
277 temp_file_position += frames_read;
278 status->progress = (float) temp_file_position / temp_file_length;
282 delete [] buf;
284 /* Tag files if necessary and send exported signal */
287 for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
288 if (tag) {
289 AudiofileTagger::tag_file ((*it)->filename(), session.metadata());
291 session.Exported ((*it)->filename(), session.name());
295 }; // namespace ARDOUR