2 * Copyright (C) 2008-2009 Sakari Bergen <sakari.bergen@beatwaves.net>
3 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
4 * Copyright (C) 2009-2014 David Robillard <d@drobilla.net>
5 * Copyright (C) 2009-2017 Paul Davis <paul@linuxaudiosystems.com>
6 * Copyright (C) 2015-2018 Robin Gareus <robin@gareus.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "ardour/audio_track_importer.h"
25 #include "ardour/audio_playlist_importer.h"
26 #include "ardour/disk_reader.h"
27 #include "ardour/session.h"
29 #include "pbd/controllable.h"
30 #include "pbd/failed_constructor.h"
31 #include "pbd/string_convert.h"
40 using namespace ARDOUR;
42 /*** AudioTrackImportHandler ***/
44 AudioTrackImportHandler::AudioTrackImportHandler (XMLTree const & source, Session & session, AudioPlaylistImportHandler & pl_handler) :
45 ElementImportHandler (source, session)
47 XMLNode const * root = source.root();
48 XMLNode const * routes;
50 if (!(routes = root->child ("Routes"))) {
51 throw failed_constructor();
54 XMLNodeList const & route_list = routes->children();
55 for (XMLNodeList::const_iterator it = route_list.begin(); it != route_list.end(); ++it) {
56 XMLProperty const * type = (*it)->property("default-type");
57 if ( (!type || type->value() == "audio") && ((*it)->property ("diskstream") != 0 || (*it)->property ("diskstream-id") != 0)) {
59 elements.push_back (ElementPtr ( new AudioTrackImporter (source, session, *this, **it, pl_handler)));
60 } catch (failed_constructor const&) {
68 AudioTrackImportHandler::get_info () const
70 return _("Audio Tracks");
74 /*** AudioTrackImporter ***/
76 AudioTrackImporter::AudioTrackImporter (XMLTree const & source,
78 AudioTrackImportHandler & track_handler,
80 AudioPlaylistImportHandler & pl_handler) :
81 ElementImporter (source, session),
82 track_handler (track_handler),
84 pl_handler (pl_handler)
88 if (!parse_route_xml ()) {
89 throw failed_constructor();
93 throw failed_constructor();
96 XMLNodeList const & controllables = node.children (Controllable::xml_node_name);
97 for (XMLNodeList::const_iterator it = controllables.begin(); it != controllables.end(); ++it) {
98 parse_controllable (**it);
101 XMLNode * remote_control = xml_track.child ("RemoteControl");
102 if (remote_control && (prop = remote_control->property ("id"))) {
103 uint32_t control_id = session.ntracks() + session.nbusses() + 1;
104 prop->set_value (to_string (control_id));
107 xml_track.remove_nodes_and_delete ("Extra");
110 AudioTrackImporter::~AudioTrackImporter ()
116 AudioTrackImporter::parse_route_xml ()
120 // Remove order keys, new ones will be generated
121 xml_track.remove_property ("order-keys");
123 XMLPropertyList const & props = xml_track.properties();
124 for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) {
125 string prop = (*it)->name();
126 if (!prop.compare ("default-type") || !prop.compare ("flags") ||
127 !prop.compare ("active") || !prop.compare ("muted") ||
128 !prop.compare ("soloed") || !prop.compare ("phase-invert") ||
129 !prop.compare ("denormal-protection") || !prop.compare("mute-affects-pre-fader") ||
130 !prop.compare ("mute-affects-post-fader") || !prop.compare("mute-affects-control-outs") ||
131 !prop.compare ("mute-affects-main-outs") || !prop.compare("mode")) {
133 } else if (!prop.compare("diskstream-id")) {
134 old_ds_id = (*it)->value();
135 (*it)->set_value (new_ds_id.to_s());
138 std::cerr << string_compose (X_("AudioTrackImporter: did not recognise XML-property \"%1\""), prop) << endmsg;
143 error << X_("AudioTrackImporter: did not find necessary XML-property \"diskstream-id\"") << endmsg;
151 AudioTrackImporter::parse_io ()
154 bool name_ok = false;
157 if (!(io = xml_track.child ("IO"))) {
161 XMLPropertyList const & props = io->properties();
163 for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) {
164 string prop = (*it)->name();
165 if (!prop.compare ("gain") || !prop.compare ("iolimits")) {
167 } else if (!prop.compare("name")) {
168 name = (*it)->value();
170 } else if (!prop.compare("id")) {
172 (*it)->set_value (id.to_s());
174 } else if (!prop.compare("inputs")) {
175 // TODO Handle this properly!
176 /* Input and output ports are counted and added empty, so that no in/output connecting function fails. */
177 uint32_t num_inputs = std::count ((*it)->value().begin(), (*it)->value().end(), '{');
179 for (uint32_t i = 0; i < num_inputs; i++) { value += "{}"; }
180 (*it)->set_value (value);
181 } else if (!prop.compare("outputs")) {
182 // TODO See comments above
183 uint32_t num_outputs = std::count ((*it)->value().begin(), (*it)->value().end(), '{');
185 for (uint32_t i = 0; i < num_outputs; i++) { value += "{}"; }
186 (*it)->set_value (value);
188 std::cerr << string_compose (X_("AudioTrackImporter: did not recognise XML-property \"%1\""), prop) << endmsg;
193 error << X_("AudioTrackImporter: did not find necessary XML-property \"name\"") << endmsg;
198 error << X_("AudioTrackImporter: did not find necessary XML-property \"id\"") << endmsg;
202 XMLNodeList const & controllables = io->children (Controllable::xml_node_name);
203 for (XMLNodeList::const_iterator it = controllables.begin(); it != controllables.end(); ++it) {
204 parse_controllable (**it);
207 XMLNodeList const & processors = io->children ("Processor");
208 for (XMLNodeList::const_iterator it = processors.begin(); it != processors.end(); ++it) {
209 parse_processor (**it);
212 XMLNodeList const & automations = io->children ("Automation");
213 for (XMLNodeList::const_iterator it = automations.begin(); it != automations.end(); ++it) {
214 parse_automation (**it);
221 AudioTrackImporter::get_info () const
227 /** @return true if everything is ok */
229 AudioTrackImporter::_prepare_move ()
231 /* Copy dependent playlists */
233 pl_handler.playlists_by_diskstream (old_ds_id, playlists);
235 for (PlaylistList::iterator it = playlists.begin(); it != playlists.end(); ++it) {
236 if (!(*it)->prepare_move ()) {
240 (*it)->set_diskstream (new_ds_id);
245 while (session.route_by_name (name) || !track_handler.check_name (name)) {
246 std::pair<bool, string> rename_pair = *Rename (_("A playlist with this name already exists, please rename it."), name);
247 if (!rename_pair.first) {
250 name = rename_pair.second;
253 XMLNode* c = xml_track.child ("IO");
255 error << _("badly-formed XML in imported track") << endmsg;
259 XMLProperty * p = c->property ("name");
261 error << _("badly-formed XML in imported track") << endmsg;
267 track_handler.add_name (name);
273 AudioTrackImporter::_cancel_move ()
275 track_handler.remove_name (name);
280 AudioTrackImporter::_move ()
286 boost::shared_ptr<XMLSharedNodeList> ds_node_list;
287 string xpath = "/Session/DiskStreams/AudioDiskstream[@id='" + old_ds_id.to_s() + "']";
288 ds_node_list = source.find (xpath);
290 if (ds_node_list->size() != 1) {
291 error << string_compose (_("Error Importing Audio track %1"), name) << endmsg;
295 boost::shared_ptr<XMLNode> ds_node = ds_node_list->front();
296 XMLProperty * p = ds_node->property (X_("id"));
298 p->set_value (new_ds_id.to_s());
300 boost::shared_ptr<DiskReader> new_ds (new DiskReader (session, *ds_node));
301 new_ds->set_name (name);
302 new_ds->do_refill_with_alloc ();
303 new_ds->set_block_size (session.get_block_size ());
305 /* Import playlists */
307 for (PlaylistList::const_iterator it = playlists.begin(); it != playlists.end(); ++it) {
313 XMLNode routes ("Routes");
314 routes.add_child_copy (xml_track);
315 session.load_routes (routes, 3000);
320 AudioTrackImporter::parse_processor (XMLNode & node)
322 XMLNode * automation = node.child ("Automation");
324 parse_automation (*automation);
331 AudioTrackImporter::parse_controllable (XMLNode & node)
335 if ((prop = node.property ("id"))) {
337 prop->set_value (new_id.to_s());
346 AudioTrackImporter::parse_automation (XMLNode & node)
349 XMLNodeList const & lists = node.children ("AutomationList");
350 for (XMLNodeList::const_iterator it = lists.begin(); it != lists.end(); ++it) {
353 if ((prop = (*it)->property ("id"))) {
355 prop->set_value (id.to_s());
358 if (!(*it)->name().compare ("events")) {
359 rate_convert_events (**it);
367 AudioTrackImporter::rate_convert_events (XMLNode & node)
369 if (node.children().empty()) {
373 XMLNode* content_node = node.children().front();
375 if (content_node->content().empty()) {
379 std::stringstream str (content_node->content());
380 std::ostringstream new_content;
397 new_content << rate_convert_samples (x) << ' ' << y;
401 error << X_("AudioTrackImporter: error in rate converting automation events") << endmsg;
405 content_node->set_content (new_content.str());