change the way thread name is managed and accessed; store thread name for JACK thread...
[ardour.git] / libs / ardour / export_processor.cc
1 /*
2     Copyright (C) 2008 Paul Davis
3     Author: Sakari Bergen
4
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.
9
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.
14
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.
18
19 */
20
21 #include "ardour/export_processor.h"
22
23 #include "pbd/error.h"
24 #include "pbd/filesystem.h"
25
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
34 #include "i18n.h"
35
36 using namespace PBD;
37
38 namespace ARDOUR
39 {
40
41 PBD::Signal1<void,const Glib::ustring&> ExportProcessor::WritingFile;
42
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())
48 {
49         reset ();
50 }
51
52 ExportProcessor::~ExportProcessor ()
53 {
54
55 }
56
57 void
58 ExportProcessor::reset ()
59 {
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();
67 }
68
69 int
70 ExportProcessor::prepare (FormatPtr format, FilenamePtr fname, uint32_t chans, bool split, nframes_t start)
71 {
72         status->format++;
73         temp_file_length = 0;
74
75         /* Reset just to be sure all references are dropped */
76
77         reset();
78
79         /* Get parameters needed later on */
80
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();
91
92         /* SRC */
93
94         src.reset (new SampleRateConverter (channels, frame_rate, format->sample_rate(), format->src_quality()));
95
96         /* Construct export pipe to temp file */
97
98         status->stage = export_PostProcess;
99
100         if (normalize) {
101                 /* Normalizing => we need a normalizer, peak reader and tempfile */
102
103                 normalizer.reset (new Normalizer (channels, format->normalize_target()));
104
105                 peak_reader.reset (new PeakReader (channels));
106                 temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
107
108                 src->pipe_to (peak_reader);
109                 peak_reader->pipe_to (temp_file);
110
111         } else if (trim_beginning || trim_end) {
112                 /* Not normalizing, but silence will be trimmed => need for a tempfile */
113
114                 temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
115                 src->pipe_to (temp_file);
116
117         } else {
118                 /* Due to complexity and time running out, a tempfile will be created for this also... */
119
120                 temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
121                 src->pipe_to (temp_file);
122         }
123
124         /* Ensure directory exists */
125
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"));
130                 }
131         }
132
133         /* prep file sinks */
134
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));
143                 }
144
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));
150         }
151
152         /* Set position info */
153
154         nframes_t start_position = ((double) format->sample_rate() / frame_rate) * start + 0.5;
155
156         for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
157                 (*it)->set_position (start_position);
158         }
159
160         /* set broadcast info if necessary */
161
162         if (broadcast_info) {
163                 for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
164
165                         BroadcastInfo bci;
166                         bci.set_from_session (session, (*it)->position());
167
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;
172                                 }
173                         } else {
174                                 if (!bci.write_to_file ((*it)->filename())) {
175                                         std::cerr << bci.get_error() << std::endl;
176                                 }
177                         }
178                 }
179         }
180
181         return 0;
182 }
183
184 nframes_t
185 ExportProcessor::process (float * data, nframes_t frames)
186 {
187         nframes_t frames_written = src->write (data, frames);
188         temp_file_length += frames_written;
189         return frames_written;
190 }
191
192 void
193 ExportProcessor::prepare_post_processors ()
194 {
195         /* Set end of input and do last write */
196         float  dummy;
197         src->set_end_of_input ();
198         src->write (&dummy, 0);
199
200         /* Trim and add silence */
201
202         temp_file->trim_beginning (trim_beginning);
203         temp_file->trim_end (trim_end);
204
205         temp_file->set_silence_beginning (silence_beginning);
206         temp_file->set_silence_end (silence_end);
207
208         /* Set up normalizer */
209
210         if (normalize) {
211                 normalizer->set_peak (peak_reader->get_peak ());
212         }
213 }
214
215 void
216 ExportProcessor::write_files ()
217 {
218         /* Write to disk */
219
220         status->stage = export_Write;
221         temp_file_position = 0;
222
223         uint32_t buffer_size = 4096; // TODO adjust buffer size?
224         float * buf = new float[channels * buffer_size];
225         int frames_read;
226
227         FloatSinkPtr disk_sink;
228
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];
234         }
235
236         if (split_files) {
237
238                 /* Get buffers for each channel separately */
239
240                 std::vector<float *> chan_bufs;
241
242                 for (uint32_t i = 0; i < channels; ++i) {
243                         chan_bufs.push_back(new float[buffer_size]);
244                 }
245
246                 /* de-interleave and write files */
247
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)];
252                                 }
253                                 if (normalize) {
254                                         normalizer->pipe_to (file_sinks[channel]);
255                                 } else {
256                                         disk_sink = file_sinks[channel];
257                                 }
258                                 disk_sink->write (chan_bufs[channel], frames_read);
259                         }
260
261                         if (status->aborted()) { break; }
262                         temp_file_position += frames_read;
263                         status->progress = (float) temp_file_position / temp_file_length;
264                 }
265
266                 /* Clean up */
267
268                 for (std::vector<float *>::iterator it = chan_bufs.begin(); it != chan_bufs.end(); ++it) {
269                         delete[] *it;
270                 }
271
272         } else {
273                 while ((frames_read = temp_file->read (buf, buffer_size)) > 0) {
274                         disk_sink->write (buf, frames_read);
275
276                         if (status->aborted()) { break; }
277                         temp_file_position += frames_read;
278                         status->progress = (float) temp_file_position / temp_file_length;
279                 }
280         }
281
282         delete [] buf;
283
284         /* Tag files if necessary and send exported signal */
285
286
287         for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
288                 if (tag) {
289                         AudiofileTagger::tag_file ((*it)->filename(), session.metadata());
290                 }
291                 session.Exported ((*it)->filename(), session.name());
292         }
293 }
294
295 }; // namespace ARDOUR