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