Initial backend support for external export encoder
[ardour.git] / libs / ardour / export_formats.cc
1 /*
2     Copyright (C) 2008 Paul Davis
3     Author: Sakari Bergen
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include "ardour/export_formats.h"
22
23 #include "pbd/i18n.h"
24
25 using namespace std;
26
27 namespace ARDOUR
28 {
29
30 bool
31 ExportFormat::has_sample_format ()
32 {
33         return dynamic_cast<HasSampleFormat *> (this);
34 }
35
36 bool
37 ExportFormat::sample_format_is_compatible (SampleFormat format) const
38 {
39         return (sample_formats.find (format) != sample_formats.end());
40 }
41
42 /*** HasSampleFormat ***/
43
44 HasSampleFormat::HasSampleFormat (ExportFormatBase::SampleFormatSet & sample_formats) :
45   _sample_formats (sample_formats)
46 {
47         /* Dither Types */
48
49         add_dither_type (ExportFormatBase::D_Shaped, _("Shaped Noise"));
50         add_dither_type (ExportFormatBase::D_Tri, _("Triangular"));
51         add_dither_type (ExportFormatBase::D_Rect, _("Rectangular"));
52         add_dither_type (ExportFormatBase::D_None,  _("None"));
53 }
54
55 void
56 HasSampleFormat::add_sample_format (ExportFormatBase::SampleFormat format)
57 {
58         _sample_formats.insert (format);
59
60         SampleFormatPtr ptr (new SampleFormatState (format, get_sample_format_name (format)));
61         sample_format_states.push_back (ptr);
62         ptr->SelectChanged.connect_same_thread (*this, boost::bind (&HasSampleFormat::update_sample_format_selection, this, _1));
63         // BOOST SIGNALS Could this be made any uglier?
64         ptr->SelectChanged.connect_same_thread (*this,
65                 boost::bind (boost::type<void> (), boost::ref (SampleFormatSelectChanged), _1, WeakSampleFormatPtr (ptr)));
66         ptr->CompatibleChanged.connect_same_thread (*this,
67                 boost::bind (boost::type<void> (), boost::ref (SampleFormatCompatibleChanged), _1, WeakSampleFormatPtr (ptr)));
68 }
69
70 void
71 HasSampleFormat::add_dither_type (ExportFormatBase::DitherType type, string name)
72 {
73         DitherTypePtr ptr (new DitherTypeState (type, name));
74         dither_type_states.push_back (ptr);
75         ptr->SelectChanged.connect_same_thread (*this, boost::bind (&HasSampleFormat::update_dither_type_selection, this, _1));
76         // BOOST SIGNALS Could this be made any uglier?
77         ptr->SelectChanged.connect_same_thread (*this,
78                 boost::bind (boost::type<void> (), boost::ref (DitherTypeSelectChanged), _1, WeakDitherTypePtr (ptr)));
79         ptr->CompatibleChanged.connect_same_thread (*this,
80                 boost::bind (boost::type<void> (),boost::ref ( DitherTypeCompatibleChanged), _1, WeakDitherTypePtr (ptr)));
81 }
82
83 HasSampleFormat::SampleFormatPtr
84 HasSampleFormat::get_selected_sample_format ()
85 {
86         for (SampleFormatList::iterator it = sample_format_states.begin(); it != sample_format_states.end(); ++it) {
87                 if ((*it)->selected()) {
88                         return *it;
89                 }
90         }
91
92         return SampleFormatPtr();
93 }
94
95 HasSampleFormat::DitherTypePtr
96 HasSampleFormat::get_selected_dither_type ()
97 {
98         for (DitherTypeList::iterator it = dither_type_states.begin(); it != dither_type_states.end(); ++it) {
99                 if ((*it)->selected()) {
100                         return *it;
101                 }
102         }
103
104         return DitherTypePtr();
105 }
106
107 void
108 HasSampleFormat::update_sample_format_selection (bool)
109 {
110         SampleFormatPtr format = get_selected_sample_format();
111         if (!format) {
112                 return;
113         }
114
115         if (format->format == ExportFormatBase::SF_24 ||
116             format->format == ExportFormatBase::SF_32 ||
117             format->format == ExportFormatBase::SF_Float ||
118             format->format == ExportFormatBase::SF_Double) {
119                 for (DitherTypeList::iterator it = dither_type_states.begin(); it != dither_type_states.end(); ++it) {
120                         if ((*it)->type == ExportFormatBase::D_None) {
121                                 (*it)->set_selected (true);
122                         } else {
123                                 (*it)->set_compatible (false);
124                         }
125                 }
126
127         } else {
128                 for (DitherTypeList::iterator it = dither_type_states.begin(); it != dither_type_states.end(); ++it) {
129                         (*it)->set_compatible (true);
130                 }
131         }
132 }
133
134 void
135 HasSampleFormat::update_dither_type_selection (bool)
136 {
137         DitherTypePtr type = get_selected_dither_type();
138         if (!type) {
139                 return;
140         }
141
142         if (!type->compatible()) {
143                 SampleFormatPtr format = get_selected_sample_format();
144                 if (format) {
145                         format->set_selected (false);
146                 }
147
148                 for (DitherTypeList::iterator it = dither_type_states.begin(); it != dither_type_states.end(); ++it) {
149                         (*it)->set_compatible (true);
150                 }
151         }
152 }
153
154 string
155 HasSampleFormat::get_sample_format_name (ExportFormatBase::SampleFormat format)
156 {
157         switch (format) {
158           case ExportFormatBase::SF_8:
159                 return _("8-bit");
160           case ExportFormatBase::SF_16:
161                 return _("16-bit");
162           case ExportFormatBase::SF_24:
163                 return _("24-bit");
164           case ExportFormatBase::SF_32:
165                 return _("32-bit");
166           case ExportFormatBase::SF_Float:
167                 return _("float");
168           case ExportFormatBase::SF_Double:
169                 return _("double");
170           case ExportFormatBase::SF_U8:
171                 return _("8-bit unsigned");
172           case ExportFormatBase::SF_Vorbis:
173                 return _("Vorbis sample format");
174           case ExportFormatBase::SF_None:
175                 return _("No sample format");
176         }
177         return "";
178 }
179
180 /*** Linear ***/
181
182 ExportFormatLinear::ExportFormatLinear (string name, FormatId format_id) :
183   HasSampleFormat (sample_formats),
184   _default_sample_format (SF_None)
185 {
186         set_name (name);
187         set_format_id (format_id);
188
189         add_sample_rate (SR_8);
190         add_sample_rate (SR_22_05);
191         add_sample_rate (SR_44_1);
192         add_sample_rate (SR_48);
193         add_sample_rate (SR_88_2);
194         add_sample_rate (SR_96);
195         add_sample_rate (SR_176_4);
196         add_sample_rate (SR_192);
197         add_sample_rate (SR_Session);
198
199         add_endianness (E_FileDefault);
200
201         set_quality (Q_LosslessLinear);
202 }
203
204 bool
205 ExportFormatLinear::set_compatibility_state (ExportFormatCompatibility const & compatibility)
206 {
207         /* Global state */
208
209         bool compatible = true;
210
211         if (!compatibility.has_quality (Q_LosslessLinear)) {
212                 compatible = false;
213         }
214
215         if (!compatibility.has_format (get_format_id())) {
216                 compatible = false;
217         }
218
219         boost::shared_ptr<ExportFormatBase> intersection = get_intersection (compatibility);
220
221         if (intersection->endiannesses_empty()) {
222                 compatible = false;
223         }
224
225         if (intersection->sample_rates_empty()) {
226                 compatible = false;
227         }
228
229         if (intersection->sample_formats_empty()) {
230                 compatible = false;
231         }
232
233         set_compatible (compatible);
234
235         /* Sample Formats */
236
237         for (SampleFormatList::iterator it = sample_format_states.begin(); it != sample_format_states.end(); ++it) {
238                 (*it)->set_compatible (compatibility.has_sample_format ((*it)->format));
239         }
240
241         return compatible;
242 }
243
244 /*** Ogg Vorbis ***/
245
246 ExportFormatOggVorbis::ExportFormatOggVorbis ()
247 {
248         /* Check system compatibility */
249
250         SF_INFO sf_info;
251         sf_info.channels = 2;
252         sf_info.samplerate = SR_44_1;
253         sf_info.format = F_Ogg | SF_Vorbis;
254         if (sf_format_check (&sf_info) != SF_TRUE) {
255                 throw ExportFormatIncompatible();
256         }
257
258         set_name ("Ogg Vorbis");
259         set_format_id (F_Ogg);
260         sample_formats.insert (SF_Vorbis);
261
262         add_sample_rate (SR_22_05);
263         add_sample_rate (SR_44_1);
264         add_sample_rate (SR_48);
265         add_sample_rate (SR_88_2);
266         add_sample_rate (SR_96);
267         add_sample_rate (SR_176_4);
268         add_sample_rate (SR_192);
269         add_sample_rate (SR_Session);
270
271         add_endianness (E_FileDefault);
272
273         set_extension ("ogg");
274         set_quality (Q_LossyCompression);
275 }
276
277 bool
278 ExportFormatOggVorbis::set_compatibility_state (ExportFormatCompatibility const & compatibility)
279 {
280         bool compatible = compatibility.has_format (F_Ogg);
281         set_compatible (compatible);
282         return compatible;
283 }
284
285 /*** FLAC ***/
286
287 ExportFormatFLAC::ExportFormatFLAC () :
288   HasSampleFormat (sample_formats)
289 {
290         /* Check system compatibility */
291
292         SF_INFO sf_info;
293         sf_info.channels = 2;
294         sf_info.samplerate = SR_44_1;
295         sf_info.format = F_FLAC | SF_16;
296         if (sf_format_check (&sf_info) != SF_TRUE) {
297                 throw ExportFormatIncompatible();
298         }
299
300         set_name ("FLAC");
301         set_format_id (F_FLAC);
302
303         add_sample_rate (SR_22_05);
304         add_sample_rate (SR_44_1);
305         add_sample_rate (SR_48);
306         add_sample_rate (SR_88_2);
307         add_sample_rate (SR_96);
308         add_sample_rate (SR_176_4);
309         add_sample_rate (SR_192);
310         add_sample_rate (SR_Session);
311
312         add_sample_format (SF_8);
313         add_sample_format (SF_16);
314         add_sample_format (SF_24);
315
316         add_endianness (E_FileDefault);
317
318         set_extension ("flac");
319         set_quality (Q_LosslessCompression);
320 }
321
322 bool
323 ExportFormatFLAC::set_compatibility_state (ExportFormatCompatibility const & compatibility)
324 {
325         bool compatible = compatibility.has_format (F_FLAC);
326         set_compatible (compatible);
327         return compatible;
328 }
329
330 /*** BWF ***/
331
332 ExportFormatBWF::ExportFormatBWF () :
333   HasSampleFormat (sample_formats)
334 {
335         set_name ("BWF");
336         set_format_id (F_WAV);
337
338         add_sample_rate (SR_22_05);
339         add_sample_rate (SR_44_1);
340         add_sample_rate (SR_48);
341         add_sample_rate (SR_88_2);
342         add_sample_rate (SR_96);
343         add_sample_rate (SR_176_4);
344         add_sample_rate (SR_192);
345         add_sample_rate (SR_Session);
346
347         add_sample_format (SF_U8);
348         add_sample_format (SF_16);
349         add_sample_format (SF_24);
350         add_sample_format (SF_32);
351         add_sample_format (SF_Float);
352         add_sample_format (SF_Double);
353
354         add_endianness (E_FileDefault);
355
356         set_extension ("wav");
357         set_quality (Q_LosslessLinear);
358 }
359
360 bool
361 ExportFormatBWF::set_compatibility_state (ExportFormatCompatibility const & compatibility)
362 {
363         bool compatible = compatibility.has_format (F_WAV);
364         set_compatible (compatible);
365         return compatible;
366 }
367
368
369 /*** FFMPEG Pipe ***/
370
371 ExportFormatFFMPEG::ExportFormatFFMPEG (std::string const& name, std::string const& ext)
372 {
373         set_name (name);
374         set_format_id (F_FFMPEG);
375         sample_formats.insert (SF_Float);
376
377         add_sample_rate (SR_22_05);
378         add_sample_rate (SR_44_1);
379         add_sample_rate (SR_48);
380         add_sample_rate (SR_88_2);
381         add_sample_rate (SR_96);
382         add_sample_rate (SR_176_4);
383         add_sample_rate (SR_192);
384         add_sample_rate (SR_Session);
385
386         add_endianness (E_Little);
387
388         set_extension (ext);
389         set_quality (Q_LossyCompression);
390 }
391
392 bool
393 ExportFormatFFMPEG::set_compatibility_state (ExportFormatCompatibility const & compatibility)
394 {
395         bool compatible = compatibility.has_format (F_FFMPEG);
396         set_compatible (compatible);
397         return compatible;
398 }
399
400
401 }; // namespace ARDOUR