changes from 2.X starting in march 2009 through oct 20 2009 (5826 inclusive)
[ardour.git] / libs / ardour / export_graph_builder.cc
1 #include "ardour/export_graph_builder.h"
2
3 #include "audiographer/process_context.h"
4 #include "audiographer/general/interleaver.h"
5 #include "audiographer/general/normalizer.h"
6 #include "audiographer/general/peak_reader.h"
7 #include "audiographer/general/sample_format_converter.h"
8 #include "audiographer/general/sr_converter.h"
9 #include "audiographer/general/silence_trimmer.h"
10 #include "audiographer/general/threader.h"
11 #include "audiographer/sndfile/tmp_file.h"
12 #include "audiographer/sndfile/sndfile_writer.h"
13
14 #include "ardour/audioengine.h"
15 #include "ardour/export_channel_configuration.h"
16 #include "ardour/export_filename.h"
17 #include "ardour/export_format_specification.h"
18 #include "ardour/sndfile_helpers.h"
19
20 #include "pbd/filesystem.h"
21
22 using namespace AudioGrapher;
23
24 namespace ARDOUR {
25
26 ExportGraphBuilder::ExportGraphBuilder (Session const & session)
27   : session (session)
28   , thread_pool (4) // FIXME thread amount to cores amount
29 {
30         process_buffer_frames = session.engine().frames_per_cycle();
31         process_buffer = new Sample[process_buffer_frames];
32 }
33
34 ExportGraphBuilder::~ExportGraphBuilder ()
35 {
36         delete [] process_buffer;
37 }
38
39 int
40 ExportGraphBuilder::process (nframes_t /* frames */, bool last_cycle)
41 {
42         for (ChannelMap::iterator it = channels.begin(); it != channels.end(); ++it) {
43                 it->first->read (process_buffer, process_buffer_frames);
44                 ProcessContext<Sample> context(process_buffer, process_buffer_frames, 1);
45                 if (last_cycle) { context.set_flag (ProcessContext<Sample>::EndOfInput); }
46                 it->second->process (context);
47         }
48         
49         return 0;
50 }
51
52 bool
53 ExportGraphBuilder::process_normalize ()
54 {
55         for (std::list<Normalizer *>::iterator it = normalizers.begin(); it != normalizers.end(); /* ++ in loop */) {
56                 if ((*it)->process()) {
57                         it = normalizers.erase (it);
58                 } else {
59                         ++it;
60                 }
61         }
62         
63         return normalizers.empty();
64 }
65
66 void
67 ExportGraphBuilder::reset ()
68 {
69         channel_configs.clear ();
70         channels.clear ();
71         normalizers.clear ();
72 }
73
74 void
75 ExportGraphBuilder::add_config (FileSpec const & config)
76 {
77         for (ChannelConfigList::iterator it = channel_configs.begin(); it != channel_configs.end(); ++it) {
78                 if (*it == config) {
79                         it->add_child (config);
80                         return;
81                 }
82         }
83         
84         // No duplicate channel config found, create new one
85         channel_configs.push_back (ChannelConfig (*this));
86         ChannelConfig & c_config (channel_configs.back());
87         c_config.init (config, channels);
88 }
89
90 /* Encoder */
91
92 template <>
93 boost::shared_ptr<AudioGrapher::Sink<Sample> >
94 ExportGraphBuilder::Encoder::init (FileSpec const & new_config)
95 {
96         config = new_config;
97         init_writer (float_writer);
98         return float_writer;
99 }
100
101 template <>
102 boost::shared_ptr<AudioGrapher::Sink<int> >
103 ExportGraphBuilder::Encoder::init (FileSpec const & new_config)
104 {
105         config = new_config;
106         init_writer (int_writer);
107         return int_writer;
108 }
109
110 template <>
111 boost::shared_ptr<AudioGrapher::Sink<short> >
112 ExportGraphBuilder::Encoder::init (FileSpec const & new_config)
113 {
114         config = new_config;
115         init_writer (short_writer);
116         return short_writer;
117 }
118
119 void
120 ExportGraphBuilder::Encoder::add_child (FileSpec const & new_config)
121 {
122         filenames.push_back (new_config.filename);
123 }
124
125 bool
126 ExportGraphBuilder::Encoder::operator== (FileSpec const & other_config) const
127 {
128         return get_real_format (config) == get_real_format (other_config);
129 }
130
131 int
132 ExportGraphBuilder::Encoder::get_real_format (FileSpec const & config)
133 {
134         ExportFormatSpecification & format = *config.format;
135         return format.format_id() | format.sample_format() | format.endianness();
136 }
137
138 template<typename T>
139 void
140 ExportGraphBuilder::Encoder::init_writer (boost::shared_ptr<AudioGrapher::SndfileWriter<T> > & writer)
141 {
142         unsigned channels = config.channel_config->get_n_chans();
143         int format = get_real_format (config);
144         Glib::ustring filename = config.filename->get_path (config.format);
145         
146         writer.reset (new AudioGrapher::SndfileWriter<T> (filename, format, channels, config.format->sample_rate()));
147         writer->FileWritten.connect (sigc::mem_fun (*this, &ExportGraphBuilder::Encoder::copy_files));
148 }
149
150 void
151 ExportGraphBuilder::Encoder::copy_files (std::string orig_path)
152 {
153         while (filenames.size()) {
154                 FilenamePtr & filename = filenames.front();
155                 PBD::sys::copy_file (orig_path, filename->get_path (config.format).c_str());
156                 filenames.pop_front();
157         }
158 }
159
160 /* SFC */
161
162 ExportGraphBuilder::FloatSinkPtr
163 ExportGraphBuilder::SFC::init (FileSpec const & new_config, nframes_t max_frames)
164 {
165         config = new_config;
166         data_width = sndfile_data_width (Encoder::get_real_format (config));
167         unsigned channels = new_config.channel_config->get_n_chans();
168         
169         if (data_width == 8 || data_width == 16) {
170                 short_converter = ShortConverterPtr (new SampleFormatConverter<short> (channels));
171                 short_converter->init (max_frames, config.format->dither_type(), data_width);
172                 add_child (config);
173                 return short_converter;
174         } else if (data_width == 24 || data_width == 32) {
175                 int_converter = IntConverterPtr (new SampleFormatConverter<int> (channels));
176                 int_converter->init (max_frames, config.format->dither_type(), data_width);
177                 add_child (config);
178                 return int_converter;
179         } else {
180                 float_converter = FloatConverterPtr (new SampleFormatConverter<Sample> (channels));
181                 float_converter->init (max_frames, config.format->dither_type(), data_width);
182                 add_child (config);
183                 return float_converter;
184         }
185 }
186
187 void
188 ExportGraphBuilder::SFC::add_child (FileSpec const & new_config)
189 {
190         for (std::list<Encoder>::iterator it = children.begin(); it != children.end(); ++it) {
191                 if (*it == new_config) {
192                         it->add_child (new_config);
193                         return;
194                 }
195         }
196         
197         children.push_back (Encoder());
198         Encoder & encoder = children.back();
199         
200         if (data_width == 8 || data_width == 16) {
201                 short_converter->add_output (encoder.init<short> (new_config));
202         } else if (data_width == 24 || data_width == 32) {
203                 int_converter->add_output (encoder.init<int> (new_config));
204         } else {
205                 float_converter->add_output (encoder.init<Sample> (new_config));
206         }
207 }
208
209 bool
210 ExportGraphBuilder::SFC::operator== (FileSpec const & other_config) const
211 {
212         return config.format->sample_format() == other_config.format->sample_format();
213 }
214
215 /* Normalizer */
216
217 ExportGraphBuilder::FloatSinkPtr
218 ExportGraphBuilder::Normalizer::init (FileSpec const & new_config, nframes_t /*max_frames*/)
219 {
220         config = new_config;
221         max_frames_out = 4086; // TODO good chunk size
222         
223         buffer.reset (new AllocatingProcessContext<Sample> (max_frames_out, config.channel_config->get_n_chans()));
224         peak_reader.reset (new PeakReader ());
225         normalizer.reset (new AudioGrapher::Normalizer (config.format->normalize_target()));
226         threader.reset (new Threader<Sample> (parent.thread_pool));
227         
228         normalizer->alloc_buffer (max_frames_out);
229         normalizer->add_output (threader);
230         
231         int format = ExportFormatBase::F_RAW | ExportFormatBase::SF_Float;
232         tmp_file.reset (new TmpFile<float> (format, config.channel_config->get_n_chans(), 
233                                             config.format->sample_rate()));
234         tmp_file->FileWritten.connect (sigc::hide (sigc::mem_fun (*this, &Normalizer::start_post_processing)));
235         
236         add_child (new_config);
237         
238         peak_reader->add_output (tmp_file);
239         return peak_reader;
240 }
241
242 void
243 ExportGraphBuilder::Normalizer::add_child (FileSpec const & new_config)
244 {
245         for (std::list<SFC>::iterator it = children.begin(); it != children.end(); ++it) {
246                 if (*it == new_config) {
247                         it->add_child (new_config);
248                         return;
249                 }
250         }
251         
252         children.push_back (SFC (parent));
253         threader->add_output (children.back().init (new_config, max_frames_out));
254 }
255
256 bool
257 ExportGraphBuilder::Normalizer::operator== (FileSpec const & other_config) const
258 {
259         return config.format->normalize() == other_config.format->normalize() &&
260                config.format->normalize_target() == other_config.format->normalize_target();
261 }
262
263 bool
264 ExportGraphBuilder::Normalizer::process()
265 {
266         nframes_t frames_read = tmp_file->read (*buffer);
267         return frames_read != buffer->frames();
268 }
269
270 void
271 ExportGraphBuilder::Normalizer::start_post_processing()
272 {
273         normalizer->set_peak (peak_reader->get_peak());
274         tmp_file->seek (0, SEEK_SET);
275         tmp_file->add_output (normalizer);
276         parent.normalizers.push_back (this);
277 }
278
279 /* SRC */
280
281 ExportGraphBuilder::FloatSinkPtr
282 ExportGraphBuilder::SRC::init (FileSpec const & new_config, nframes_t max_frames)
283 {
284         config = new_config;
285         converter.reset (new SampleRateConverter (new_config.channel_config->get_n_chans()));
286         ExportFormatSpecification & format = *new_config.format;
287         converter->init (parent.session.nominal_frame_rate(), format.sample_rate(), format.src_quality());
288         max_frames_out = converter->allocate_buffers (max_frames);
289         
290         add_child (new_config);
291         
292         return converter;
293 }
294
295 void
296 ExportGraphBuilder::SRC::add_child (FileSpec const & new_config)
297 {
298         if (new_config.format->normalize()) {
299                 add_child_to_list (new_config, normalized_children);
300         } else {
301                 add_child_to_list (new_config, children);
302         }
303 }
304
305 template<typename T>
306 void
307 ExportGraphBuilder::SRC::add_child_to_list (FileSpec const & new_config, std::list<T> & list)
308 {
309         for (typename std::list<T>::iterator it = list.begin(); it != list.end(); ++it) {
310                 if (*it == new_config) {
311                         it->add_child (new_config);
312                         return;
313                 }
314         }
315         
316         list.push_back (T (parent));
317         converter->add_output (list.back().init (new_config, max_frames_out));
318 }
319
320 bool
321 ExportGraphBuilder::SRC::operator== (FileSpec const & other_config) const
322 {
323         return config.format->sample_rate() == other_config.format->sample_rate();
324 }
325
326 /* SilenceHandler */
327 ExportGraphBuilder::FloatSinkPtr
328 ExportGraphBuilder::SilenceHandler::init (FileSpec const & new_config, nframes_t max_frames)
329 {
330         config = new_config;
331         max_frames_in = max_frames;
332         nframes_t sample_rate = parent.session.nominal_frame_rate();
333         
334         silence_trimmer.reset (new SilenceTrimmer<Sample>(max_frames_in));
335         silence_trimmer->set_trim_beginning (config.format->trim_beginning());
336         silence_trimmer->set_trim_end (config.format->trim_end());
337         silence_trimmer->add_silence_to_beginning (config.format->silence_beginning(sample_rate));
338         silence_trimmer->add_silence_to_end (config.format->silence_end(sample_rate));
339         
340         add_child (new_config);
341         
342         return silence_trimmer;
343 }
344
345 void
346 ExportGraphBuilder::SilenceHandler::add_child (FileSpec const & new_config)
347 {
348         for (std::list<SRC>::iterator it = children.begin(); it != children.end(); ++it) {
349                 if (*it == new_config) {
350                         it->add_child (new_config);
351                         return;
352                 }
353         }
354         
355         children.push_back (SRC (parent));
356         silence_trimmer->add_output (children.back().init (new_config, max_frames_in));
357 }
358
359 bool
360 ExportGraphBuilder::SilenceHandler::operator== (FileSpec const & other_config) const
361 {
362         ExportFormatSpecification & format = *config.format;
363         ExportFormatSpecification & other_format = *other_config.format;
364         return (format.trim_beginning() == other_format.trim_beginning()) &&
365                (format.trim_end() == other_format.trim_end()) &&
366                (format.silence_beginning() == other_format.silence_beginning()) &&
367                (format.silence_end() == other_format.silence_end());
368 }
369
370 /* ChannelConfig */
371
372 void
373 ExportGraphBuilder::ChannelConfig::init (FileSpec const & new_config, ChannelMap & channel_map)
374 {
375         typedef ExportChannelConfiguration::ChannelList ChannelList;
376         
377         config = new_config;
378         max_frames = parent.session.engine().frames_per_cycle();
379         
380         interleaver.reset (new Interleaver<Sample> ());
381         interleaver->init (new_config.channel_config->get_n_chans(), max_frames);
382         
383         ChannelList const & channel_list = config.channel_config->get_channels();
384         unsigned chan = 0;
385         for (ChannelList::const_iterator it = channel_list.begin(); it != channel_list.end(); ++it, ++chan) {
386                 ChannelMap::iterator map_it = channel_map.find (*it);
387                 if (map_it == channel_map.end()) {
388                         std::pair<ChannelMap::iterator, bool> result_pair =
389                                 channel_map.insert (std::make_pair (*it, IdentityVertexPtr (new IdentityVertex<Sample> ())));
390                         assert (result_pair.second);
391                         map_it = result_pair.first;
392                 }
393                 map_it->second->add_output (interleaver->input (chan));
394         }
395         
396         add_child (new_config);
397 }
398
399 void
400 ExportGraphBuilder::ChannelConfig::add_child (FileSpec const & new_config)
401 {
402         for (std::list<SilenceHandler>::iterator it = children.begin(); it != children.end(); ++it) {
403                 if (*it == new_config) {
404                         it->add_child (new_config);
405                         return;
406                 }
407         }
408         
409         children.push_back (SilenceHandler (parent));
410         nframes_t max_frames_out = new_config.channel_config->get_n_chans() * max_frames;
411         interleaver->add_output (children.back().init (new_config, max_frames_out));
412 }
413
414 bool
415 ExportGraphBuilder::ChannelConfig::operator== (FileSpec const & other_config) const
416 {
417         return config.channel_config == other_config.channel_config;
418 }
419
420 } // namespace ARDOUR