ardour
audio_playlist_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 
23 #include <sstream>
24 
25 #include "pbd/failed_constructor.h"
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28 
30 #include "ardour/session.h"
33 
34 #include "i18n.h"
35 
36 using namespace std;
37 using namespace PBD;
38 using namespace ARDOUR;
39 
40 /**** Handler ***/
41 AudioPlaylistImportHandler::AudioPlaylistImportHandler (XMLTree const & source, Session & session, AudioRegionImportHandler & region_handler, const char * nodename) :
42  ElementImportHandler (source, session),
43  region_handler (region_handler)
44 {
45  XMLNode const * root = source.root();
46  XMLNode const * playlists;
47 
48  if (!(playlists = root->child (nodename))) {
49  throw failed_constructor();
50  }
51 
52  XMLNodeList const & pl_children = playlists->children();
53  for (XMLNodeList::const_iterator it = pl_children.begin(); it != pl_children.end(); ++it) {
54  const XMLProperty* type = (*it)->property("type");
55  if ( !type || type->value() == "audio" ) {
56  try {
57  elements.push_back (ElementPtr ( new AudioPlaylistImporter (source, session, *this, **it)));
58  } catch (failed_constructor err) {
59  set_dirty();
60  }
61  }
62  }
63 }
64 
65 string
67 {
68  return _("Audio Playlists");
69 }
70 
71 void
73 {
75 }
76 
77 void
79 {
80  PBD::ID old_id (id_prop->value());
81  PBD::ID new_id (region_handler.get_new_id (old_id));
82  id_prop->set_value (new_id.to_s());
83 }
84 
85 void
87 {
88  for (ElementList::const_iterator it = elements.begin(); it != elements.end(); ++it) {
90  if (pl && pl->orig_diskstream() == id) {
91  list.push_back (PlaylistPtr (new AudioPlaylistImporter (*pl)));
92  }
93  }
94 }
95 
96 /*** AudioPlaylistImporter ***/
98  ElementImporter (source, session),
99  handler (handler),
100  orig_node (node),
101  xml_playlist (node),
102  diskstream_id ("0")
103 {
104  bool ds_ok = false;
105 
107 
108  // Parse XML
109  XMLPropertyList const & props = xml_playlist.properties();
110  for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) {
111  string prop = (*it)->name();
112  if (!prop.compare("type") || !prop.compare("frozen")) {
113  // All ok
114  } else if (!prop.compare("name")) {
115  name = (*it)->value();
116  } else if (!prop.compare("orig-diskstream-id")) {
117  orig_diskstream_id = (*it)->value();
118  ds_ok = true;
119  } else {
120  std::cerr << string_compose (X_("AudioPlaylistImporter did not recognise XML-property \"%1\""), prop) << endmsg;
121  }
122  }
123 
124  if (!ds_ok) {
125  error << string_compose (X_("AudioPlaylistImporter (%1): did not find XML-property \"orig_diskstream_id\" which is mandatory"), name) << endmsg;
126  throw failed_constructor();
127  }
128 }
129 
131  ElementImporter (other.source, other.session),
132  handler (other.handler),
133  orig_node (other.orig_node),
134  xml_playlist (other.xml_playlist),
135  orig_diskstream_id (other.orig_diskstream_id)
136 {
138 }
139 
141 {
142 
143 }
144 
145 string
147 {
148  XMLNodeList children = xml_playlist.children();
149  unsigned int regions = 0;
150  std::ostringstream oss;
151 
152  for (XMLNodeIterator it = children.begin(); it != children.end(); it++) {
153  if ((*it)->name() == "Region") {
154  ++regions;
155  }
156  }
157 
158  oss << regions << " ";
159 
160  if (regions == 1) {
161  oss << _("region");
162  } else {
163  oss << _("regions");
164  }
165 
166  return oss.str();
167 }
168 
169 bool
171 {
172  // Rename
173  while (session.playlists->by_name (name) || !handler.check_name (name)) {
174  std::pair<bool, string> rename_pair = *Rename (_("A playlist with this name already exists, please rename it."), name);
175  if (!rename_pair.first) {
176  return false;
177  }
178  name = rename_pair.second;
179  }
180 
181  XMLProperty* p = xml_playlist.property ("name");
182  if (!p) {
183  error << _("badly-formed XML in imported playlist") << endmsg;
184  return false;
185  }
186 
187  p->set_value (name);
189 
190  return true;
191 }
192 
193 void
195 {
197 }
198 
199 void
201 {
203 
204  // Update diskstream id
205  xml_playlist.property ("orig-diskstream-id")->set_value (diskstream_id.to_s());
206 
207  // Update region XML in playlist and prepare sources
208  xml_playlist.remove_nodes("Region");
209  for (RegionList::iterator it = regions.begin(); it != regions.end(); ++it) {
210  xml_playlist.add_child_copy ((*it)->get_xml());
211  (*it)->add_sources_to_session();
212  if ((*it)->broken()) {
213  handler.set_dirty();
214  set_broken();
215  return; // TODO clean up?
216  }
217  }
218 
219  // Update region ids in crossfades
220  XMLNodeList crossfades = xml_playlist.children("Crossfade");
221  for (XMLNodeIterator it = crossfades.begin(); it != crossfades.end(); ++it) {
222  XMLProperty* in = (*it)->property("in");
223  XMLProperty* out = (*it)->property("out");
224  if (!in || !out) {
225  error << string_compose (X_("AudioPlaylistImporter (%1): did not find the \"in\" or \"out\" property from a crossfade"), name) << endmsg;
226  continue; // or fatal?
227  }
228 
231 
232  // rate convert length and position
233  XMLProperty* length = (*it)->property("length");
234  if (length) {
235  length->set_value (rate_convert_samples (length->value()));
236  }
237 
238  XMLProperty* position = (*it)->property("position");
239  if (position) {
240  position->set_value (rate_convert_samples (position->value()));
241  }
242  }
243 
244  // Create playlist
245  playlist = PlaylistFactory::create (session, xml_playlist, false, true);
246 }
247 
248 void
250 {
251  diskstream_id = id;
252 }
253 
254 void
256 {
258  handler.get_regions (orig_node, elements);
259  for (ElementImportHandler::ElementList::iterator it = elements.begin(); it != elements.end(); ++it) {
260  regions.push_back (boost::dynamic_pointer_cast<AudioRegionImporter> (*it));
261  }
262 }
263 
264 string
266 {
267  return _("Audio Playlists (unused)");
268 }
AudioRegionImportHandler & region_handler
void playlists_by_diskstream(PBD::ID const &id, PlaylistList &list) const
PBD::ID const & get_new_id(PBD::ID &old_id) const
void update_region_id(XMLProperty *id_prop)
XMLNodeList::iterator XMLNodeIterator
Definition: xml++.h:48
const XMLPropertyList & properties() const
Definition: xml++.h:119
std::string name
Name of element.
const std::string & value() const
Definition: xml++.h:159
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
std::list< XMLProperty * > XMLPropertyList
Definition: xml++.h:50
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
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
AudioPlaylistImporter(XMLTree const &source, Session &session, AudioPlaylistImportHandler &handler, XMLNode const &node)
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
PBD::ID const & orig_diskstream() const
#define _(Text)
Definition: i18n.h:11
Virtual interface class for element importers.
#define X_(Text)
Definition: i18n.h:13
XMLProperty * property(const char *)
Definition: xml++.cc:413
void set_diskstream(PBD::ID const &id)
XMLNode * root() const
Definition: xml++.h:62
Definition: amp.h:29
std::string to_s() const
Definition: id.cc:78
AudioPlaylistImportHandler & handler
virtual std::string get_info() const
void remove_nodes(const std::string &)
Definition: xml++.cc:497
Virtual interface class for element import handlers.
std::list< ElementPtr > ElementList
ElementList elements
Elements this handler handles.
void remove_name(const std::string &name)
Removes name from the list of used names.
Definition: xml++.h:95
void add_name(std::string name)
Adds name to the list of used names.
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
Definition: debug.h:30
void get_regions(XMLNode const &node, ElementList &list) const
void set_broken()
Set element broken.
XMLNode * child(const char *) const
Definition: xml++.cc:309
boost::shared_ptr< SessionPlaylists > playlists
Definition: session.h:907
void create_regions_from_children(XMLNode const &node, ElementList &list)
const std::string & set_value(const std::string &v)
Definition: xml++.h:160
static boost::shared_ptr< Playlist > create(Session &, const XMLNode &, bool hidden=false, bool unused=false)
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
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
Definition: region.cc:64