1 #include "ardour/export_graph_builder.h"
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"
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"
20 #include "pbd/filesystem.h"
22 using namespace AudioGrapher;
26 ExportGraphBuilder::ExportGraphBuilder (Session const & session)
28 , thread_pool (4) // FIXME thread amount to cores amount
30 process_buffer_frames = session.engine().frames_per_cycle();
31 process_buffer = new Sample[process_buffer_frames];
34 ExportGraphBuilder::~ExportGraphBuilder ()
36 delete [] process_buffer;
40 ExportGraphBuilder::process (nframes_t /* frames */, bool last_cycle)
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);
53 ExportGraphBuilder::process_normalize ()
55 for (std::list<Normalizer *>::iterator it = normalizers.begin(); it != normalizers.end(); /* ++ in loop */) {
56 if ((*it)->process()) {
57 it = normalizers.erase (it);
63 return normalizers.empty();
67 ExportGraphBuilder::reset ()
69 channel_configs.clear ();
75 ExportGraphBuilder::add_config (FileSpec const & config)
77 for (ChannelConfigList::iterator it = channel_configs.begin(); it != channel_configs.end(); ++it) {
79 it->add_child (config);
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);
93 boost::shared_ptr<AudioGrapher::Sink<Sample> >
94 ExportGraphBuilder::Encoder::init (FileSpec const & new_config)
97 init_writer (float_writer);
102 boost::shared_ptr<AudioGrapher::Sink<int> >
103 ExportGraphBuilder::Encoder::init (FileSpec const & new_config)
106 init_writer (int_writer);
111 boost::shared_ptr<AudioGrapher::Sink<short> >
112 ExportGraphBuilder::Encoder::init (FileSpec const & new_config)
115 init_writer (short_writer);
120 ExportGraphBuilder::Encoder::add_child (FileSpec const & new_config)
122 filenames.push_back (new_config.filename);
126 ExportGraphBuilder::Encoder::operator== (FileSpec const & other_config) const
128 return get_real_format (config) == get_real_format (other_config);
132 ExportGraphBuilder::Encoder::get_real_format (FileSpec const & config)
134 ExportFormatSpecification & format = *config.format;
135 return format.format_id() | format.sample_format() | format.endianness();
140 ExportGraphBuilder::Encoder::init_writer (boost::shared_ptr<AudioGrapher::SndfileWriter<T> > & writer)
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);
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));
151 ExportGraphBuilder::Encoder::copy_files (std::string orig_path)
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();
162 ExportGraphBuilder::FloatSinkPtr
163 ExportGraphBuilder::SFC::init (FileSpec const & new_config, nframes_t max_frames)
166 data_width = sndfile_data_width (Encoder::get_real_format (config));
167 unsigned channels = new_config.channel_config->get_n_chans();
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);
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);
178 return int_converter;
180 float_converter = FloatConverterPtr (new SampleFormatConverter<Sample> (channels));
181 float_converter->init (max_frames, config.format->dither_type(), data_width);
183 return float_converter;
188 ExportGraphBuilder::SFC::add_child (FileSpec const & new_config)
190 for (std::list<Encoder>::iterator it = children.begin(); it != children.end(); ++it) {
191 if (*it == new_config) {
192 it->add_child (new_config);
197 children.push_back (Encoder());
198 Encoder & encoder = children.back();
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));
205 float_converter->add_output (encoder.init<Sample> (new_config));
210 ExportGraphBuilder::SFC::operator== (FileSpec const & other_config) const
212 return config.format->sample_format() == other_config.format->sample_format();
217 ExportGraphBuilder::FloatSinkPtr
218 ExportGraphBuilder::Normalizer::init (FileSpec const & new_config, nframes_t /*max_frames*/)
221 max_frames_out = 4086; // TODO good chunk size
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));
228 normalizer->alloc_buffer (max_frames_out);
229 normalizer->add_output (threader);
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)));
236 add_child (new_config);
238 peak_reader->add_output (tmp_file);
243 ExportGraphBuilder::Normalizer::add_child (FileSpec const & new_config)
245 for (std::list<SFC>::iterator it = children.begin(); it != children.end(); ++it) {
246 if (*it == new_config) {
247 it->add_child (new_config);
252 children.push_back (SFC (parent));
253 threader->add_output (children.back().init (new_config, max_frames_out));
257 ExportGraphBuilder::Normalizer::operator== (FileSpec const & other_config) const
259 return config.format->normalize() == other_config.format->normalize() &&
260 config.format->normalize_target() == other_config.format->normalize_target();
264 ExportGraphBuilder::Normalizer::process()
266 nframes_t frames_read = tmp_file->read (*buffer);
267 return frames_read != buffer->frames();
271 ExportGraphBuilder::Normalizer::start_post_processing()
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);
281 ExportGraphBuilder::FloatSinkPtr
282 ExportGraphBuilder::SRC::init (FileSpec const & new_config, nframes_t max_frames)
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);
290 add_child (new_config);
296 ExportGraphBuilder::SRC::add_child (FileSpec const & new_config)
298 if (new_config.format->normalize()) {
299 add_child_to_list (new_config, normalized_children);
301 add_child_to_list (new_config, children);
307 ExportGraphBuilder::SRC::add_child_to_list (FileSpec const & new_config, std::list<T> & list)
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);
316 list.push_back (T (parent));
317 converter->add_output (list.back().init (new_config, max_frames_out));
321 ExportGraphBuilder::SRC::operator== (FileSpec const & other_config) const
323 return config.format->sample_rate() == other_config.format->sample_rate();
327 ExportGraphBuilder::FloatSinkPtr
328 ExportGraphBuilder::SilenceHandler::init (FileSpec const & new_config, nframes_t max_frames)
331 max_frames_in = max_frames;
332 nframes_t sample_rate = parent.session.nominal_frame_rate();
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));
340 add_child (new_config);
342 return silence_trimmer;
346 ExportGraphBuilder::SilenceHandler::add_child (FileSpec const & new_config)
348 for (std::list<SRC>::iterator it = children.begin(); it != children.end(); ++it) {
349 if (*it == new_config) {
350 it->add_child (new_config);
355 children.push_back (SRC (parent));
356 silence_trimmer->add_output (children.back().init (new_config, max_frames_in));
360 ExportGraphBuilder::SilenceHandler::operator== (FileSpec const & other_config) const
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());
373 ExportGraphBuilder::ChannelConfig::init (FileSpec const & new_config, ChannelMap & channel_map)
375 typedef ExportChannelConfiguration::ChannelList ChannelList;
378 max_frames = parent.session.engine().frames_per_cycle();
380 interleaver.reset (new Interleaver<Sample> ());
381 interleaver->init (new_config.channel_config->get_n_chans(), max_frames);
383 ChannelList const & channel_list = config.channel_config->get_channels();
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;
393 map_it->second->add_output (interleaver->input (chan));
396 add_child (new_config);
400 ExportGraphBuilder::ChannelConfig::add_child (FileSpec const & new_config)
402 for (std::list<SilenceHandler>::iterator it = children.begin(); it != children.end(); ++it) {
403 if (*it == new_config) {
404 it->add_child (new_config);
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));
415 ExportGraphBuilder::ChannelConfig::operator== (FileSpec const & other_config) const
417 return config.channel_config == other_config.channel_config;
420 } // namespace ARDOUR