summaryrefslogtreecommitdiff
path: root/libs/ardour/import.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/import.cc')
-rw-r--r--libs/ardour/import.cc368
1 files changed, 125 insertions, 243 deletions
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index bc16cde156..bd6351cf05 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -32,9 +32,9 @@
#include <glibmm.h>
#include <pbd/basename.h>
+#include <pbd/convert.h>
#include <ardour/ardour.h>
-#include <ardour/types.h>
#include <ardour/session.h>
#include <ardour/session_directory.h>
#include <ardour/audio_diskstream.h>
@@ -43,82 +43,22 @@
#include <ardour/audioregion.h>
#include <ardour/region_factory.h>
#include <ardour/source_factory.h>
-
+#include <ardour/resampled_source.h>
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
-#define BLOCKSIZE 4096U
-
-class ImportableSource {
- public:
- ImportableSource (SNDFILE* sf, SF_INFO* info) : in (sf), sf_info (info) {}
- virtual ~ImportableSource() {}
-
- virtual nframes_t read (Sample* buffer, nframes_t nframes) {
- nframes_t per_channel = nframes / sf_info->channels;
- per_channel = sf_readf_float (in, buffer, per_channel);
- return per_channel * sf_info->channels;
- }
-
- virtual float ratio() const { return 1.0f; }
-
-protected:
- SNDFILE* in;
- SF_INFO* sf_info;
-};
-
-class ResampledImportableSource : public ImportableSource {
- public:
- ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate) : ImportableSource (sf, info) {
- int err;
-
- sf_seek (in, 0, SEEK_SET) ;
-
- /* Initialize the sample rate converter. */
-
- if ((src_state = src_new (SRC_SINC_BEST_QUALITY, sf_info->channels, &err)) == 0) {
- error << string_compose(_("Import: src_new() failed : %1"), src_strerror (err)) << endmsg ;
- throw failed_constructor ();
- }
-
- src_data.end_of_input = 0 ; /* Set this later. */
-
- /* Start with zero to force load in while loop. */
-
- src_data.input_frames = 0 ;
- src_data.data_in = input ;
-
- src_data.src_ratio = ((float) rate) / sf_info->samplerate ;
-
- }
-
- ~ResampledImportableSource () {
- src_state = src_delete (src_state) ;
- }
-
- nframes_t read (Sample* buffer, nframes_t nframes);
-
- float ratio() const { return src_data.src_ratio; }
-
- private:
- float input[BLOCKSIZE];
- SRC_STATE* src_state;
- SRC_DATA src_data;
-};
-
int
Session::import_audiofile (import_status& status)
{
SNDFILE *in;
vector<boost::shared_ptr<AudioFileSource> > newfiles;
- SourceList sources;
SF_INFO info;
float *data = 0;
Sample **channel_data = 0;
- long nfiles = 0;
+ int nfiles = 0;
string basepath;
string sounds_dir;
nframes_t so_far;
@@ -127,178 +67,166 @@ Session::import_audiofile (import_status& status)
vector<string> new_paths;
struct tm* now;
ImportableSource* importable = 0;
- const nframes_t nframes = BLOCKSIZE;
-
- status.new_regions.clear ();
-
- if ((in = sf_open (status.paths.front().c_str(), SFM_READ, &info)) == 0) {
- error << string_compose(_("Import: cannot open input sound file \"%1\""), status.paths.front()) << endmsg;
- status.done = 1;
- status.cancel = 1;
- return -1;
- }
-
- if ((nframes_t) info.samplerate != frame_rate()) {
- importable = new ResampledImportableSource (in, &info, frame_rate());
- } else {
- importable = new ImportableSource (in, &info);
- }
-
- for (int n = 0; n < info.channels; ++n) {
- newfiles.push_back (boost::shared_ptr<AudioFileSource>());
- }
+ const nframes_t nframes = ResampledImportableSource::blocksize;
+ uint32_t cnt = 1;
- SessionDirectory sdir(get_best_session_directory_for_new_source ());
- sounds_dir = sdir.sound_path().to_string();
-
- basepath = PBD::basename_nosuffix (status.paths.front());
+ status.sources.clear ();
+
+ for (vector<Glib::ustring>::iterator p = status.paths.begin(); p != status.paths.end(); ++p, ++cnt) {
- for (int n = 0; n < info.channels; ++n) {
+ if ((in = sf_open ((*p).c_str(), SFM_READ, &info)) == 0) {
+ error << string_compose(_("Import: cannot open input sound file \"%1\""), (*p)) << endmsg;
+ status.done = 1;
+ status.cancel = 1;
+ return -1;
+ }
+
+ if ((nframes_t) info.samplerate != frame_rate()) {
+ importable = new ResampledImportableSource (in, &info, frame_rate(), status.quality);
+ } else {
+ importable = new ImportableSource (in, &info);
+ }
+
+ newfiles.clear ();
- bool goodfile = false;
+ for (int n = 0; n < info.channels; ++n) {
+ newfiles.push_back (boost::shared_ptr<AudioFileSource>());
+ }
+
+ SessionDirectory sdir(get_best_session_directory_for_new_source ());
+ sounds_dir = sdir.sound_path().to_string();
- do {
- if (info.channels == 2) {
- if (n == 0) {
- snprintf (buf, sizeof(buf), "%s/%s-L.wav", sounds_dir.c_str(), basepath.c_str());
+ basepath = PBD::basename_nosuffix ((*p));
+
+ for (int n = 0; n < info.channels; ++n) {
+
+ bool goodfile = false;
+
+ do {
+ if (info.channels == 2) {
+ if (n == 0) {
+ snprintf (buf, sizeof(buf), "%s/%s-L.wav", sounds_dir.c_str(), basepath.c_str());
+ } else {
+ snprintf (buf, sizeof(buf), "%s/%s-R.wav", sounds_dir.c_str(), basepath.c_str());
+ }
+ } else if (info.channels > 1) {
+ snprintf (buf, sizeof(buf), "%s/%s-c%d.wav", sounds_dir.c_str(), basepath.c_str(), n+1);
} else {
- snprintf (buf, sizeof(buf), "%s/%s-R.wav", sounds_dir.c_str(), basepath.c_str());
+ snprintf (buf, sizeof(buf), "%s/%s.wav", sounds_dir.c_str(), basepath.c_str());
}
- } else if (info.channels > 1) {
- snprintf (buf, sizeof(buf), "%s/%s-c%d.wav", sounds_dir.c_str(), basepath.c_str(), n+1);
- } else {
- snprintf (buf, sizeof(buf), "%s/%s.wav", sounds_dir.c_str(), basepath.c_str());
- }
- if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
+ if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
- /* if the file already exists, we must come up with
- * a new name for it. for now we just keep appending
- * _ to basepath
- */
+ /* if the file already exists, we must come up with
+ * a new name for it. for now we just keep appending
+ * _ to basepath
+ */
- basepath += "_";
+ basepath += "_";
- } else {
+ } else {
- goodfile = true;
- }
+ goodfile = true;
+ }
- } while ( !goodfile);
+ } while ( !goodfile);
- try {
- newfiles[n] = boost::dynamic_pointer_cast<AudioFileSource> (
- SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
- }
+ try {
+ newfiles[n] = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
+ }
- catch (failed_constructor& err) {
- error << string_compose(_("Session::import_audiofile: cannot open new file source for channel %1"), n+1) << endmsg;
- goto out;
- }
+ catch (failed_constructor& err) {
+ error << string_compose(_("Session::import_audiofile: cannot open new file source for channel %1"), n+1) << endmsg;
+ goto out;
+ }
- new_paths.push_back (buf);
- nfiles++;
- }
+ new_paths.push_back (buf);
+ newfiles[n]->prepare_for_peakfile_writes ();
+ nfiles++;
+ }
- data = new float[nframes * info.channels];
- channel_data = new Sample * [ info.channels ];
+ data = new float[nframes * info.channels];
+ channel_data = new Sample * [ info.channels ];
- for (int n = 0; n < info.channels; ++n) {
- channel_data[n] = new Sample[nframes];
- }
+ for (int n = 0; n < info.channels; ++n) {
+ channel_data[n] = new Sample[nframes];
+ }
- so_far = 0;
+ so_far = 0;
- status.doing_what = _("converting audio");
- status.progress = 0.0;
+ if ((nframes_t) info.samplerate != frame_rate()) {
+ status.doing_what = string_compose (_("converting %1\n(resample from %2KHz to %3KHz)\n(%4 of %5)"),
+ basepath,
+ info.samplerate/1000.0f,
+ frame_rate()/1000.0f,
+ cnt, status.paths.size());
+
+ } else {
+ status.doing_what = string_compose (_("converting %1\n(%2 of %3)"),
+ basepath,
+ cnt, status.paths.size());
- while (!status.cancel) {
+ }
+
+ status.progress = 0.0;
+
+ while (!status.cancel) {
- nframes_t nread, nfread;
- long x;
- long chn;
+ nframes_t nread, nfread;
+ long x;
+ long chn;
- if ((nread = importable->read (data, nframes)) == 0) {
- break;
- }
- nfread = nread / info.channels;
+ if ((nread = importable->read (data, nframes)) == 0) {
+ break;
+ }
+ nfread = nread / info.channels;
- /* de-interleave */
+ /* de-interleave */
- for (chn = 0; chn < info.channels; ++chn) {
+ for (chn = 0; chn < info.channels; ++chn) {
- nframes_t n;
- for (x = chn, n = 0; n < nfread; x += info.channels, ++n) {
- channel_data[chn][n] = (Sample) data[x];
+ nframes_t n;
+ for (x = chn, n = 0; n < nfread; x += info.channels, ++n) {
+ channel_data[chn][n] = (Sample) data[x];
+ }
}
- }
- /* flush to disk */
+ /* flush to disk */
- for (chn = 0; chn < info.channels; ++chn) {
- newfiles[chn]->write (channel_data[chn], nfread);
- }
+ for (chn = 0; chn < info.channels; ++chn) {
+ newfiles[chn]->write (channel_data[chn], nfread);
+ }
- so_far += nread;
- status.progress = so_far / (importable->ratio () * info.frames * info.channels);
- }
+ so_far += nread;
+ status.progress = so_far / (importable->ratio () * info.frames * info.channels);
+ }
- if (status.cancel) {
- goto out;
- }
+ if (status.cancel) {
+ goto out;
+ }
+
+ for (int n = 0; n < info.channels; ++n) {
+ status.sources.push_back (newfiles[n]);
+ }
- if (status.multichan) {
- status.doing_what = _("building region");
- } else {
- status.doing_what = _("building regions");
+ if (status.cancel) {
+ goto out;
+ }
}
-
+
status.freeze = true;
time_t xnow;
time (&xnow);
now = localtime (&xnow);
- if (status.multichan) {
- /* all sources are used in a single multichannel region */
+ /* flush the final length(s) to the header(s) */
- for (int n = 0; n < nfiles && !status.cancel; ++n) {
- /* flush the final length to the header */
- newfiles[n]->update_header(0, *now, xnow);
- sources.push_back(newfiles[n]);
- }
-
- bool strip_paired_suffixes = (newfiles.size() > 1);
-
- boost::shared_ptr<AudioRegion> r (boost::dynamic_pointer_cast<AudioRegion>
- (RegionFactory::create (sources, 0,
- newfiles[0]->length(),
- region_name_from_path (basepath, strip_paired_suffixes),
- 0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile))));
-
- status.new_regions.push_back (r);
-
- } else {
- for (int n = 0; n < nfiles && !status.cancel; ++n) {
-
- /* flush the final length to the header */
-
- newfiles[n]->update_header(0, *now, xnow);
-
- /* The sources had zero-length when created, which means that the Session
- did not bother to create whole-file AudioRegions for them. Do it now.
-
- Note: leave any trailing paired indicators from the file names as part
- of the region name.
- */
-
- status.new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion>
- (RegionFactory::create (boost::static_pointer_cast<Source> (newfiles[n]), 0, newfiles[n]->length(),
- region_name_from_path (newfiles[n]->name(), false),
- 0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile | AudioRegion::Import))));
- }
+ for (SourceList::iterator x = status.sources.begin(); x != status.sources.end() && !status.cancel; ++x) {
+ boost::dynamic_pointer_cast<AudioFileSource>(*x)->update_header(0, *now, xnow);
+ boost::dynamic_pointer_cast<AudioSource>(*x)->done_with_peakfile_writes ();
}
-
+
/* save state so that we don't lose these new Sources */
if (!status.cancel) {
@@ -321,7 +249,8 @@ Session::import_audiofile (import_status& status)
}
if (status.cancel) {
- status.new_regions.clear ();
+
+ status.sources.clear ();
for (vector<string>::iterator i = new_paths.begin(); i != new_paths.end(); ++i) {
unlink ((*i).c_str());
@@ -337,50 +266,3 @@ Session::import_audiofile (import_status& status)
return ret;
}
-
-nframes_t
-ResampledImportableSource::read (Sample* output, nframes_t nframes)
-{
- int err;
-
- /* If the input buffer is empty, refill it. */
-
- if (src_data.input_frames == 0) {
-
- src_data.input_frames = ImportableSource::read (input, BLOCKSIZE);
-
- /* The last read will not be a full buffer, so set end_of_input. */
-
- if ((nframes_t) src_data.input_frames < BLOCKSIZE) {
- src_data.end_of_input = SF_TRUE ;
- }
-
- src_data.input_frames /= sf_info->channels;
- src_data.data_in = input ;
- }
-
- src_data.data_out = output;
-
- if (!src_data.end_of_input) {
- src_data.output_frames = nframes / sf_info->channels ;
- } else {
- src_data.output_frames = src_data.input_frames;
- }
-
- if ((err = src_process (src_state, &src_data))) {
- error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ;
- return 0 ;
- }
-
- /* Terminate if at end */
-
- if (src_data.end_of_input && src_data.output_frames_gen == 0) {
- return 0;
- }
-
- src_data.data_in += src_data.input_frames_used * sf_info->channels ;
- src_data.input_frames -= src_data.input_frames_used ;
-
- return src_data.output_frames_gen * sf_info->channels;
-}
-