2 Copyright (C) 2008 Paul Davis
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.
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.
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.
21 #include "ardour/audio_region_importer.h"
25 #include "pbd/failed_constructor.h"
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
29 #include "ardour/session.h"
30 #include "ardour/region.h"
31 #include "ardour/source_factory.h"
32 #include "ardour/region_factory.h"
33 #include "ardour/session_directory.h"
39 using namespace ARDOUR
;
42 AudioRegionImportHandler::AudioRegionImportHandler (XMLTree
const & source
, Session
& session
) :
43 ElementImportHandler (source
, session
)
45 XMLNode
const * root
= source
.root();
46 XMLNode
const * regions
;
48 if (!(regions
= root
->child (X_("Regions")))) {
49 throw failed_constructor();
52 create_regions_from_children (*regions
, elements
);
56 AudioRegionImportHandler::create_regions_from_children (XMLNode
const & node
, ElementList
& list
)
58 XMLNodeList
const & children
= node
.children();
59 for (XMLNodeList::const_iterator it
= children
.begin(); it
!= children
.end(); ++it
) {
60 XMLProperty
const * type
= (*it
)->property("type");
61 if (!(*it
)->name().compare ("Region") && (!type
|| type
->value() == "audio") ) {
63 list
.push_back (ElementPtr ( new AudioRegionImporter (source
, session
, *this, **it
)));
64 } catch (failed_constructor err
) {
72 AudioRegionImportHandler::get_info () const
74 return _("Audio Regions");
78 AudioRegionImportHandler::check_source (string
const & filename
) const
80 return (sources
.find (filename
) != sources
.end());
84 AudioRegionImportHandler::add_source (string
const & filename
, boost::shared_ptr
<Source
> const & source
)
86 sources
.insert (SourcePair (filename
, source
));
89 boost::shared_ptr
<Source
> const &
90 AudioRegionImportHandler::get_source (string
const & filename
) const
92 return (sources
.find (filename
))->second
;
96 AudioRegionImportHandler::register_id (PBD::ID
& old_id
, PBD::ID
& new_id
)
98 id_map
.insert (IdPair (old_id
, new_id
));
102 AudioRegionImportHandler::get_new_id (PBD::ID
& old_id
) const
104 return (id_map
.find (old_id
))->second
;
107 /*** AudioRegionImporter ***/
108 AudioRegionImporter::AudioRegionImporter (XMLTree
const & source
, Session
& session
, AudioRegionImportHandler
& handler
, XMLNode
const & node
) :
109 ElementImporter (source
, session
),
113 region_prepared (false),
114 sources_prepared (false)
116 if (!parse_xml_region () || !parse_source_xml ()) {
117 throw failed_constructor();
119 handler
.register_id (old_id
, id
);
122 AudioRegionImporter::~AudioRegionImporter ()
127 AudioRegionImporter::get_info () const
129 framecnt_t length
, position
;
130 Timecode::Time length_time
, position_time
;
131 std::ostringstream oss
;
133 // Get sample positions
134 std::istringstream
iss_length(xml_region
.property ("length")->value());
135 iss_length
>> length
;
136 std::istringstream
iss_position(xml_region
.property ("position")->value());
137 iss_position
>> position
;
139 // Convert to timecode
140 session
.sample_to_timecode(length
, length_time
, true, false);
141 session
.sample_to_timecode(position
, position_time
, true, false);
144 oss
<< _("Length: ") <<
145 timecode_to_string(length_time
) <<
147 timecode_to_string(position_time
) <<
149 xml_region
.property ("channels")->value();
156 AudioRegionImporter::_prepare_move ()
162 AudioRegionImporter::_cancel_move ()
167 AudioRegionImporter::_move ()
169 if (!region_prepared
) {
171 if (!region_prepared
) {
182 AudioRegionImporter::parse_xml_region ()
184 XMLPropertyList
const & props
= xml_region
.properties();
186 bool name_ok
= false;
188 for (XMLPropertyList::const_iterator it
= props
.begin(); it
!= props
.end(); ++it
) {
189 string prop
= (*it
)->name();
190 if (!prop
.compare ("type") || !prop
.compare ("stretch") ||
191 !prop
.compare ("shift") || !prop
.compare ("first_edit") ||
192 !prop
.compare ("layer") || !prop
.compare ("flags") ||
193 !prop
.compare ("scale-gain") || !prop
.compare("channels") ||
194 !prop
.compare ("first-edit") ||
195 prop
.find ("master-source-") == 0 || prop
.find ("source-") == 0) {
197 } else if (!prop
.compare ("start") || !prop
.compare ("length") ||
198 !prop
.compare ("position") || !prop
.compare ("ancestral-start") ||
199 !prop
.compare ("ancestral-length") || !prop
.compare ("sync-position")) {
200 // Sample rate conversion
201 (*it
)->set_value (rate_convert_samples ((*it
)->value()));
202 } else if (!prop
.compare("id")) {
203 // get old id and update id
204 old_id
= (*it
)->value();
205 (*it
)->set_value (id
.to_s());
207 } else if (!prop
.compare("name")) {
208 // rename region if necessary
209 name
= (*it
)->value();
210 name
= RegionFactory::new_region_name (name
);
211 (*it
)->set_value (name
);
214 std::cerr
<< string_compose (X_("AudioRegionImporter (%1): did not recognise XML-property \"%2\""), name
, prop
) << endmsg
;
219 error
<< string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"id\""), name
) << endmsg
;
224 error
<< X_("AudioRegionImporter: did not find necessary XML-property \"name\"") << endmsg
;
232 AudioRegionImporter::parse_source_xml ()
236 PBD::sys::path source_dir
= get_sound_dir (source
);
237 PBD::sys::path source_path
;
238 XMLNode
* source_node
;
241 // Get XML for sources
242 if (!(source_node
= source
.root()->child (X_("Sources")))) {
245 XMLNodeList
const & sources
= source_node
->children();
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
;
253 channels
= atoi (prop
->value().c_str());
254 for (uint32_t i
= 0; i
< channels
; ++i
) {
255 bool source_found
= false;
257 // Get id for source-n
258 snprintf (buf
, sizeof(buf
), X_("source-%d"), i
);
259 prop
= xml_region
.property (buf
);
261 error
<< string_compose (X_("AudioRegionImporter (%1): did not find necessary XML-property \"%2\""), name
, buf
) << endmsg
;
264 string source_id
= prop
->value();
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 source_path
= source_dir
;
271 prop
= (*it
)->property ("name");
273 error
<< string_compose (X_("AudioRegionImporter (%1): source %2 has no \"name\" property"), name
, source_id
) << endmsg
;
276 source_path
/= prop
->value();
277 filenames
.push_back (source_path
.to_string());
285 error
<< string_compose (X_("AudioRegionImporter (%1): could not find all necessary sources"), name
) << endmsg
;
294 AudioRegionImporter::get_sound_dir (XMLTree
const & tree
)
296 PBD::sys::path source_dir
= tree
.filename();
297 source_dir
= source_dir
.branch_path();
298 SessionDirectory
session_dir(source_dir
);
299 source_dir
= session_dir
.sound_path();
305 AudioRegionImporter::prepare_region ()
307 if (region_prepared
) {
311 SourceList source_list
;
314 // Create source list
315 for (std::list
<string
>::iterator it
= filenames
.begin(); it
!= filenames
.end(); ++it
) {
316 source_list
.push_back (handler
.get_source (*it
));
319 // create region and update XML
320 region
.push_back (RegionFactory::create (source_list
, xml_region
));
321 if (*region
.begin()) {
322 xml_region
= (*region
.begin())->get_state();
324 error
<< string_compose (X_("AudioRegionImporter (%1): could not construct Region"), name
) << endmsg
;
325 handler
.set_errors();
328 region_prepared
= true;
332 AudioRegionImporter::prepare_sources ()
334 if (sources_prepared
) {
339 status
.replace_existing_source
= false;
341 status
.cancel
= false;
342 status
.freeze
= false;
343 status
.progress
= 0.0;
344 status
.quality
= SrcBest
; // TODO other qualities also
346 // Get sources that still need to be imported
347 for (std::list
<string
>::iterator it
= filenames
.begin(); it
!= filenames
.end(); ++it
) {
348 if (!handler
.check_source (*it
)) {
349 status
.paths
.push_back (*it
);
355 // TODO: threading & exception handling
356 session
.import_audiofiles (status
);
358 // Add imported sources to handlers map
359 std::vector
<string
>::iterator file_it
= status
.paths
.begin();
360 for (SourceList::iterator source_it
= status
.sources
.begin(); source_it
!= status
.sources
.end(); ++source_it
) {
362 handler
.add_source(*file_it
, *source_it
);
364 error
<< string_compose (X_("AudioRegionImporter (%1): could not import all necessary sources"), name
) << endmsg
;
365 handler
.set_errors();
372 sources_prepared
= true;
376 AudioRegionImporter::add_sources_to_session ()
378 if (!sources_prepared
) {
386 for (std::list
<string
>::iterator it
= filenames
.begin(); it
!= filenames
.end(); ++it
) {
387 session
.add_source (handler
.get_source (*it
));
392 AudioRegionImporter::get_xml ()
394 if(!region_prepared
) {