ardour
audio_region_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 <glibmm/miscutils.h>
26 
27 #include "pbd/failed_constructor.h"
28 #include "pbd/compose.h"
29 #include "pbd/error.h"
30 
31 #include "ardour/session.h"
32 #include "ardour/region.h"
33 #include "ardour/region_factory.h"
35 
36 #include "i18n.h"
37 
38 using namespace std;
39 using namespace PBD;
40 using namespace ARDOUR;
41 
42 /**** Handler ***/
43 AudioRegionImportHandler::AudioRegionImportHandler (XMLTree const & source, Session & session) :
44  ElementImportHandler (source, session)
45 {
46  XMLNode const * root = source.root();
47  XMLNode const * regions;
48 
49  if (!(regions = root->child (X_("Regions")))) {
50  throw failed_constructor();
51  }
52 
54 }
55 
56 void
58 {
59  XMLNodeList const & children = node.children();
60  for (XMLNodeList::const_iterator it = children.begin(); it != children.end(); ++it) {
61  XMLProperty const * type = (*it)->property("type");
62  if (!(*it)->name().compare ("Region") && (!type || type->value() == "audio") ) {
63  try {
64  list.push_back (ElementPtr ( new AudioRegionImporter (source, session, *this, **it)));
65  } catch (failed_constructor err) {
66  set_dirty();
67  }
68  }
69  }
70 }
71 
72 string
74 {
75  return _("Audio Regions");
76 }
77 
78 bool
79 AudioRegionImportHandler::check_source (string const & filename) const
80 {
81  return (sources.find (filename) != sources.end());
82 }
83 
84 void
85 AudioRegionImportHandler::add_source (string const & filename, boost::shared_ptr<Source> const & source)
86 {
87  sources.insert (SourcePair (filename, source));
88 }
89 
91 AudioRegionImportHandler::get_source (string const & filename) const
92 {
93  return (sources.find (filename))->second;
94 }
95 
96 void
98 {
99  id_map.insert (IdPair (old_id, new_id));
100 }
101 
102 PBD::ID const &
104 {
105  return (id_map.find (old_id))->second;
106 }
107 
108 /*** AudioRegionImporter ***/
109 AudioRegionImporter::AudioRegionImporter (XMLTree const & source, Session & session, AudioRegionImportHandler & handler, XMLNode const & node) :
110  ElementImporter (source, session),
111  xml_region (node),
112  handler (handler),
113  old_id ("0"),
114  region_prepared (false),
115  sources_prepared (false)
116 {
117  if (!parse_xml_region () || !parse_source_xml ()) {
118  throw failed_constructor();
119  }
120  handler.register_id (old_id, id);
121 }
122 
124 {
125 }
126 
127 string
129 {
131  Timecode::Time length_time, position_time;
132  std::ostringstream oss;
133 
134  // Get sample positions
135  std::istringstream iss_length(xml_region.property ("length")->value());
136  iss_length >> length;
137  std::istringstream iss_position(xml_region.property ("position")->value());
138  iss_position >> position;
139 
140  // Convert to timecode
141  session.sample_to_timecode(length, length_time, true, false);
142  session.sample_to_timecode(position, position_time, true, false);
143 
144  // return info
145  oss << _("Length: ") <<
146  timecode_to_string(length_time) <<
147  _("\nPosition: ") <<
148  timecode_to_string(position_time) <<
149  _("\nChannels: ") <<
150  xml_region.property ("channels")->value();
151 
152 
153  return oss.str();
154 }
155 
156 bool
158 {
159  return true;
160 }
161 
162 void
164 {
165 }
166 
167 void
169 {
170  if (!region_prepared) {
171  prepare_region();
172  if (!region_prepared) {
173  return;
174  }
175  }
176 
177  if (broken()) {
178  return;
179  }
180 }
181 
182 bool
184 {
185  XMLPropertyList const & props = xml_region.properties();
186  bool id_ok = false;
187  bool name_ok = false;
188 
189  for (XMLPropertyList::const_iterator it = props.begin(); it != props.end(); ++it) {
190  string prop = (*it)->name();
191  if (!prop.compare ("type") || !prop.compare ("stretch") ||
192  !prop.compare ("shift") || !prop.compare ("first_edit") ||
193  !prop.compare ("layer") || !prop.compare ("flags") ||
194  !prop.compare ("scale-gain") || !prop.compare("channels") ||
195  !prop.compare ("first-edit") ||
196  prop.find ("master-source-") == 0 || prop.find ("source-") == 0) {
197  // All ok
198  } else if (!prop.compare ("start") || !prop.compare ("length") ||
199  !prop.compare ("position") || !prop.compare ("ancestral-start") ||
200  !prop.compare ("ancestral-length") || !prop.compare ("sync-position")) {
201  // Sample rate conversion
202  (*it)->set_value (rate_convert_samples ((*it)->value()));
203  } else if (!prop.compare("id")) {
204  // get old id and update id
205  old_id = (*it)->value();
206  (*it)->set_value (id.to_s());
207  id_ok = true;
208  } else if (!prop.compare("name")) {
209  // rename region if necessary
210  name = (*it)->value();
212  (*it)->set_value (name);
213  name_ok = true;
214  } else {
215  std::cerr << string_compose (X_("AudioRegionImporter (%1): did not recognise XML-property \"%2\""), name, prop) << endmsg;
216  }
217  }
218 
219  if (!id_ok) {
220  error << string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"id\""), name) << endmsg;
221  return false;
222  }
223 
224  if (!name_ok) {
225  error << X_("AudioRegionImporter: did not find necessary XML-property \"name\"") << endmsg;
226  return false;
227  }
228 
229  return true;
230 }
231 
232 bool
234 {
235  uint32_t channels;
236  char buf[128];
237  std::string source_dir(get_sound_dir (source));
238  XMLNode * source_node;
239  XMLProperty *prop;
240 
241  // Get XML for sources
242  if (!(source_node = source.root()->child (X_("Sources")))) {
243  return false;
244  }
245  XMLNodeList const & sources = source_node->children();
246 
247  // Get source for each channel
248  if (!(prop = xml_region.property ("channels"))) {
249  error << string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"channels\""), name) << endmsg;
250  return false;
251  }
252 
253  channels = atoi (prop->value().c_str());
254  for (uint32_t i = 0; i < channels; ++i) {
255  bool source_found = false;
256 
257  // Get id for source-n
258  snprintf (buf, sizeof(buf), X_("source-%d"), i);
259  prop = xml_region.property (buf);
260  if (!prop) {
261  error << string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"%2\""), name, buf) << endmsg;
262  return false;
263  }
264  string source_id = prop->value();
265 
266  // Get source
267  for (XMLNodeList::const_iterator it = sources.begin(); it != sources.end(); ++it) {
268  prop = (*it)->property ("id");
269  if (prop && !source_id.compare (prop->value())) {
270  prop = (*it)->property ("name");
271  if (!prop) {
272  error << string_compose (X_("AudioRegionImporter (%1): source %2 has no \"name\" property"), name, source_id) << endmsg;
273  return false;
274  }
275  filenames.push_back (Glib::build_filename (source_dir, prop->value()));
276  source_found = true;
277  break;
278  }
279  }
280 
281  if (!source_found) {
282  error << string_compose (X_("AudioRegionImporter (%1): could not find all necessary sources"), name) << endmsg;
283  return false;
284  }
285  }
286 
287  return true;
288 }
289 
290 std::string
292 {
293  SessionDirectory session_dir(Glib::path_get_dirname (tree.filename()));
294  return session_dir.sound_path();
295 }
296 
297 void
299 {
300  if (region_prepared) {
301  return;
302  }
303 
304  SourceList source_list;
305  prepare_sources();
306 
307  // Create source list
308  for (std::list<string>::iterator it = filenames.begin(); it != filenames.end(); ++it) {
309  source_list.push_back (handler.get_source (*it));
310  }
311 
312  // create region and update XML
314  if (session.config.get_glue_new_regions_to_bars_and_beats ()) {
316  }
317  region.push_back (r);
318  if (*region.begin()) {
319  xml_region = (*region.begin())->get_state();
320  } else {
321  error << string_compose (X_("AudioRegionImporter (%1): could not construct Region"), name) << endmsg;
323  }
324 
325  region_prepared = true;
326 }
327 
328 void
330 {
331  if (sources_prepared) {
332  return;
333  }
334 
335  status.total = 0;
337  status.done = false;
338  status.cancel = false;
339  status.freeze = false;
340  status.progress = 0.0;
341  status.quality = SrcBest; // TODO other qualities also
342 
343  // Get sources that still need to be imported
344  for (std::list<string>::iterator it = filenames.begin(); it != filenames.end(); ++it) {
345  if (!handler.check_source (*it)) {
346  status.paths.push_back (*it);
347  status.total++;
348  }
349  }
350 
351  // import files
352  // TODO: threading & exception handling
354 
355  // Add imported sources to handlers map
356  std::vector<string>::iterator file_it = status.paths.begin();
357  for (SourceList::iterator source_it = status.sources.begin(); source_it != status.sources.end(); ++source_it) {
358  if (*source_it) {
359  handler.add_source(*file_it, *source_it);
360  } else {
361  error << string_compose (X_("AudioRegionImporter (%1): could not import all necessary sources"), name) << endmsg;
363  set_broken();
364  }
365 
366  ++file_it;
367  }
368 
369  sources_prepared = true;
370 }
371 
372 void
374 {
375  if (!sources_prepared) {
376  prepare_sources();
377  }
378 
379  if (broken()) {
380  return;
381  }
382 
383  for (std::list<string>::iterator it = filenames.begin(); it != filenames.end(); ++it) {
385  }
386 }
387 
388 XMLNode const &
390 {
391  if(!region_prepared) {
392  prepare_region();
393  }
394 
395  return xml_region;
396 }
AudioRegionImporter(XMLTree const &source, Session &session, AudioRegionImportHandler &handler, XMLNode const &node)
PBD::ID const & get_new_id(PBD::ID &old_id) const
std::pair< PBD::ID, PBD::ID > IdPair
int atoi(const string &s)
Definition: convert.cc:140
const XMLPropertyList & properties() const
Definition: xml++.h:119
std::string name
Name of element.
const std::string & value() const
Definition: xml++.h:159
boost::shared_ptr< Source > const & get_source(std::string const &filename) const
std::list< XMLProperty * > XMLPropertyList
Definition: xml++.h:50
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
SessionConfiguration config
Definition: session.h:866
bool check_source(std::string const &filename) const
ARDOUR::Session & session
Target session.
framecnt_t rate_convert_samples(framecnt_t samples) const
Converts samples so that times match the sessions sample rate.
Definition: xml++.h:55
volatile bool freeze
Definition: import_status.h:42
Definition: id.h:32
AudioRegionImportHandler & handler
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
#define _(Text)
Definition: i18n.h:11
std::list< std::string > filenames
static std::string new_region_name(std::string)
Virtual interface class for element importers.
std::pair< std::string, boost::shared_ptr< Source > > SourcePair
#define X_(Text)
Definition: i18n.h:13
int64_t framecnt_t
Definition: types.h:76
XMLProperty * property(const char *)
Definition: xml++.cc:413
ARDOUR::Session & session
Destination session.
XMLNode * root() const
Definition: xml++.h:62
Definition: amp.h:29
XMLTree const & source
Source session XML tree.
const std::string & filename() const
Definition: xml++.h:65
std::vector< boost::shared_ptr< Region > > region
const std::string sound_path() const
std::string get_sound_dir(XMLTree const &tree)
LIBARDOUR_API PBD::PropertyDescriptor< bool > regions
Definition: playlist.cc:51
void sample_to_timecode(framepos_t sample, Timecode::Time &timecode, bool use_offset, bool use_subframes) const
void add_source(std::string const &filename, boost::shared_ptr< Source > const &source)
Virtual interface class for element import handlers.
std::list< ElementPtr > ElementList
ElementList elements
Elements this handler handles.
XMLTree const & source
Source XML-tree.
Definition: xml++.h:95
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
Definition: region.cc:65
Definition: debug.h:30
void add_source(boost::shared_ptr< Source >)
Definition: session.cc:3598
std::string timecode_to_string(Timecode::Time &time) const
Converts timecode time to a string.
void set_broken()
Set element broken.
void register_id(PBD::ID &old_id, PBD::ID &new_id)
XMLNode * child(const char *) const
Definition: xml++.cc:309
static void set_errors()
Sets handler dirty.
void import_files(ImportStatus &)
Definition: import.cc:452
void set_position_lock_style(PositionLockStyle ps)
Definition: region.cc:543
void create_regions_from_children(XMLNode const &node, ElementList &list)
static boost::shared_ptr< Region > create(boost::shared_ptr< const Region > other, bool announce=false)
std::vector< std::string > paths
Definition: import_status.h:43
static void set_dirty()
Sets handler dirty.
std::vector< boost::shared_ptr< Source > > SourceList
Definition: types.h:520
bool broken()
Check if element is broken. Cannot be moved if broken.
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