X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fexport_profile_manager.cc;h=6c4f829bb89fca383e02a54fc106cd93fac7a9ec;hb=80d9eaf96cd00f3084d18c32b4b31aabda0e6737;hp=2b1b15dbce0e534a0cf5987be75d4acb92f611ce;hpb=bb9cc45cd22af67ac275a5e73accbe14fee664d8;p=ardour.git diff --git a/libs/ardour/export_profile_manager.cc b/libs/ardour/export_profile_manager.cc index 2b1b15dbce..6c4f829bb8 100644 --- a/libs/ardour/export_profile_manager.cc +++ b/libs/ardour/export_profile_manager.cc @@ -21,22 +21,30 @@ #include #include +#include +#include + #include +#include #include "pbd/enumwriter.h" #include "pbd/xml++.h" #include "pbd/convert.h" #include "ardour/export_profile_manager.h" -#include "ardour/export_file_io.h" #include "ardour/export_format_specification.h" +#include "ardour/export_formats_search_path.h" #include "ardour/export_timespan.h" #include "ardour/export_channel_configuration.h" #include "ardour/export_filename.h" #include "ardour/export_preset.h" #include "ardour/export_handler.h" +#include "ardour/export_failed.h" +#include "ardour/directory_names.h" #include "ardour/filename_extensions.h" +#include "ardour/route.h" #include "ardour/session.h" +#include "ardour/broadcast_info.h" #include "i18n.h" @@ -47,30 +55,31 @@ using namespace PBD; namespace ARDOUR { -ExportProfileManager::ExportProfileManager (Session & s) : - handler (s.get_export_handler()), - session (s), +ExportProfileManager::ExportProfileManager (Session & s, std::string xml_node_name) + : xml_node_name (xml_node_name) + , handler (s.get_export_handler()) + , session (s) - session_range (new Location ()), - ranges (new LocationList ()), - single_range_mode (false), + , session_range (new Location (s)) + , ranges (new LocationList ()) + , single_range_mode (false) - format_list (new FormatList ()) + , format_list (new FormatList ()) { - /* Initialize path variables */ - export_config_dir = user_config_directory(); - export_config_dir /= "export"; - search_path += export_config_dir; + export_config_dir = Glib::build_filename (user_config_directory(), export_dir_name); + + search_path += export_formats_search_path(); - search_path += ardour_search_path().add_subdirectory_to_paths("export"); - search_path += system_config_search_path().add_subdirectory_to_paths("export");; + info << string_compose (_("Searching for export formats in %1"), search_path.to_string()) << endmsg; /* create export config directory if necessary */ - if (!sys::exists (export_config_dir)) { - sys::create_directory (export_config_dir); + if (!Glib::file_test (export_config_dir, Glib::FILE_TEST_EXISTS)) { + if (g_mkdir_with_parents (export_config_dir.c_str(), 0755) != 0) { + error << string_compose (_("Unable to create export format directory %1: %2"), export_config_dir, g_strerror(errno)) << endmsg; + } } load_presets (); @@ -87,9 +96,7 @@ ExportProfileManager::ExportProfileManager (Session & s) : ExportProfileManager::~ExportProfileManager () { - if (single_range_mode) { return; } - - XMLNode * instant_xml (new XMLNode ("ExportProfile")); + XMLNode * instant_xml (new XMLNode (xml_node_name)); serialize_profile (*instant_xml); session.add_instant_xml (*instant_xml, false); } @@ -97,11 +104,11 @@ ExportProfileManager::~ExportProfileManager () void ExportProfileManager::load_profile () { - XMLNode * instant_node = session.instant_xml ("ExportProfile"); + XMLNode * instant_node = session.instant_xml (xml_node_name); if (instant_node) { set_state (*instant_node); } else { - XMLNode empty_node ("ExportProfile"); + XMLNode empty_node (xml_node_name); set_state (empty_node); } } @@ -109,25 +116,38 @@ ExportProfileManager::load_profile () void ExportProfileManager::prepare_for_export () { - ChannelConfigPtr channel_config = channel_configs.front()->config; TimespanListPtr ts_list = timespans.front()->timespans; FormatStateList::const_iterator format_it; FilenameStateList::const_iterator filename_it; + // For each timespan for (TimespanList::iterator ts_it = ts_list->begin(); ts_it != ts_list->end(); ++ts_it) { + // ..., each format-filename pair for (format_it = formats.begin(), filename_it = filenames.begin(); format_it != formats.end() && filename_it != filenames.end(); ++format_it, ++filename_it) { + ExportFilenamePtr filename = (*filename_it)->filename; // filename->include_timespan = (ts_list->size() > 1); Disabled for now... - handler->add_export_config (*ts_it, channel_config, (*format_it)->format, (*filename_it)->filename); + + boost::shared_ptr b; + if ((*format_it)->format->has_broadcast_info()) { + b.reset (new BroadcastInfo); + b->set_from_session (session, (*ts_it)->get_start()); + } + + // ...and each channel config + filename->include_channel_config = (channel_configs.size() > 1); + for(ChannelConfigStateList::iterator cc_it = channel_configs.begin(); cc_it != channel_configs.end(); ++cc_it) { + handler->add_export_config (*ts_it, (*cc_it)->config, (*format_it)->format, filename, b); + } } } } bool -ExportProfileManager::load_preset (PresetPtr preset) +ExportProfileManager::load_preset (ExportPresetPtr preset) { bool ok = true; @@ -151,17 +171,34 @@ ExportProfileManager::load_preset (PresetPtr preset) void ExportProfileManager::load_presets () { - vector found = find_file (string_compose (X_("*%1"),export_preset_suffix)); + vector found = find_file (string_compose (X_("*%1"),export_preset_suffix)); - for (vector::iterator it = found.begin(); it != found.end(); ++it) { + for (vector::iterator it = found.begin(); it != found.end(); ++it) { load_preset_from_disk (*it); } } -ExportProfileManager::PresetPtr +std::string +ExportProfileManager::preset_filename (std::string const & preset_name) +{ + string safe_name = legalize_for_path (preset_name); + return Glib::build_filename (export_config_dir, safe_name + export_preset_suffix); +} + +ExportPresetPtr +ExportProfileManager::new_preset (string const & name) +{ + // Generate new ID and do regular save + string filename = preset_filename (name); + current_preset.reset (new ExportPreset (filename, session)); + preset_list.push_back (current_preset); + return save_preset (name); +} + +ExportPresetPtr ExportProfileManager::save_preset (string const & name) { - string filename = export_config_dir.to_string() + "/" + name + export_preset_suffix; + string filename = preset_filename (name); if (!current_preset) { current_preset.reset (new ExportPreset (filename, session)); @@ -197,7 +234,9 @@ ExportProfileManager::remove_preset () FileMap::iterator it = preset_file_map.find (current_preset->id()); if (it != preset_file_map.end()) { - sys::remove (it->second); + if (g_remove (it->second.c_str()) != 0) { + error << string_compose (_("Unable to remove export preset %1: %2"), it->second, g_strerror(errno)) << endmsg; + } preset_file_map.erase (it); } @@ -206,9 +245,9 @@ ExportProfileManager::remove_preset () } void -ExportProfileManager::load_preset_from_disk (PBD::sys::path const & path) +ExportProfileManager::load_preset_from_disk (std::string const & path) { - PresetPtr preset (new ExportPreset (path.to_string(), session)); + ExportPresetPtr preset (new ExportPreset (path, session)); /* Handle id to filename mapping and don't add duplicates to list */ @@ -221,20 +260,20 @@ ExportProfileManager::load_preset_from_disk (PBD::sys::path const & path) bool ExportProfileManager::set_state (XMLNode const & root) { - return set_global_state (root) && set_local_state (root); + return set_global_state (root) & set_local_state (root); } bool ExportProfileManager::set_global_state (XMLNode const & root) { - return init_filenames (root.children ("ExportFilename")) && + return init_filenames (root.children ("ExportFilename")) & init_formats (root.children ("ExportFormat")); } bool ExportProfileManager::set_local_state (XMLNode const & root) { - return init_timespans (root.children ("ExportTimespan")) && + return init_timespans (root.children ("ExportTimespan")) & init_channel_configs (root.children ("ExportChannelConfiguration")); } @@ -269,10 +308,10 @@ ExportProfileManager::serialize_local_profile (XMLNode & root) } } -std::vector +std::vector ExportProfileManager::find_file (std::string const & pattern) { - vector found; + vector found; Glib::PatternSpec pattern_spec (pattern); find_matching_files_in_search_path (search_path, pattern_spec, found); @@ -281,11 +320,11 @@ ExportProfileManager::find_file (std::string const & pattern) } void -ExportProfileManager::set_selection_range (nframes_t start, nframes_t end) +ExportProfileManager::set_selection_range (framepos_t start, framepos_t end) { if (start || end) { - selection_range.reset (new Location()); + selection_range.reset (new Location (session)); selection_range->set_name (_("Selection")); selection_range->set (start, end); } else { @@ -298,11 +337,11 @@ ExportProfileManager::set_selection_range (nframes_t start, nframes_t end) } std::string -ExportProfileManager::set_single_range (nframes_t start, nframes_t end, Glib::ustring name) +ExportProfileManager::set_single_range (framepos_t start, framepos_t end, string name) { single_range_mode = true; - single_range.reset (new Location()); + single_range.reset (new Location (session)); single_range->set_name (name); single_range->set (start, end); @@ -326,8 +365,15 @@ ExportProfileManager::init_timespans (XMLNodeList nodes) } if (timespans.empty()) { - TimespanStatePtr timespan (new TimespanState (session_range, selection_range, ranges)); - timespans.push_back (timespan); + TimespanStatePtr state (new TimespanState (session_range, selection_range, ranges)); + timespans.push_back (state); + + // Add session as default selection + ExportTimespanPtr timespan = handler->add_timespan(); + timespan->set_name (session_range->name()); + timespan->set_range_id ("session"); + timespan->set_range (session_range->start(), session_range->end()); + state->timespans->push_back (timespan); return false; } @@ -345,13 +391,13 @@ ExportProfileManager::deserialize_timespan (XMLNode & root) prop = (*node_it)->property ("id"); if (!prop) { continue; } - ustring id = prop->value(); + string id = prop->value(); for (LocationList::iterator it = ranges->begin(); it != ranges->end(); ++it) { if ((!id.compare ("session") && *it == session_range.get()) || (!id.compare ("selection") && *it == selection_range.get()) || (!id.compare ((*it)->id().to_s()))) { - TimespanPtr timespan = handler->add_timespan(); + ExportTimespanPtr timespan = handler->add_timespan(); timespan->set_name ((*it)->name()); timespan->set_range_id (id); timespan->set_range ((*it)->start(), (*it)->end()); @@ -417,6 +463,14 @@ ExportProfileManager::update_ranges () { } } +ExportProfileManager::ChannelConfigStatePtr +ExportProfileManager::add_channel_config () +{ + ChannelConfigStatePtr ptr(new ChannelConfigState(handler->add_channel_config())); + channel_configs.push_back(ptr); + return ptr; +} + bool ExportProfileManager::init_channel_configs (XMLNodeList nodes) { @@ -425,6 +479,18 @@ ExportProfileManager::init_channel_configs (XMLNodeList nodes) if (nodes.empty()) { ChannelConfigStatePtr config (new ChannelConfigState (handler->add_channel_config())); channel_configs.push_back (config); + + // Add master outs as default + IO* master_out = session.master_out()->output().get(); + if (!master_out) { return false; } + + for (uint32_t n = 0; n < master_out->n_ports().n_audio(); ++n) { + PortExportChannel * channel = new PortExportChannel (); + channel->add_port (master_out->audio (n)); + + ExportChannelPtr chan_ptr (channel); + config->config->register_channel (chan_ptr); + } return false; } @@ -459,29 +525,32 @@ ExportProfileManager::remove_format_state (FormatStatePtr state) } } -sys::path -ExportProfileManager::save_format_to_disk (FormatPtr format) +std::string +ExportProfileManager::save_format_to_disk (ExportFormatSpecPtr format) { // TODO filename character stripping /* Get filename for file */ - Glib::ustring new_name = format->name(); + string new_name = format->name(); new_name += export_format_suffix; - sys::path new_path (export_config_dir); - new_path /= new_name; + /* make sure its legal for the filesystem */ + + new_name = legalize_for_path (new_name); + + std::string new_path = Glib::build_filename (export_config_dir, new_name); /* Check if format is on disk already */ FileMap::iterator it; if ((it = format_file_map.find (format->id())) != format_file_map.end()) { /* Check if config is not in user config dir */ - if (it->second.branch_path().to_string().compare (export_config_dir.to_string())) { + if (Glib::path_get_dirname (it->second) != export_config_dir) { /* Write new file */ - XMLTree tree (new_path.to_string()); + XMLTree tree (new_path); tree.set_root (&format->get_state()); tree.write(); @@ -489,12 +558,14 @@ ExportProfileManager::save_format_to_disk (FormatPtr format) /* Update file and rename if necessary */ - XMLTree tree (it->second.to_string()); + XMLTree tree (it->second); tree.set_root (&format->get_state()); tree.write(); - if (new_name.compare (it->second.leaf())) { - sys::rename (it->second, new_path); + if (new_name != Glib::path_get_basename (it->second)) { + if (g_rename (it->second.c_str(), new_path.c_str()) != 0) { + error << string_compose (_("Unable to rename export format %1 to %2: %3"), it->second, new_path, g_strerror(errno)) << endmsg; + }; } } @@ -503,7 +574,7 @@ ExportProfileManager::save_format_to_disk (FormatPtr format) } else { /* Write new file */ - XMLTree tree (new_path.to_string()); + XMLTree tree (new_path); tree.set_root (&format->get_state()); tree.write(); } @@ -513,7 +584,7 @@ ExportProfileManager::save_format_to_disk (FormatPtr format) } void -ExportProfileManager::remove_format_profile (FormatPtr format) +ExportProfileManager::remove_format_profile (ExportFormatSpecPtr format) { for (FormatList::iterator it = format_list->begin(); it != format_list->end(); ++it) { if (*it == format) { @@ -524,17 +595,20 @@ ExportProfileManager::remove_format_profile (FormatPtr format) FileMap::iterator it = format_file_map.find (format->id()); if (it != format_file_map.end()) { - sys::remove (it->second); + if (g_remove (it->second.c_str()) != 0) { + error << string_compose (_("Unable to remove export profile %1: %2"), it->second, g_strerror(errno)) << endmsg; + return; + } format_file_map.erase (it); } FormatListChanged (); } -ExportProfileManager::FormatPtr -ExportProfileManager::get_new_format (FormatPtr original) +ExportFormatSpecPtr +ExportProfileManager::get_new_format (ExportFormatSpecPtr original) { - FormatPtr format; + ExportFormatSpecPtr format; if (original) { format.reset (new ExportFormatSpecification (*original)); } else { @@ -542,7 +616,7 @@ ExportProfileManager::get_new_format (FormatPtr original) format->set_name ("empty format"); } - sys::path path = save_format_to_disk (format); + std::string path = save_format_to_disk (format); FilePair pair (format->id(), path); format_file_map.insert (pair); @@ -566,7 +640,7 @@ ExportProfileManager::init_formats (XMLNodeList nodes) } if (formats.empty ()) { - FormatStatePtr format (new FormatState (format_list, FormatPtr ())); + FormatStatePtr format (new FormatState (format_list, ExportFormatSpecPtr ())); formats.push_back (format); return false; } @@ -607,18 +681,18 @@ ExportProfileManager::serialize_format (FormatStatePtr state) void ExportProfileManager::load_formats () { - vector found = find_file (string_compose ("*%1", export_format_suffix)); + vector found = find_file (string_compose ("*%1", export_format_suffix)); - for (vector::iterator it = found.begin(); it != found.end(); ++it) { + for (vector::iterator it = found.begin(); it != found.end(); ++it) { load_format_from_disk (*it); } } void -ExportProfileManager::load_format_from_disk (PBD::sys::path const & path) +ExportProfileManager::load_format_from_disk (std::string const & path) { - XMLTree const tree (path.to_string()); - FormatPtr format = handler->add_format (*tree.root()); + XMLTree const tree (path); + ExportFormatSpecPtr format = handler->add_format (*tree.root()); /* Handle id to filename mapping and don't add duplicates to list */ @@ -649,13 +723,28 @@ ExportProfileManager::remove_filename_state (FilenameStatePtr state) } } +std::string +ExportProfileManager::get_sample_filename_for_format (ExportFilenamePtr filename, ExportFormatSpecPtr format) +{ + assert (format); + + if (channel_configs.empty()) { return ""; } + + std::list filenames; + build_filenames (filenames, filename, timespans.front()->timespans, + channel_configs.front()->config, format); + + if (filenames.empty()) { return ""; } + return filenames.front(); +} + bool ExportProfileManager::init_filenames (XMLNodeList nodes) { filenames.clear (); for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { - FilenamePtr filename = handler->add_filename(); + ExportFilenamePtr filename = handler->add_filename(); filename->set_state (**it); filenames.push_back (FilenameStatePtr (new FilenameState (filename))); } @@ -674,13 +763,21 @@ ExportProfileManager::get_warnings () { boost::shared_ptr warnings (new Warnings ()); - ChannelConfigStatePtr channel_config_state = channel_configs.front(); + ChannelConfigStatePtr channel_config_state; + if (!channel_configs.empty ()) { + channel_config_state = channel_configs.front(); + } + TimespanStatePtr timespan_state = timespans.front(); /*** Check "global" config ***/ TimespanListPtr timespans = timespan_state->timespans; - ChannelConfigPtr channel_config = channel_config_state->config; + + ExportChannelConfigPtr channel_config; + if (channel_config_state) { + channel_config = channel_config_state->config; + } /* Check Timespans are not empty */ @@ -688,22 +785,27 @@ ExportProfileManager::get_warnings () warnings->errors.push_back (_("No timespan has been selected!")); } - /* Check channel config ports */ - - if (!channel_config->all_channels_have_ports ()) { - warnings->warnings.push_back (_("Some channels are empty")); + if (channel_config_state == 0) { + warnings->errors.push_back (_("No channels have been selected!")); + } else { + /* Check channel config ports */ + if (!channel_config->all_channels_have_ports ()) { + warnings->warnings.push_back (_("Some channels are empty")); + } } /*** Check files ***/ - FormatStateList::const_iterator format_it; - FilenameStateList::const_iterator filename_it; - for (format_it = formats.begin(), filename_it = filenames.begin(); - format_it != formats.end() && filename_it != filenames.end(); - ++format_it, ++filename_it) { + if (channel_config_state) { + FormatStateList::const_iterator format_it; + FilenameStateList::const_iterator filename_it; + for (format_it = formats.begin(), filename_it = filenames.begin(); + format_it != formats.end() && filename_it != filenames.end(); + ++format_it, ++filename_it) { check_config (warnings, timespan_state, channel_config_state, *format_it, *filename_it); + } } - + return warnings; } @@ -715,16 +817,16 @@ ExportProfileManager::check_config (boost::shared_ptr warnings, FilenameStatePtr filename_state) { TimespanListPtr timespans = timespan_state->timespans; - ChannelConfigPtr channel_config = channel_config_state->config; - FormatPtr format = format_state->format; - FilenamePtr filename = filename_state->filename; + ExportChannelConfigPtr channel_config = channel_config_state->config; + ExportFormatSpecPtr format = format_state->format; + ExportFilenamePtr filename = filename_state->filename; /* Check format and maximum channel count */ if (!format || !format->type()) { warnings->errors.push_back (_("No format selected!")); } else if (!channel_config->get_n_chans()) { warnings->errors.push_back (_("All channels are empty!")); - } else if (!ExportFileFactory::check (format, channel_config->get_n_chans())) { + } else if (!check_format (format, channel_config->get_n_chans())) { warnings->errors.push_back (_("One or more of the selected formats is not compatible with this system!")); } else if (format->channel_limit() < channel_config->get_n_chans()) { warnings->errors.push_back @@ -740,7 +842,63 @@ ExportProfileManager::check_config (boost::shared_ptr warnings, // filename->include_timespan = (timespans->size() > 1); Disabled for now... - for (std::list::iterator timespan_it = timespans->begin(); timespan_it != timespans->end(); ++timespan_it) { + std::list paths; + build_filenames(paths, filename, timespans, channel_config, format); + + for (std::list::const_iterator path_it = paths.begin(); path_it != paths.end(); ++path_it) { + + string path = *path_it; + + if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) { + warnings->conflicting_filenames.push_back (path); + } + + if (format->with_toc()) { + string marker_file = handler->get_cd_marker_filename(path, CDMarkerTOC); + if (Glib::file_test (marker_file, Glib::FILE_TEST_EXISTS)) { + warnings->conflicting_filenames.push_back (marker_file); + } + } + + if (format->with_cue()) { + string marker_file = handler->get_cd_marker_filename(path, CDMarkerCUE); + if (Glib::file_test (marker_file, Glib::FILE_TEST_EXISTS)) { + warnings->conflicting_filenames.push_back (marker_file); + } + } + } +} + +bool +ExportProfileManager::check_format (ExportFormatSpecPtr format, uint32_t channels) +{ + switch (format->type()) { + case ExportFormatBase::T_Sndfile: + return check_sndfile_format (format, channels); + + default: + throw ExportFailed (X_("Invalid format given for ExportFileFactory::check!")); + } +} + +bool +ExportProfileManager::check_sndfile_format (ExportFormatSpecPtr format, unsigned int channels) +{ + SF_INFO sf_info; + sf_info.channels = channels; + sf_info.samplerate = format->sample_rate (); + sf_info.format = format->format_id () | format->sample_format (); + + return (sf_format_check (&sf_info) == SF_TRUE ? true : false); +} + +void +ExportProfileManager::build_filenames(std::list & result, ExportFilenamePtr filename, + TimespanListPtr timespans, ExportChannelConfigPtr channel_config, + ExportFormatSpecPtr format) +{ + for (std::list::iterator timespan_it = timespans->begin(); + timespan_it != timespans->end(); ++timespan_it) { filename->set_timespan (*timespan_it); if (channel_config->get_split()) { @@ -748,20 +906,12 @@ ExportProfileManager::check_config (boost::shared_ptr warnings, for (uint32_t chan = 1; chan <= channel_config->get_n_chans(); ++chan) { filename->set_channel (chan); - - Glib::ustring path = filename->get_path (format); - - if (sys::exists (sys::path (path))) { - warnings->conflicting_filenames.push_back (path); - } + result.push_back(filename->get_path (format)); } } else { - Glib::ustring path = filename->get_path (format); - - if (sys::exists (sys::path (path))) { - warnings->conflicting_filenames.push_back (path); - } + filename->include_channel = false; + result.push_back(filename->get_path (format)); } } }