new files from sakari, missed last time
[ardour.git] / libs / ardour / export_profile_manager.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_profile_manager.h>
22
23 #include <cassert>
24 #include <stdexcept>
25
26 #include <glibmm/fileutils.h>
27
28 #include <pbd/enumwriter.h>
29 #include <pbd/xml++.h>
30 #include <pbd/convert.h>
31
32 #include <ardour/audioengine.h>
33 #include <ardour/export_failed.h>
34 #include <ardour/export_format_specification.h>
35 #include <ardour/export_timespan.h>
36 #include <ardour/export_channel_configuration.h>
37 #include <ardour/export_filename.h>
38 #include <ardour/export_handler.h>
39 #include <ardour/session.h>
40
41 #include "i18n.h"
42
43 using namespace PBD;
44
45 namespace ARDOUR
46 {
47
48 ExportProfileManager::Preset::Preset (string filename, Session & s) :
49   _id (0), session (s), global (filename), local (0)
50 {
51         XMLNode * root;
52         if ((root = global.root())) {
53                 XMLProperty * prop;
54                 if ((prop = root->property ("id"))) {
55                         set_id ((uint32_t) atoi (prop->value()));
56                 }
57                 if ((prop = root->property ("name"))) {
58                         set_name (prop->value());
59                 }
60                 
61                 XMLNode * instant_xml = get_instant_xml ();
62                 if (instant_xml) {
63                         XMLNode * instant_copy = new XMLNode (*instant_xml);
64                         set_local_state (*instant_copy);
65                 }
66         }
67 }
68
69 ExportProfileManager::Preset::~Preset ()
70 {
71         if (local) {
72                 delete local;
73         }
74 }
75
76 void
77 ExportProfileManager::Preset::set_name (string name)
78 {
79         _name = name;
80
81         XMLNode * node; 
82         if ((node = global.root())) {
83                 node->add_property ("name", name);
84         }
85         if (local) {
86                 local->add_property ("name", name);
87         }
88 }
89
90 void
91 ExportProfileManager::Preset::set_id (uint32_t id)
92 {
93         _id = id;
94
95         XMLNode * node;
96         if ((node = global.root())) {
97                 node->add_property ("id", id);
98         }
99         if (local) {
100                 local->add_property ("id", id);
101         }
102 }
103
104 void
105 ExportProfileManager::Preset::set_global_state (XMLNode & state)
106 {
107         delete global.root ();
108         global.set_root (&state);
109         
110         set_id (_id);
111         set_name (_name);
112 }
113
114 void
115 ExportProfileManager::Preset::set_local_state (XMLNode & state)
116 {
117         delete local;
118         local = &state;
119         
120         set_id (_id);
121         set_name (_name);
122 }
123
124 void
125 ExportProfileManager::Preset::save () const
126 {
127         save_instant_xml ();
128         if (global.root()) {
129                 global.write ();
130         }
131 }
132
133 void
134 ExportProfileManager::Preset::remove_local () const
135 {
136         remove_instant_xml ();
137 }
138
139 XMLNode *
140 ExportProfileManager::Preset::get_instant_xml () const
141 {
142         XMLNode * instant_xml;
143         
144         if ((instant_xml = session.instant_xml ("ExportPresets"))) {
145                 XMLNodeList children = instant_xml->children ("ExportPreset");
146                 for (XMLNodeList::iterator it = children.begin(); it != children.end(); ++it) {
147                         XMLProperty * prop;
148                         if ((prop = (*it)->property ("id")) && _id == (uint32_t) atoi (prop->value())) {
149                                 return *it;
150                         }
151                 }
152         }
153         
154         return 0;
155 }
156
157 void
158 ExportProfileManager::Preset::save_instant_xml () const
159 {
160         if (!local) { return; }
161
162         /* First remove old, then add new */
163         
164         remove_instant_xml ();
165         
166         XMLNode * instant_xml;
167         if ((instant_xml = session.instant_xml ("ExportPresets"))) {
168                 instant_xml->add_child_copy (*local);
169         } else {
170                 instant_xml = new XMLNode ("ExportPresets");
171                 instant_xml->add_child_copy (*local);
172                 session.add_instant_xml (*instant_xml, false);
173         }
174 }
175
176 void
177 ExportProfileManager::Preset::remove_instant_xml () const
178 {
179         XMLNode * instant_xml;
180         if ((instant_xml = session.instant_xml ("ExportPresets"))) {
181                 instant_xml->remove_nodes_and_delete ("id", to_string (_id, std::dec));
182         }
183 }
184
185 ExportProfileManager::ExportProfileManager (Session & s) :
186   handler (s.get_export_handler()),
187   session (s),
188
189   session_range (new Location ()),
190   ranges (new LocationList ()),
191
192   format_list (new FormatList ())
193 {
194
195         /* Initialize path variables */
196
197         sys::path path;
198
199         export_config_dir = user_config_directory();
200         export_config_dir /= "export";
201         search_path += export_config_dir;
202         
203         path = ardour_search_path().to_string();
204         path /= "export";
205         search_path += path;
206         
207         path = system_config_search_path().to_string();
208         path /= "export";
209         search_path += path;
210         
211         /* create export config directory if necessary */
212
213         if (!sys::exists (export_config_dir)) {
214                 sys::create_directory (export_config_dir);
215         }
216         
217         load_presets ();
218         load_formats ();
219 }
220
221 ExportProfileManager::~ExportProfileManager ()
222 {
223         XMLNode * instant_xml (new XMLNode ("ExportProfile"));
224         serialize_profile (*instant_xml);
225         session.add_instant_xml (*instant_xml, false);
226 }
227
228 void
229 ExportProfileManager::load_profile ()
230 {
231         XMLNode * instant_node = session.instant_xml ("ExportProfile");
232         if (instant_node) {
233                 set_state (*instant_node);
234         } else {
235                 XMLNode empty_node ("ExportProfile");
236                 set_state (empty_node);
237         }
238 }
239
240 void
241 ExportProfileManager::prepare_for_export ()
242 {
243         ChannelConfigPtr channel_config = channel_configs.front()->config;
244         TimespanListPtr ts_list = timespans.front()->timespans;
245         
246         FormatStateList::const_iterator format_it;
247         FilenameStateList::const_iterator filename_it;
248         
249         for (TimespanList::iterator ts_it = ts_list->begin(); ts_it != ts_list->end(); ++ts_it) {
250                 for (format_it = formats.begin(), filename_it = filenames.begin();
251                      format_it != formats.end() && filename_it != filenames.end();
252                      ++format_it, ++filename_it) {
253                 
254 //                      filename->include_timespan = (ts_list->size() > 1); Disabled for now...
255                         handler->add_export_config (*ts_it, channel_config, (*format_it)->format, (*filename_it)->filename);
256                 }
257         }
258 }
259
260 void
261 ExportProfileManager::load_preset (PresetPtr preset)
262 {
263         current_preset = preset;
264         if (!preset) { return; }
265
266         XMLNode const * state;
267         if ((state = preset->get_local_state())) {
268                 set_local_state (*state);
269         }
270         
271         if ((state = preset->get_global_state())) {
272                 set_global_state (*state);
273         }
274 }
275
276 void
277 ExportProfileManager::load_presets ()
278 {
279         preset_id_counter = 0;
280         
281         vector<sys::path> found = find_file ("*.preset");
282
283         for (vector<sys::path>::iterator it = found.begin(); it != found.end(); ++it) {
284                 preset_id_counter = std::max (preset_id_counter, load_preset_from_disk (*it));
285         }
286 }
287
288 ExportProfileManager::PresetPtr
289 ExportProfileManager::save_preset (string const & name)
290 {
291         if (!current_preset) {
292                 ++preset_id_counter;
293                 string filename = export_config_dir.to_string() + "/" + to_string (preset_id_counter, std::dec) + ".preset";
294                 current_preset.reset (new Preset (filename, session));
295                 preset_list.push_back (current_preset);
296                 current_preset->set_id (preset_id_counter);
297         }
298         
299         XMLNode * global_preset = new XMLNode ("ExportPreset");
300         XMLNode * local_preset = new XMLNode ("ExportPreset");
301
302         serialize_global_profile (*global_preset);
303         serialize_local_profile (*local_preset);
304
305         current_preset->set_name (name);
306         current_preset->set_global_state (*global_preset);
307         current_preset->set_local_state (*local_preset);
308         
309         current_preset->save();
310         
311         return current_preset;
312 }
313
314 void
315 ExportProfileManager::remove_preset ()
316 {
317         if (!current_preset) { return; }
318
319         for (PresetList::iterator it = preset_list.begin(); it != preset_list.end(); ++it) {
320                 if (*it == current_preset) {
321                         preset_list.erase (it);
322                         break;
323                 }
324         }
325
326         FileMap::iterator it = preset_file_map.find (current_preset->id());
327         if (it != preset_file_map.end()) {
328                 sys::remove (it->second);
329                 preset_file_map.erase (it);
330         }
331         
332         current_preset->remove_local();
333         current_preset.reset();
334 }
335
336 uint32_t
337 ExportProfileManager::load_preset_from_disk (PBD::sys::path const & path)
338 {
339         PresetPtr preset (new Preset (path.to_string(), session));
340         preset_list.push_back (preset);
341         
342         /* Handle id to filename mapping */
343         
344         FilePair pair (preset->id(), path);
345         preset_file_map.insert (pair);
346         
347         return preset->id();
348 }
349
350 void
351 ExportProfileManager::set_state (XMLNode const & root)
352 {
353         set_global_state (root);
354         set_local_state (root);
355 }
356
357 void
358 ExportProfileManager::set_global_state (XMLNode const & root)
359 {
360         init_formats (root.children ("ExportFormat"));
361         init_filenames (root.children ("ExportFilename"));
362 }
363
364 void
365 ExportProfileManager::set_local_state (XMLNode const & root)
366 {
367         init_timespans (root.children ("ExportTimespan"));;
368         init_channel_configs (root.children ("ExportChannelConfiguration"));
369 }
370
371 void
372 ExportProfileManager::serialize_profile (XMLNode & root)
373 {
374         serialize_local_profile (root);
375         serialize_global_profile (root);
376 }
377
378 void
379 ExportProfileManager::serialize_global_profile (XMLNode & root)
380 {
381         for (FormatStateList::iterator it = formats.begin(); it != formats.end(); ++it) {
382                 root.add_child_nocopy (serialize_format (*it));
383         }
384
385         for (FilenameStateList::iterator it = filenames.begin(); it != filenames.end(); ++it) {
386                 root.add_child_nocopy (serialize_filename (*it));
387         }
388 }
389
390 void
391 ExportProfileManager::serialize_local_profile (XMLNode & root)
392 {
393         for (TimespanStateList::iterator it = timespans.begin(); it != timespans.end(); ++it) {
394                 root.add_child_nocopy (serialize_timespan (*it));
395         }
396         
397         for (ChannelConfigStateList::iterator it = channel_configs.begin(); it != channel_configs.end(); ++it) {
398                 root.add_child_nocopy (serialize_channel_config (*it));
399         }
400 }
401
402 std::vector<sys::path>
403 ExportProfileManager::find_file (std::string const & pattern)
404 {
405         vector<sys::path> found;
406
407         Glib::PatternSpec pattern_spec (pattern);
408         find_matching_files_in_search_path (search_path, pattern_spec, found);
409
410         return found;
411 }
412
413 void
414 ExportProfileManager::set_selection_range (nframes_t start, nframes_t end)
415 {
416
417         if (start || end) {
418                 selection_range.reset (new Location());
419                 selection_range->set_name (_("Selection"));
420                 selection_range->set (start, end);
421         } else {
422                 selection_range.reset();
423         }
424         
425         for (TimespanStateList::iterator it = timespans.begin(); it != timespans.end(); ++it) {
426                 (*it)->selection_range = selection_range;
427         }
428 }
429
430 void
431 ExportProfileManager::init_timespans (XMLNodeList nodes)
432 {
433         timespans.clear ();
434
435         if (nodes.empty()) {
436                 update_ranges ();
437         
438                 TimespanStatePtr timespan (new TimespanState (session_range, selection_range, ranges));
439         
440                 timespans.push_back (timespan);
441                 return;
442         }
443
444         for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
445                 timespans.push_back (deserialize_timespan (**it));
446         }
447 }
448
449 ExportProfileManager::TimespanStatePtr
450 ExportProfileManager::deserialize_timespan (XMLNode & root)
451 {
452         TimespanStatePtr state (new TimespanState (session_range, selection_range, ranges));
453         XMLProperty const * prop;
454         
455         update_ranges ();
456         
457         XMLNodeList spans = root.children ("Range");
458         for (XMLNodeList::iterator node_it = spans.begin(); node_it != spans.end(); ++node_it) {
459                 
460                 prop = (*node_it)->property ("id");
461                 if (!prop) { continue; }
462                 ustring id = prop->value();
463         
464                 for (LocationList::iterator it = ranges->begin(); it != ranges->end(); ++it) {
465                         if ((!id.compare ("session") && *it == session_range.get()) ||
466                             (!id.compare ("selection") && *it == selection_range.get()) ||
467                             (!id.compare ((*it)->id().to_s()))) {
468                                 TimespanPtr timespan = handler->add_timespan();
469                                 timespan->set_name ((*it)->name());
470                                 timespan->set_range_id (id);
471                                 timespan->set_range ((*it)->start(), (*it)->end());
472                                 state->timespans->push_back (timespan);
473                         }
474                 }
475         }
476         
477         if ((prop = root.property ("format"))) {
478                 state->time_format = (TimeFormat) string_2_enum (prop->value(), TimeFormat);
479         }
480         
481         return state;
482 }
483
484 XMLNode &
485 ExportProfileManager::serialize_timespan (TimespanStatePtr state)
486 {
487         XMLNode & root = *(new XMLNode ("ExportTimespan"));
488         XMLNode * span;
489         
490         update_ranges ();
491         
492         for (TimespanList::iterator it = state->timespans->begin(); it != state->timespans->end(); ++it) {
493                 if ((span = root.add_child ("Range"))) {
494                         span->add_property ("id", (*it)->range_id());
495                 }
496         }
497         
498         root.add_property ("format", enum_2_string (state->time_format));
499         
500         return root;
501 }
502
503 void
504 ExportProfileManager::update_ranges () {
505         ranges->clear();
506
507         /* Session */
508
509         session_range->set_name (_("Session"));
510         session_range->set (session.current_start_frame(), session.current_end_frame());
511         ranges->push_back (session_range.get());
512         
513         /* Selection */
514         
515         if (selection_range) {
516                 ranges->push_back (selection_range.get());
517         }
518         
519         /* ranges */
520         
521         LocationList const & list (session.locations()->list());
522         for (LocationList::const_iterator it = list.begin(); it != list.end(); ++it) {
523                 if ((*it)->is_range_marker()) {
524                         ranges->push_back (*it);
525                 }
526         }
527 }
528
529 void
530 ExportProfileManager::init_channel_configs (XMLNodeList nodes)
531 {
532         channel_configs.clear();
533
534         if (nodes.empty()) {    
535                 ChannelConfigStatePtr config (new ChannelConfigState (handler->add_channel_config()));
536                 channel_configs.push_back (config);
537                 return;
538         }
539         
540         for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
541                 channel_configs.push_back (deserialize_channel_config (**it));
542         }
543 }
544
545 ExportProfileManager::ChannelConfigStatePtr
546 ExportProfileManager::deserialize_channel_config (XMLNode & root)
547 {
548
549         ChannelConfigStatePtr state (new ChannelConfigState (handler->add_channel_config()));
550         XMLProperty const * prop;
551         
552         if ((prop = root.property ("split"))) {
553                 state->config->set_split(!prop->value().compare ("true"));
554         }
555
556         XMLNodeList channels = root.children ("Channel");
557         for (XMLNodeList::iterator it = channels.begin(); it != channels.end(); ++it) {
558                 boost::shared_ptr<ExportChannel> channel (new ExportChannel ());
559         
560                 XMLNodeList ports = (*it)->children ("Port");
561                 for (XMLNodeList::iterator p_it = ports.begin(); p_it != ports.end(); ++p_it) {
562                         if ((prop = (*p_it)->property ("name"))) {
563                                 channel->add_port (dynamic_cast<AudioPort *> (session.engine().get_port_by_name (prop->value())));
564                         }
565                 }
566         
567                 state->config->register_channel (channel);
568         }
569
570         return state;
571 }
572
573 XMLNode &
574 ExportProfileManager::serialize_channel_config (ChannelConfigStatePtr state)
575 {
576         XMLNode * root = new XMLNode ("ExportChannelConfiguration");
577         XMLNode * channel;
578         XMLNode * port_node;
579         
580         root->add_property ("split", state->config->get_split() ? "true" : "false");
581         root->add_property ("channels", to_string (state->config->get_n_chans(), std::dec));
582         
583         uint32_t i = 1;
584         ExportChannelConfiguration::ChannelList const & chan_list = state->config->get_channels();
585         for (ExportChannelConfiguration::ChannelList::const_iterator c_it = chan_list.begin(); c_it != chan_list.end(); ++c_it) {
586                 channel = root->add_child ("Channel");
587                 if (!channel) { continue; }
588                 
589                 channel->add_property ("number", to_string (i, std::dec));
590                 
591                 for (ExportChannel::const_iterator p_it = (*c_it)->begin(); p_it != (*c_it)->end(); ++p_it) {
592                         if ((port_node = channel->add_child ("Port"))) {
593                                 port_node->add_property ("name", (*p_it)->name());
594                         }
595                 }
596                 
597                 ++i;
598         }
599         
600         return *root;
601 }
602
603 ExportProfileManager::FormatStatePtr
604 ExportProfileManager::duplicate_format_state (FormatStatePtr state)
605 {
606         /* Note: The pointer in the new FormatState should point to the same format spec
607                  as the original state's pointer. The spec itself should not be copied!   */
608
609         FormatStatePtr format (new FormatState (format_list, state->format));
610         formats.push_back (format);
611         return format;
612 }
613
614 void
615 ExportProfileManager::remove_format_state (FormatStatePtr state)
616 {
617         for (FormatStateList::iterator it = formats.begin(); it != formats.end(); ++it) {
618                 if (*it == state) {
619                         formats.erase (it);
620                         return;
621                 }
622         }
623 }
624
625 sys::path
626 ExportProfileManager::save_format_to_disk (FormatPtr format)
627 {
628         // TODO filename character stripping
629
630         /* Get filename for file */
631
632         Glib::ustring new_name = format->name();
633         new_name += ".format";
634         
635         sys::path new_path (export_config_dir);
636         new_path /= new_name;
637
638         /* Check if format is on disk already */
639         FileMap::iterator it;
640         if ((it = format_file_map.find (format->id())) != format_file_map.end()) {
641                 /* Update data */
642                 {
643                         XMLTree tree (it->second.to_string());
644                         tree.set_root (&format->get_state());
645                         tree.write();
646                 }
647                 
648                 /* Rename if necessary */
649                 
650                 if (new_name.compare (it->second.leaf())) {
651                         sys::rename (it->second, new_path);
652                 }
653                 
654         } else {
655                 /* Write new file */
656                 
657                 XMLTree tree (new_path.to_string());
658                 tree.set_root (&format->get_state());
659                 tree.write();
660         }
661         
662         FormatListChanged ();
663         return new_path;
664 }
665
666 void
667 ExportProfileManager::remove_format_profile (FormatPtr format)
668 {
669         for (FormatList::iterator it = format_list->begin(); it != format_list->end(); ++it) {
670                 if (*it == format) {
671                         format_list->erase (it);
672                         break;
673                 }
674         }
675
676         FileMap::iterator it = format_file_map.find (format->id());
677         if (it != format_file_map.end()) {
678                 sys::remove (it->second);
679                 format_file_map.erase (it);
680         }
681         
682         FormatListChanged ();
683 }
684
685 ExportProfileManager::FormatPtr
686 ExportProfileManager::get_new_format (FormatPtr original)
687 {       
688         FormatPtr format;
689         if (original) {
690                 format.reset (new ExportFormatSpecification (*original));
691         } else {
692                 format = handler->add_format();
693                 format->set_name ("empty format");
694         }
695         
696         sys::path path = save_format_to_disk (format);
697         FilePair pair (format->id(), path);
698         format_file_map.insert (pair);
699         
700         format_list->push_back (format);
701         FormatListChanged ();
702         
703         return format;
704 }
705
706 void
707 ExportProfileManager::init_formats (XMLNodeList nodes)
708 {
709         formats.clear();
710
711         if (nodes.empty()) {
712                 FormatStatePtr format (new FormatState (format_list, FormatPtr ()));
713                 formats.push_back (format);
714                 return;
715         }
716         
717         for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
718                 FormatStatePtr format;
719                 if ((format = deserialize_format (**it))) {
720                         formats.push_back (format);
721                 }
722         }
723         
724         if (formats.empty ()) {
725                 FormatStatePtr format (new FormatState (format_list, FormatPtr ()));
726                 formats.push_back (format);
727         }
728 }
729
730 ExportProfileManager::FormatStatePtr
731 ExportProfileManager::deserialize_format (XMLNode & root)
732 {
733         XMLProperty * prop;
734         uint32_t id = 0;
735         
736         if ((prop = root.property ("id"))) {
737                 id = atoi (prop->value());
738         }
739         
740         for (FormatList::iterator it = format_list->begin(); it != format_list->end(); ++it) {
741                 if ((*it)->id() == id) {
742                         return FormatStatePtr (new FormatState (format_list, *it));
743                 }
744         }
745
746         return FormatStatePtr ();
747 }
748
749 XMLNode &
750 ExportProfileManager::serialize_format (FormatStatePtr state)
751 {
752         XMLNode * root = new XMLNode ("ExportFormat");
753         
754         string id = state->format ? to_string (state->format->id(), std::dec) : "0";
755         root->add_property ("id", id);
756         
757         return *root;
758 }
759
760 void
761 ExportProfileManager::load_formats ()
762 {
763         vector<sys::path> found = find_file ("*.format");
764
765         for (vector<sys::path>::iterator it = found.begin(); it != found.end(); ++it) {
766                 load_format_from_disk (*it);
767         }
768 }
769
770 void
771 ExportProfileManager::load_format_from_disk (PBD::sys::path const & path)
772 {
773         XMLTree const tree (path.to_string());
774         FormatPtr format = handler->add_format (*tree.root());
775         format_list->push_back (format);
776         
777         /* Handle id to filename mapping */
778         
779         FilePair pair (format->id(), path);
780         format_file_map.insert (pair);
781         
782         FormatListChanged ();
783 }
784
785 ExportProfileManager::FilenameStatePtr
786 ExportProfileManager::duplicate_filename_state (FilenameStatePtr state)
787 {
788         FilenameStatePtr filename (new FilenameState (handler->add_filename_copy (state->filename)));
789         filenames.push_back (filename);
790         return filename;
791 }
792
793 void
794 ExportProfileManager::remove_filename_state (FilenameStatePtr state)
795 {
796         for (FilenameStateList::iterator it = filenames.begin(); it != filenames.end(); ++it) {
797                 if (*it == state) {
798                         filenames.erase (it);
799                         return;
800                 }
801         }
802 }
803
804 void
805 ExportProfileManager::init_filenames (XMLNodeList nodes)
806 {
807         filenames.clear ();
808
809         if (nodes.empty()) {
810                 FilenameStatePtr filename (new FilenameState (handler->add_filename()));
811                 filenames.push_back (filename);
812                 return;
813         }
814         
815         for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
816                 filenames.push_back (deserialize_filename (**it));
817         }
818 }
819
820 ExportProfileManager::FilenameStatePtr
821 ExportProfileManager::deserialize_filename (XMLNode & root)
822 {
823         FilenamePtr filename = handler->add_filename();
824         filename->set_state (root);
825         return FilenameStatePtr (new FilenameState (filename));
826 }
827
828 XMLNode &
829 ExportProfileManager::serialize_filename (FilenameStatePtr state)
830 {
831         return state->filename->get_state();
832 }
833
834 boost::shared_ptr<ExportProfileManager::Warnings>
835 ExportProfileManager::get_warnings ()
836 {
837         boost::shared_ptr<Warnings> warnings (new Warnings ());
838
839         ChannelConfigStatePtr channel_config_state = channel_configs.front();
840         TimespanStatePtr timespan_state = timespans.front();
841         
842         /*** Check "global" config ***/
843         
844         TimespanListPtr timespans = timespan_state->timespans;
845         ChannelConfigPtr channel_config = channel_config_state->config;
846
847         /* Check Timespans are not empty */
848         
849         if (timespans->empty()) {
850                 warnings->errors.push_back (_("No timespan has been selected!"));
851         }
852
853         /* Check channel config ports */
854         
855         if (!channel_config->all_channels_have_ports ()) {
856                 warnings->warnings.push_back (_("Some channels are empty"));
857         }
858         
859         /*** Check files ***/
860         
861         FormatStateList::const_iterator format_it;
862         FilenameStateList::const_iterator filename_it;
863         for (format_it = formats.begin(), filename_it = filenames.begin();
864              format_it != formats.end() && filename_it != filenames.end();
865              ++format_it, ++filename_it) {
866                         check_config (warnings, timespan_state, channel_config_state, *format_it, *filename_it);
867         }
868         
869         return warnings;
870 }
871
872 void
873 ExportProfileManager::check_config (boost::shared_ptr<Warnings> warnings,
874                                     TimespanStatePtr timespan_state,
875                                     ChannelConfigStatePtr channel_config_state,
876                                     FormatStatePtr format_state,
877                                     FilenameStatePtr filename_state)
878 {
879         TimespanListPtr timespans = timespan_state->timespans;
880         ChannelConfigPtr channel_config = channel_config_state->config;
881         FormatPtr format = format_state->format;
882         FilenamePtr filename = filename_state->filename;
883
884         /* Check format and maximum channel count */
885         if (!format || !format->type()) {
886                 warnings->errors.push_back (_("No format selected!"));
887         } else if (format->channel_limit() < channel_config->get_n_chans()) {
888                 warnings->errors.push_back
889                   (string_compose (_("%1 supports only %2 channels, but you have %3 channels in your channel configuration"),
890                                      format->format_name(),
891                                      format->channel_limit(),
892                                      channel_config->get_n_chans()));
893         }
894         
895         if (!warnings->errors.empty()) { return; }
896         
897         /* Check filenames */
898         
899 //      filename->include_timespan = (timespans->size() > 1); Disabled for now...
900         
901         for (std::list<TimespanPtr>::iterator timespan_it = timespans->begin(); timespan_it != timespans->end(); ++timespan_it) {
902                 filename->set_timespan (*timespan_it);
903         
904                 if (channel_config->get_split()) {
905                         filename->include_channel = true;
906                         
907                         for (uint32_t chan = 1; chan <= channel_config->get_n_chans(); ++chan) {
908                                 filename->set_channel (chan);
909                                 
910                                 Glib::ustring path = filename->get_path (format);
911                                 
912                                 if (sys::exists (sys::path (path))) {
913                                         warnings->conflicting_filenames.push_back (path);
914                                 }
915                         }
916                         
917                 } else {
918                         Glib::ustring path = filename->get_path (format);
919                         
920                         if (sys::exists (sys::path (path))) {
921                                 warnings->conflicting_filenames.push_back (path);
922                         }
923                 }
924         }
925 }
926
927 }; // namespace ARDOUR