Consolidate VST Plugin Info
[ardour.git] / libs / ardour / export_format_specification.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_format_specification.h"
22
23 #include "ardour/export_format_compatibility.h"
24 #include "ardour/export_formats.h"
25 #include "ardour/session.h"
26 #include "ardour/types_convert.h"
27
28 #include "pbd/error.h"
29 #include "pbd/xml++.h"
30 #include "pbd/enumwriter.h"
31 #include "pbd/enum_convert.h"
32 #include "pbd/string_convert.h"
33 #include "pbd/types_convert.h"
34
35 #include "pbd/i18n.h"
36
37 namespace PBD {
38         DEFINE_ENUM_CONVERT (ARDOUR::ExportFormatBase::FormatId)
39         DEFINE_ENUM_CONVERT (ARDOUR::ExportFormatBase::SampleRate)
40         DEFINE_ENUM_CONVERT (ARDOUR::ExportFormatBase::SampleFormat)
41         DEFINE_ENUM_CONVERT (ARDOUR::ExportFormatBase::DitherType)
42         DEFINE_ENUM_CONVERT (ARDOUR::ExportFormatBase::SRCQuality)
43         DEFINE_ENUM_CONVERT (ARDOUR::ExportFormatBase::Type)
44 }
45
46 namespace ARDOUR
47 {
48
49 using namespace PBD;
50 using std::string;
51 using std::list;
52
53 ExportFormatSpecification::Time &
54 ExportFormatSpecification::Time::operator= (AnyTime const & other)
55 {
56         static_cast<AnyTime &>(*this) = other;
57         return *this;
58 }
59
60 samplecnt_t
61 ExportFormatSpecification::Time::get_samples_at (samplepos_t position, samplecnt_t target_rate) const
62 {
63         samplecnt_t duration = session.any_duration_to_samples (position, *this);
64         return ((double) target_rate / session.sample_rate()) * duration + 0.5;
65 }
66
67 XMLNode &
68 ExportFormatSpecification::Time::get_state ()
69 {
70
71         XMLNode * node = new XMLNode ("Duration");
72
73         node->set_property ("format", type);
74
75         switch (type) {
76           case Timecode:
77                 node->set_property ("hours", timecode.hours);
78                 node->set_property ("minutes", timecode.minutes);
79                 node->set_property ("seconds", timecode.seconds);
80                 node->set_property ("frames", timecode.frames);
81                 break;
82           case BBT:
83                 node->set_property ("bars", bbt.bars);
84                 node->set_property ("beats", bbt.beats);
85                 node->set_property ("ticks", bbt.ticks);
86                 break;
87           case Samples:
88                 node->set_property ("samples", samples);
89                 break;
90           case Seconds:
91                 node->set_property ("seconds", seconds);
92                 break;
93         }
94
95         return *node;
96 }
97
98 int
99 ExportFormatSpecification::Time::set_state (const XMLNode & node)
100 {
101         if (!node.get_property ("format", type)) {
102                 return -1;
103         }
104
105         switch (type) {
106         case Timecode:
107                 node.get_property ("hours", timecode.hours);
108                 node.get_property ("minutes", timecode.minutes);
109                 node.get_property ("seconds", timecode.seconds);
110                 node.get_property ("frames", timecode.frames);
111                 break;
112
113         case BBT:
114                 node.get_property ("bars", bbt.bars);
115                 node.get_property ("beats", bbt.beats);
116                 node.get_property ("ticks", bbt.ticks);
117                 break;
118
119         case Samples:
120                 node.get_property ("samples", samples);
121                 break;
122
123         case Seconds:
124                 node.get_property ("seconds", seconds);
125                 break;
126
127         }
128
129         return 0;
130 }
131
132 ExportFormatSpecification::ExportFormatSpecification (Session & s)
133         : session (s)
134
135         , has_sample_format (false)
136         , supports_tagging (false)
137         , _has_broadcast_info (false)
138         , _channel_limit (0)
139         , _dither_type (D_None)
140         , _src_quality (SRC_SincBest)
141         , _tag (true)
142
143         , _trim_beginning (false)
144         , _silence_beginning (s)
145         , _trim_end (false)
146         , _silence_end (s)
147
148         , _normalize (false)
149         , _normalize_loudness (false)
150         , _normalize_dbfs (GAIN_COEFF_UNITY)
151         , _normalize_lufs (-23)
152         , _normalize_dbtp (-1)
153         , _with_toc (false)
154         , _with_cue (false)
155         , _with_mp4chaps (false)
156         , _soundcloud_upload (false)
157         , _command ("")
158         , _analyse (true)
159 {
160         format_ids.insert (F_None);
161         endiannesses.insert (E_FileDefault);
162         sample_formats.insert (SF_None);
163         sample_rates.insert (SR_None);
164         qualities.insert (Q_None);
165 }
166
167 ExportFormatSpecification::ExportFormatSpecification (Session & s, XMLNode const & state)
168         : session (s)
169
170         , has_sample_format (false)
171         , supports_tagging (false)
172         , _has_broadcast_info (false)
173         , _channel_limit (0)
174         , _dither_type (D_None)
175         , _src_quality (SRC_SincBest)
176         , _tag (true)
177
178         , _trim_beginning (false)
179         , _silence_beginning (s)
180         , _trim_end (false)
181         , _silence_end (s)
182
183         , _normalize (false)
184         , _normalize_loudness (false)
185         , _normalize_dbfs (GAIN_COEFF_UNITY)
186         , _normalize_lufs (-23)
187         , _normalize_dbtp (-1)
188         , _with_toc (false)
189         , _with_cue (false)
190         , _with_mp4chaps (false)
191         , _soundcloud_upload (false)
192         , _command ("")
193         , _analyse (true)
194 {
195         _silence_beginning.type = Time::Timecode;
196         _silence_end.type = Time::Timecode;
197
198         set_state (state);
199 }
200
201 ExportFormatSpecification::ExportFormatSpecification (ExportFormatSpecification const & other, bool modify_name)
202         : ExportFormatBase(other)
203         , session (other.session)
204         , _silence_beginning (other.session)
205         , _silence_end (other.session)
206         , _soundcloud_upload (false)
207         , _analyse (other._analyse)
208 {
209         if (modify_name) {
210                 set_name (other.name() + " (copy)");
211         } else {
212                 set_name (other.name());
213         }
214
215         _format_name = other._format_name;
216         has_sample_format = other.has_sample_format;
217
218         supports_tagging = other.supports_tagging;
219         _has_broadcast_info = other._has_broadcast_info;
220         _channel_limit = other._channel_limit;
221
222         set_type (other.type());
223         set_format_id (other.format_id());
224         set_endianness (other.endianness());
225         set_sample_format (other.sample_format());
226         set_sample_rate (other.sample_rate());
227         set_quality (other.quality());
228
229         set_dither_type (other.dither_type());
230         set_src_quality (other.src_quality());
231         set_trim_beginning (other.trim_beginning());
232         set_trim_end (other.trim_end());
233         set_normalize (other.normalize());
234         set_normalize_loudness (other.normalize_loudness());
235         set_normalize_dbfs (other.normalize_dbfs());
236         set_normalize_lufs (other.normalize_lufs());
237         set_normalize_dbtp (other.normalize_dbtp());
238
239         set_tag (other.tag());
240
241         set_silence_beginning (other.silence_beginning_time());
242         set_silence_end (other.silence_end_time());
243
244         set_extension(other.extension());
245 }
246
247 ExportFormatSpecification::~ExportFormatSpecification ()
248 {
249 }
250
251 XMLNode &
252 ExportFormatSpecification::get_state ()
253 {
254         XMLNode * node;
255         XMLNode * root = new XMLNode ("ExportFormatSpecification");
256
257         root->set_property ("name", _name);
258         root->set_property ("id", _id.to_s());
259         root->set_property ("with-cue", _with_cue);
260         root->set_property ("with-toc", _with_toc);
261         root->set_property ("with-mp4chaps", _with_mp4chaps);
262         root->set_property ("command", _command);
263         root->set_property ("analyse", _analyse);
264         root->set_property ("soundcloud-upload", _soundcloud_upload);
265
266         node = root->add_child ("Encoding");
267         node->set_property ("id", format_id());
268         node->set_property ("type", type());
269         node->set_property ("extension", extension());
270         node->set_property ("name", _format_name);
271         node->set_property ("has-sample-format", has_sample_format);
272         node->set_property ("channel-limit", _channel_limit);
273
274         node = root->add_child ("SampleRate");
275         node->set_property ("rate", sample_rate());
276
277         node = root->add_child ("SRCQuality");
278         node->set_property ("quality", src_quality());
279
280         XMLNode * enc_opts = root->add_child ("EncodingOptions");
281
282         add_option (enc_opts, "sample-format", to_string(sample_format()));
283         add_option (enc_opts, "dithering", to_string (dither_type()));
284         add_option (enc_opts, "tag-metadata", to_string (_tag));
285         add_option (enc_opts, "tag-support", to_string (supports_tagging));
286         add_option (enc_opts, "broadcast-info", to_string (_has_broadcast_info));
287
288         XMLNode * processing = root->add_child ("Processing");
289
290         node = processing->add_child ("Normalize");
291         node->set_property ("enabled", normalize());
292         node->set_property ("loudness", normalize_loudness());
293         node->set_property ("dbfs", normalize_dbfs());
294         node->set_property ("lufs", normalize_lufs());
295         node->set_property ("dbtp", normalize_dbtp());
296
297         XMLNode * silence = processing->add_child ("Silence");
298         XMLNode * start = silence->add_child ("Start");
299         XMLNode * end = silence->add_child ("End");
300
301         node = start->add_child ("Trim");
302         node->set_property ("enabled", trim_beginning());
303
304         node = start->add_child ("Add");
305         node->set_property ("enabled", _silence_beginning.not_zero());
306         node->add_child_nocopy (_silence_beginning.get_state());
307
308         node = end->add_child ("Trim");
309         node->set_property ("enabled", trim_end());
310
311         node = end->add_child ("Add");
312         node->set_property ("enabled", _silence_end.not_zero());
313         node->add_child_nocopy (_silence_end.get_state());
314
315         return *root;
316 }
317
318 int
319 ExportFormatSpecification::set_state (const XMLNode & root)
320 {
321         XMLNode const * child;
322         string str;
323
324         root.get_property ("name", _name);
325
326         if (root.get_property ("id", str)) {
327                 _id = str;
328         }
329
330         if (!root.get_property ("with-cue", _with_cue)) {
331                 _with_cue = false;
332         }
333
334         if (!root.get_property ("with-toc", _with_toc)) {
335                 _with_toc = false;
336         }
337
338         if (!root.get_property ("with-mp4chaps", _with_mp4chaps)) {
339                 _with_mp4chaps = false;
340         }
341
342         if (!root.get_property ("command", _command)) {
343                 _command = "";
344         }
345
346         if (!root.get_property ("analyse", _analyse)) {
347                 _analyse = false;
348         }
349
350         if (!root.get_property ("soundcloud-upload", _soundcloud_upload)) {
351                 _soundcloud_upload = false;
352         }
353
354         /* Encoding and SRC */
355
356         if ((child = root.child ("Encoding"))) {
357                 FormatId fid;
358                 if (child->get_property ("id", fid)) {
359                         set_format_id (fid);
360                 }
361
362                 ExportFormatBase::Type type;
363                 if (child->get_property ("type", type)) {
364                         set_type (type);
365                 }
366
367                 if (child->get_property ("extension", str)) {
368                         set_extension (str);
369                 }
370
371                 child->get_property ("name", _format_name);
372                 child->get_property ("has-sample-format", has_sample_format);
373                 child->get_property ("channel-limit", _channel_limit);
374         }
375
376         if ((child = root.child ("SampleRate"))) {
377                 SampleRate rate;
378                 if (child->get_property ("rate", rate)) {
379                         set_sample_rate (rate);
380                 }
381         }
382
383         if ((child = root.child ("SRCQuality"))) {
384                 child->get_property ("quality", _src_quality);
385         }
386
387         /* Encoding options */
388
389         if ((child = root.child ("EncodingOptions"))) {
390                 set_sample_format ((SampleFormat) string_2_enum (get_option (child, "sample-format"), SampleFormat));
391                 set_dither_type ((DitherType) string_2_enum (get_option (child, "dithering"), DitherType));
392                 set_tag (string_to<bool>(get_option (child, "tag-metadata")));
393                 supports_tagging = string_to<bool>(get_option (child, "tag-support"));
394                 _has_broadcast_info = string_to<bool>(get_option (child, "broadcast-info"));
395         }
396
397         /* Processing */
398
399         XMLNode const * proc = root.child ("Processing");
400         if (!proc) { std::cerr << X_("Could not load processing for export format") << std::endl; return -1; }
401
402         if ((child = proc->child ("Normalize"))) {
403                 child->get_property ("enabled", _normalize);
404                 // old formats before ~ 4.7-930ish
405                 child->get_property ("target", _normalize_dbfs);
406                 child->get_property ("loudness", _normalize_loudness);
407                 child->get_property ("dbfs", _normalize_dbfs);
408                 child->get_property ("lufs", _normalize_lufs);
409                 child->get_property ("dbtp", _normalize_dbtp);
410         }
411
412         XMLNode const * silence = proc->child ("Silence");
413         if (!silence) { std::cerr << X_("Could not load silence for export format") << std::endl; return -1; }
414
415         XMLNode const * start = silence->child ("Start");
416         XMLNode const * end = silence->child ("End");
417         if (!start || !end) { std::cerr << X_("Could not load end or start silence for export format") << std::endl; return -1; }
418
419         /* Silence start */
420
421         if ((child = start->child ("Trim"))) {
422                 child->get_property ("enabled", _trim_beginning);
423         }
424
425         bool enabled;
426         if ((child = start->child ("Add"))) {
427                 if (child->get_property ("enabled", enabled) && enabled) {
428                         if ((child = child->child ("Duration"))) {
429                                 _silence_beginning.set_state (*child);
430                         }
431                 } else {
432                         _silence_beginning.type = Time::Timecode;
433                 }
434         }
435
436         /* Silence end */
437
438         if ((child = end->child ("Trim"))) {
439                 child->get_property ("enabled", _trim_end);
440         }
441
442         if ((child = end->child ("Add"))) {
443                 if (child->get_property ("enabled", enabled) && enabled) {
444                         if ((child = child->child ("Duration"))) {
445                                 _silence_end.set_state (*child);
446                         }
447                 } else {
448                                 _silence_end.type = Time::Timecode;
449                 }
450         }
451
452         return 0;
453 }
454
455 bool
456 ExportFormatSpecification::is_compatible_with (ExportFormatCompatibility const & compatibility) const
457 {
458         boost::shared_ptr<ExportFormatBase> intersection = get_intersection (compatibility);
459
460         if (intersection->formats_empty() && format_id() != 0) {
461                 return false;
462         }
463
464         if (intersection->endiannesses_empty() && endianness() != E_FileDefault) {
465                 return false;
466         }
467
468         if (intersection->sample_rates_empty() && sample_rate() != SR_None) {
469                 return false;
470         }
471
472         if (intersection->sample_formats_empty() && sample_format() != SF_None) {
473                 return false;
474         }
475
476         if (intersection->qualities_empty() && quality() != Q_None) {
477                 return false;
478         }
479
480         return true;
481 }
482
483 bool
484 ExportFormatSpecification::is_complete () const
485 {
486         if (type() == T_None) {
487                 return false;
488         }
489
490         if (!format_id()) {
491                 return false;
492         }
493
494         if (!sample_rate()) {
495                 return false;
496         }
497
498         if (has_sample_format) {
499                 if (sample_format() == SF_None) {
500                         return false;
501                 }
502         }
503
504         return true;
505 }
506
507 void
508 ExportFormatSpecification::set_format (boost::shared_ptr<ExportFormat> format)
509 {
510         if (format) {
511                 set_format_id (format->get_format_id ());
512                 set_type (format->get_type());
513                 set_extension (format->extension());
514
515                 if (format->get_explicit_sample_format()) {
516                         set_sample_format (format->get_explicit_sample_format());
517                 }
518
519                 if (format->has_sample_format()) {
520                         has_sample_format = true;
521                 }
522
523                 if (format->has_broadcast_info()) {
524                         _has_broadcast_info = true;
525                 }
526
527                 supports_tagging = format->supports_tagging ();
528                 _channel_limit = format->get_channel_limit();
529
530                 _format_name = format->name();
531         } else {
532                 set_format_id (F_None);
533                 set_type (T_None);
534                 set_extension ("");
535                 _has_broadcast_info = false;
536                 has_sample_format = false;
537                 supports_tagging = false;
538                 _channel_limit = 0;
539                 _format_name = "";
540         }
541 }
542
543 string
544 ExportFormatSpecification::description (bool include_name)
545 {
546         list<string> components;
547
548         if (_normalize) {
549                 if (_normalize_loudness) {
550                         components.push_back (_("normalize loudness"));
551                 } else {
552                         components.push_back (_("normalize peak"));
553                 }
554         }
555
556         if (_trim_beginning && _trim_end) {
557                 components.push_back ( _("trim"));
558         } else if (_trim_beginning) {
559                 components.push_back (_("trim start"));
560         } else if (_trim_end) {
561                 components.push_back (_("trim end"));
562         }
563
564         if (_format_name != "") {
565                 components.push_back (_format_name);
566         }
567
568         if (has_sample_format) {
569                 components.push_back (HasSampleFormat::get_sample_format_name (sample_format()));
570         }
571
572         switch (sample_rate()) {
573         case SR_8:
574                 components.push_back ("8 kHz");
575                 break;
576         case SR_22_05:
577                 components.push_back ("22,5 kHz");
578                 break;
579         case SR_44_1:
580                 components.push_back ("44,1 kHz");
581                 break;
582         case SR_48:
583                 components.push_back ("48 kHz");
584                 break;
585         case SR_88_2:
586                 components.push_back ("88,2 kHz");
587                 break;
588         case SR_96:
589                 components.push_back ("96 kHz");
590                 break;
591         case SR_176_4:
592                 components.push_back ("176.4 kHz");
593                 break;
594         case SR_192:
595                 components.push_back ("192 kHz");
596                 break;
597         case SR_Session:
598                 components.push_back (_("Session rate"));
599                 break;
600         case SR_None:
601                 break;
602         }
603
604         if (_with_toc) {
605                 components.push_back ("TOC");
606         }
607
608         if (_with_cue) {
609                 components.push_back ("CUE");
610         }
611
612         if (_with_mp4chaps) {
613                 components.push_back ("MP4ch");
614         }
615
616         if (!_command.empty()) {
617                 components.push_back ("+");
618         }
619
620         string desc;
621         if (include_name) {
622                 desc = _name + ": ";
623         }
624
625         for (list<string>::const_iterator it = components.begin(); it != components.end(); ++it) {
626                 if (it != components.begin()) { desc += ", "; }
627                 desc += *it;
628         }
629         return desc;
630 }
631
632 void
633 ExportFormatSpecification::add_option (XMLNode * node, std::string const & name, std::string const & value)
634 {
635         node = node->add_child ("Option");
636         node->set_property ("name", name);
637         node->set_property ("value", value);
638 }
639
640 std::string
641 ExportFormatSpecification::get_option (XMLNode const * node, std::string const & name)
642 {
643         XMLNodeList list (node->children ("Option"));
644
645         for (XMLNodeList::iterator it = list.begin(); it != list.end(); ++it) {
646                 std::string str;
647                 if ((*it)->get_property ("name", str) && name == str) {
648                         if ((*it)->get_property ("value", str)) {
649                                 return str;
650                         }
651                 }
652         }
653
654         std::cerr << "Could not load encoding option \"" << name << "\" for export format" << std::endl;
655
656         return "";
657 }
658
659 }; // namespace ARDOUR