ardour
audio_track_importer.cc
Go to the documentation of this file.
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 
22 
25 #include "ardour/session.h"
26 
27 #include "pbd/controllable.h"
28 #include "pbd/convert.h"
29 #include "pbd/failed_constructor.h"
30 
31 #include <sstream>
32 #include <algorithm>
33 
34 #include "i18n.h"
35 
36 using namespace std;
37 using namespace PBD;
38 using namespace ARDOUR;
39 
40 /*** AudioTrackImportHandler ***/
41 
42 AudioTrackImportHandler::AudioTrackImportHandler (XMLTree const & source, Session & session, AudioPlaylistImportHandler & pl_handler) :
43  ElementImportHandler (source, session)
44 {
45  XMLNode const * root = source.root();
46  XMLNode const * routes;
47 
48  if (!(routes = root->child ("Routes"))) {
49  throw failed_constructor();
50  }
51 
52  XMLNodeList const & route_list = routes->children();
53  for (XMLNodeList::const_iterator it = route_list.begin(); it != route_list.end(); ++it) {
54  const XMLProperty* type = (*it)->property("default-type");
55  if ( (!type || type->value() == "audio") && ((*it)->property ("diskstream") != 0 || (*it)->property ("diskstream-id") != 0)) {
56  try {
57  elements.push_back (ElementPtr ( new AudioTrackImporter (source, session, *this, **it, pl_handler)));
58  } catch (failed_constructor err) {
59  set_dirty();
60  }
61  }
62  }
63 }
64 
65 string
67 {
68  return _("Audio Tracks");
69 }
70 
71 
72 /*** AudioTrackImporter ***/
73 
75  Session & session,
76  AudioTrackImportHandler & track_handler,
77  XMLNode const & node,
78  AudioPlaylistImportHandler & pl_handler) :
79  ElementImporter (source, session),
80  track_handler (track_handler),
81  xml_track (node),
82  pl_handler (pl_handler)
83 {
84  XMLProperty * prop;
85 
86  if (!parse_route_xml ()) {
87  throw failed_constructor();
88  }
89 
90  if (!parse_io ()) {
91  throw failed_constructor();
92  }
93 
94  XMLNodeList const & controllables = node.children (Controllable::xml_node_name);
95  for (XMLNodeList::const_iterator it = controllables.begin(); it != controllables.end(); ++it) {
96  parse_controllable (**it);
97  }
98 
99  XMLNode * remote_control = xml_track.child ("RemoteControl");
100  if (remote_control && (prop = remote_control->property ("id"))) {
101  uint32_t control_id = session.ntracks() + session.nbusses() + 1;
102  prop->set_value (to_string (control_id, std::dec));
103  }
104 
106 }
107 
109 {
110  playlists.clear ();
111 }
112 
113 bool
115 {
116  bool ds_ok = false;
117 
118  // Remove order keys, new ones will be generated
119  xml_track.remove_property ("order-keys");
120 
121  XMLPropertyList const & props = xml_track.properties();
122  for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) {
123  string prop = (*it)->name();
124  if (!prop.compare ("default-type") || !prop.compare ("flags") ||
125  !prop.compare ("active") || !prop.compare ("muted") ||
126  !prop.compare ("soloed") || !prop.compare ("phase-invert") ||
127  !prop.compare ("denormal-protection") || !prop.compare("mute-affects-pre-fader") ||
128  !prop.compare ("mute-affects-post-fader") || !prop.compare("mute-affects-control-outs") ||
129  !prop.compare ("mute-affects-main-outs") || !prop.compare("mode")) {
130  // All ok
131  } else if (!prop.compare("diskstream-id")) {
132  old_ds_id = (*it)->value();
133  (*it)->set_value (new_ds_id.to_s());
134  ds_ok = true;
135  } else {
136  std::cerr << string_compose (X_("AudioTrackImporter: did not recognise XML-property \"%1\""), prop) << endmsg;
137  }
138  }
139 
140  if (!ds_ok) {
141  error << X_("AudioTrackImporter: did not find necessary XML-property \"diskstream-id\"") << endmsg;
142  return false;
143  }
144 
145  return true;
146 }
147 
148 bool
150 {
151  XMLNode * io;
152  bool name_ok = false;
153  bool id_ok = false;
154 
155  if (!(io = xml_track.child ("IO"))) {
156  return false;
157  }
158 
159  XMLPropertyList const & props = io->properties();
160 
161  for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) {
162  string prop = (*it)->name();
163  if (!prop.compare ("gain") || !prop.compare ("iolimits")) {
164  // All ok
165  } else if (!prop.compare("name")) {
166  name = (*it)->value();
167  name_ok = true;
168  } else if (!prop.compare("id")) {
169  PBD::ID id;
170  (*it)->set_value (id.to_s());
171  id_ok = true;
172  } else if (!prop.compare("inputs")) {
173  // TODO Handle this properly!
174  /* Input and output ports are counted and added empty, so that no in/output connecting function fails. */
175  uint32_t num_inputs = std::count ((*it)->value().begin(), (*it)->value().end(), '{');
176  std::string value;
177  for (uint32_t i = 0; i < num_inputs; i++) { value += "{}"; }
178  (*it)->set_value (value);
179  } else if (!prop.compare("outputs")) {
180  // TODO See comments above
181  uint32_t num_outputs = std::count ((*it)->value().begin(), (*it)->value().end(), '{');
182  std::string value;
183  for (uint32_t i = 0; i < num_outputs; i++) { value += "{}"; }
184  (*it)->set_value (value);
185  } else {
186  std::cerr << string_compose (X_("AudioTrackImporter: did not recognise XML-property \"%1\""), prop) << endmsg;
187  }
188  }
189 
190  if (!name_ok) {
191  error << X_("AudioTrackImporter: did not find necessary XML-property \"name\"") << endmsg;
192  return false;
193  }
194 
195  if (!id_ok) {
196  error << X_("AudioTrackImporter: did not find necessary XML-property \"id\"") << endmsg;
197  return false;
198  }
199 
200  XMLNodeList const & controllables = io->children (Controllable::xml_node_name);
201  for (XMLNodeList::const_iterator it = controllables.begin(); it != controllables.end(); ++it) {
202  parse_controllable (**it);
203  }
204 
205  XMLNodeList const & processors = io->children ("Processor");
206  for (XMLNodeList::const_iterator it = processors.begin(); it != processors.end(); ++it) {
207  parse_processor (**it);
208  }
209 
210  XMLNodeList const & automations = io->children ("Automation");
211  for (XMLNodeList::const_iterator it = automations.begin(); it != automations.end(); ++it) {
212  parse_automation (**it);
213  }
214 
215  return true;
216 }
217 
218 string
220 {
221  // TODO
222  return name;
223 }
224 
226 bool
228 {
229  /* Copy dependent playlists */
230 
232 
233  for (PlaylistList::iterator it = playlists.begin(); it != playlists.end(); ++it) {
234  if (!(*it)->prepare_move ()) {
235  playlists.clear ();
236  return false;
237  }
238  (*it)->set_diskstream (new_ds_id);
239  }
240 
241  /* Rename */
242 
244  std::pair<bool, string> rename_pair = *Rename (_("A playlist with this name already exists, please rename it."), name);
245  if (!rename_pair.first) {
246  return false;
247  }
248  name = rename_pair.second;
249  }
250 
251  XMLNode* c = xml_track.child ("IO");
252  if (!c) {
253  error << _("badly-formed XML in imported track") << endmsg;
254  return false;
255  }
256 
257  XMLProperty* p = c->property ("name");
258  if (!p) {
259  error << _("badly-formed XML in imported track") << endmsg;
260  return false;
261  }
262 
263  p->set_value (name);
264 
266 
267  return true;
268 }
269 
270 void
272 {
274  playlists.clear ();
275 }
276 
277 void
279 {
280  /* Add diskstream */
281 
283  string xpath = "/Session/DiskStreams/AudioDiskstream[@id='" + old_ds_id.to_s() + "']";
284  ds_node_list = source.find (xpath);
285 
286  if (ds_node_list->size() != 1) {
287  error << string_compose (_("Error Importing Audio track %1"), name) << endmsg;
288  return;
289  }
290 
291  boost::shared_ptr<XMLNode> ds_node = ds_node_list->front();
292  XMLProperty* p = ds_node->property (X_("id"));
293  assert (p);
294  p->set_value (new_ds_id.to_s());
295 
296  boost::shared_ptr<Diskstream> new_ds (new AudioDiskstream (session, *ds_node));
297  new_ds->set_name (name);
298  new_ds->do_refill_with_alloc ();
300 
301  /* Import playlists */
302 
303  for (PlaylistList::const_iterator it = playlists.begin(); it != playlists.end(); ++it) {
304  (*it)->move ();
305  }
306 
307  /* Import track */
308 
309  XMLNode routes ("Routes");
310  routes.add_child_copy (xml_track);
311  session.load_routes (routes, 3000);
312 }
313 
314 bool
316 {
317  XMLNode * automation = node.child ("Automation");
318  if (automation) {
319  parse_automation (*automation);
320  }
321 
322  return true;
323 }
324 
325 bool
327 {
328  XMLProperty * prop;
329 
330  if ((prop = node.property ("id"))) {
331  PBD::ID new_id;
332  prop->set_value (new_id.to_s());
333  } else {
334  return false;
335  }
336 
337  return true;
338 }
339 
340 bool
342 {
343 
344  XMLNodeList const & lists = node.children ("AutomationList");
345  for (XMLNodeList::const_iterator it = lists.begin(); it != lists.end(); ++it) {
346  XMLProperty * prop;
347 
348  if ((prop = (*it)->property ("id"))) {
349  PBD::ID id;
350  prop->set_value (id.to_s());
351  }
352 
353  if (!(*it)->name().compare ("events")) {
354  rate_convert_events (**it);
355  }
356  }
357 
358  return true;
359 }
360 
361 bool
363 {
364  if (node.children().empty()) {
365  return false;
366  }
367 
368  XMLNode* content_node = node.children().front();
369 
370  if (content_node->content().empty()) {
371  return false;
372  }
373 
374  std::stringstream str (content_node->content());
375  std::ostringstream new_content;
376 
377  framecnt_t x;
378  double y;
379  bool ok = true;
380 
381  while (str) {
382  str >> x;
383  if (!str) {
384  break;
385  }
386  str >> y;
387  if (!str) {
388  ok = false;
389  break;
390  }
391 
392  new_content << rate_convert_samples (x) << ' ' << y;
393  }
394 
395  if (!ok) {
396  error << X_("AudioTrackImporter: error in rate converting automation events") << endmsg;
397  return false;
398  }
399 
400  content_node->set_content (new_content.str());
401 
402  return true;
403 }
void playlists_by_diskstream(PBD::ID const &id, PlaylistList &list) const
std::string to_string(T t, std::ios_base &(*f)(std::ios_base &))
Definition: convert.h:53
const XMLPropertyList & properties() const
Definition: xml++.h:119
std::string name
Name of element.
const std::string & content() const
Definition: xml++.h:107
const std::string & value() const
Definition: xml++.h:159
virtual std::string get_info() const
virtual bool set_name(const std::string &str)
Definition: diskstream.cc:440
AudioPlaylistImportHandler & pl_handler
boost::shared_ptr< XMLSharedNodeList > find(const std::string xpath, XMLNode *=0) const
Definition: xml++.cc:371
bool parse_automation(XMLNode &node)
std::list< XMLProperty * > XMLPropertyList
Definition: xml++.h:50
bool parse_controllable(XMLNode &node)
uint32_t nbusses() const
Definition: session.cc:4885
XMLNode * add_child_copy(const XMLNode &)
Definition: xml++.cc:363
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
bool parse_processor(XMLNode &node)
AudioTrackImporter(XMLTree const &source, Session &session, AudioTrackImportHandler &track_handler, XMLNode const &node, AudioPlaylistImportHandler &pl_handler)
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
ARDOUR::Session & session
Target session.
framecnt_t rate_convert_samples(framecnt_t samples) const
Converts samples so that times match the sessions sample rate.
static PBD::Signal2< std::pair< bool, std::string >, std::string, std::string > Rename
Signal that requests for anew name.
Definition: xml++.h:55
Definition: id.h:32
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
#define _(Text)
Definition: i18n.h:11
Virtual interface class for element importers.
#define X_(Text)
Definition: i18n.h:13
int64_t framecnt_t
Definition: types.h:76
XMLProperty * property(const char *)
Definition: xml++.cc:413
uint32_t ntracks() const
Definition: session.cc:4870
bool rate_convert_events(XMLNode &node)
XMLNode * root() const
Definition: xml++.h:62
Definition: amp.h:29
std::string to_s() const
Definition: id.cc:78
static const std::string xml_node_name
Definition: controllable.h:116
Virtual interface class for element import handlers.
ElementList elements
Elements this handler handles.
pframes_t get_block_size() const
Definition: session.h:393
boost::shared_ptr< Route > route_by_name(std::string)
Definition: session.cc:3324
void remove_name(const std::string &name)
Removes name from the list of used names.
XMLTree const & source
Source XML-tree.
Definition: xml++.h:95
void add_name(std::string name)
Adds name to the list of used names.
void remove_property(const std::string &)
Definition: xml++.cc:476
const std::string & set_content(const std::string &)
Definition: xml++.cc:295
virtual int do_refill_with_alloc()=0
Definition: debug.h:30
XMLNode * child(const char *) const
Definition: xml++.cc:309
int load_routes(const XMLNode &, int)
const std::string & set_value(const std::string &v)
Definition: xml++.h:160
void remove_nodes_and_delete(const std::string &)
AudioTrackImportHandler & track_handler
virtual void set_block_size(pframes_t)=0
static void set_dirty()
Sets handler dirty.
bool check_name(const std::string &name) const
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208