1 /*
2  * Copyright (C) 2008-2010 Sakari Bergen <sakari.bergen@beatwaves.net>
3  * Copyright (C) 2008-2016 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2009 David Robillard <d@drobilla.net>
5  * Copyright (C) 2017-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 #include "ardour/export_formats.h"
23 
24 #include "pbd/i18n.h"
25 
26 using namespace std;
27 
28 namespace ARDOUR
29 {
30 
31 bool
has_sample_format()32 ExportFormat::has_sample_format ()
33 {
34 	return dynamic_cast<HasSampleFormat *> (this);
35 }
36 
37 bool
has_codec_quality()38 ExportFormat::has_codec_quality ()
39 {
40 	return dynamic_cast<HasCodecQuality *> (this);
41 }
42 
43 
44 bool
sample_format_is_compatible(SampleFormat format) const45 ExportFormat::sample_format_is_compatible (SampleFormat format) const
46 {
47 	return (sample_formats.find (format) != sample_formats.end());
48 }
49 
50 /*** HasSampleFormat ***/
51 
HasSampleFormat(ExportFormatBase::SampleFormatSet & sample_formats)52 HasSampleFormat::HasSampleFormat (ExportFormatBase::SampleFormatSet & sample_formats) :
53   _sample_formats (sample_formats)
54 {
55 	/* Dither Types */
56 
57 	add_dither_type (ExportFormatBase::D_Shaped, _("Shaped Noise"));
58 	add_dither_type (ExportFormatBase::D_Tri, _("Triangular"));
59 	add_dither_type (ExportFormatBase::D_Rect, _("Rectangular"));
60 	add_dither_type (ExportFormatBase::D_None,  _("None"));
61 }
62 
63 void
add_sample_format(ExportFormatBase::SampleFormat format)64 HasSampleFormat::add_sample_format (ExportFormatBase::SampleFormat format)
65 {
66 	_sample_formats.insert (format);
67 
68 	SampleFormatPtr ptr (new SampleFormatState (format, get_sample_format_name (format)));
69 	sample_format_states.push_back (ptr);
70 	ptr->SelectChanged.connect_same_thread (*this, boost::bind (&HasSampleFormat::update_sample_format_selection, this, _1));
71 	// BOOST SIGNALS Could this be made any uglier?
72 	ptr->SelectChanged.connect_same_thread (*this,
73 		boost::bind (boost::type<void> (), boost::ref (SampleFormatSelectChanged), _1, WeakSampleFormatPtr (ptr)));
74 	ptr->CompatibleChanged.connect_same_thread (*this,
75 		boost::bind (boost::type<void> (), boost::ref (SampleFormatCompatibleChanged), _1, WeakSampleFormatPtr (ptr)));
76 }
77 
78 void
add_dither_type(ExportFormatBase::DitherType type,string name)79 HasSampleFormat::add_dither_type (ExportFormatBase::DitherType type, string name)
80 {
81 	DitherTypePtr ptr (new DitherTypeState (type, name));
82 	dither_type_states.push_back (ptr);
83 	ptr->SelectChanged.connect_same_thread (*this, boost::bind (&HasSampleFormat::update_dither_type_selection, this, _1));
84 	// BOOST SIGNALS Could this be made any uglier?
85 	ptr->SelectChanged.connect_same_thread (*this,
86 		boost::bind (boost::type<void> (), boost::ref (DitherTypeSelectChanged), _1, WeakDitherTypePtr (ptr)));
87 	ptr->CompatibleChanged.connect_same_thread (*this,
88 		boost::bind (boost::type<void> (),boost::ref ( DitherTypeCompatibleChanged), _1, WeakDitherTypePtr (ptr)));
89 }
90 
91 HasSampleFormat::SampleFormatPtr
get_selected_sample_format()92 HasSampleFormat::get_selected_sample_format ()
93 {
94 	for (SampleFormatList::iterator it = sample_format_states.begin(); it != sample_format_states.end(); ++it) {
95 		if ((*it)->selected()) {
96 			return *it;
97 		}
98 	}
99 
100 	return SampleFormatPtr();
101 }
102 
103 HasSampleFormat::DitherTypePtr
get_selected_dither_type()104 HasSampleFormat::get_selected_dither_type ()
105 {
106 	for (DitherTypeList::iterator it = dither_type_states.begin(); it != dither_type_states.end(); ++it) {
107 		if ((*it)->selected()) {
108 			return *it;
109 		}
110 	}
111 
112 	return DitherTypePtr();
113 }
114 
115 void
update_sample_format_selection(bool)116 HasSampleFormat::update_sample_format_selection (bool)
117 {
118 	SampleFormatPtr format = get_selected_sample_format();
119 	if (!format) {
120 		return;
121 	}
122 
123 	if (format->format == ExportFormatBase::SF_24 ||
124 	    format->format == ExportFormatBase::SF_32 ||
125 	    format->format == ExportFormatBase::SF_Float ||
126 	    format->format == ExportFormatBase::SF_Double) {
127 		for (DitherTypeList::iterator it = dither_type_states.begin(); it != dither_type_states.end(); ++it) {
128 			if ((*it)->type == ExportFormatBase::D_None) {
129 				(*it)->set_selected (true);
130 			} else {
131 				(*it)->set_compatible (false);
132 			}
133 		}
134 
135 	} else {
136 		for (DitherTypeList::iterator it = dither_type_states.begin(); it != dither_type_states.end(); ++it) {
137 			(*it)->set_compatible (true);
138 		}
139 	}
140 }
141 
142 void
update_dither_type_selection(bool)143 HasSampleFormat::update_dither_type_selection (bool)
144 {
145 	DitherTypePtr type = get_selected_dither_type();
146 	if (!type) {
147 		return;
148 	}
149 
150 	if (!type->compatible()) {
151 		SampleFormatPtr format = get_selected_sample_format();
152 		if (format) {
153 			format->set_selected (false);
154 		}
155 
156 		for (DitherTypeList::iterator it = dither_type_states.begin(); it != dither_type_states.end(); ++it) {
157 			(*it)->set_compatible (true);
158 		}
159 	}
160 }
161 
162 string
get_sample_format_name(ExportFormatBase::SampleFormat format)163 HasSampleFormat::get_sample_format_name (ExportFormatBase::SampleFormat format)
164 {
165 	switch (format) {
166 	  case ExportFormatBase::SF_8:
167 		return _("8-bit");
168 	  case ExportFormatBase::SF_16:
169 		return _("16-bit");
170 	  case ExportFormatBase::SF_24:
171 		return _("24-bit");
172 	  case ExportFormatBase::SF_32:
173 		return _("32-bit");
174 	  case ExportFormatBase::SF_Float:
175 		return _("float");
176 	  case ExportFormatBase::SF_Double:
177 		return _("double");
178 	  case ExportFormatBase::SF_U8:
179 		return _("8-bit unsigned");
180 	  case ExportFormatBase::SF_Vorbis:
181 		return _("Vorbis sample format");
182 	  case ExportFormatBase::SF_None:
183 		return _("No sample format");
184 	}
185 	return "";
186 }
187 
188 /*** Linear ***/
189 
ExportFormatLinear(string name,FormatId format_id)190 ExportFormatLinear::ExportFormatLinear (string name, FormatId format_id) :
191   HasSampleFormat (sample_formats),
192   _default_sample_format (SF_None)
193 {
194 	set_name (name);
195 	set_format_id (format_id);
196 
197 	add_sample_rate (SR_8);
198 	add_sample_rate (SR_22_05);
199 	add_sample_rate (SR_44_1);
200 	add_sample_rate (SR_48);
201 	add_sample_rate (SR_88_2);
202 	add_sample_rate (SR_96);
203 	add_sample_rate (SR_176_4);
204 	add_sample_rate (SR_192);
205 	add_sample_rate (SR_Session);
206 
207 	add_endianness (E_FileDefault);
208 
209 	set_quality (Q_LosslessLinear);
210 }
211 
212 bool
set_compatibility_state(ExportFormatCompatibility const & compatibility)213 ExportFormatLinear::set_compatibility_state (ExportFormatCompatibility const & compatibility)
214 {
215 	/* Global state */
216 
217 	bool compatible = true;
218 
219 	if (!compatibility.has_quality (Q_LosslessLinear)) {
220 		compatible = false;
221 	}
222 
223 	if (!compatibility.has_format (get_format_id())) {
224 		compatible = false;
225 	}
226 
227 	boost::shared_ptr<ExportFormatBase> intersection = get_intersection (compatibility);
228 
229 	if (intersection->endiannesses_empty()) {
230 		compatible = false;
231 	}
232 
233 	if (intersection->sample_rates_empty()) {
234 		compatible = false;
235 	}
236 
237 	if (intersection->sample_formats_empty()) {
238 		compatible = false;
239 	}
240 
241 	set_compatible (compatible);
242 
243 	/* Sample Formats */
244 
245 	for (SampleFormatList::iterator it = sample_format_states.begin(); it != sample_format_states.end(); ++it) {
246 		(*it)->set_compatible (compatibility.has_sample_format ((*it)->format));
247 	}
248 
249 	return compatible;
250 }
251 
252 /*** Ogg Vorbis ***/
253 
ExportFormatOggVorbis()254 ExportFormatOggVorbis::ExportFormatOggVorbis ()
255 {
256 	/* Check system compatibility */
257 
258 	SF_INFO sf_info;
259 	sf_info.channels = 2;
260 	sf_info.samplerate = SR_44_1;
261 	sf_info.format = F_Ogg | SF_Vorbis;
262 	if (sf_format_check (&sf_info) != SF_TRUE) {
263 		throw ExportFormatIncompatible();
264 	}
265 
266 	set_name ("Ogg Vorbis");
267 	set_format_id (F_Ogg);
268 	sample_formats.insert (SF_Vorbis);
269 
270 	add_sample_rate (SR_22_05);
271 	add_sample_rate (SR_44_1);
272 	add_sample_rate (SR_48);
273 	add_sample_rate (SR_88_2);
274 	add_sample_rate (SR_96);
275 	add_sample_rate (SR_176_4);
276 	add_sample_rate (SR_192);
277 	add_sample_rate (SR_Session);
278 
279 	/* these are 100 vorbis_encode_init_vbr() quality */
280 	add_codec_quality ("Low (0)",           0);
281 	add_codec_quality ("Default (4)",      40);
282 	add_codec_quality ("High (6)",         60);
283 	add_codec_quality ("Very High (10)",  100);
284 
285 	add_endianness (E_FileDefault);
286 
287 	set_extension ("ogg");
288 	set_quality (Q_LossyCompression);
289 }
290 
291 bool
set_compatibility_state(ExportFormatCompatibility const & compatibility)292 ExportFormatOggVorbis::set_compatibility_state (ExportFormatCompatibility const & compatibility)
293 {
294 	bool compatible = compatibility.has_format (F_Ogg);
295 	set_compatible (compatible);
296 	return compatible;
297 }
298 
299 /*** FLAC ***/
300 
ExportFormatFLAC()301 ExportFormatFLAC::ExportFormatFLAC () :
302   HasSampleFormat (sample_formats)
303 {
304 	/* Check system compatibility */
305 
306 	SF_INFO sf_info;
307 	sf_info.channels = 2;
308 	sf_info.samplerate = SR_44_1;
309 	sf_info.format = F_FLAC | SF_16;
310 	if (sf_format_check (&sf_info) != SF_TRUE) {
311 		throw ExportFormatIncompatible();
312 	}
313 
314 	set_name ("FLAC");
315 	set_format_id (F_FLAC);
316 
317 	add_sample_rate (SR_22_05);
318 	add_sample_rate (SR_44_1);
319 	add_sample_rate (SR_48);
320 	add_sample_rate (SR_88_2);
321 	add_sample_rate (SR_96);
322 	add_sample_rate (SR_176_4);
323 	add_sample_rate (SR_192);
324 	add_sample_rate (SR_Session);
325 
326 	add_sample_format (SF_8);
327 	add_sample_format (SF_16);
328 	add_sample_format (SF_24);
329 
330 	add_endianness (E_FileDefault);
331 
332 	set_extension ("flac");
333 	set_quality (Q_LosslessCompression);
334 }
335 
336 bool
set_compatibility_state(ExportFormatCompatibility const & compatibility)337 ExportFormatFLAC::set_compatibility_state (ExportFormatCompatibility const & compatibility)
338 {
339 	bool compatible = compatibility.has_format (F_FLAC);
340 	set_compatible (compatible);
341 	return compatible;
342 }
343 
344 /*** BWF ***/
345 
ExportFormatBWF()346 ExportFormatBWF::ExportFormatBWF () :
347   HasSampleFormat (sample_formats)
348 {
349 	set_name ("BWF");
350 	set_format_id (F_WAV);
351 
352 	add_sample_rate (SR_22_05);
353 	add_sample_rate (SR_44_1);
354 	add_sample_rate (SR_48);
355 	add_sample_rate (SR_88_2);
356 	add_sample_rate (SR_96);
357 	add_sample_rate (SR_176_4);
358 	add_sample_rate (SR_192);
359 	add_sample_rate (SR_Session);
360 
361 	add_sample_format (SF_U8);
362 	add_sample_format (SF_16);
363 	add_sample_format (SF_24);
364 	add_sample_format (SF_32);
365 	add_sample_format (SF_Float);
366 	add_sample_format (SF_Double);
367 
368 	add_endianness (E_FileDefault);
369 
370 	set_extension ("wav");
371 	set_quality (Q_LosslessLinear);
372 }
373 
374 bool
set_compatibility_state(ExportFormatCompatibility const & compatibility)375 ExportFormatBWF::set_compatibility_state (ExportFormatCompatibility const & compatibility)
376 {
377 	bool compatible = compatibility.has_format (F_WAV);
378 	set_compatible (compatible);
379 	return compatible;
380 }
381 
382 
383 /*** FFMPEG Pipe ***/
384 
ExportFormatFFMPEG(std::string const & name,std::string const & ext)385 ExportFormatFFMPEG::ExportFormatFFMPEG (std::string const& name, std::string const& ext)
386 {
387 	set_name (name);
388 	set_format_id (F_FFMPEG);
389 	sample_formats.insert (SF_Float);
390 
391 	add_sample_rate (SR_8);
392 	add_sample_rate (SR_22_05);
393 	add_sample_rate (SR_44_1);
394 	add_sample_rate (SR_48);
395 	add_sample_rate (SR_Session);
396 
397 	add_endianness (E_Little);
398 
399 	add_codec_quality ("VBR 220-260 kb/s",  0);
400 	add_codec_quality ("VBR 190-250 kb/s", -1);
401 	add_codec_quality ("VBR 170-210 kb/s", -2);
402 	add_codec_quality ("VBR 150-195 kb/s", -3);
403 	add_codec_quality ("VBR 140-185 kb/s", -4);
404 	add_codec_quality ("VBR 120-150 kb/s", -5);
405 	add_codec_quality ("VBR 100-130 kb/s", -6);
406 	add_codec_quality ("VBR 80-120 kb/s",  -7);
407 	add_codec_quality ("VBR 70-105 kb/s",  -8);
408 	add_codec_quality ("VBR 45-85 kb/s",   -9);
409 	/*  Available CBR options are:
410 	 *  8, 16, 24, 32, 40, 48, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320
411 	 */
412 	add_codec_quality ("CBR  64 kb/s",     64);
413 	add_codec_quality ("CBR 128 kb/s",    128);
414 	add_codec_quality ("CBR 160 kb/s",    160);
415 	add_codec_quality ("CBR 192 kb/s",    192);
416 	add_codec_quality ("CBR 256 kb/s",    256);
417 	add_codec_quality ("CBR 320 kb/s",    320);
418 
419 	set_extension (ext);
420 	set_quality (Q_LossyCompression);
421 }
422 
423 bool
set_compatibility_state(ExportFormatCompatibility const & compatibility)424 ExportFormatFFMPEG::set_compatibility_state (ExportFormatCompatibility const & compatibility)
425 {
426 	bool compatible = compatibility.has_format (F_FFMPEG);
427 	set_compatible (compatible);
428 	return compatible;
429 }
430 
431 
432 }; // namespace ARDOUR
433