ardour
export_profile_manager.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 
21 #include <cassert>
22 #include <stdexcept>
23 #include <cerrno>
24 
25 #include <glib.h>
26 #include <glib/gstdio.h>
27 
28 #include <glibmm/fileutils.h>
29 #include <glibmm/miscutils.h>
30 
31 #include "pbd/enumwriter.h"
32 #include "pbd/xml++.h"
33 #include "pbd/convert.h"
34 
37 #include "ardour/search_paths.h"
38 #include "ardour/export_timespan.h"
40 #include "ardour/export_filename.h"
41 #include "ardour/export_preset.h"
42 #include "ardour/export_handler.h"
43 #include "ardour/export_failed.h"
44 #include "ardour/directory_names.h"
46 #include "ardour/route.h"
47 #include "ardour/session.h"
48 #include "ardour/broadcast_info.h"
49 
50 #include "i18n.h"
51 
52 using namespace std;
53 using namespace Glib;
54 using namespace PBD;
55 
56 namespace ARDOUR
57 {
58 
59 ExportProfileManager::ExportProfileManager (Session & s, ExportType type)
60  : type(type)
61  , handler (s.get_export_handler())
62  , session (s)
63 
64  , ranges (new LocationList ())
65  , single_range_mode (false)
66 
67  , format_list (new FormatList ())
68 {
69  switch(type) {
70  case RegularExport:
71  xml_node_name = X_("ExportProfile");
72  break;
73  case RangeExport:
74  xml_node_name = X_("RangeExportProfile");
75  break;
76  case SelectionExport:
77  xml_node_name = X_("SelectionExportProfile");
78  break;
79  case RegionExport:
80  xml_node_name = X_("RegionExportProfile");
81  break;
82  case StemExport:
83  xml_node_name = X_("StemExportProfile");
84  break;
85  }
86 
87  /* Initialize path variables */
88 
89  export_config_dir = Glib::build_filename (user_config_directory(), export_dir_name);
90 
92 
93  info << string_compose (_("Searching for export formats in %1"), search_path.to_string()) << endmsg;
94 
95  /* create export config directory if necessary */
96 
97  if (!Glib::file_test (export_config_dir, Glib::FILE_TEST_EXISTS)) {
98  if (g_mkdir_with_parents (export_config_dir.c_str(), 0755) != 0) {
99  error << string_compose (_("Unable to create export format directory %1: %2"), export_config_dir, g_strerror(errno)) << endmsg;
100  }
101  }
102 
103  load_presets ();
104  load_formats ();
105 
106  /* Initialize all lists with an empty config */
107 
108  XMLNodeList dummy;
109  init_timespans (dummy);
110  init_channel_configs (dummy);
111  init_formats (dummy);
112  init_filenames (dummy);
113 }
114 
116 {
117  XMLNode * extra_xml (new XMLNode (xml_node_name));
118  serialize_profile (*extra_xml);
119  session.add_extra_xml (*extra_xml);
120 }
121 
122 void
124 {
125  XMLNode * extra_node = session.extra_xml (xml_node_name);
126  /* Legacy sessions used Session instant.xml for this */
127  if (!extra_node) {
128  extra_node = session.instant_xml (xml_node_name);
129  }
130 
131  if (extra_node) {
132  set_state (*extra_node);
133  } else {
134  XMLNode empty_node (xml_node_name);
135  set_state (empty_node);
136  }
137 }
138 
139 void
141 {
142  TimespanListPtr ts_list = timespans.front()->timespans;
143 
144  FormatStateList::const_iterator format_it;
145  FilenameStateList::const_iterator filename_it;
146 
147  // For each timespan
148  for (TimespanList::iterator ts_it = ts_list->begin(); ts_it != ts_list->end(); ++ts_it) {
149  // ..., each format-filename pair
150  for (format_it = formats.begin(), filename_it = filenames.begin();
151  format_it != formats.end() && filename_it != filenames.end();
152  ++format_it, ++filename_it) {
153 
154  ExportFilenamePtr filename = (*filename_it)->filename;
155 // filename->include_timespan = (ts_list->size() > 1); Disabled for now...
156 
158  if ((*format_it)->format->has_broadcast_info()) {
159  b.reset (new BroadcastInfo);
160  b->set_from_session (session, (*ts_it)->get_start());
161  }
162 
163  // ...and each channel config
164  filename->include_channel_config = (type == StemExport) ||
165  (channel_configs.size() > 1);
166  for(ChannelConfigStateList::iterator cc_it = channel_configs.begin(); cc_it != channel_configs.end(); ++cc_it) {
167  handler->add_export_config (*ts_it, (*cc_it)->config, (*format_it)->format, filename, b);
168  }
169  }
170  }
171 }
172 
173 bool
175 {
176  bool ok = true;
177 
178  current_preset = preset;
179  if (!preset) { return false; }
180 
181  XMLNode const * state;
182  if ((state = preset->get_local_state())) {
183  set_local_state (*state);
184  } else { ok = false; }
185 
186  if ((state = preset->get_global_state())) {
187  if (!set_global_state (*state)) {
188  ok = false;
189  }
190  } else { ok = false; }
191 
192  return ok;
193 }
194 
195 void
197 {
198  vector<std::string> found = find_file (string_compose (X_("*%1"),export_preset_suffix));
199 
200  for (vector<std::string>::iterator it = found.begin(); it != found.end(); ++it) {
201  load_preset_from_disk (*it);
202  }
203 }
204 
205 std::string
206 ExportProfileManager::preset_filename (std::string const & preset_name)
207 {
208  string safe_name = legalize_for_path (preset_name);
209  return Glib::build_filename (export_config_dir, safe_name + export_preset_suffix);
210 }
211 
214 {
215  // Generate new ID and do regular save
216  string filename = preset_filename (name);
217  current_preset.reset (new ExportPreset (filename, session));
218  preset_list.push_back (current_preset);
219  return save_preset (name);
220 }
221 
224 {
225  string filename = preset_filename (name);
226 
227  if (!current_preset) {
228  current_preset.reset (new ExportPreset (filename, session));
229  preset_list.push_back (current_preset);
230  }
231 
232  XMLNode * global_preset = new XMLNode ("ExportPreset");
233  XMLNode * local_preset = new XMLNode ("ExportPreset");
234 
235  serialize_global_profile (*global_preset);
236  serialize_local_profile (*local_preset);
237 
238  current_preset->set_name (name);
239  current_preset->set_global_state (*global_preset);
240  current_preset->set_local_state (*local_preset);
241 
242  current_preset->save (filename);
243 
244  return current_preset;
245 }
246 
247 void
249 {
250  if (!current_preset) { return; }
251 
252  for (PresetList::iterator it = preset_list.begin(); it != preset_list.end(); ++it) {
253  if (*it == current_preset) {
254  preset_list.erase (it);
255  break;
256  }
257  }
258 
259  FileMap::iterator it = preset_file_map.find (current_preset->id());
260  if (it != preset_file_map.end()) {
261  if (g_remove (it->second.c_str()) != 0) {
262  error << string_compose (_("Unable to remove export preset %1: %2"), it->second, g_strerror(errno)) << endmsg;
263  }
264  preset_file_map.erase (it);
265  }
266 
267  current_preset->remove_local();
269 }
270 
271 void
273 {
274  ExportPresetPtr preset (new ExportPreset (path, session));
275 
276  /* Handle id to filename mapping and don't add duplicates to list */
277 
278  FilePair pair (preset->id(), path);
279  if (preset_file_map.insert (pair).second) {
280  preset_list.push_back (preset);
281  }
282 }
283 
284 bool
286 {
287  return set_global_state (root) & set_local_state (root);
288 }
289 
290 bool
292 {
293  return init_filenames (root.children ("ExportFilename")) &
294  init_formats (root.children ("ExportFormat"));
295 }
296 
297 bool
299 {
300  return init_timespans (root.children ("ExportTimespan")) &
301  init_channel_configs (root.children ("ExportChannelConfiguration"));
302 }
303 
304 void
306 {
309 }
310 
311 void
313 {
314  for (FormatStateList::iterator it = formats.begin(); it != formats.end(); ++it) {
315  root.add_child_nocopy (serialize_format (*it));
316  }
317 
318  for (FilenameStateList::iterator it = filenames.begin(); it != filenames.end(); ++it) {
319  root.add_child_nocopy ((*it)->filename->get_state());
320  }
321 }
322 
323 void
325 {
326  for (TimespanStateList::iterator it = timespans.begin(); it != timespans.end(); ++it) {
328  }
329 
330  for (ChannelConfigStateList::iterator it = channel_configs.begin(); it != channel_configs.end(); ++it) {
331  root.add_child_nocopy ((*it)->config->get_state());
332  }
333 }
334 
335 std::vector<std::string>
336 ExportProfileManager::find_file (std::string const & pattern)
337 {
338  vector<std::string> found;
339 
340  find_files_matching_pattern (found, search_path, pattern);
341 
342  return found;
343 }
344 
345 void
347 {
348 
349  if (start || end) {
350  selection_range.reset (new Location (session));
351  selection_range->set_name (_("Selection"));
352  selection_range->set (start, end);
353  } else {
354  selection_range.reset();
355  }
356 
357  for (TimespanStateList::iterator it = timespans.begin(); it != timespans.end(); ++it) {
358  (*it)->selection_range = selection_range;
359  }
360 }
361 
362 std::string
364 {
365  single_range_mode = true;
366 
367  single_range.reset (new Location (session));
368  single_range->set_name (name);
369  single_range->set (start, end);
370 
371  update_ranges ();
372 
373  return single_range->id().to_s();
374 }
375 
376 bool
378 {
379  timespans.clear ();
380  update_ranges ();
381 
382  bool ok = true;
383  for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
385  if (span) {
386  timespans.push_back (span);
387  } else { ok = false; }
388  }
389 
390  if (timespans.empty()) {
392  timespans.push_back (state);
393 
394  // Add session as default selection
395  Location * session_range = session.locations()->session_range_location();
396  if (!session_range) { return false; }
397 
398  ExportTimespanPtr timespan = handler->add_timespan();
399  timespan->set_name (session_range->name());
400  timespan->set_range_id (session_range->id().to_s());
401  timespan->set_range (session_range->start(), session_range->end());
402  state->timespans->push_back (timespan);
403  return false;
404  }
405 
406  return ok;
407 }
408 
411 {
413  XMLProperty const * prop;
414 
415  XMLNodeList spans = root.children ("Range");
416  for (XMLNodeList::iterator node_it = spans.begin(); node_it != spans.end(); ++node_it) {
417 
418  prop = (*node_it)->property ("id");
419  if (!prop) { continue; }
420  string id = prop->value();
421 
422  Location * location = 0;
423  for (LocationList::iterator it = ranges->begin(); it != ranges->end(); ++it) {
424  if ((id == "selection" && *it == selection_range.get()) ||
425  (id == (*it)->id().to_s())) {
426  location = *it;
427  break;
428  }
429  }
430 
431  if (!location) { continue; }
432 
433  ExportTimespanPtr timespan = handler->add_timespan();
434  timespan->set_name (location->name());
435  timespan->set_range_id (location->id().to_s());
436  timespan->set_range (location->start(), location->end());
437  state->timespans->push_back (timespan);
438  }
439 
440  if ((prop = root.property ("format"))) {
441  state->time_format = (TimeFormat) string_2_enum (prop->value(), TimeFormat);
442  }
443 
444  if (state->timespans->empty()) {
445  return TimespanStatePtr();
446  }
447 
448  return state;
449 }
450 
451 XMLNode &
453 {
454  XMLNode & root = *(new XMLNode ("ExportTimespan"));
455  XMLNode * span;
456 
457  update_ranges ();
458  for (TimespanList::iterator it = state->timespans->begin(); it != state->timespans->end(); ++it) {
459  if ((span = root.add_child ("Range"))) {
460  span->add_property ("id", (*it)->range_id());
461  }
462  }
463 
464  root.add_property ("format", enum_2_string (state->time_format));
465 
466  return root;
467 }
468 
469 void
471  ranges->clear();
472 
473  if (single_range_mode) {
474  ranges->push_back (single_range.get());
475  return;
476  }
477 
478  /* Session */
479 
480  Location * session_range = session.locations()->session_range_location();
481  if (session_range) {
482  ranges->push_back (session_range);
483  }
484 
485  /* Selection */
486 
487  if (selection_range) {
488  ranges->push_back (selection_range.get());
489  }
490 
491  /* ranges */
492 
493  LocationList const & list (session.locations()->list());
494  for (LocationList::const_iterator it = list.begin(); it != list.end(); ++it) {
495  if ((*it)->is_range_marker()) {
496  ranges->push_back (*it);
497  }
498  }
499 }
500 
503 {
504  ChannelConfigStatePtr ptr(new ChannelConfigState(handler->add_channel_config()));
505  channel_configs.push_back(ptr);
506  return ptr;
507 }
508 
509 bool
511 {
512  channel_configs.clear();
513 
514  if (nodes.empty()) {
515  ChannelConfigStatePtr config (new ChannelConfigState (handler->add_channel_config()));
516  channel_configs.push_back (config);
517 
518  // Add master outs as default
519  if (!session.master_out()) { return false; }
520 
521  IO* master_out = session.master_out()->output().get();
522  if (!master_out) { return false; }
523 
524  for (uint32_t n = 0; n < master_out->n_ports().n_audio(); ++n) {
525  PortExportChannel * channel = new PortExportChannel ();
526  channel->add_port (master_out->audio (n));
527 
528  ExportChannelPtr chan_ptr (channel);
529  config->config->register_channel (chan_ptr);
530  }
531  return false;
532  }
533 
534  for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
535  ChannelConfigStatePtr config (new ChannelConfigState (handler->add_channel_config()));
536  config->config->set_state (**it);
537  channel_configs.push_back (config);
538  }
539 
540  return true;
541 }
542 
545 {
546  /* Note: The pointer in the new FormatState should point to the same format spec
547  as the original state's pointer. The spec itself should not be copied! */
548 
549  FormatStatePtr format (new FormatState (format_list, state->format));
550  formats.push_back (format);
551  return format;
552 }
553 
554 void
556 {
557  for (FormatStateList::iterator it = formats.begin(); it != formats.end(); ++it) {
558  if (*it == state) {
559  formats.erase (it);
560  return;
561  }
562  }
563 }
564 
565 std::string
567 {
568  // TODO filename character stripping
569 
570  /* Get filename for file */
571 
572  string new_name = format->name();
573  new_name += export_format_suffix;
574 
575  /* make sure its legal for the filesystem */
576 
577  new_name = legalize_for_path (new_name);
578 
579  std::string new_path = Glib::build_filename (export_config_dir, new_name);
580 
581  /* Check if format is on disk already */
582  FileMap::iterator it;
583  if ((it = format_file_map.find (format->id())) != format_file_map.end()) {
584 
585  /* Check if config is not in user config dir */
586  if (Glib::path_get_dirname (it->second) != export_config_dir) {
587 
588  /* Write new file */
589 
590  XMLTree tree (new_path);
591  tree.set_root (&format->get_state());
592  tree.write();
593 
594  } else {
595 
596  /* Update file and rename if necessary */
597 
598  XMLTree tree (it->second);
599  tree.set_root (&format->get_state());
600  tree.write();
601 
602  if (new_name != Glib::path_get_basename (it->second)) {
603  if (g_rename (it->second.c_str(), new_path.c_str()) != 0) {
604  error << string_compose (_("Unable to rename export format %1 to %2: %3"), it->second, new_path, g_strerror(errno)) << endmsg;
605  };
606  }
607  }
608 
609  it->second = new_path;
610 
611  } else {
612  /* Write new file */
613 
614  XMLTree tree (new_path);
615  tree.set_root (&format->get_state());
616  tree.write();
617  }
618 
620  return new_path;
621 }
622 
623 void
625 {
626  for (FormatList::iterator it = format_list->begin(); it != format_list->end(); ++it) {
627  if (*it == format) {
628  format_list->erase (it);
629  break;
630  }
631  }
632 
633  FileMap::iterator it = format_file_map.find (format->id());
634  if (it != format_file_map.end()) {
635  if (g_remove (it->second.c_str()) != 0) {
636  error << string_compose (_("Unable to remove export profile %1: %2"), it->second, g_strerror(errno)) << endmsg;
637  return;
638  }
639  format_file_map.erase (it);
640  }
641 
643 }
644 
647 {
648  ExportFormatSpecPtr format;
649  if (original) {
650  format.reset (new ExportFormatSpecification (*original));
651  std::cerr << "After new format created from original, format has id [" << format->id().to_s() << ']' << std::endl;
652  } else {
653  format = handler->add_format();
654  format->set_name (_("empty format"));
655  }
656 
657  std::string path = save_format_to_disk (format);
658  FilePair pair (format->id(), path);
659  format_file_map.insert (pair);
660 
661  format_list->push_back (format);
663 
664  return format;
665 }
666 
667 bool
669 {
670  formats.clear();
671 
672  bool ok = true;
673  for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
674  FormatStatePtr format = deserialize_format (**it);
675  if (format) {
676  formats.push_back (format);
677  } else { ok = false; }
678  }
679 
680  if (formats.empty ()) {
682  formats.push_back (format);
683  return false;
684  }
685 
686  return ok;
687 }
688 
691 {
692  XMLProperty * prop;
693  PBD::UUID id;
694 
695  if ((prop = root.property ("id"))) {
696  id = prop->value();
697  }
698 
699  for (FormatList::iterator it = format_list->begin(); it != format_list->end(); ++it) {
700  if ((*it)->id() == id) {
701  return FormatStatePtr (new FormatState (format_list, *it));
702  }
703  }
704 
705  return FormatStatePtr ();
706 }
707 
708 XMLNode &
710 {
711  XMLNode * root = new XMLNode ("ExportFormat");
712 
713  string id = state->format ? state->format->id().to_s() : "";
714  root->add_property ("id", id);
715 
716  return *root;
717 }
718 
719 void
721 {
722  vector<std::string> found = find_file (string_compose ("*%1", export_format_suffix));
723 
724  for (vector<std::string>::iterator it = found.begin(); it != found.end(); ++it) {
725  load_format_from_disk (*it);
726  }
727 }
728 
729 void
731 {
732  XMLTree tree;
733 
734  if (!tree.read (path)) {
735  error << string_compose (_("Cannot load export format from %1"), path) << endmsg;
736  return;
737  }
738 
739  XMLNode* root = tree.root();
740  if (!root) {
741  error << string_compose (_("Cannot export format read from %1"), path) << endmsg;
742  return;
743  }
744 
745  ExportFormatSpecPtr format = handler->add_format (*root);
746 
747  /* Handle id to filename mapping and don't add duplicates to list */
748 
749  FilePair pair (format->id(), path);
750  if (format_file_map.insert (pair).second) {
751  format_list->push_back (format);
752  }
753 
755 }
756 
759 {
760  FilenameStatePtr filename (new FilenameState (handler->add_filename_copy (state->filename)));
761  filenames.push_back (filename);
762  return filename;
763 }
764 
765 void
767 {
768  for (FilenameStateList::iterator it = filenames.begin(); it != filenames.end(); ++it) {
769  if (*it == state) {
770  filenames.erase (it);
771  return;
772  }
773  }
774 }
775 
776 std::string
778 {
779  assert (format);
780 
781  if (channel_configs.empty()) { return ""; }
782 
783  std::list<string> filenames;
784  build_filenames (filenames, filename, timespans.front()->timespans,
785  channel_configs.front()->config, format);
786 
787  if (filenames.empty()) { return ""; }
788  return filenames.front();
789 }
790 
791 bool
793 {
794  filenames.clear ();
795 
796  for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
797  ExportFilenamePtr filename = handler->add_filename();
798  filename->set_state (**it);
799  filenames.push_back (FilenameStatePtr (new FilenameState (filename)));
800  }
801 
802  if (filenames.empty()) {
803  FilenameStatePtr filename (new FilenameState (handler->add_filename()));
804  filenames.push_back (filename);
805  return false;
806  }
807 
808  return true;
809 }
810 
813 {
814  boost::shared_ptr<Warnings> warnings (new Warnings ());
815 
816  ChannelConfigStatePtr channel_config_state;
817  if (!channel_configs.empty ()) {
818  channel_config_state = channel_configs.front();
819  }
820 
821  TimespanStatePtr timespan_state = timespans.front();
822 
823  /*** Check "global" config ***/
824 
825  TimespanListPtr timespans = timespan_state->timespans;
826 
827  ExportChannelConfigPtr channel_config;
828  if (channel_config_state) {
829  channel_config = channel_config_state->config;
830  }
831 
832  /* Check Timespans are not empty */
833 
834  if (timespans->empty()) {
835  warnings->errors.push_back (_("No timespan has been selected!"));
836  }
837 
838  if (channel_config_state == 0) {
839  warnings->errors.push_back (_("No channels have been selected!"));
840  } else {
841  /* Check channel config ports */
842  if (!channel_config->all_channels_have_ports ()) {
843  warnings->warnings.push_back (_("Some channels are empty"));
844  }
845  }
846 
847  /*** Check files ***/
848 
849  if (channel_config_state) {
850  FormatStateList::const_iterator format_it;
851  FilenameStateList::const_iterator filename_it;
852  for (format_it = formats.begin(), filename_it = filenames.begin();
853  format_it != formats.end() && filename_it != filenames.end();
854  ++format_it, ++filename_it) {
855  check_config (warnings, timespan_state, channel_config_state, *format_it, *filename_it);
856  }
857  }
858 
859  return warnings;
860 }
861 
862 void
864  TimespanStatePtr timespan_state,
865  ChannelConfigStatePtr channel_config_state,
866  FormatStatePtr format_state,
867  FilenameStatePtr filename_state)
868 {
869  TimespanListPtr timespans = timespan_state->timespans;
870  ExportChannelConfigPtr channel_config = channel_config_state->config;
871  ExportFormatSpecPtr format = format_state->format;
872  ExportFilenamePtr filename = filename_state->filename;
873 
874  /* Check format and maximum channel count */
875  if (!format || !format->type()) {
876  warnings->errors.push_back (_("No format selected!"));
877  } else if (!channel_config->get_n_chans()) {
878  warnings->errors.push_back (_("All channels are empty!"));
879  } else if (!check_format (format, channel_config->get_n_chans())) {
880  warnings->errors.push_back (_("One or more of the selected formats is not compatible with this system!"));
881  } else if (format->channel_limit() < channel_config->get_n_chans()) {
882  warnings->errors.push_back
883  (string_compose (_("%1 supports only %2 channels, but you have %3 channels in your channel configuration"),
884  format->format_name(),
885  format->channel_limit(),
886  channel_config->get_n_chans()));
887  }
888 
889  if (!warnings->errors.empty()) { return; }
890 
891  /* Check filenames */
892 
893 // filename->include_timespan = (timespans->size() > 1); Disabled for now...
894 
895  std::list<string> paths;
896  build_filenames(paths, filename, timespans, channel_config, format);
897 
898  for (std::list<string>::const_iterator path_it = paths.begin(); path_it != paths.end(); ++path_it) {
899 
900  string path = *path_it;
901 
902  if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
903  warnings->conflicting_filenames.push_back (path);
904  }
905 
906  if (format->with_toc()) {
907  string marker_file = handler->get_cd_marker_filename(path, CDMarkerTOC);
908  if (Glib::file_test (marker_file, Glib::FILE_TEST_EXISTS)) {
909  warnings->conflicting_filenames.push_back (marker_file);
910  }
911  }
912 
913  if (format->with_cue()) {
914  string marker_file = handler->get_cd_marker_filename(path, CDMarkerCUE);
915  if (Glib::file_test (marker_file, Glib::FILE_TEST_EXISTS)) {
916  warnings->conflicting_filenames.push_back (marker_file);
917  }
918  }
919  }
920 }
921 
922 bool
924 {
925  switch (format->type()) {
927  return check_sndfile_format (format, channels);
928 
929  default:
930  throw ExportFailed (X_("Invalid format given for ExportFileFactory::check!"));
931  }
932 }
933 
934 bool
936 {
937  SF_INFO sf_info;
938  sf_info.channels = channels;
939  sf_info.samplerate = format->sample_rate ();
940  sf_info.format = format->format_id () | format->sample_format ();
941 
942  return (sf_format_check (&sf_info) == SF_TRUE ? true : false);
943 }
944 
945 void
946 ExportProfileManager::build_filenames(std::list<std::string> & result, ExportFilenamePtr filename,
947  TimespanListPtr timespans, ExportChannelConfigPtr channel_config,
948  ExportFormatSpecPtr format)
949 {
950  for (std::list<ExportTimespanPtr>::iterator timespan_it = timespans->begin();
951  timespan_it != timespans->end(); ++timespan_it) {
952  filename->set_timespan (*timespan_it);
953 
954  if (channel_config->get_split()) {
955  filename->include_channel = true;
956 
957  for (uint32_t chan = 1; chan <= channel_config->get_n_chans(); ++chan) {
958  filename->set_channel (chan);
959  result.push_back(filename->get_path (format));
960  }
961 
962  } else {
963  filename->include_channel = false;
964  result.push_back(filename->get_path (format));
965  }
966  }
967 }
968 
969 }; // namespace ARDOUR
XMLNode & serialize_timespan(TimespanStatePtr state)
boost::shared_ptr< TimespanState > TimespanStatePtr
void build_filenames(std::list< std::string > &result, ExportFilenamePtr filename, TimespanListPtr timespans, ExportChannelConfigPtr channel_config, ExportFormatSpecPtr format)
const std::string & value() const
Definition: xml++.h:159
boost::shared_ptr< FormatList > format_list
std::string get_sample_filename_for_format(ExportFilenamePtr filename, ExportFormatSpecPtr format)
bool check_sndfile_format(ExportFormatSpecPtr format, unsigned int channels)
bool write() const
Definition: xml++.cc:147
#define enum_2_string(e)
Definition: enumwriter.h:97
LIBARDOUR_API std::string legalize_for_path(const std::string &str)
FormatStatePtr deserialize_format(XMLNode &root)
LIBARDOUR_API const char *const export_dir_name
void remove_format_state(FormatStatePtr state)
XMLNode & serialize_format(FormatStatePtr state)
uint32_t n_audio() const
Definition: chan_count.h:63
Basic export channel that reads from AudioPorts.
framepos_t end() const
Definition: location.h:72
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
bool set_local_state(XMLNode const &root)
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
FormatStatePtr duplicate_format_state(FormatStatePtr state)
void load_format_from_disk(std::string const &path)
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
ChannelConfigStateList channel_configs
XMLNode * add_child(const char *)
Definition: xml++.cc:351
std::string set_single_range(framepos_t start, framepos_t end, std::string name)
Definition: xml++.h:55
ExportPresetPtr save_preset(std::string const &name)
Location * session_range_location() const
Definition: location.cc:1348
boost::shared_ptr< AudioPort > audio(uint32_t n) const
Definition: io.cc:1430
bool init_channel_configs(XMLNodeList nodes)
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
Locations * locations()
Definition: session.h:382
#define _(Text)
Definition: i18n.h:11
LIBARDOUR_API std::string user_config_directory(int version=-1)
bool check_format(ExportFormatSpecPtr format, uint32_t channels)
void remove_format_profile(ExportFormatSpecPtr format)
const ChanCount & n_ports() const
Definition: io.h:135
ExportPresetPtr new_preset(std::string const &name)
#define X_(Text)
Definition: i18n.h:13
void find_files_matching_pattern(vector< string > &result, const Searchpath &paths, const Glib::PatternSpec &pattern)
Definition: file_utils.cc:168
XMLProperty * property(const char *)
Definition: xml++.cc:413
ChannelConfigStatePtr add_channel_config()
#define string_2_enum(str, e)
Definition: enumwriter.h:98
bool init_timespans(XMLNodeList nodes)
XMLNode * set_root(XMLNode *n)
Definition: xml++.h:63
const LocationList & list()
Definition: location.h:172
XMLNode * root() const
Definition: xml++.h:62
Definition: amp.h:29
boost::shared_ptr< Route > master_out() const
Definition: session.h:718
const PBD::ID & id() const
Definition: stateful.h:68
void set_selection_range(framepos_t start=0, framepos_t end=0)
std::string to_s() const
Definition: id.cc:78
void add_port(boost::weak_ptr< AudioPort > port)
bool read()
Definition: xml++.h:71
ExportFormatSpecPtr get_new_format(ExportFormatSpecPtr original)
int64_t framepos_t
Definition: types.h:66
T * get() const
Definition: shared_ptr.hpp:268
LIBPBD_API Transmitter info
LIBARDOUR_API PBD::Searchpath export_formats_search_path()
Definition: search_paths.cc:73
void remove_filename_state(FilenameStatePtr state)
boost::shared_ptr< FormatState > FormatStatePtr
LIBARDOUR_API const char *const export_format_suffix
XMLProperty * add_property(const char *name, const std::string &value)
std::vector< std::string > find_file(std::string const &pattern)
const char * name
boost::shared_ptr< Warnings > get_warnings()
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
const std::string & name() const
Definition: location.h:81
std::pair< PBD::UUID, std::string > FilePair
void serialize_local_profile(XMLNode &root)
XMLNode * instant_xml(const std::string &str)
Definition: xml++.h:95
LIBPBD_TEMPLATE_MEMBER_API const std::string to_string() const
Definition: search_path.cc:99
std::list< ExportFormatSpecPtr > FormatList
TimespanStatePtr deserialize_timespan(XMLNode &root)
XMLNode * extra_xml(const std::string &str, bool add_if_missing=false)
Definition: stateful.cc:77
Definition: debug.h:30
bool init_formats(XMLNodeList nodes)
bool set_global_state(XMLNode const &root)
void load_preset_from_disk(std::string const &path)
bool init_filenames(XMLNodeList nodes)
framepos_t start() const
Definition: location.h:71
boost::shared_ptr< Location > single_range
Definition: uuid.h:32
std::string save_format_to_disk(ExportFormatSpecPtr format)
void check_config(boost::shared_ptr< Warnings > warnings, TimespanStatePtr timespan_state, ChannelConfigStatePtr channel_config_state, FormatStatePtr format_state, FilenameStatePtr filename_state)
void serialize_global_profile(XMLNode &root)
LIBARDOUR_API const char *const export_preset_suffix
void add_extra_xml(XMLNode &)
Definition: stateful.cc:66
bool load_preset(ExportPresetPtr preset)
std::list< Location * > LocationList
PBD::Signal0< void > FormatListChanged
FilenameStatePtr duplicate_filename_state(FilenameStatePtr state)
boost::shared_ptr< Location > selection_range
std::string preset_filename(std::string const &preset_name)
bool set_state(XMLNode const &root)
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
Definition: io.h:67
boost::shared_ptr< LocationList > ranges