1 /*
2  * Copyright (C) 2009-2012 Sakari Bergen <sakari.bergen@beatwaves.net>
3  * Copyright (C) 2010-2012 David Robillard <d@drobilla.net>
4  * Copyright (C) 2013-2017 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2016-2019 Robin Gareus <robin@gareus.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #ifndef __ardour_export_graph_builder_h__
23 #define __ardour_export_graph_builder_h__
24 
25 #include "ardour/export_handler.h"
26 #include "ardour/export_analysis.h"
27 
28 #include "audiographer/utils/identity_vertex.h"
29 
30 #include <boost/ptr_container/ptr_list.hpp>
31 #include <glibmm/threadpool.h>
32 
33 namespace AudioGrapher {
34 	class SampleRateConverter;
35 	class PeakReader;
36 	class LoudnessReader;
37 	class Normalizer;
38 	class Limiter;
39 	class Analyser;
40 	class DemoNoiseAdder;
41 	template <typename T> class Chunker;
42 	template <typename T> class SampleFormatConverter;
43 	template <typename T> class Interleaver;
44 	template <typename T> class SndfileWriter;
45 	template <typename T> class CmdPipeWriter;
46 	template <typename T> class SilenceTrimmer;
47 	template <typename T> class TmpFile;
48 	template <typename T> class Threader;
49 	template <typename T> class AllocatingProcessContext;
50 }
51 
52 namespace ARDOUR
53 {
54 
55 class ExportTimespan;
56 class Session;
57 
58 class LIBARDOUR_API ExportGraphBuilder
59 {
60   private:
61 	typedef ExportHandler::FileSpec FileSpec;
62 
63 	typedef boost::shared_ptr<AudioGrapher::Sink<Sample> > FloatSinkPtr;
64 	typedef boost::shared_ptr<AudioGrapher::IdentityVertex<Sample> > IdentityVertexPtr;
65 	typedef boost::shared_ptr<AudioGrapher::Analyser> AnalysisPtr;
66 	typedef std::map<ExportChannelPtr,  IdentityVertexPtr> ChannelMap;
67 	typedef std::map<std::string, AnalysisPtr> AnalysisMap;
68 
69   public:
70 
71 	ExportGraphBuilder (Session const & session);
72 	~ExportGraphBuilder ();
73 
74 	samplecnt_t process (samplecnt_t samples, bool last_cycle);
75 	bool post_process (); // returns true when finished
need_postprocessing()76 	bool need_postprocessing () const { return !intermediates.empty(); }
realtime()77 	bool realtime() const { return _realtime; }
78 	unsigned get_postprocessing_cycle_count() const;
79 
80 	void reset ();
81 	void cleanup (bool remove_out_files = false);
82 	void set_current_timespan (boost::shared_ptr<ExportTimespan> span);
83 	void add_config (FileSpec const & config, bool rt);
84 	void get_analysis_results (AnalysisResults& results);
85 
86   private:
87 
add_analyser(const std::string & fn,AnalysisPtr ap)88 	void add_analyser (const std::string& fn, AnalysisPtr ap) {
89 		analysis_map.insert (std::make_pair (fn, ap));
90 	}
91 
92 	void add_split_config (FileSpec const & config);
93 
94 	class Encoder {
95             public:
96 		template <typename T> boost::shared_ptr<AudioGrapher::Sink<T> > init (FileSpec const & new_config);
97 		void add_child (FileSpec const & new_config);
98 		void remove_children ();
99 		void destroy_writer (bool delete_out_file);
100 		bool operator== (FileSpec const & other_config) const;
101 
102 		static int get_real_format (FileSpec const & config);
103 
104 	                                        private:
105 		typedef boost::shared_ptr<AudioGrapher::SndfileWriter<Sample> > FloatWriterPtr;
106 		typedef boost::shared_ptr<AudioGrapher::SndfileWriter<int> >    IntWriterPtr;
107 		typedef boost::shared_ptr<AudioGrapher::SndfileWriter<short> >  ShortWriterPtr;
108 
109 		typedef boost::shared_ptr<AudioGrapher::CmdPipeWriter<Sample> > FloatPipePtr;
110 
111 		template<typename T> void init_writer (boost::shared_ptr<AudioGrapher::SndfileWriter<T> > & writer);
112 		template<typename T> void init_writer (boost::shared_ptr<AudioGrapher::CmdPipeWriter<T> > & writer);
113 
114 		void copy_files (std::string orig_path);
115 
116 		FileSpec               config;
117 		std::list<ExportFilenamePtr> filenames;
118 		PBD::ScopedConnection  copy_files_connection;
119 
120 		std::string writer_filename;
121 
122 		// Only one of these should be available at a time
123 		FloatWriterPtr float_writer;
124 		IntWriterPtr   int_writer;
125 		ShortWriterPtr short_writer;
126 		FloatPipePtr   pipe_writer;
127 	};
128 
129 	// sample format converter
130 	class SFC {
131 	public:
132 		// This constructor so that this can be constructed like a Normalizer
133 		SFC (ExportGraphBuilder &, FileSpec const & new_config, samplecnt_t max_samples);
134 		FloatSinkPtr sink ();
135 		void add_child (FileSpec const & new_config);
136 		void remove_children (bool remove_out_files);
137 		bool operator== (FileSpec const & other_config) const;
138 
139 		void set_duration (samplecnt_t);
140 		void set_peak_dbfs (float, bool force = false);
141 		void set_peak_lufs (AudioGrapher::LoudnessReader const&);
142 
143 	private:
144 		typedef boost::shared_ptr<AudioGrapher::Chunker<float> > ChunkerPtr;
145 		typedef boost::shared_ptr<AudioGrapher::DemoNoiseAdder> DemoNoisePtr;
146 		typedef boost::shared_ptr<AudioGrapher::Normalizer> NormalizerPtr;
147 		typedef boost::shared_ptr<AudioGrapher::Limiter> LimiterPtr;
148 		typedef boost::shared_ptr<AudioGrapher::SampleFormatConverter<Sample> > FloatConverterPtr;
149 		typedef boost::shared_ptr<AudioGrapher::SampleFormatConverter<int> >   IntConverterPtr;
150 		typedef boost::shared_ptr<AudioGrapher::SampleFormatConverter<short> > ShortConverterPtr;
151 
152 		FileSpec           config;
153 		int                data_width;
154 		boost::ptr_list<Encoder> children;
155 
156 		NormalizerPtr   normalizer;
157 		LimiterPtr      limiter;
158 		DemoNoisePtr    demo_noise_adder;
159 		ChunkerPtr      chunker;
160 		AnalysisPtr     analyser;
161 		bool            _analyse;
162 		// Only one of these should be available at a time
163 		FloatConverterPtr float_converter;
164 		IntConverterPtr int_converter;
165 		ShortConverterPtr short_converter;
166 	};
167 
168 	class Intermediate {
169 	public:
170 		Intermediate (ExportGraphBuilder & parent, FileSpec const & new_config, samplecnt_t max_samples);
171 		FloatSinkPtr sink ();
172 		void add_child (FileSpec const & new_config);
173 		void remove_children (bool remove_out_files);
174 		bool operator== (FileSpec const & other_config) const;
175 
176 		unsigned get_postprocessing_cycle_count() const;
177 
178 		/// Returns true when finished
179 		bool process ();
180 
181 	private:
182 		typedef boost::shared_ptr<AudioGrapher::PeakReader> PeakReaderPtr;
183 		typedef boost::shared_ptr<AudioGrapher::LoudnessReader> LoudnessReaderPtr;
184 		typedef boost::shared_ptr<AudioGrapher::TmpFile<Sample> > TmpFilePtr;
185 		typedef boost::shared_ptr<AudioGrapher::Threader<Sample> > ThreaderPtr;
186 		typedef boost::shared_ptr<AudioGrapher::AllocatingProcessContext<Sample> > BufferPtr;
187 
188 		void prepare_post_processing ();
189 		void start_post_processing ();
190 
191 		ExportGraphBuilder & parent;
192 
193 		FileSpec        config;
194 		samplecnt_t     max_samples_out;
195 		bool            use_loudness;
196 		bool            use_peak;
197 		BufferPtr       buffer;
198 		PeakReaderPtr   peak_reader;
199 		TmpFilePtr      tmp_file;
200 		ThreaderPtr     threader;
201 
202 		LoudnessReaderPtr    loudness_reader;
203 		boost::ptr_list<SFC> children;
204 
205 		PBD::ScopedConnectionList post_processing_connection;
206 	};
207 
208 	// sample rate converter
209 	class SRC {
210             public:
211 		SRC (ExportGraphBuilder & parent, FileSpec const & new_config, samplecnt_t max_samples);
212 		FloatSinkPtr sink ();
213 		void add_child (FileSpec const & new_config);
214 		void remove_children (bool remove_out_files);
215 
216 		bool operator== (FileSpec const & other_config) const;
217 
218 	                                        private:
219 		typedef boost::shared_ptr<AudioGrapher::SampleRateConverter> SRConverterPtr;
220 
221 		template<typename T>
222 		void add_child_to_list (FileSpec const & new_config, boost::ptr_list<T> & list);
223 
224 		ExportGraphBuilder &  parent;
225 		FileSpec              config;
226 		boost::ptr_list<SFC>  children;
227 		boost::ptr_list<Intermediate> intermediate_children;
228 		SRConverterPtr        converter;
229 		samplecnt_t           max_samples_out;
230 	};
231 
232 	// Silence trimmer + adder
233 	class SilenceHandler {
234 	    public:
235 		SilenceHandler (ExportGraphBuilder & parent, FileSpec const & new_config, samplecnt_t max_samples);
236 		FloatSinkPtr sink ();
237 		void add_child (FileSpec const & new_config);
238 		void remove_children (bool remove_out_files);
239 		bool operator== (FileSpec const & other_config) const;
240 
241 	                                        private:
242 		typedef boost::shared_ptr<AudioGrapher::SilenceTrimmer<Sample> > SilenceTrimmerPtr;
243 
244 		ExportGraphBuilder & parent;
245 		FileSpec             config;
246 		boost::ptr_list<SRC> children;
247 		SilenceTrimmerPtr    silence_trimmer;
248 		samplecnt_t          max_samples_in;
249 	};
250 
251 	// channel configuration
252 	class ChannelConfig {
253 	    public:
254 		ChannelConfig (ExportGraphBuilder & parent, FileSpec const & new_config, ChannelMap & channel_map);
255 		void add_child (FileSpec const & new_config);
256 		void remove_children (bool remove_out_files);
257 		bool operator== (FileSpec const & other_config) const;
258 
259 	                                        private:
260 		typedef boost::shared_ptr<AudioGrapher::Interleaver<Sample> > InterleaverPtr;
261 		typedef boost::shared_ptr<AudioGrapher::Chunker<Sample> > ChunkerPtr;
262 
263 		ExportGraphBuilder &      parent;
264 		FileSpec                  config;
265 		boost::ptr_list<SilenceHandler> children;
266 		InterleaverPtr            interleaver;
267 		ChunkerPtr                chunker;
268 		samplecnt_t               max_samples_out;
269 	};
270 
271 	Session const & session;
272 	boost::shared_ptr<ExportTimespan> timespan;
273 
274 	// Roots for export processor trees
275 	typedef boost::ptr_list<ChannelConfig> ChannelConfigList;
276 	ChannelConfigList channel_configs;
277 
278 	// The sources of all data, each channel is read only once
279 	ChannelMap channels;
280 
281 	samplecnt_t process_buffer_samples;
282 
283 	std::list<Intermediate *> intermediates;
284 
285 	AnalysisMap analysis_map;
286 
287 	bool        _realtime;
288 	samplecnt_t _master_align;
289 
290 	Glib::ThreadPool     thread_pool;
291 	Glib::Threads::Mutex engine_request_lock;
292 };
293 
294 } // namespace ARDOUR
295 
296 #endif /* __ardour_export_graph_builder_h__ */
297