/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
+
+#ifdef WAF_BUILD
+#include "libardour-config.h"
+#endif
+
#include <cstdio>
#include <cstdlib>
#include <string>
#include <unistd.h>
#include <sys/stat.h>
#include <time.h>
+#include <stdint.h>
#include <sndfile.h>
#include <samplerate.h>
#include "evoral/SMF.hpp"
+#include "ardour/analyser.h"
#include "ardour/ardour.h"
-#include "ardour/session.h"
-#include "ardour/session_directory.h"
#include "ardour/audio_diskstream.h"
#include "ardour/audioengine.h"
-#include "ardour/sndfilesource.h"
-#include "ardour/sndfile_helpers.h"
#include "ardour/audioregion.h"
+#include "ardour/import_status.h"
#include "ardour/region_factory.h"
-#include "ardour/source_factory.h"
#include "ardour/resampled_source.h"
-#include "ardour/sndfileimportable.h"
-#include "ardour/analyser.h"
+#include "ardour/session.h"
+#include "ardour/session_directory.h"
#include "ardour/smf_source.h"
+#include "ardour/sndfile_helpers.h"
+#include "ardour/sndfileimportable.h"
+#include "ardour/sndfilesource.h"
+#include "ardour/source_factory.h"
#include "ardour/tempo.h"
#ifdef HAVE_COREAUDIO
-#ifdef USE_COREAUDIO_FOR_FILE_IO
#include "ardour/caimportable.h"
#endif
-#endif
#include "i18n.h"
static boost::shared_ptr<ImportableSource>
open_importable_source (const string& path, nframes_t samplerate, ARDOUR::SrcQuality quality)
{
-#ifdef HAVE_COREAUDIO
-#ifdef USE_COREAUDIO_FOR_FILE_IO
+ /* try libsndfile first, because it can get BWF info from .wav, which ExtAudioFile cannot.
+ We don't necessarily need that information in an ImportableSource, but it keeps the
+ logic the same as in SourceFactory::create()
+ */
- /* see if we can use CoreAudio to handle the IO */
-
try {
- CAImportableSource* src = new CAImportableSource(path);
- boost::shared_ptr<CAImportableSource> source (src);
+ boost::shared_ptr<SndFileImportableSource> source(new SndFileImportableSource(path));
if (source->samplerate() == samplerate) {
return source;
}
/* rewrap as a resampled source */
-
+
return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
}
catch (...) {
- /* fall back to SndFile */
-#endif
-#endif
+#ifdef HAVE_COREAUDIO
- try {
- boost::shared_ptr<SndFileImportableSource> source(new SndFileImportableSource(path));
-
- if (source->samplerate() == samplerate) {
- return source;
- }
-
- /* rewrap as a resampled source */
-
- return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
- }
+ /* libsndfile failed, see if we can use CoreAudio to handle the IO */
+
+ CAImportableSource* src = new CAImportableSource(path);
+ boost::shared_ptr<CAImportableSource> source (src);
- catch (...) {
- throw; // rethrow
+ if (source->samplerate() == samplerate) {
+ return source;
}
-#ifdef HAVE_COREAUDIO
-#ifdef USE_COREAUDIO_FOR_FILE_IO
- }
-#endif
+ /* rewrap as a resampled source */
+
+ return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
+
+#else
+ throw; // rethrow
#endif
+
+ }
}
static std::string
-get_non_existent_filename (DataType type, const bool allow_replacing, const std::string destdir, const std::string& basename, uint channel, uint channels)
+get_non_existent_filename (DataType type, const bool allow_replacing, const std::string& destdir, const std::string& basename, uint channel, uint channels)
{
char buf[PATH_MAX+1];
bool goodfile = false;
} else {
snprintf (buf, sizeof(buf), "%s.%s", base.c_str(), ext);
}
-
+
string tempname = destdir + "/" + buf;
if (!allow_replacing && Glib::file_test (tempname, Glib::FILE_TEST_EXISTS)) {
? sdir.midi_path().to_string() : sdir.sound_path().to_string();
filepath += '/';
- filepath += get_non_existent_filename (type, allow_replacing, filepath, basename, n, channels);
+ filepath += get_non_existent_filename (type, allow_replacing, filepath, basename, n, channels);
new_paths.push_back (filepath);
}
}
static bool
-map_existing_mono_sources (const vector<string>& new_paths, Session& sess,
- uint samplerate, vector<boost::shared_ptr<Source> >& newfiles, Session *session)
+map_existing_mono_sources (const vector<string>& new_paths, Session& /*sess*/,
+ uint /*samplerate*/, vector<boost::shared_ptr<Source> >& newfiles, Session *session)
{
for (vector<string>::const_iterator i = new_paths.begin();
i != new_paths.end(); ++i)
static bool
create_mono_sources_for_writing (const vector<string>& new_paths, Session& sess,
- uint samplerate, vector<boost::shared_ptr<Source> >& newfiles)
+ uint samplerate, vector<boost::shared_ptr<Source> >& newfiles,
+ framepos_t timeline_position)
{
- for (vector<string>::const_iterator i = new_paths.begin();
- i != new_paths.end(); ++i)
+ for (vector<string>::const_iterator i = new_paths.begin(); i != new_paths.end(); ++i)
{
boost::shared_ptr<Source> source;
{
const DataType type = ((*i).rfind(".mid") != string::npos)
? DataType::MIDI : DataType::AUDIO;
-
+
+
source = SourceFactory::createWritable (type, sess,
- i->c_str(), true,
+ i->c_str(),
false, // destructive
samplerate);
}
}
newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
+
+ /* for audio files, reset the timeline position so that any BWF-ish
+ information in the original files we are importing from is maintained.
+ */
+
+ boost::shared_ptr<AudioFileSource> afs;
+ if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
+ afs->set_timeline_position(timeline_position);
+ }
}
return true;
}
uint total_files)
{
if (file_samplerate != session_samplerate) {
- return string_compose (_("converting %1\n(resample from %2KHz to %3KHz)\n(%4 of %5)"),
+ return string_compose (_("resampling %1 from %2kHz to %3kHz\n(%4 of %5)"),
Glib::path_get_basename (path),
file_samplerate/1000.0f,
session_samplerate/1000.0f,
current_file, total_files);
}
- return string_compose (_("converting %1\n(%2 of %3)"),
- Glib::path_get_basename (path),
- current_file, total_files);
+ return string_compose (_("copying %1\n(%2 of %3)"),
+ Glib::path_get_basename (path),
+ current_file, total_files);
}
static void
-write_audio_data_to_new_files (ImportableSource* source, Session::ImportStatus& status,
+write_audio_data_to_new_files (ImportableSource* source, ImportStatus& status,
vector<boost::shared_ptr<Source> >& newfiles)
{
const nframes_t nframes = ResampledImportableSource::blocksize;
for (uint n = 0; n < channels; ++n) {
channel_data.push_back(boost::shared_array<Sample>(new Sample[nframes]));
}
-
+
uint read_count = 0;
status.progress = 0.0f;
}
static void
-write_midi_data_to_new_files (Evoral::SMF* source, Session::ImportStatus& status,
- vector<boost::shared_ptr<Source> >& newfiles)
+write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
+ vector<boost::shared_ptr<Source> >& newfiles)
{
uint32_t buf_size = 4;
uint8_t* buf = (uint8_t*)malloc(buf_size);
for (unsigned i = 1; i <= source->num_tracks(); ++i) {
boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource>(newfiles[i-1]);
smfs->drop_model();
-
+
source->seek_to_track(i);
-
+
uint64_t t = 0;
uint32_t delta_t = 0;
uint32_t size = 0;
-
+ bool first = true;
+
while (!status.cancel) {
size = buf_size;
if (ret < 0) { // EOT
break;
}
-
+
t += delta_t;
if (ret == 0) { // Meta
continue;
}
+
+ if (first) {
+ smfs->mark_streaming_write_started ();
+ first = false;
+ }
smfs->append_event_unlocked_beats(Evoral::Event<double>(0,
(double)t / (double)source->ppqn(),
const nframes64_t pos = 0;
const double length_beats = ceil(t / (double)source->ppqn());
- BeatsFramesConverter converter(smfs->session(), pos);
+ BeatsFramesConverter converter(smfs->session().tempo_map(), pos);
smfs->update_length(pos, converter.to(length_beats));
- smfs->end_write();
+ smfs->mark_streaming_write_completed ();
if (status.cancel) {
break;
uint channels = 0;
status.sources.clear ();
-
+
for (vector<Glib::ustring>::iterator p = status.paths.begin();
p != status.paths.end() && !status.cancel;
++p, ++cnt)
{
boost::shared_ptr<ImportableSource> source;
std::auto_ptr<Evoral::SMF> smf_reader;
- const DataType type = ((*p).rfind(".mid") != string::npos) ?
+ const DataType type = ((*p).rfind(".mid") != string::npos) ?
DataType::MIDI : DataType::AUDIO;
-
+
if (type == DataType::AUDIO) {
try {
source = open_importable_source (*p, frame_rate(), status.quality);
get_best_session_directory_for_new_source (),
channels);
Sources newfiles;
+ framepos_t natural_position = source ? source->natural_position() : 0;
if (status.replace_existing_source) {
- fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endl;
+ fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endmsg;
status.cancel = !map_existing_mono_sources (new_paths, *this, frame_rate(), newfiles, this);
} else {
- status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles);
+ status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles, natural_position);
}
// copy on cancel/failure so that any files that were created will be removed below
std::copy (newfiles.begin(), newfiles.end(), std::back_inserter(all_new_sources));
- if (status.cancel) break;
+ if (status.cancel) {
+ break;
+ }
for (Sources::iterator i = newfiles.begin(); i != newfiles.end(); ++i) {
if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*i)) != 0) {
for (Sources::iterator x = all_new_sources.begin(); x != all_new_sources.end(); ) {
if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*x)) != 0) {
- afs->update_header(0, *now, xnow);
+ afs->update_header((*x)->natural_position(), *now, xnow);
afs->done_with_peakfile_writes ();
-
+
/* now that there is data there, requeue the file for analysis */
-
+
if (Config->get_auto_analyse_audio()) {
Analyser::queue_source_for_analysis (boost::static_pointer_cast<Source>(*x), false);
}
}
-
+
/* don't create tracks for empty MIDI sources (channels) */
if ((smfs = boost::dynamic_pointer_cast<SMFSource>(*x)) != 0 && smfs->is_empty()) {