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"),
254 Glib::path_get_basename (path),
255 file_samplerate/1000.0f,
256 session_samplerate/1000.0f);
259 return string_compose (_("Copying %1"), Glib::path_get_basename (path));
263 write_audio_data_to_new_files (ImportableSource* source, ImportStatus& status,
264 vector<boost::shared_ptr<Source> >& newfiles)
266 const nframes_t nframes = ResampledImportableSource::blocksize;
267 boost::shared_ptr<AudioFileSource> afs;
268 uint channels = source->channels();
270 boost::scoped_array<float> data(new float[nframes * channels]);
271 vector<boost::shared_array<Sample> > channel_data;
273 for (uint n = 0; n < channels; ++n) {
274 channel_data.push_back(boost::shared_array<Sample>(new Sample[nframes]));
279 boost::shared_ptr<AudioSource> s = boost::dynamic_pointer_cast<AudioSource> (newfiles[0]);
282 status.progress = 0.0f;
283 float progress_multiplier = 1;
284 float progress_base = 0;
286 if (!source->clamped_at_unity() && s->clamped_at_unity()) {
288 /* The source we are importing from can return sample values with a magnitude greater than 1,
289 and the file we are writing the imported data to cannot handle such values. Compute the gain
290 factor required to normalize the input sources to have a magnitude of less than 1.
296 while (!status.cancel) {
297 nframes_t const nread = source->read (data.get(), nframes);
302 peak = compute_peak (data.get(), nread, peak);
305 status.progress = 0.5 * read_count / (source->ratio() * source->length() * channels);
309 /* we are out of range: compute a gain to fix it */
310 gain = (1 - FLT_EPSILON) / peak;
314 progress_multiplier = 0.5;
320 while (!status.cancel) {
322 nframes_t nread, nfread;
326 if ((nread = source->read (data.get(), nframes)) == 0) {
331 /* here is the gain fix for out-of-range sample values that we computed earlier */
332 apply_gain_to_buffer (data.get(), nread, gain);
335 nfread = nread / channels;
339 for (chn = 0; chn < channels; ++chn) {
342 for (x = chn, n = 0; n < nfread; x += channels, ++n) {
343 channel_data[chn][n] = (Sample) data[x];
349 for (chn = 0; chn < channels; ++chn) {
350 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(newfiles[chn])) != 0) {
351 afs->write (channel_data[chn].get(), nfread);
356 status.progress = progress_base + progress_multiplier * read_count / (source->ratio () * source->length() * channels);
361 write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
362 vector<boost::shared_ptr<Source> >& newfiles)
364 uint32_t buf_size = 4;
365 uint8_t* buf = (uint8_t*)malloc(buf_size);
367 status.progress = 0.0f;
371 for (unsigned i = 1; i <= source->num_tracks(); ++i) {
372 boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource>(newfiles[i-1]);
375 source->seek_to_track(i);
378 uint32_t delta_t = 0;
382 while (!status.cancel) {
385 int ret = source->read_event(&delta_t, &size, &buf);
389 if (ret < 0) { // EOT
395 if (ret == 0) { // Meta
400 smfs->mark_streaming_write_started ();
404 smfs->append_event_unlocked_beats(Evoral::Event<double>(0,
405 (double)t / (double)source->ppqn(),
409 if (status.progress < 0.99)
410 status.progress += 0.01;
413 const nframes64_t pos = 0;
414 const double length_beats = ceil(t / (double)source->ppqn());
415 BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
416 smfs->update_length(pos, converter.to(length_beats));
417 smfs->mark_streaming_write_completed ();
425 error << "Corrupt MIDI file " << source->file_path() << endl;
430 remove_file_source (boost::shared_ptr<Source> source)
432 ::unlink (source->path().c_str());
435 // This function is still unable to cleanly update an existing source, even though
436 // it is possible to set the ImportStatus flag accordingly. The functinality
437 // is disabled at the GUI until the Source implementations are able to provide
438 // the necessary API.
440 Session::import_audiofiles (ImportStatus& status)
442 typedef vector<boost::shared_ptr<Source> > Sources;
443 Sources all_new_sources;
444 boost::shared_ptr<AudioFileSource> afs;
445 boost::shared_ptr<SMFSource> smfs;
448 status.sources.clear ();
450 for (vector<Glib::ustring>::iterator p = status.paths.begin();
451 p != status.paths.end() && !status.cancel;
454 boost::shared_ptr<ImportableSource> source;
455 std::auto_ptr<Evoral::SMF> smf_reader;
456 const DataType type = ((*p).rfind(".mid") != string::npos) ?
457 DataType::MIDI : DataType::AUDIO;
459 if (type == DataType::AUDIO) {
461 source = open_importable_source (*p, frame_rate(), status.quality);
462 channels = source->channels();
463 } catch (const failed_constructor& err) {
464 error << string_compose(_("Import: cannot open input sound file \"%1\""), (*p)) << endmsg;
465 status.done = status.cancel = true;
471 smf_reader = std::auto_ptr<Evoral::SMF>(new Evoral::SMF());
472 smf_reader->open(*p);
473 channels = smf_reader->num_tracks();
475 error << _("Import: error opening MIDI file") << endmsg;
476 status.done = status.cancel = true;
481 vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source, *p,
482 get_best_session_directory_for_new_source (),
485 framepos_t natural_position = source ? source->natural_position() : 0;
487 if (status.replace_existing_source) {
488 fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endmsg;
489 status.cancel = !map_existing_mono_sources (new_paths, *this, frame_rate(), newfiles, this);
491 status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles, natural_position);
494 // copy on cancel/failure so that any files that were created will be removed below
495 std::copy (newfiles.begin(), newfiles.end(), std::back_inserter(all_new_sources));
501 for (Sources::iterator i = newfiles.begin(); i != newfiles.end(); ++i) {
502 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*i)) != 0) {
503 afs->prepare_for_peakfile_writes ();
507 if (source) { // audio
508 status.doing_what = compose_status_message (*p, source->samplerate(),
509 frame_rate(), status.current, status.total);
510 write_audio_data_to_new_files (source.get(), status, newfiles);
511 } else if (smf_reader.get()) { // midi
512 status.doing_what = string_compose(_("Loading MIDI file %1"), *p);
513 write_midi_data_to_new_files (smf_reader.get(), status, newfiles);
520 if (!status.cancel) {
524 now = localtime (&xnow);
525 status.freeze = true;
527 /* flush the final length(s) to the header(s) */
529 for (Sources::iterator x = all_new_sources.begin(); x != all_new_sources.end(); ) {
530 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*x)) != 0) {
531 afs->update_header((*x)->natural_position(), *now, xnow);
532 afs->done_with_peakfile_writes ();
534 /* now that there is data there, requeue the file for analysis */
536 if (Config->get_auto_analyse_audio()) {
537 Analyser::queue_source_for_analysis (boost::static_pointer_cast<Source>(*x), false);
541 /* don't create tracks for empty MIDI sources (channels) */
543 if ((smfs = boost::dynamic_pointer_cast<SMFSource>(*x)) != 0 && smfs->is_empty()) {
544 x = all_new_sources.erase(x);
550 /* save state so that we don't lose these new Sources */
554 std::copy (all_new_sources.begin(), all_new_sources.end(), std::back_inserter(status.sources));
556 // this can throw...but it seems very unlikely
557 std::for_each (all_new_sources.begin(), all_new_sources.end(), remove_file_source);