second (and hopefully) final part of changes to respond to header format changes...
[ArdourMidi.git] / libs / ardour / import.cc
blob156186dbe4251a57dfcbdb05832e529978fbbc67
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.
21 #ifdef WAF_BUILD
22 #include "libardour-config.h"
23 #endif
25 #include <cstdio>
26 #include <cstdlib>
27 #include <string>
28 #include <climits>
29 #include <cerrno>
30 #include <unistd.h>
31 #include <sys/stat.h>
32 #include <time.h>
33 #include <stdint.h>
35 #include <sndfile.h>
36 #include <samplerate.h>
38 #include <glibmm.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"
65 #ifdef HAVE_COREAUDIO
66 #include "ardour/caimportable.h"
67 #endif
69 #include "i18n.h"
71 using namespace std;
72 using namespace ARDOUR;
73 using namespace PBD;
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()
83 try {
84 boost::shared_ptr<SndFileImportableSource> source(new SndFileImportableSource(path));
86 if (source->samplerate() == samplerate) {
87 return source;
90 /* rewrap as a resampled source */
92 return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
95 catch (...) {
97 #ifdef HAVE_COREAUDIO
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) {
105 return source;
108 /* rewrap as a resampled source */
110 return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
112 #else
113 throw; // rethrow
114 #endif
119 static std::string
120 get_non_existent_filename (HeaderFormat hf, 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 string ext = native_header_format_extension (hf, type);
127 do {
129 if (type == DataType::AUDIO && channels == 2) {
130 if (channel == 0) {
131 snprintf (buf, sizeof(buf), "%s-L%s", base.c_str(), ext.c_str());
132 } else {
133 snprintf (buf, sizeof(buf), "%s-R%s", base.c_str(), ext.c_str());
135 } else if (channels > 1) {
136 snprintf (buf, sizeof(buf), "%s-c%d%s", base.c_str(), channel, ext.c_str());
137 } else {
138 snprintf (buf, sizeof(buf), "%s%s", base.c_str(), ext.c_str());
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
147 * _ to basename
150 base += "_";
152 } else {
154 goodfile = true;
157 } while ( !goodfile);
159 return buf;
162 static vector<string>
163 get_paths_for_new_sources (HeaderFormat hf, 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 = SMFSource::safe_midi_file_extension (import_file_path) ? DataType::MIDI : DataType::AUDIO;
174 std::string filepath = (type == DataType::MIDI)
175 ? sdir.midi_path().to_string() : sdir.sound_path().to_string();
177 filepath += '/';
178 filepath += get_non_existent_filename (hf, type, allow_replacing, filepath, basename, n, channels);
179 new_paths.push_back (filepath);
182 return new_paths;
185 static bool
186 map_existing_mono_sources (const vector<string>& new_paths, Session& /*sess*/,
187 uint /*samplerate*/, vector<boost::shared_ptr<Source> >& newfiles, Session *session)
189 for (vector<string>::const_iterator i = new_paths.begin();
190 i != new_paths.end(); ++i)
192 boost::shared_ptr<Source> source = session->source_by_path_and_channel(*i, 0);
194 if (source == 0) {
195 error << string_compose(_("Could not find a source for %1 even though we are updating this file!"), (*i)) << endl;
196 return false;
199 newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
201 return true;
204 static bool
205 create_mono_sources_for_writing (const vector<string>& new_paths, Session& sess,
206 uint samplerate, vector<boost::shared_ptr<Source> >& newfiles,
207 framepos_t timeline_position)
209 for (vector<string>::const_iterator i = new_paths.begin(); i != new_paths.end(); ++i)
211 boost::shared_ptr<Source> source;
215 const DataType type = SMFSource::safe_midi_file_extension (*i) ? DataType::MIDI : DataType::AUDIO;
218 source = SourceFactory::createWritable (type, sess,
219 i->c_str(),
220 false, // destructive
221 samplerate);
223 catch (const failed_constructor& err)
225 error << string_compose (_("Unable to create file %1 during import"), *i) << endmsg;
226 return false;
229 newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
231 /* for audio files, reset the timeline position so that any BWF-ish
232 information in the original files we are importing from is maintained.
235 boost::shared_ptr<AudioFileSource> afs;
236 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
237 afs->set_timeline_position(timeline_position);
240 return true;
243 static Glib::ustring
244 compose_status_message (const string& path,
245 uint file_samplerate,
246 uint session_samplerate,
247 uint current_file,
248 uint total_files)
250 if (file_samplerate != session_samplerate) {
251 return string_compose (_("Resampling %1 from %2kHz to %3kHz"),
252 Glib::path_get_basename (path),
253 file_samplerate/1000.0f,
254 session_samplerate/1000.0f);
257 return string_compose (_("Copying %1"), Glib::path_get_basename (path));
260 static void
261 write_audio_data_to_new_files (ImportableSource* source, ImportStatus& status,
262 vector<boost::shared_ptr<Source> >& newfiles)
264 const nframes_t nframes = ResampledImportableSource::blocksize;
265 boost::shared_ptr<AudioFileSource> afs;
266 uint channels = source->channels();
268 boost::scoped_array<float> data(new float[nframes * channels]);
269 vector<boost::shared_array<Sample> > channel_data;
271 for (uint n = 0; n < channels; ++n) {
272 channel_data.push_back(boost::shared_array<Sample>(new Sample[nframes]));
275 float gain = 1;
277 boost::shared_ptr<AudioSource> s = boost::dynamic_pointer_cast<AudioSource> (newfiles[0]);
278 assert (s);
280 status.progress = 0.0f;
281 float progress_multiplier = 1;
282 float progress_base = 0;
284 if (!source->clamped_at_unity() && s->clamped_at_unity()) {
286 /* The source we are importing from can return sample values with a magnitude greater than 1,
287 and the file we are writing the imported data to cannot handle such values. Compute the gain
288 factor required to normalize the input sources to have a magnitude of less than 1.
291 float peak = 0;
292 uint read_count = 0;
294 while (!status.cancel) {
295 nframes_t const nread = source->read (data.get(), nframes);
296 if (nread == 0) {
297 break;
300 peak = compute_peak (data.get(), nread, peak);
302 read_count += nread;
303 status.progress = 0.5 * read_count / (source->ratio() * source->length() * channels);
306 if (peak >= 1) {
307 /* we are out of range: compute a gain to fix it */
308 gain = (1 - FLT_EPSILON) / peak;
311 source->seek (0);
312 progress_multiplier = 0.5;
313 progress_base = 0.5;
316 uint read_count = 0;
318 while (!status.cancel) {
320 nframes_t nread, nfread;
321 uint x;
322 uint chn;
324 if ((nread = source->read (data.get(), nframes)) == 0) {
325 break;
328 if (gain != 1) {
329 /* here is the gain fix for out-of-range sample values that we computed earlier */
330 apply_gain_to_buffer (data.get(), nread, gain);
333 nfread = nread / channels;
335 /* de-interleave */
337 for (chn = 0; chn < channels; ++chn) {
339 nframes_t n;
340 for (x = chn, n = 0; n < nfread; x += channels, ++n) {
341 channel_data[chn][n] = (Sample) data[x];
345 /* flush to disk */
347 for (chn = 0; chn < channels; ++chn) {
348 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(newfiles[chn])) != 0) {
349 afs->write (channel_data[chn].get(), nfread);
353 read_count += nread;
354 status.progress = progress_base + progress_multiplier * read_count / (source->ratio () * source->length() * channels);
358 static void
359 write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
360 vector<boost::shared_ptr<Source> >& newfiles)
362 uint32_t buf_size = 4;
363 uint8_t* buf = (uint8_t*)malloc(buf_size);
365 status.progress = 0.0f;
367 try {
369 for (unsigned i = 1; i <= source->num_tracks(); ++i) {
370 boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource>(newfiles[i-1]);
371 smfs->drop_model();
373 source->seek_to_track(i);
375 uint64_t t = 0;
376 uint32_t delta_t = 0;
377 uint32_t size = 0;
378 bool first = true;
380 while (!status.cancel) {
381 gint ignored; // imported files either don't have NoteID's or
382 // we ignore them.
384 size = buf_size;
386 int ret = source->read_event(&delta_t, &size, &buf, &ignored);
387 if (size > buf_size)
388 buf_size = size;
390 if (ret < 0) { // EOT
391 break;
394 t += delta_t;
396 if (ret == 0) { // Meta
397 continue;
400 if (first) {
401 smfs->mark_streaming_write_started ();
402 first = false;
405 smfs->append_event_unlocked_beats(Evoral::Event<double>(0,
406 (double)t / (double)source->ppqn(),
407 size,
408 buf));
410 if (status.progress < 0.99)
411 status.progress += 0.01;
414 const nframes64_t pos = 0;
415 const double length_beats = ceil(t / (double)source->ppqn());
416 BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
417 smfs->update_length(pos, converter.to(length_beats));
418 smfs->mark_streaming_write_completed ();
420 if (status.cancel) {
421 break;
425 } catch (...) {
426 error << "Corrupt MIDI file " << source->file_path() << endl;
430 static void
431 remove_file_source (boost::shared_ptr<Source> source)
433 ::unlink (source->path().c_str());
436 // This function is still unable to cleanly update an existing source, even though
437 // it is possible to set the ImportStatus flag accordingly. The functinality
438 // is disabled at the GUI until the Source implementations are able to provide
439 // the necessary API.
440 void
441 Session::import_audiofiles (ImportStatus& status)
443 typedef vector<boost::shared_ptr<Source> > Sources;
444 Sources all_new_sources;
445 boost::shared_ptr<AudioFileSource> afs;
446 boost::shared_ptr<SMFSource> smfs;
447 uint channels = 0;
449 status.sources.clear ();
451 for (vector<Glib::ustring>::iterator p = status.paths.begin();
452 p != status.paths.end() && !status.cancel;
453 ++p)
455 boost::shared_ptr<ImportableSource> source;
456 std::auto_ptr<Evoral::SMF> smf_reader;
457 const DataType type = SMFSource::safe_midi_file_extension (*p) ? DataType::MIDI : DataType::AUDIO;
459 if (type == DataType::AUDIO) {
460 try {
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;
466 return;
469 } else {
470 try {
471 smf_reader = std::auto_ptr<Evoral::SMF>(new Evoral::SMF());
472 smf_reader->open(*p);
473 channels = smf_reader->num_tracks();
474 } catch (...) {
475 error << _("Import: error opening MIDI file") << endmsg;
476 status.done = status.cancel = true;
477 return;
481 vector<string> new_paths = get_paths_for_new_sources (config.get_native_file_header_format(),
482 status.replace_existing_source, *p,
483 get_best_session_directory_for_new_source (),
484 channels);
485 Sources newfiles;
486 framepos_t natural_position = source ? source->natural_position() : 0;
488 if (status.replace_existing_source) {
489 fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endmsg;
490 status.cancel = !map_existing_mono_sources (new_paths, *this, frame_rate(), newfiles, this);
491 } else {
492 status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles, natural_position);
495 // copy on cancel/failure so that any files that were created will be removed below
496 std::copy (newfiles.begin(), newfiles.end(), std::back_inserter(all_new_sources));
498 if (status.cancel) {
499 break;
502 for (Sources::iterator i = newfiles.begin(); i != newfiles.end(); ++i) {
503 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*i)) != 0) {
504 afs->prepare_for_peakfile_writes ();
508 if (source) { // audio
509 status.doing_what = compose_status_message (*p, source->samplerate(),
510 frame_rate(), status.current, status.total);
511 write_audio_data_to_new_files (source.get(), status, newfiles);
512 } else if (smf_reader.get()) { // midi
513 status.doing_what = string_compose(_("Loading MIDI file %1"), *p);
514 write_midi_data_to_new_files (smf_reader.get(), status, newfiles);
517 ++status.current;
518 status.progress = 0;
521 if (!status.cancel) {
522 struct tm* now;
523 time_t xnow;
524 time (&xnow);
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);
546 } else {
547 ++x;
551 /* save state so that we don't lose these new Sources */
553 save_state (_name);
555 std::copy (all_new_sources.begin(), all_new_sources.end(), std::back_inserter(status.sources));
556 } else {
557 // this can throw...but it seems very unlikely
558 std::for_each (all_new_sources.begin(), all_new_sources.end(), remove_file_source);
561 status.done = true;