diff options
author | Sakari Bergen <sakari.bergen@beatwaves.net> | 2008-09-26 08:29:30 +0000 |
---|---|---|
committer | Sakari Bergen <sakari.bergen@beatwaves.net> | 2008-09-26 08:29:30 +0000 |
commit | 572fa80aa713e723f63e1e1822db614307eea6af (patch) | |
tree | 6d8e8ed27d6192790f54482f14e93dda73d3a485 /libs/ardour/audio_region_importer.cc | |
parent | 10d57b266cbec7054399f20f8e8c76cdff7e1592 (diff) |
Add Import from session -functionality
git-svn-id: svn://localhost/ardour2/branches/3.0@3805 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour/audio_region_importer.cc')
-rw-r--r-- | libs/ardour/audio_region_importer.cc | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/libs/ardour/audio_region_importer.cc b/libs/ardour/audio_region_importer.cc new file mode 100644 index 0000000000..ab8261a369 --- /dev/null +++ b/libs/ardour/audio_region_importer.cc @@ -0,0 +1,398 @@ +/* + Copyright (C) 2008 Paul Davis + Author: Sakari Bergen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <ardour/audio_region_importer.h> + +#include <sstream> + +#include <pbd/failed_constructor.h> +#include <pbd/compose.h> +#include <pbd/error.h> + +#include <ardour/session.h> +#include <ardour/region.h> +#include <ardour/source_factory.h> +#include <ardour/region_factory.h> +#include <ardour/session_directory.h> + +#include "i18n.h" + +using namespace PBD; +using namespace ARDOUR; + +/**** Handler ***/ +AudioRegionImportHandler::AudioRegionImportHandler (XMLTree const & source, Session & session) : + ElementImportHandler (source, session) +{ + XMLNode const * root = source.root(); + XMLNode const * regions; + + if (!(regions = root->child (X_("Regions")))) { + throw failed_constructor(); + } + + create_regions_from_children (*regions, elements); +} + +void +AudioRegionImportHandler::create_regions_from_children (XMLNode const & node, ElementList & list) +{ + XMLNodeList const & children = node.children(); + for (XMLNodeList::const_iterator it = children.begin(); it != children.end(); ++it) { + XMLProperty const * type = (*it)->property("type"); + if (!(*it)->name().compare ("Region") && (!type || type->value() == "audio") ) { + try { + list.push_back (ElementPtr ( new AudioRegionImporter (source, session, *this, **it))); + } catch (failed_constructor err) { + set_dirty(); + } + } + } +} + +string +AudioRegionImportHandler::get_info () const +{ + return _("Audio Regions"); +} + +bool +AudioRegionImportHandler::check_source (string const & filename) const +{ + return (sources.find (filename) != sources.end()); +} + +void +AudioRegionImportHandler::add_source (string const & filename, boost::shared_ptr<Source> const & source) +{ + sources.insert (SourcePair (filename, source)); +} + +boost::shared_ptr<Source> const & +AudioRegionImportHandler::get_source (string const & filename) const +{ + return (sources.find (filename))->second; +} + +void +AudioRegionImportHandler::register_id (PBD::ID & old_id, PBD::ID & new_id) +{ + id_map.insert (IdPair (old_id, new_id)); +} + +PBD::ID const & +AudioRegionImportHandler::get_new_id (PBD::ID & old_id) const +{ + return (id_map.find (old_id))->second; +} + +/*** AudioRegionImporter ***/ +AudioRegionImporter::AudioRegionImporter (XMLTree const & source, Session & session, AudioRegionImportHandler & handler, XMLNode const & node) : + ElementImporter (source, session), + xml_region (node), + handler (handler), + old_id ("0"), + region_prepared (false), + sources_prepared (false) +{ + if (!parse_xml_region () || !parse_source_xml ()) { + throw failed_constructor(); + } + handler.register_id (old_id, id); +} + +string +AudioRegionImporter::get_info () const +{ + nframes_t length, position; + SMPTE::Time length_time, position_time; + std::ostringstream oss; + + // Get sample positions + std::istringstream iss_length(xml_region.property ("length")->value()); + iss_length >> length; + std::istringstream iss_position(xml_region.property ("position")->value()); + iss_position >> position; + + // Convert to smpte + session.sample_to_smpte(length, length_time, true, false); + session.sample_to_smpte(position, position_time, true, false); + + // return info + oss << _("Length: ") << + smpte_to_string(length_time) << + _("\nPosition: ") << + smpte_to_string(position_time) << + _("\nChannels: ") << + xml_region.property ("channels")->value(); + + + return oss.str(); +} + +bool +AudioRegionImporter::prepare_move () +{ + queued = true; + return true; +} + +void +AudioRegionImporter::cancel_move () +{ + queued = false; +} + +void +AudioRegionImporter::move () +{ + if (!region_prepared) { + prepare_region(); + if (!region_prepared) { + return; + } + } + + if (broken()) { + return; + } + + session.add_regions (region); +} + +bool +AudioRegionImporter::parse_xml_region () +{ + XMLPropertyList const & props = xml_region.properties();; + bool id_ok = false; + bool name_ok = false; + + for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) { + string prop = (*it)->name(); + if (!prop.compare ("type") || !prop.compare ("stretch") || + !prop.compare ("shift") || !prop.compare ("first_edit") || + !prop.compare ("layer") || !prop.compare ("flags") || + !prop.compare ("scale-gain") || !prop.compare("channels") || + prop.find ("master-source-") == 0 || prop.find ("source-") == 0) { + // All ok + } else if (!prop.compare ("start") || !prop.compare ("length") || + !prop.compare ("position") || !prop.compare ("ancestral-start") || + !prop.compare ("ancestral-length") || !prop.compare ("sync-position")) { + // Sample rate conversion + (*it)->set_value (rate_convert_samples ((*it)->value())); + } else if (!prop.compare("id")) { + // get old id and update id + old_id = (*it)->value(); + (*it)->set_value (id.to_s()); + id_ok = true; + } else if (!prop.compare("name")) { + // rename region if necessary + name = (*it)->value(); + name = session.new_region_name (name); + (*it)->set_value (name); + name_ok = true; + } else { + std::cerr << string_compose (X_("AudioRegionImporter (%1): did not recognise XML-property \"%1\""), name, prop) << endmsg; + } + } + + if (!id_ok) { + error << string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"id\""), name) << endmsg; + return false; + } + + if (!name_ok) { + error << X_("AudioRegionImporter: did not find necessary XML-property \"name\"") << endmsg; + return false; + } + + return true; +} + +bool +AudioRegionImporter::parse_source_xml () +{ + uint32_t channels; + char buf[128]; + PBD::sys::path source_dir = get_sound_dir (source); + PBD::sys::path source_path; + XMLNode * source_node; + XMLProperty *prop; + + // Get XML for sources + if (!(source_node = source.root()->child (X_("Sources")))) { + return false; + } + XMLNodeList const & sources = source_node->children(); + + // Get source for each channel + if (!(prop = xml_region.property ("channels"))) { + error << string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"channels\""), name) << endmsg; + return false; + } + + channels = atoi (prop->value()); + for (uint32_t i = 0; i < channels; ++i) { + bool source_found = false; + + // Get id for source-n + snprintf (buf, sizeof(buf), X_("source-%d"), i); + prop = xml_region.property (buf); + if (!prop) { + error << string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"%3\""), name, buf) << endmsg; + return false; + } + string source_id = prop->value(); + + // Get source + for (XMLNodeList::const_iterator it = sources.begin(); it != sources.end(); it++) { + prop = (*it)->property ("id"); + if (prop && !source_id.compare (prop->value())) { + source_path = source_dir; + prop = (*it)->property ("name"); + if (!prop) { + error << string_compose (X_("AudioRegionImporter (%1): source %2 has no \"name\" property"), name, source_id) << endmsg; + return false; + } + source_path /= prop->value(); + filenames.push_back (source_path.to_string()); + + source_found = true; + break; + } + } + + if (!source_found) { + error << string_compose (X_("AudioRegionImporter (%1): could not find all necessary sources"), name) << endmsg; + return false; + } + } + + return true; +} + +PBD::sys::path +AudioRegionImporter::get_sound_dir (XMLTree const & tree) +{ + PBD::sys::path source_dir = tree.filename(); + source_dir = source_dir.branch_path(); + SessionDirectory session_dir(source_dir); + source_dir = session_dir.sound_path(); + + return source_dir; +} + +void +AudioRegionImporter::prepare_region () +{ + if (region_prepared) { + return; + } + + SourceList source_list; + prepare_sources(); + + // Create source list + for (std::list<string>::iterator it = filenames.begin(); it != filenames.end(); ++it) { + source_list.push_back (handler.get_source (*it)); + } + + // create region and update XML + region.push_back (RegionFactory::create (source_list, xml_region)); + if (*region.begin()) { + xml_region = (*region.begin())->get_state(); + } else { + error << string_compose (X_("AudioRegionImporter (%1): could not construct Region"), name) << endmsg; + handler.set_errors(); + } + + region_prepared = true; +} + +void +AudioRegionImporter::prepare_sources () +{ + if (sources_prepared) { + return; + } + + Session::import_status status; + + // Get sources that still need to be imported + for (std::list<string>::iterator it = filenames.begin(); it != filenames.end(); ++it) { + if (!handler.check_source (*it)) { + status.paths.push_back (*it); + } + } + + // Prepare rest of import struct TODO quality + status.replace_existing_source = false; + status.done = false; + status.cancel = false; + status.freeze = false; + status.progress = 0.0; + status.quality = SrcBest; + + // import files + // TODO: threading & exception handling + session.import_audiofiles (status); + + // Add imported sources to handlers map + std::vector<Glib::ustring>::iterator file_it = status.paths.begin(); + for (SourceList::iterator source_it = status.sources.begin(); source_it != status.sources.end(); ++source_it) { + if (*source_it) { + handler.add_source(*file_it, *source_it); + } else { + error << string_compose (X_("AudioRegionImporter (%1): could not import all necessary sources"), name) << endmsg; + handler.set_errors(); + set_broken(); + } + + ++file_it; + } + + sources_prepared = true; +} + +void +AudioRegionImporter::add_sources_to_session () +{ + if (!sources_prepared) { + prepare_sources(); + } + + if (broken()) { + return; + } + + for (std::list<string>::iterator it = filenames.begin(); it != filenames.end(); ++it) { + session.add_source (handler.get_source (*it)); + } +} + +XMLNode const & +AudioRegionImporter::get_xml () +{ + if(!region_prepared) { + prepare_region(); + } + + return xml_region; +} |