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 #include "libardour-config.h"
35 #include <samplerate.h>
37 #include "pbd/gstdio_compat.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/runtime_functions.h"
57 #include "ardour/session.h"
58 #include "ardour/session_directory.h"
59 #include "ardour/smf_source.h"
60 #include "ardour/sndfile_helpers.h"
61 #include "ardour/sndfileimportable.h"
62 #include "ardour/sndfilesource.h"
63 #include "ardour/source_factory.h"
64 #include "ardour/tempo.h"
67 #include "ardour/caimportable.h"
73 using namespace ARDOUR;
76 static boost::shared_ptr<ImportableSource>
77 open_importable_source (const string& path, framecnt_t samplerate, ARDOUR::SrcQuality quality)
79 /* try libsndfile first, because it can get BWF info from .wav, which ExtAudioFile cannot.
80 We don't necessarily need that information in an ImportableSource, but it keeps the
81 logic the same as in SourceFactory::create()
85 boost::shared_ptr<SndFileImportableSource> source(new SndFileImportableSource(path));
87 if (source->samplerate() == samplerate) {
91 /* rewrap as a resampled source */
93 return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
100 /* libsndfile failed, see if we can use CoreAudio to handle the IO */
102 CAImportableSource* src = new CAImportableSource(path);
103 boost::shared_ptr<CAImportableSource> source (src);
105 if (source->samplerate() == samplerate) {
109 /* rewrap as a resampled source */
111 return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
121 Session::get_paths_for_new_sources (bool /*allow_replacing*/, const string& import_file_path, uint32_t channels)
123 vector<string> new_paths;
124 const string basename = basename_nosuffix (import_file_path);
126 for (uint32_t n = 0; n < channels; ++n) {
128 const DataType type = SMFSource::safe_midi_file_extension (import_file_path) ? DataType::MIDI : DataType::AUDIO;
134 string mchn_name = string_compose ("%1-t%2", basename, n);
135 filepath = new_midi_source_path (mchn_name);
137 filepath = new_midi_source_path (basename);
140 case DataType::AUDIO:
141 filepath = new_audio_source_path (basename, channels, n, false, false);
145 if (filepath.empty()) {
146 error << string_compose (_("Cannot find new filename for imported file %1"), import_file_path) << endmsg;
147 return vector<string>();
150 new_paths.push_back (filepath);
157 map_existing_mono_sources (const vector<string>& new_paths, Session& /*sess*/,
158 uint32_t /*samplerate*/, vector<boost::shared_ptr<Source> >& newfiles, Session *session)
160 for (vector<string>::const_iterator i = new_paths.begin();
161 i != new_paths.end(); ++i)
163 boost::shared_ptr<Source> source = session->audio_source_by_path_and_channel(*i, 0);
166 error << string_compose(_("Could not find a source for %1 even though we are updating this file!"), (*i)) << endl;
170 newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
176 create_mono_sources_for_writing (const vector<string>& new_paths,
177 Session& sess, uint32_t samplerate,
178 vector<boost::shared_ptr<Source> >& newfiles,
179 framepos_t timeline_position)
181 for (vector<string>::const_iterator i = new_paths.begin(); i != new_paths.end(); ++i) {
183 boost::shared_ptr<Source> source;
186 const DataType type = SMFSource::safe_midi_file_extension (*i) ? DataType::MIDI : DataType::AUDIO;
188 source = SourceFactory::createWritable (type, sess,
190 false, // destructive
194 catch (const failed_constructor& err) {
195 error << string_compose (_("Unable to create file %1 during import"), *i) << endmsg;
199 newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
201 /* for audio files, reset the timeline position so that any BWF-ish
202 information in the original files we are importing from is maintained.
205 boost::shared_ptr<AudioFileSource> afs;
206 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
207 afs->set_timeline_position(timeline_position);
214 compose_status_message (const string& path,
215 uint32_t file_samplerate,
216 uint32_t session_samplerate,
217 uint32_t /* current_file */,
218 uint32_t /* total_files */)
220 if (file_samplerate != session_samplerate) {
221 return string_compose (_("Resampling %1 from %2kHz to %3kHz"),
222 Glib::path_get_basename (path),
223 file_samplerate/1000.0f,
224 session_samplerate/1000.0f);
227 return string_compose (_("Copying %1"), Glib::path_get_basename (path));
231 write_audio_data_to_new_files (ImportableSource* source, ImportStatus& status,
232 vector<boost::shared_ptr<Source> >& newfiles)
234 const framecnt_t nframes = ResampledImportableSource::blocksize;
235 boost::shared_ptr<AudioFileSource> afs;
236 uint32_t channels = source->channels();
241 boost::scoped_array<float> data(new float[nframes * channels]);
242 vector<boost::shared_array<Sample> > channel_data;
244 for (uint32_t n = 0; n < channels; ++n) {
245 channel_data.push_back(boost::shared_array<Sample>(new Sample[nframes]));
250 boost::shared_ptr<AudioSource> s = boost::dynamic_pointer_cast<AudioSource> (newfiles[0]);
253 status.progress = 0.0f;
254 float progress_multiplier = 1;
255 float progress_base = 0;
257 if (!source->clamped_at_unity() && s->clamped_at_unity()) {
259 /* The source we are importing from can return sample values with a magnitude greater than 1,
260 and the file we are writing the imported data to cannot handle such values. Compute the gain
261 factor required to normalize the input sources to have a magnitude of less than 1.
265 uint32_t read_count = 0;
267 while (!status.cancel) {
268 framecnt_t const nread = source->read (data.get(), nframes);
273 peak = compute_peak (data.get(), nread, peak);
276 status.progress = 0.5 * read_count / (source->ratio() * source->length() * channels);
280 /* we are out of range: compute a gain to fix it */
281 gain = (1 - FLT_EPSILON) / peak;
285 progress_multiplier = 0.5;
289 framecnt_t read_count = 0;
291 while (!status.cancel) {
293 framecnt_t nread, nfread;
297 if ((nread = source->read (data.get(), nframes)) == 0) {
298 #ifdef PLATFORM_WINDOWS
299 /* Flush the data once we've finished importing the file. Windows can */
300 /* cache the data for very long periods of time (perhaps not writing */
301 /* it to disk until Ardour closes). So let's force it to flush now. */
302 for (chn = 0; chn < channels; ++chn)
303 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(newfiles[chn])) != 0)
310 /* here is the gain fix for out-of-range sample values that we computed earlier */
311 apply_gain_to_buffer (data.get(), nread, gain);
314 nfread = nread / channels;
318 for (chn = 0; chn < channels; ++chn) {
321 for (x = chn, n = 0; n < nfread; x += channels, ++n) {
322 channel_data[chn][n] = (Sample) data[x];
328 for (chn = 0; chn < channels; ++chn) {
329 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(newfiles[chn])) != 0) {
330 afs->write (channel_data[chn].get(), nfread);
335 status.progress = progress_base + progress_multiplier * read_count / (source->ratio () * source->length() * channels);
340 write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
341 vector<boost::shared_ptr<Source> >& newfiles)
343 uint32_t buf_size = 4;
344 uint8_t* buf = (uint8_t*) malloc (buf_size);
346 status.progress = 0.0f;
348 assert (newfiles.size() == source->num_tracks());
351 vector<boost::shared_ptr<Source> >::iterator s = newfiles.begin();
353 for (unsigned i = 1; i <= source->num_tracks(); ++i) {
355 boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource> (*s);
357 Glib::Threads::Mutex::Lock source_lock(smfs->mutex());
359 smfs->drop_model (source_lock);
360 source->seek_to_track (i);
363 uint32_t delta_t = 0;
367 while (!status.cancel) {
368 gint note_id_ignored; // imported files either don't have NoteID's or we ignore them.
372 int ret = source->read_event (&delta_t, &size, &buf, ¬e_id_ignored);
374 if (size > buf_size) {
378 if (ret < 0) { // EOT
384 if (ret == 0) { // Meta
389 smfs->mark_streaming_write_started (source_lock);
393 smfs->append_event_beats(
395 Evoral::Event<Evoral::Beats>(
397 Evoral::Beats::ticks_at_rate(t, source->ppqn()),
401 if (status.progress < 0.99) {
402 status.progress += 0.01;
408 /* we wrote something */
410 const framepos_t pos = 0;
411 const Evoral::Beats length_beats = Evoral::Beats::ticks_at_rate(t, source->ppqn());
412 BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
413 smfs->update_length(pos + converter.to(length_beats.round_up_to_beat()));
414 smfs->mark_streaming_write_completed (source_lock);
420 info << string_compose (_("Track %1 of %2 contained no usable MIDI data"), i, source->num_tracks()) << endmsg;
426 } catch (exception& e) {
427 error << string_compose (_("MIDI file could not be written (best guess: %1)"), e.what()) << endmsg;
436 remove_file_source (boost::shared_ptr<Source> source)
438 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (source);
440 fs->DropReferences ();
443 ::g_unlink (fs->path().c_str());
447 // This function is still unable to cleanly update an existing source, even though
448 // it is possible to set the ImportStatus flag accordingly. The functinality
449 // is disabled at the GUI until the Source implementations are able to provide
450 // the necessary API.
452 Session::import_files (ImportStatus& status)
454 typedef vector<boost::shared_ptr<Source> > Sources;
455 Sources all_new_sources;
456 boost::shared_ptr<AudioFileSource> afs;
457 boost::shared_ptr<SMFSource> smfs;
458 uint32_t channels = 0;
460 status.sources.clear ();
462 for (vector<string>::const_iterator p = status.paths.begin();
463 p != status.paths.end() && !status.cancel;
466 boost::shared_ptr<ImportableSource> source;
467 std::auto_ptr<Evoral::SMF> smf_reader;
468 const DataType type = SMFSource::safe_midi_file_extension (*p) ? DataType::MIDI : DataType::AUDIO;
470 if (type == DataType::AUDIO) {
472 source = open_importable_source (*p, frame_rate(), status.quality);
473 channels = source->channels();
474 } catch (const failed_constructor& err) {
475 error << string_compose(_("Import: cannot open input sound file \"%1\""), (*p)) << endmsg;
476 status.done = status.cancel = true;
482 smf_reader = std::auto_ptr<Evoral::SMF>(new Evoral::SMF());
483 smf_reader->open(*p);
484 channels = smf_reader->num_tracks();
486 error << _("Import: error opening MIDI file") << endmsg;
487 status.done = status.cancel = true;
493 error << _("Import: file contains no channels.") << endmsg;
497 vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source, *p, channels);
499 framepos_t natural_position = source ? source->natural_position() : 0;
502 if (status.replace_existing_source) {
503 fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endmsg;
504 status.cancel = !map_existing_mono_sources (new_paths, *this, frame_rate(), newfiles, this);
506 status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles, natural_position);
509 // copy on cancel/failure so that any files that were created will be removed below
510 std::copy (newfiles.begin(), newfiles.end(), std::back_inserter(all_new_sources));
516 for (Sources::iterator i = newfiles.begin(); i != newfiles.end(); ++i) {
517 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*i)) != 0) {
518 afs->prepare_for_peakfile_writes ();
522 if (source) { // audio
523 status.doing_what = compose_status_message (*p, source->samplerate(),
524 frame_rate(), status.current, status.total);
525 write_audio_data_to_new_files (source.get(), status, newfiles);
526 } else if (smf_reader.get()) { // midi
527 status.doing_what = string_compose(_("Loading MIDI file %1"), *p);
528 write_midi_data_to_new_files (smf_reader.get(), status, newfiles);
535 if (!status.cancel) {
539 now = localtime (&xnow);
540 status.freeze = true;
542 /* flush the final length(s) to the header(s) */
544 for (Sources::iterator x = all_new_sources.begin(); x != all_new_sources.end(); ) {
546 if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*x)) != 0) {
547 afs->update_header((*x)->natural_position(), *now, xnow);
548 afs->done_with_peakfile_writes ();
550 /* now that there is data there, requeue the file for analysis */
552 if (Config->get_auto_analyse_audio()) {
553 Analyser::queue_source_for_analysis (boost::static_pointer_cast<Source>(*x), false);
557 /* imported, copied files cannot be written or removed
560 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource>(*x);
562 /* Only audio files should be marked as
563 immutable - we may need to rewrite MIDI
566 if (boost::dynamic_pointer_cast<AudioFileSource> (fs)) {
567 fs->mark_immutable ();
569 fs->mark_immutable_except_write ();
571 fs->mark_nonremovable ();
574 /* don't create tracks for empty MIDI sources (channels) */
576 if ((smfs = boost::dynamic_pointer_cast<SMFSource>(*x)) != 0 && smfs->is_empty()) {
577 x = all_new_sources.erase(x);
583 /* save state so that we don't lose these new Sources */
587 std::copy (all_new_sources.begin(), all_new_sources.end(), std::back_inserter(status.sources));
590 std::for_each (all_new_sources.begin(), all_new_sources.end(), remove_file_source);
592 error << _("Failed to remove some files after failed/cancelled import operation") << endmsg;