ardour
export_format_specification.cc
Go to the documentation of this file.
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 
22 
23 #include <sstream>
24 
26 #include "ardour/export_formats.h"
27 #include "ardour/session.h"
28 
29 #include "pbd/error.h"
30 #include "pbd/xml++.h"
31 #include "pbd/enumwriter.h"
32 #include "pbd/convert.h"
33 
34 #include "i18n.h"
35 
36 namespace ARDOUR
37 {
38 
39 using namespace PBD;
40 using std::string;
41 using std::list;
42 
43 ExportFormatSpecification::Time &
45 {
46  static_cast<AnyTime &>(*this) = other;
47  return *this;
48 }
49 
52 {
53  framecnt_t duration = session.any_duration_to_frames (position, *this);
54  return ((double) target_rate / session.frame_rate()) * duration + 0.5;
55 }
56 
57 XMLNode &
59 {
60 
61  XMLNode * node = new XMLNode ("Duration");
62 
63  node->add_property ("format", enum_2_string (type));
64 
65  switch (type) {
66  case Timecode:
67  node->add_property ("hours", to_string (timecode.hours, std::dec));
68  node->add_property ("minutes", to_string (timecode.minutes, std::dec));
69  node->add_property ("seconds", to_string (timecode.seconds, std::dec));
70  node->add_property ("frames", to_string (timecode.frames, std::dec));
71  break;
72  case BBT:
73  node->add_property ("bars", to_string (bbt.bars, std::dec));
74  node->add_property ("beats", to_string (bbt.beats, std::dec));
75  node->add_property ("ticks", to_string (bbt.ticks, std::dec));
76  break;
77  case Frames:
78  node->add_property ("frames", to_string (frames, std::dec));
79  break;
80  case Seconds:
81  node->add_property ("seconds", to_string (seconds, std::dec));
82  break;
83  }
84 
85  return *node;
86 }
87 
88 int
90 {
91  XMLProperty const * prop;
92 
93  prop = node.property ("format");
94 
95  if (!prop) { return -1; }
96 
97  type = (Type) string_2_enum (prop->value(), Type);
98 
99  switch (type) {
100  case Timecode:
101  if ((prop = node.property ("hours"))) {
102  timecode.hours = atoi (prop->value());
103  }
104 
105  if ((prop = node.property ("minutes"))) {
106  timecode.minutes = atoi (prop->value());
107  }
108 
109  if ((prop = node.property ("seconds"))) {
110  timecode.seconds = atoi (prop->value());
111  }
112 
113  if ((prop = node.property ("frames"))) {
114  timecode.frames = atoi (prop->value());
115  }
116 
117  break;
118 
119  case BBT:
120  if ((prop = node.property ("bars"))) {
121  bbt.bars = atoi (prop->value());
122  }
123 
124  if ((prop = node.property ("beats"))) {
125  bbt.beats = atoi (prop->value());
126  }
127 
128  if ((prop = node.property ("ticks"))) {
129  bbt.ticks = atoi (prop->value());
130  }
131 
132  break;
133 
134  case Frames:
135  if ((prop = node.property ("frames"))) {
136  std::istringstream iss (prop->value());
137  iss >> frames;
138  }
139 
140  break;
141 
142  case Seconds:
143  if ((prop = node.property ("seconds"))) {
144  seconds = atof (prop->value());
145  }
146 
147  break;
148  }
149 
150  return 0;
151 }
152 
154  : session (s)
155 
156  , has_sample_format (false)
157  , supports_tagging (false)
158  , _has_broadcast_info (false)
159  , _channel_limit (0)
160  , _dither_type (D_None)
161  , _src_quality (SRC_SincBest)
162  , _tag (true)
163 
164  , _trim_beginning (false)
165  , _silence_beginning (s)
166  , _trim_end (false)
167  , _silence_end (s)
168 
169  , _normalize (false)
170  , _normalize_target (GAIN_COEFF_UNITY)
171  , _with_toc (false)
172  , _with_cue (false)
173  , _with_mp4chaps (false)
174  , _soundcloud_upload (false)
175  , _command ("")
176 {
177  format_ids.insert (F_None);
178  endiannesses.insert (E_FileDefault);
179  sample_formats.insert (SF_None);
180  sample_rates.insert (SR_None);
181  qualities.insert (Q_None);
182 }
183 
185  : session (s)
186  , _silence_beginning (s)
187  , _silence_end (s)
188  , _soundcloud_upload (false)
189 {
192 
193  set_state (state);
194 }
195 
197  : ExportFormatBase(other)
198  , session (other.session)
199  , _silence_beginning (other.session)
200  , _silence_end (other.session)
201  , _soundcloud_upload (false)
202 {
203  if (modify_name) {
204  set_name (other.name() + " (copy)");
205  } else {
206  set_name (other.name());
207  }
208 
209  _format_name = other._format_name;
211 
215 
216  set_type (other.type());
217  set_format_id (other.format_id());
218  set_endianness (other.endianness());
220  set_sample_rate (other.sample_rate());
221  set_quality (other.quality());
222 
223  set_dither_type (other.dither_type());
224  set_src_quality (other.src_quality());
226  set_trim_end (other.trim_end());
227  set_normalize (other.normalize());
229 
230  set_tag (other.tag());
231 
234 
235  set_extension(other.extension());
236 }
237 
239 {
240 }
241 
242 XMLNode &
244 {
245  XMLNode * node;
246  XMLNode * root = new XMLNode ("ExportFormatSpecification");
247 
248  root->add_property ("name", _name);
249  root->add_property ("id", _id.to_s());
250  root->add_property ("with-cue", _with_cue ? "true" : "false");
251  root->add_property ("with-toc", _with_toc ? "true" : "false");
252  root->add_property ("with-mp4chaps", _with_mp4chaps ? "true" : "false");
253  root->add_property ("command", _command);
254 
255  node = root->add_child ("Encoding");
256  node->add_property ("id", enum_2_string (format_id()));
257  node->add_property ("type", enum_2_string (type()));
258  node->add_property ("extension", extension());
259  node->add_property ("name", _format_name);
260  node->add_property ("has-sample-format", has_sample_format ? "true" : "false");
261  node->add_property ("channel-limit", to_string (_channel_limit, std::dec));
262 
263  node = root->add_child ("SampleRate");
264  node->add_property ("rate", to_string (sample_rate(), std::dec));
265 
266  node = root->add_child ("SRCQuality");
267  node->add_property ("quality", enum_2_string (src_quality()));
268 
269  XMLNode * enc_opts = root->add_child ("EncodingOptions");
270 
271  add_option (enc_opts, "sample-format", enum_2_string (sample_format()));
272  add_option (enc_opts, "dithering", enum_2_string (dither_type()));
273  add_option (enc_opts, "tag-metadata", _tag ? "true" : "false");
274  add_option (enc_opts, "tag-support", supports_tagging ? "true" : "false");
275  add_option (enc_opts, "broadcast-info", _has_broadcast_info ? "true" : "false");
276 
277  XMLNode * processing = root->add_child ("Processing");
278 
279  node = processing->add_child ("Normalize");
280  node->add_property ("enabled", normalize() ? "true" : "false");
281  node->add_property ("target", to_string (normalize_target(), std::dec));
282 
283  XMLNode * silence = processing->add_child ("Silence");
284  XMLNode * start = silence->add_child ("Start");
285  XMLNode * end = silence->add_child ("End");
286 
287  node = start->add_child ("Trim");
288  node->add_property ("enabled", trim_beginning() ? "true" : "false");
289 
290  node = start->add_child ("Add");
291  node->add_property ("enabled", _silence_beginning.not_zero() ? "true" : "false");
293 
294  node = end->add_child ("Trim");
295  node->add_property ("enabled", trim_end() ? "true" : "false");
296 
297  node = end->add_child ("Add");
298  node->add_property ("enabled", _silence_end.not_zero() ? "true" : "false");
300 
301  return *root;
302 }
303 
304 int
306 {
307  XMLProperty const * prop;
308  XMLNode const * child;
309  string value;
310 
311  if ((prop = root.property ("name"))) {
312  _name = prop->value();
313  }
314 
315  if ((prop = root.property ("id"))) {
316  _id = prop->value();
317  }
318 
319  if ((prop = root.property ("with-cue"))) {
321  } else {
322  _with_cue = false;
323  }
324 
325  if ((prop = root.property ("with-toc"))) {
327  } else {
328  _with_toc = false;
329  }
330 
331  if ((prop = root.property ("with-mp4chaps"))) {
333  } else {
334  _with_mp4chaps = false;
335  }
336 
337  if ((prop = root.property ("command"))) {
338  _command = prop->value();
339  } else {
340  _command = "";
341  }
342 
343  /* Encoding and SRC */
344 
345  if ((child = root.child ("Encoding"))) {
346  if ((prop = child->property ("id"))) {
348  }
349 
350  if ((prop = child->property ("type"))) {
351  set_type ((Type) string_2_enum (prop->value(), Type));
352  }
353 
354  if ((prop = child->property ("extension"))) {
355  set_extension (prop->value());
356  }
357 
358  if ((prop = child->property ("name"))) {
359  _format_name = prop->value();
360  }
361 
362  if ((prop = child->property ("has-sample-format"))) {
364  }
365 
366  if ((prop = child->property ("has-sample-format"))) {
368  }
369 
370  if ((prop = child->property ("channel-limit"))) {
371  _channel_limit = atoi (prop->value());
372  }
373  }
374 
375  if ((child = root.child ("SampleRate"))) {
376  if ((prop = child->property ("rate"))) {
378  }
379  }
380 
381  if ((child = root.child ("SRCQuality"))) {
382  if ((prop = child->property ("quality"))) {
384  }
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 (!(get_option (child, "tag-metadata").compare ("true")));
393  supports_tagging = (!(get_option (child, "tag-support").compare ("true")));
394  _has_broadcast_info = (!(get_option (child, "broadcast-info").compare ("true")));
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  if ((prop = child->property ("enabled"))) {
404  _normalize = (!prop->value().compare ("true"));
405  }
406 
407  if ((prop = child->property ("target"))) {
408  _normalize_target = atof (prop->value());
409  }
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  if ((prop = child->property ("enabled"))) {
423  _trim_beginning = (!prop->value().compare ("true"));
424  }
425  }
426 
427  if ((child = start->child ("Add"))) {
428  if ((prop = child->property ("enabled"))) {
429  if (!prop->value().compare ("true")) {
430  if ((child = child->child ("Duration"))) {
431  _silence_beginning.set_state (*child);
432  }
433  } else {
435  }
436  }
437  }
438 
439  /* Silence end */
440 
441  if ((child = end->child ("Trim"))) {
442  if ((prop = child->property ("enabled"))) {
443  _trim_end = (!prop->value().compare ("true"));
444  }
445  }
446 
447  if ((child = end->child ("Add"))) {
448  if ((prop = child->property ("enabled"))) {
449  if (!prop->value().compare ("true")) {
450  if ((child = child->child ("Duration"))) {
451  _silence_end.set_state (*child);
452  }
453  } else {
455  }
456  }
457  }
458 
459  return 0;
460 }
461 
462 bool
464 {
465  boost::shared_ptr<ExportFormatBase> intersection = get_intersection (compatibility);
466 
467  if (intersection->formats_empty() && format_id() != 0) {
468  return false;
469  }
470 
471  if (intersection->endiannesses_empty() && endianness() != E_FileDefault) {
472  return false;
473  }
474 
475  if (intersection->sample_rates_empty() && sample_rate() != SR_None) {
476  return false;
477  }
478 
479  if (intersection->sample_formats_empty() && sample_format() != SF_None) {
480  return false;
481  }
482 
483  if (intersection->qualities_empty() && quality() != Q_None) {
484  return false;
485  }
486 
487  return true;
488 }
489 
490 bool
492 {
493  if (type() == T_None) {
494  return false;
495  }
496 
497  if (!format_id()) {
498  return false;
499  }
500 
501  if (!sample_rate()) {
502  return false;
503  }
504 
505  if (has_sample_format) {
506  if (sample_format() == SF_None) {
507  return false;
508  }
509  }
510 
511  return true;
512 }
513 
514 void
516 {
517  if (format) {
518  set_format_id (format->get_format_id ());
519  set_type (format->get_type());
520  set_extension (format->extension());
521 
522  if (format->get_explicit_sample_format()) {
523  set_sample_format (format->get_explicit_sample_format());
524  }
525 
526  if (format->has_sample_format()) {
527  has_sample_format = true;
528  }
529 
530  if (format->has_broadcast_info()) {
531  _has_broadcast_info = true;
532  }
533 
534  supports_tagging = format->supports_tagging ();
535  _channel_limit = format->get_channel_limit();
536 
537  _format_name = format->name();
538  } else {
540  set_type (T_None);
541  set_extension ("");
542  _has_broadcast_info = false;
543  has_sample_format = false;
544  supports_tagging = false;
545  _channel_limit = 0;
546  _format_name = "";
547  }
548 }
549 
550 string
552 {
553  list<string> components;
554 
555  if (_normalize) {
556  components.push_back (_("normalize"));
557  }
558 
559  if (_trim_beginning && _trim_end) {
560  components.push_back ( _("trim"));
561  } else if (_trim_beginning) {
562  components.push_back (_("trim start"));
563  } else if (_trim_end) {
564  components.push_back (_("trim end"));
565  }
566 
567  if (_format_name != "") {
568  components.push_back (_format_name);
569  }
570 
571  if (has_sample_format) {
572  components.push_back (HasSampleFormat::get_sample_format_name (sample_format()));
573  }
574 
575  switch (sample_rate()) {
576  case SR_8:
577  components.push_back ("8 kHz");
578  break;
579  case SR_22_05:
580  components.push_back ("22,5 kHz");
581  break;
582  case SR_44_1:
583  components.push_back ("44,1 kHz");
584  break;
585  case SR_48:
586  components.push_back ("48 kHz");
587  break;
588  case SR_88_2:
589  components.push_back ("88,2 kHz");
590  break;
591  case SR_96:
592  components.push_back ("96 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->add_property ("name", name);
637  node->add_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  XMLProperty * prop = (*it)->property ("name");
647  if (prop && !name.compare (prop->value())) {
648  prop = (*it)->property ("value");
649  if (prop) {
650  return prop->value();
651  }
652  }
653  }
654 
655  std::cerr << "Could not load encoding option \"" << name << "\" for export format" << std::endl;
656 
657  return "";
658 }
659 
660 }; // namespace ARDOUR
void set_extension(std::string const &extension)
std::string to_string(T t, std::ios_base &(*f)(std::ios_base &))
Definition: convert.h:53
int atoi(const string &s)
Definition: convert.cc:140
const std::string & value() const
Definition: xml++.h:159
#define enum_2_string(e)
Definition: enumwriter.h:97
boost::shared_ptr< ExportFormatBase > get_intersection(ExportFormatBase const &other) const
void set_name(std::string const &name)
bool not_zero() const
Definition: types.h:266
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
XMLNode * add_child(const char *)
Definition: xml++.cc:351
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
#define _(Text)
Definition: i18n.h:11
#define X_(Text)
Definition: i18n.h:13
int64_t framecnt_t
Definition: types.h:76
XMLProperty * property(const char *)
Definition: xml++.cc:413
#define string_2_enum(str, e)
Definition: enumwriter.h:98
std::string to_s() const
Definition: uuid.cc:33
framecnt_t get_frames_at(framepos_t position, framecnt_t target_rate) const
bool string_is_affirmative(const std::string &str)
Definition: convert.cc:282
Definition: amp.h:29
int64_t framepos_t
Definition: types.h:66
bool is_compatible_with(ExportFormatCompatibility const &compatibility) const
XMLProperty * add_property(const char *name, const std::string &value)
const char * name
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
std::string get_option(XMLNode const *node, std::string const &name)
void set_silence_beginning(AnyTime const &value)
static std::string get_sample_format_name(ExportFormatBase::SampleFormat format)
void set_format(boost::shared_ptr< ExportFormat > format)
void add_option(XMLNode *node, std::string const &name, std::string const &value)
Definition: xml++.h:95
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
Definition: debug.h:30
XMLNode * child(const char *) const
Definition: xml++.cc:309
Allows adding to all sets. A format should be able to test if it is compatible with this...
#define GAIN_COEFF_UNITY
Definition: dB.h:28
std::string description(bool include_name=true)
double atof(const string &s)
Definition: convert.cc:158
std::string const & extension() const