X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudio_track_importer.cc;h=b3ac93e010696ebc091b9533c5907edc1cdce499;hb=b9054a1f723f6107f42a04ae9838820bbbd1f0ce;hp=68827fb1613170996f081a838cbfb440b0e677fd;hpb=23b1ff94b9b5058b98c0563bba04079c7cc88226;p=ardour.git diff --git a/libs/ardour/audio_track_importer.cc b/libs/ardour/audio_track_importer.cc index 68827fb161..b3ac93e010 100644 --- a/libs/ardour/audio_track_importer.cc +++ b/libs/ardour/audio_track_importer.cc @@ -18,37 +18,44 @@ */ -#include +#include "ardour/audio_track_importer.h" -#include +#include "ardour/audio_playlist_importer.h" +#include "ardour/audio_diskstream.h" +#include "ardour/session.h" -#include -#include -#include +#include "pbd/controllable.h" +#include "pbd/convert.h" +#include "pbd/failed_constructor.h" + +#include +#include #include "i18n.h" +using namespace std; using namespace PBD; using namespace ARDOUR; /*** AudioTrackImportHandler ***/ -AudioTrackImportHandler::AudioTrackImportHandler (XMLTree const & source, Session & session) : - ElementImportHandler (source, session) +AudioTrackImportHandler::AudioTrackImportHandler (XMLTree const & source, Session & session, AudioPlaylistImportHandler & pl_handler) : + ElementImportHandler (source, session), + pl_handler (pl_handler) { XMLNode const * root = source.root(); XMLNode const * routes; - + if (!(routes = root->child ("Routes"))) { throw failed_constructor(); } - + XMLNodeList const & route_list = routes->children(); for (XMLNodeList::const_iterator it = route_list.begin(); it != route_list.end(); ++it) { const XMLProperty* type = (*it)->property("default-type"); - if ( !type || type->value() == "audio" ) { + if ( (!type || type->value() == "audio") && ((*it)->property ("diskstream") != 0 || (*it)->property ("diskstream-id") != 0)) { try { - elements.push_back (ElementPtr ( new AudioTrackImporter (source, session, *this, **it))); + elements.push_back (ElementPtr ( new AudioTrackImporter (source, session, *this, **it, pl_handler))); } catch (failed_constructor err) { set_dirty(); } @@ -65,39 +72,54 @@ AudioTrackImportHandler::get_info () const /*** AudioTrackImporter ***/ -AudioTrackImporter::AudioTrackImporter (XMLTree const & source, Session & session, AudioTrackImportHandler & handler, XMLNode const & node) : +AudioTrackImporter::AudioTrackImporter (XMLTree const & source, + Session & session, + AudioTrackImportHandler & track_handler, + XMLNode const & node, + AudioPlaylistImportHandler & pl_handler) : ElementImporter (source, session), - xml_track (node) + track_handler (track_handler), + xml_track (node), + pl_handler (pl_handler) { XMLProperty * prop; if (!parse_route_xml ()) { throw failed_constructor(); } - + if (!parse_io ()) { throw failed_constructor(); } - - XMLNodeList const & controllables = node.children ("controllable"); + + XMLNodeList const & controllables = node.children (Controllable::xml_node_name); for (XMLNodeList::const_iterator it = controllables.begin(); it != controllables.end(); ++it) { parse_controllable (**it); } - - XMLNode * remote_control = xml_track.child ("remote_control"); + + XMLNode * remote_control = xml_track.child ("RemoteControl"); if (remote_control && (prop = remote_control->property ("id"))) { uint32_t control_id = session.ntracks() + session.nbusses() + 1; prop->set_value (to_string (control_id, std::dec)); } - - xml_track.remove_nodes_and_delete ("extra"); + + xml_track.remove_nodes_and_delete ("Extra"); +} + +AudioTrackImporter::~AudioTrackImporter () +{ + playlists.clear (); } bool AudioTrackImporter::parse_route_xml () { - XMLPropertyList const & props = xml_track.properties(); + bool ds_ok = false; + + // Remove order keys, new ones will be generated + xml_track.remove_property ("order-keys"); + XMLPropertyList const & props = xml_track.properties(); for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) { string prop = (*it)->name(); if (!prop.compare ("default-type") || !prop.compare ("flags") || @@ -107,15 +129,20 @@ AudioTrackImporter::parse_route_xml () !prop.compare ("mute-affects-post-fader") || !prop.compare("mute-affects-control-outs") || !prop.compare ("mute-affects-main-outs") || !prop.compare("mode")) { // All ok - } else if (!prop.compare("order-keys")) { - // TODO } else if (!prop.compare("diskstream-id")) { - // TODO + old_ds_id = (*it)->value(); + (*it)->set_value (new_ds_id.to_s()); + ds_ok = true; } else { std::cerr << string_compose (X_("AudioTrackImporter: did not recognise XML-property \"%1\""), prop) << endmsg; } } - + + if (!ds_ok) { + error << X_("AudioTrackImporter: did not find necessary XML-property \"diskstream-id\"") << endmsg; + return false; + } + return true; } @@ -129,7 +156,7 @@ AudioTrackImporter::parse_io () if (!(io = xml_track.child ("IO"))) { return false; } - + XMLPropertyList const & props = io->properties(); for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) { @@ -137,47 +164,55 @@ AudioTrackImporter::parse_io () if (!prop.compare ("gain") || !prop.compare ("iolimits")) { // All ok } else if (!prop.compare("name")) { - name = prop; + name = (*it)->value(); name_ok = true; } else if (!prop.compare("id")) { PBD::ID id; (*it)->set_value (id.to_s()); id_ok = true; - // TODO } else if (!prop.compare("inputs")) { - // TODO + // TODO Handle this properly! + /* Input and output ports are counted and added empty, so that no in/output connecting function fails. */ + uint32_t num_inputs = std::count ((*it)->value().begin(), (*it)->value().end(), '{'); + std::string value; + for (uint32_t i = 0; i < num_inputs; i++) { value += "{}"; } + (*it)->set_value (value); } else if (!prop.compare("outputs")) { - // TODO + // TODO See comments above + uint32_t num_outputs = std::count ((*it)->value().begin(), (*it)->value().end(), '{'); + std::string value; + for (uint32_t i = 0; i < num_outputs; i++) { value += "{}"; } + (*it)->set_value (value); } else { std::cerr << string_compose (X_("AudioTrackImporter: did not recognise XML-property \"%1\""), prop) << endmsg; } } - + if (!name_ok) { error << X_("AudioTrackImporter: did not find necessary XML-property \"name\"") << endmsg; return false; } - + if (!id_ok) { error << X_("AudioTrackImporter: did not find necessary XML-property \"id\"") << endmsg; return false; } - - XMLNodeList const & controllables = io->children ("controllable"); + + XMLNodeList const & controllables = io->children (Controllable::xml_node_name); for (XMLNodeList::const_iterator it = controllables.begin(); it != controllables.end(); ++it) { parse_controllable (**it); } - + XMLNodeList const & processors = io->children ("Processor"); for (XMLNodeList::const_iterator it = processors.begin(); it != processors.end(); ++it) { parse_processor (**it); } - + XMLNodeList const & automations = io->children ("Automation"); for (XMLNodeList::const_iterator it = automations.begin(); it != automations.end(); ++it) { parse_automation (**it); } - + return true; } @@ -188,23 +223,93 @@ AudioTrackImporter::get_info () const return name; } +/** @return true if everything is ok */ bool -AudioTrackImporter::prepare_move () +AudioTrackImporter::_prepare_move () { - // TODO - return false; + /* Copy dependent playlists */ + + pl_handler.playlists_by_diskstream (old_ds_id, playlists); + + for (PlaylistList::iterator it = playlists.begin(); it != playlists.end(); ++it) { + if (!(*it)->prepare_move ()) { + playlists.clear (); + return false; + } + (*it)->set_diskstream (new_ds_id); + } + + /* Rename */ + + while (session.route_by_name (name) || !track_handler.check_name (name)) { + std::pair rename_pair = *Rename (_("A playlist with this name already exists, please rename it."), name); + if (!rename_pair.first) { + return false; + } + name = rename_pair.second; + } + + XMLNode* c = xml_track.child ("IO"); + if (!c) { + error << _("badly-formed XML in imported track") << endmsg; + return false; + } + + XMLProperty* p = c->property ("name"); + if (!p) { + error << _("badly-formed XML in imported track") << endmsg; + return false; + } + + p->set_value (name); + + track_handler.add_name (name); + + return true; } void -AudioTrackImporter::cancel_move () +AudioTrackImporter::_cancel_move () { - // TODO + track_handler.remove_name (name); + playlists.clear (); } void -AudioTrackImporter::move () +AudioTrackImporter::_move () { - // TODO + /* Add diskstream */ + + boost::shared_ptr ds_node_list; + string xpath = "/Session/DiskStreams/AudioDiskstream[@id='" + old_ds_id.to_s() + "']"; + ds_node_list = source.find (xpath); + + if (ds_node_list->size() != 1) { + error << string_compose (_("Error Importing Audio track %1"), name) << endmsg; + return; + } + + boost::shared_ptr ds_node = ds_node_list->front(); + XMLProperty* p = ds_node->property (X_("id")); + assert (p); + p->set_value (new_ds_id.to_s()); + + boost::shared_ptr new_ds (new AudioDiskstream (session, *ds_node)); + new_ds->set_name (name); + new_ds->do_refill_with_alloc (); + new_ds->set_block_size (session.get_block_size ()); + + /* Import playlists */ + + for (PlaylistList::const_iterator it = playlists.begin(); it != playlists.end(); ++it) { + (*it)->move (); + } + + /* Import track */ + + XMLNode routes ("Routes"); + routes.add_child_copy (xml_track); + session.load_routes (routes, 3000); } bool @@ -214,7 +319,7 @@ AudioTrackImporter::parse_processor (XMLNode & node) if (automation) { parse_automation (*automation); } - + return true; } @@ -222,7 +327,7 @@ bool AudioTrackImporter::parse_controllable (XMLNode & node) { XMLProperty * prop; - + if ((prop = node.property ("id"))) { PBD::ID new_id; prop->set_value (new_id.to_s()); @@ -240,14 +345,60 @@ AudioTrackImporter::parse_automation (XMLNode & node) XMLNodeList const & lists = node.children ("AutomationList"); for (XMLNodeList::const_iterator it = lists.begin(); it != lists.end(); ++it) { XMLProperty * prop; - + if ((prop = (*it)->property ("id"))) { PBD::ID id; prop->set_value (id.to_s()); } - - // TODO rate convert events + + if (!(*it)->name().compare ("events")) { + rate_convert_events (**it); + } + } + + return true; +} + +bool +AudioTrackImporter::rate_convert_events (XMLNode & node) +{ + if (node.children().empty()) { + return false; + } + + XMLNode* content_node = node.children().front(); + + if (content_node->content().empty()) { + return false; + } + + std::stringstream str (content_node->content()); + std::ostringstream new_content; + + framecnt_t x; + double y; + bool ok = true; + + while (str) { + str >> x; + if (!str) { + break; + } + str >> y; + if (!str) { + ok = false; + break; + } + + new_content << rate_convert_samples (x) << ' ' << y; + } + + if (!ok) { + error << X_("AudioTrackImporter: error in rate converting automation events") << endmsg; + return false; } + content_node->set_content (new_content.str()); + return true; }