initial volley of work for AudioPlaylistSource, the basic prototype for sources-that...
[ardour2.git] / libs / ardour / import.cc
blobdd1eefe4ef5d9bf55c68a160b6e5c697d4475758
1 /*
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.
20 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
24 #include <cstdio>
25 #include <cstdlib>
26 #include <string>
27 #include <climits>
28 #include <cerrno>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <time.h>
32 #include <stdint.h>
34 #include <sndfile.h>
35 #include <samplerate.h>
37 #include <glibmm.h>
39 #include <boost/scoped_array.hpp>
40 #include <boost/shared_array.hpp>
42 #include "pbd/basename.h"
43 #include "pbd/convert.h"
45 #include "evoral/SMF.hpp"
47 #include "ardour/analyser.h"
48 #include "ardour/ardour.h"
49 #include "ardour/audio_diskstream.h"
50 #include "ardour/audioengine.h"
51 #include "ardour/audioregion.h"
52 #include "ardour/import_status.h"
53 #include "ardour/region_factory.h"
54 #include "ardour/resampled_source.h"
55 #include "ardour/session.h"
56 #include "ardour/session_directory.h"
57 #include "ardour/smf_source.h"
58 #include "ardour/sndfile_helpers.h"
59 #include "ardour/sndfileimportable.h"
60 #include "ardour/sndfilesource.h"
61 #include "ardour/source_factory.h"
62 #include "ardour/tempo.h"
64 #ifdef HAVE_COREAUDIO
65 #include "ardour/caimportable.h"
66 #endif
68 #include "i18n.h"
70 using namespace std;
71 using namespace ARDOUR;
72 using namespace PBD;
74 static boost::shared_ptr<ImportableSource>
75 open_importable_source (const string& path, framecnt_t samplerate, ARDOUR::SrcQuality quality)
77 /* try libsndfile first, because it can get BWF info from .wav, which ExtAudioFile cannot.
78 We don't necessarily need that information in an ImportableSource, but it keeps the
79 logic the same as in SourceFactory::create()
82 try {
83 boost::shared_ptr<SndFileImportableSource> source(new SndFileImportableSource(path));
85 if (source->samplerate() == samplerate) {
86 return source;
89 /* rewrap as a resampled source */
91 return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
94 catch (...) {
96 #ifdef HAVE_COREAUDIO
98 /* libsndfile failed, see if we can use CoreAudio to handle the IO */
100 CAImportableSource* src = new CAImportableSource(path);
101 boost::shared_ptr<CAImportableSource> source (src);
103 if (source->samplerate() == samplerate) {
104 return source;
107 /* rewrap as a resampled source */
109 return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
111 #else
112 throw; // rethrow
113 #endif
118 static std::string
119 get_non_existent_filename (HeaderFormat hf, DataType type, const bool allow_replacing, const std::string& destdir, const std::string& basename, uint channel, uint channels)
121 char buf[PATH_MAX+1];
122 bool goodfile = false;
123 string base = basename;
124 string ext = native_header_format_extension (hf, type);
125 uint32_t cnt = 1;
127 do {
129 if (type == DataType::AUDIO && channels == 2) {
130 if (channel == 0) {
131 if (cnt == 1) {
132 snprintf (buf, sizeof(buf), "%s-L%s", base.c_str(), ext.c_str());
133 } else {
134 snprintf (buf, sizeof(buf), "%s-%d-L%s", base.c_str(), cnt, ext.c_str());
136 } else {
137 if (cnt == 1) {
138 snprintf (buf, sizeof(buf), "%s-R%s", base.c_str(), ext.c_str());
139 } else {
140 snprintf (buf, sizeof(buf), "%s-%d-R%s", base.c_str(), cnt, ext.c_str());
143 } else if (channels > 1) {
144 if (cnt == 1) {
145 snprintf (buf, sizeof(buf), "%s-c%d%s", base.c_str(), channel, ext.c_str());
146 } else {
147 snprintf (buf, sizeof(buf), "%s-%d-c%d%s", base.c_str(), cnt, channel, ext.c_str());
149 } else {
150 if (cnt == 1) {
151 snprintf (buf, sizeof(buf), "%s%s", base.c_str(), ext.c_str());
152 } else {
153 snprintf (buf, sizeof(buf), "%s-%d%s", base.c_str(), cnt, ext.c_str());
157 string tempname = destdir + "/" + buf;
159 if (!allow_replacing && Glib::file_test (tempname, Glib::FILE_TEST_EXISTS)) {
161 cnt++;
163 } else {
165 goodfile = true;
168 } while (!goodfile);
170 return buf;
173 static vector<string>
174 get_paths_for_new_sources (HeaderFormat hf, const bool allow_replacing, const string& import_file_path, const string& session_dir, uint channels)
176 vector<string> new_paths;
177 const string basename = basename_nosuffix (import_file_path);
179 SessionDirectory sdir(session_dir);
181 for (uint n = 0; n < channels; ++n) {
183 const DataType type = SMFSource::safe_midi_file_extension (import_file_path) ? DataType::MIDI : DataType::AUDIO;
185 std::string filepath = (type == DataType::MIDI)
186 ? sdir.midi_path().to_string() : sdir.sound_path().to_string();
188 filepath = Glib::build_filename (filepath,
189 get_non_existent_filename (hf, type, allow_replacing, filepath, basename, n, channels));
190 new_paths.push_back (filepath);
193 return new_paths;
196 static bool
197 map_existing_mono_sources (const vector<string>& new_paths, Session& /*sess*/,
198 uint /*samplerate*/, vector<boost::shared_ptr<Source> >& newfiles, Session *session)
200 for (vector<string>::const_iterator i = new_paths.begin();
201 i != new_paths.end(); ++i)
203 boost::shared_ptr<Source> source = session->source_by_path_and_channel(*i, 0);
205 if (source == 0) {
206 error << string_compose(_("Could not find a source for %1 even though we are updating this file!"), (*i)) << endl;
207 return false;
210 newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
212 return true;
215 static bool
216 create_mono_sources_for_writing (const string& origin,
217 const vector<string>& new_paths,
218 Session& sess, uint samplerate,
219 vector<boost::shared_ptr<Source> >& newfiles,
220 framepos_t timeline_position)
222 for (vector<string>::const_iterator i = new_paths.begin(); i != new_paths.end(); ++i) {
224 boost::shared_ptr<Source> source;
226 try {
227 const DataType type = SMFSource::safe_midi_file_extension (*i) ? DataType::MIDI : DataType::AUDIO;
229 source = SourceFactory::createWritable (type, sess,
230 i->c_str(),
231 origin,
232 false, // destructive
233 samplerate);
236 catch (const failed_constructor& err) {
237 error << string_compose (_("Unable to create file %1 during import"), *i) << endmsg;
238 return false;
241 newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
243 /* for audio files, reset the timeline position so that any BWF-ish
244 information in the original files we are importing from is maintained.
247 boost::shared_ptr<AudioFileSource> afs;
248 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
249 afs->set_timeline_position(timeline_position);
252 return true;
255 static string
256 compose_status_message (const string& path,
257 uint file_samplerate,
258 uint session_samplerate,
259 uint /* current_file */,
260 uint /* total_files */)
262 if (file_samplerate != session_samplerate) {
263 return string_compose (_("Resampling %1 from %2kHz to %3kHz"),
264 Glib::path_get_basename (path),
265 file_samplerate/1000.0f,
266 session_samplerate/1000.0f);
269 return string_compose (_("Copying %1"), Glib::path_get_basename (path));
272 static void
273 write_audio_data_to_new_files (ImportableSource* source, ImportStatus& status,
274 vector<boost::shared_ptr<Source> >& newfiles)
276 const framecnt_t nframes = ResampledImportableSource::blocksize;
277 boost::shared_ptr<AudioFileSource> afs;
278 uint channels = source->channels();
280 boost::scoped_array<float> data(new float[nframes * channels]);
281 vector<boost::shared_array<Sample> > channel_data;
283 for (uint n = 0; n < channels; ++n) {
284 channel_data.push_back(boost::shared_array<Sample>(new Sample[nframes]));
287 float gain = 1;
289 boost::shared_ptr<AudioSource> s = boost::dynamic_pointer_cast<AudioSource> (newfiles[0]);
290 assert (s);
292 status.progress = 0.0f;
293 float progress_multiplier = 1;
294 float progress_base = 0;
296 if (!source->clamped_at_unity() && s->clamped_at_unity()) {
298 /* The source we are importing from can return sample values with a magnitude greater than 1,
299 and the file we are writing the imported data to cannot handle such values. Compute the gain
300 factor required to normalize the input sources to have a magnitude of less than 1.
303 float peak = 0;
304 uint read_count = 0;
306 while (!status.cancel) {
307 framecnt_t const nread = source->read (data.get(), nframes);
308 if (nread == 0) {
309 break;
312 peak = compute_peak (data.get(), nread, peak);
314 read_count += nread;
315 status.progress = 0.5 * read_count / (source->ratio() * source->length() * channels);
318 if (peak >= 1) {
319 /* we are out of range: compute a gain to fix it */
320 gain = (1 - FLT_EPSILON) / peak;
323 source->seek (0);
324 progress_multiplier = 0.5;
325 progress_base = 0.5;
328 uint read_count = 0;
330 while (!status.cancel) {
332 framecnt_t nread, nfread;
333 uint x;
334 uint chn;
336 if ((nread = source->read (data.get(), nframes)) == 0) {
337 break;
340 if (gain != 1) {
341 /* here is the gain fix for out-of-range sample values that we computed earlier */
342 apply_gain_to_buffer (data.get(), nread, gain);
345 nfread = nread / channels;
347 /* de-interleave */
349 for (chn = 0; chn < channels; ++chn) {
351 framecnt_t n;
352 for (x = chn, n = 0; n < nfread; x += channels, ++n) {
353 channel_data[chn][n] = (Sample) data[x];
357 /* flush to disk */
359 for (chn = 0; chn < channels; ++chn) {
360 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(newfiles[chn])) != 0) {
361 afs->write (channel_data[chn].get(), nfread);
365 read_count += nread;
366 status.progress = progress_base + progress_multiplier * read_count / (source->ratio () * source->length() * channels);
370 static void
371 write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
372 vector<boost::shared_ptr<Source> >& newfiles)
374 uint32_t buf_size = 4;
375 uint8_t* buf = (uint8_t*) malloc (buf_size);
377 status.progress = 0.0f;
379 assert (newfiles.size() == source->num_tracks());
381 try {
382 vector<boost::shared_ptr<Source> >::iterator s = newfiles.begin();
384 for (unsigned i = 1; i <= source->num_tracks(); ++i) {
386 boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource> (*s);
388 smfs->drop_model ();
389 source->seek_to_track (i);
391 uint64_t t = 0;
392 uint32_t delta_t = 0;
393 uint32_t size = 0;
394 bool first = true;
396 while (!status.cancel) {
397 gint note_id_ignored; // imported files either don't have NoteID's or we ignore them.
399 size = buf_size;
401 int ret = source->read_event (&delta_t, &size, &buf, &note_id_ignored);
403 if (size > buf_size) {
404 buf_size = size;
407 if (ret < 0) { // EOT
408 break;
411 t += delta_t;
413 if (ret == 0) { // Meta
414 continue;
417 if (first) {
418 smfs->mark_streaming_write_started ();
419 first = false;
422 smfs->append_event_unlocked_beats(Evoral::Event<double>(0,
423 (double)t / (double)source->ppqn(),
424 size,
425 buf));
427 if (status.progress < 0.99) {
428 status.progress += 0.01;
432 if (!first) {
434 /* we wrote something */
436 const framepos_t pos = 0;
437 const double length_beats = ceil(t / (double)source->ppqn());
438 BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
439 smfs->update_length(pos, converter.to(length_beats));
440 smfs->mark_streaming_write_completed ();
442 if (status.cancel) {
443 break;
445 } else {
446 warning << string_compose (_("Track %1 of %2 contained no usable MIDI data"), i, source->file_path()) << endmsg;
449 ++s; // next source
452 } catch (...) {
453 error << string_compose (_("MIDI file %1 was not readable (no reason available"), source->file_path()) << endmsg;
456 if (buf) {
457 free (buf);
461 static void
462 remove_file_source (boost::shared_ptr<Source> source)
464 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (source);
466 if (fs) {
467 ::unlink (fs->path().c_str());
471 // This function is still unable to cleanly update an existing source, even though
472 // it is possible to set the ImportStatus flag accordingly. The functinality
473 // is disabled at the GUI until the Source implementations are able to provide
474 // the necessary API.
475 void
476 Session::import_audiofiles (ImportStatus& status)
478 typedef vector<boost::shared_ptr<Source> > Sources;
479 Sources all_new_sources;
480 boost::shared_ptr<AudioFileSource> afs;
481 boost::shared_ptr<SMFSource> smfs;
482 uint channels = 0;
484 status.sources.clear ();
486 for (vector<string>::iterator p = status.paths.begin();
487 p != status.paths.end() && !status.cancel;
488 ++p)
490 boost::shared_ptr<ImportableSource> source;
491 std::auto_ptr<Evoral::SMF> smf_reader;
492 const DataType type = SMFSource::safe_midi_file_extension (*p) ? DataType::MIDI : DataType::AUDIO;
494 if (type == DataType::AUDIO) {
495 try {
496 source = open_importable_source (*p, frame_rate(), status.quality);
497 channels = source->channels();
498 } catch (const failed_constructor& err) {
499 error << string_compose(_("Import: cannot open input sound file \"%1\""), (*p)) << endmsg;
500 status.done = status.cancel = true;
501 return;
504 } else {
505 try {
506 smf_reader = std::auto_ptr<Evoral::SMF>(new Evoral::SMF());
507 smf_reader->open(*p);
508 channels = smf_reader->num_tracks();
509 } catch (...) {
510 error << _("Import: error opening MIDI file") << endmsg;
511 status.done = status.cancel = true;
512 return;
516 vector<string> new_paths = get_paths_for_new_sources (config.get_native_file_header_format(),
517 status.replace_existing_source, *p,
518 get_best_session_directory_for_new_source (),
519 channels);
520 Sources newfiles;
521 framepos_t natural_position = source ? source->natural_position() : 0;
524 if (status.replace_existing_source) {
525 fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endmsg;
526 status.cancel = !map_existing_mono_sources (new_paths, *this, frame_rate(), newfiles, this);
527 } else {
528 status.cancel = !create_mono_sources_for_writing (*p, new_paths, *this, frame_rate(), newfiles, natural_position);
531 // copy on cancel/failure so that any files that were created will be removed below
532 std::copy (newfiles.begin(), newfiles.end(), std::back_inserter(all_new_sources));
534 if (status.cancel) {
535 break;
538 for (Sources::iterator i = newfiles.begin(); i != newfiles.end(); ++i) {
539 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*i)) != 0) {
540 afs->prepare_for_peakfile_writes ();
544 if (source) { // audio
545 status.doing_what = compose_status_message (*p, source->samplerate(),
546 frame_rate(), status.current, status.total);
547 write_audio_data_to_new_files (source.get(), status, newfiles);
548 } else if (smf_reader.get()) { // midi
549 status.doing_what = string_compose(_("Loading MIDI file %1"), *p);
550 write_midi_data_to_new_files (smf_reader.get(), status, newfiles);
553 ++status.current;
554 status.progress = 0;
557 if (!status.cancel) {
558 struct tm* now;
559 time_t xnow;
560 time (&xnow);
561 now = localtime (&xnow);
562 status.freeze = true;
564 /* flush the final length(s) to the header(s) */
566 for (Sources::iterator x = all_new_sources.begin(); x != all_new_sources.end(); ) {
567 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*x)) != 0) {
568 afs->update_header((*x)->natural_position(), *now, xnow);
569 afs->done_with_peakfile_writes ();
571 /* now that there is data there, requeue the file for analysis */
573 if (Config->get_auto_analyse_audio()) {
574 Analyser::queue_source_for_analysis (boost::static_pointer_cast<Source>(*x), false);
578 /* don't create tracks for empty MIDI sources (channels) */
580 if ((smfs = boost::dynamic_pointer_cast<SMFSource>(*x)) != 0 && smfs->is_empty()) {
581 x = all_new_sources.erase(x);
582 } else {
583 ++x;
587 /* save state so that we don't lose these new Sources */
589 save_state (_name);
591 std::copy (all_new_sources.begin(), all_new_sources.end(), std::back_inserter(status.sources));
592 } else {
593 // this can throw...but it seems very unlikely
594 std::for_each (all_new_sources.begin(), all_new_sources.end(), remove_file_source);
597 status.done = true;