2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
36 #include <samplerate.h>
40 #include <boost/scoped_array.hpp>
41 #include <boost/shared_array.hpp>
43 #include "pbd/basename.h"
44 #include "pbd/convert.h"
46 #include "evoral/SMF.hpp"
48 #include "ardour/analyser.h"
49 #include "ardour/ardour.h"
50 #include "ardour/audio_diskstream.h"
51 #include "ardour/audioengine.h"
52 #include "ardour/audioregion.h"
53 #include "ardour/import_status.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/resampled_source.h"
56 #include "ardour/session.h"
57 #include "ardour/session_directory.h"
58 #include "ardour/smf_source.h"
59 #include "ardour/sndfile_helpers.h"
60 #include "ardour/sndfileimportable.h"
61 #include "ardour/sndfilesource.h"
62 #include "ardour/source_factory.h"
63 #include "ardour/tempo.h"
66 #include "ardour/caimportable.h"
72 using namespace ARDOUR;
75 static boost::shared_ptr<ImportableSource>
76 open_importable_source (const string& path, nframes_t samplerate, ARDOUR::SrcQuality quality)
78 /* try libsndfile first, because it can get BWF info from .wav, which ExtAudioFile cannot.
79 We don't necessarily need that information in an ImportableSource, but it keeps the
80 logic the same as in SourceFactory::create()
84 boost::shared_ptr<SndFileImportableSource> source(new SndFileImportableSource(path));
86 if (source->samplerate() == samplerate) {
90 /* rewrap as a resampled source */
92 return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
99 /* libsndfile failed, see if we can use CoreAudio to handle the IO */
101 CAImportableSource* src = new CAImportableSource(path);
102 boost::shared_ptr<CAImportableSource> source (src);
104 if (source->samplerate() == samplerate) {
108 /* rewrap as a resampled source */
110 return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
120 get_non_existent_filename (DataType type, const bool allow_replacing, const std::string& destdir, const std::string& basename, uint channel, uint channels)
122 char buf[PATH_MAX+1];
123 bool goodfile = false;
124 string base(basename);
125 const char* ext = (type == DataType::AUDIO) ? "wav" : "mid";
129 if (type == DataType::AUDIO && channels == 2) {
131 snprintf (buf, sizeof(buf), "%s-L.wav", base.c_str());
133 snprintf (buf, sizeof(buf), "%s-R.wav", base.c_str());
135 } else if (channels > 1) {
136 snprintf (buf, sizeof(buf), "%s-c%d.%s", base.c_str(), channel, ext);
138 snprintf (buf, sizeof(buf), "%s.%s", base.c_str(), ext);
142 string tempname = destdir + "/" + buf;
143 if (!allow_replacing && Glib::file_test (tempname, Glib::FILE_TEST_EXISTS)) {
145 /* if the file already exists, we must come up with
146 * a new name for it. for now we just keep appending
157 } while ( !goodfile);
162 static vector<string>
163 get_paths_for_new_sources (const bool allow_replacing, const string& import_file_path, const string& session_dir, uint channels)
165 vector<string> new_paths;
166 const string basename = basename_nosuffix (import_file_path);
168 SessionDirectory sdir(session_dir);
170 for (uint n = 0; n < channels; ++n) {
172 const DataType type = (import_file_path.rfind(".mid") != string::npos)
173 ? DataType::MIDI : DataType::AUDIO;
175 std::string filepath = (type == DataType::MIDI)
176 ? sdir.midi_path().to_string() : sdir.sound_path().to_string();
179 filepath += get_non_existent_filename (type, allow_replacing, filepath, basename, n, channels);
180 new_paths.push_back (filepath);
187 map_existing_mono_sources (const vector<string>& new_paths, Session& /*sess*/,
188 uint /*samplerate*/, vector<boost::shared_ptr<Source> >& newfiles, Session *session)
190 for (vector<string>::const_iterator i = new_paths.begin();
191 i != new_paths.end(); ++i)
193 boost::shared_ptr<Source> source = session->source_by_path_and_channel(*i, 0);
196 error << string_compose(_("Could not find a source for %1 even though we are updating this file!"), (*i)) << endl;
200 newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
206 create_mono_sources_for_writing (const vector<string>& new_paths, Session& sess,
207 uint samplerate, vector<boost::shared_ptr<Source> >& newfiles,
208 framepos_t timeline_position)
210 for (vector<string>::const_iterator i = new_paths.begin(); i != new_paths.end(); ++i)
212 boost::shared_ptr<Source> source;
216 const DataType type = ((*i).rfind(".mid") != string::npos)
217 ? DataType::MIDI : DataType::AUDIO;
220 source = SourceFactory::createWritable (type, sess,
222 false, // destructive
225 catch (const failed_constructor& err)
227 error << string_compose (_("Unable to create file %1 during import"), *i) << endmsg;
231 newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
233 /* for audio files, reset the timeline position so that any BWF-ish
234 information in the original files we are importing from is maintained.
237 boost::shared_ptr<AudioFileSource> afs;
238 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
239 afs->set_timeline_position(timeline_position);
246 compose_status_message (const string& path,
247 uint file_samplerate,
248 uint session_samplerate,
252 if (file_samplerate != session_samplerate) {
253 return string_compose (_("resampling %1 from %2kHz to %3kHz\n(%4 of %5)"),
254 Glib::path_get_basename (path),
255 file_samplerate/1000.0f,
256 session_samplerate/1000.0f,
257 current_file, total_files);
260 return string_compose (_("copying %1\n(%2 of %3)"),
261 Glib::path_get_basename (path),
262 current_file, total_files);
266 write_audio_data_to_new_files (ImportableSource* source, ImportStatus& status,
267 vector<boost::shared_ptr<Source> >& newfiles)
269 const nframes_t nframes = ResampledImportableSource::blocksize;
270 boost::shared_ptr<AudioFileSource> afs;
271 uint channels = source->channels();
273 boost::scoped_array<float> data(new float[nframes * channels]);
274 vector<boost::shared_array<Sample> > channel_data;
276 for (uint n = 0; n < channels; ++n) {
277 channel_data.push_back(boost::shared_array<Sample>(new Sample[nframes]));
282 boost::shared_ptr<AudioSource> s = boost::dynamic_pointer_cast<AudioSource> (newfiles[0]);
285 status.progress = 0.0f;
286 float progress_multiplier = 1;
287 float progress_base = 0;
289 if (!source->clamped_at_unity() && s->clamped_at_unity()) {
291 /* The source we are importing from can return sample values with a magnitude greater than 1,
292 and the file we are writing the imported data to cannot handle such values. Compute the gain
293 factor required to normalize the input sources to have a magnitude of less than 1.
299 while (!status.cancel) {
300 nframes_t const nread = source->read (data.get(), nframes);
305 peak = compute_peak (data.get(), nread, peak);
308 status.progress = 0.5 * read_count / (source->ratio() * source->length() * channels);
312 /* we are out of range: compute a gain to fix it */
313 gain = (1 - FLT_EPSILON) / peak;
317 progress_multiplier = 0.5;
323 while (!status.cancel) {
325 nframes_t nread, nfread;
329 if ((nread = source->read (data.get(), nframes)) == 0) {
334 /* here is the gain fix for out-of-range sample values that we computed earlier */
335 apply_gain_to_buffer (data.get(), nread, gain);
338 nfread = nread / channels;
342 for (chn = 0; chn < channels; ++chn) {
345 for (x = chn, n = 0; n < nfread; x += channels, ++n) {
346 channel_data[chn][n] = (Sample) data[x];
352 for (chn = 0; chn < channels; ++chn) {
353 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(newfiles[chn])) != 0) {
354 afs->write (channel_data[chn].get(), nfread);
359 status.progress = progress_base + progress_multiplier * read_count / (source->ratio () * source->length() * channels);
364 write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
365 vector<boost::shared_ptr<Source> >& newfiles)
367 uint32_t buf_size = 4;
368 uint8_t* buf = (uint8_t*)malloc(buf_size);
370 status.progress = 0.0f;
374 for (unsigned i = 1; i <= source->num_tracks(); ++i) {
375 boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource>(newfiles[i-1]);
378 source->seek_to_track(i);
381 uint32_t delta_t = 0;
385 while (!status.cancel) {
388 int ret = source->read_event(&delta_t, &size, &buf);
392 if (ret < 0) { // EOT
398 if (ret == 0) { // Meta
403 smfs->mark_streaming_write_started ();
407 smfs->append_event_unlocked_beats(Evoral::Event<double>(0,
408 (double)t / (double)source->ppqn(),
412 if (status.progress < 0.99)
413 status.progress += 0.01;
416 const nframes64_t pos = 0;
417 const double length_beats = ceil(t / (double)source->ppqn());
418 BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
419 smfs->update_length(pos, converter.to(length_beats));
420 smfs->mark_streaming_write_completed ();
428 error << "Corrupt MIDI file " << source->file_path() << endl;
433 remove_file_source (boost::shared_ptr<Source> source)
435 ::unlink (source->path().c_str());
438 // This function is still unable to cleanly update an existing source, even though
439 // it is possible to set the ImportStatus flag accordingly. The functinality
440 // is disabled at the GUI until the Source implementations are able to provide
441 // the necessary API.
443 Session::import_audiofiles (ImportStatus& status)
446 typedef vector<boost::shared_ptr<Source> > Sources;
447 Sources all_new_sources;
448 boost::shared_ptr<AudioFileSource> afs;
449 boost::shared_ptr<SMFSource> smfs;
452 status.sources.clear ();
454 for (vector<Glib::ustring>::iterator p = status.paths.begin();
455 p != status.paths.end() && !status.cancel;
458 boost::shared_ptr<ImportableSource> source;
459 std::auto_ptr<Evoral::SMF> smf_reader;
460 const DataType type = ((*p).rfind(".mid") != string::npos) ?
461 DataType::MIDI : DataType::AUDIO;
463 if (type == DataType::AUDIO) {
465 source = open_importable_source (*p, frame_rate(), status.quality);
466 channels = source->channels();
467 } catch (const failed_constructor& err) {
468 error << string_compose(_("Import: cannot open input sound file \"%1\""), (*p)) << endmsg;
469 status.done = status.cancel = true;
475 smf_reader = std::auto_ptr<Evoral::SMF>(new Evoral::SMF());
476 smf_reader->open(*p);
477 channels = smf_reader->num_tracks();
479 error << _("Import: error opening MIDI file") << endmsg;
480 status.done = status.cancel = true;
485 vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source, *p,
486 get_best_session_directory_for_new_source (),
489 framepos_t natural_position = source ? source->natural_position() : 0;
491 if (status.replace_existing_source) {
492 fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endmsg;
493 status.cancel = !map_existing_mono_sources (new_paths, *this, frame_rate(), newfiles, this);
495 status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles, natural_position);
498 // copy on cancel/failure so that any files that were created will be removed below
499 std::copy (newfiles.begin(), newfiles.end(), std::back_inserter(all_new_sources));
505 for (Sources::iterator i = newfiles.begin(); i != newfiles.end(); ++i) {
506 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*i)) != 0) {
507 afs->prepare_for_peakfile_writes ();
511 if (source) { // audio
512 status.doing_what = compose_status_message (*p, source->samplerate(),
513 frame_rate(), cnt, status.total);
514 write_audio_data_to_new_files (source.get(), status, newfiles);
515 } else if (smf_reader.get()) { // midi
516 status.doing_what = string_compose(_("Loading MIDI file %1"), *p);
517 write_midi_data_to_new_files (smf_reader.get(), status, newfiles);
521 if (!status.cancel) {
525 now = localtime (&xnow);
526 status.freeze = true;
528 /* flush the final length(s) to the header(s) */
530 for (Sources::iterator x = all_new_sources.begin(); x != all_new_sources.end(); ) {
531 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*x)) != 0) {
532 afs->update_header((*x)->natural_position(), *now, xnow);
533 afs->done_with_peakfile_writes ();
535 /* now that there is data there, requeue the file for analysis */
537 if (Config->get_auto_analyse_audio()) {
538 Analyser::queue_source_for_analysis (boost::static_pointer_cast<Source>(*x), false);
542 /* don't create tracks for empty MIDI sources (channels) */
544 if ((smfs = boost::dynamic_pointer_cast<SMFSource>(*x)) != 0 && smfs->is_empty()) {
545 x = all_new_sources.erase(x);
551 /* save state so that we don't lose these new Sources */
555 std::copy (all_new_sources.begin(), all_new_sources.end(), std::back_inserter(status.sources));
557 // this can throw...but it seems very unlikely
558 std::for_each (all_new_sources.begin(), all_new_sources.end(), remove_file_source);