From 2e4fc4c3f13d192c774f38fd27561f728eee68de Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 27 Feb 2007 03:59:37 +0000 Subject: totally redesign import code to avoid stupid intermediate file copy [beta] git-svn-id: svn://localhost/ardour2/trunk@1520 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/import.cc | 247 ++++++++++++++++++++++++-------------------------- 1 file changed, 117 insertions(+), 130 deletions(-) (limited to 'libs') diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index 5fbd4e0750..e6d3c5ba5e 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -50,6 +50,63 @@ 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) { + + 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 err; +}; + int Session::import_audiofile (import_status& status) { @@ -68,32 +125,20 @@ Session::import_audiofile (import_status& status) int ret = -1; vector new_paths; struct tm* now; - string tmp_convert_file; - + 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; return -1; + } + + if ((nframes_t) info.samplerate != frame_rate()) { + importable = new ResampledImportableSource (in, &info, frame_rate()); } else { - if ((uint32_t) info.samplerate != frame_rate()) { - sf_close(in); - status.doing_what = _("resampling audio"); - // resample to session frame_rate - if (sample_rate_convert(status, status.paths.front(), tmp_convert_file)) { - if ((in = sf_open (tmp_convert_file.c_str(), SFM_READ, &info)) == 0) { - error << string_compose(_("Import: cannot open converted sound file \"%1\""), tmp_convert_file) << endmsg; - return -1; - } - } else if (!status.cancel){ - // error - error << string_compose(_("Import: error while resampling sound file \"%1\""), status.paths.front()) << endmsg; - return -1; - } else { - // canceled - goto out; - } - } + importable = new ImportableSource (in, &info); } for (n = 0; n < info.channels; ++n) { @@ -149,12 +194,11 @@ Session::import_audiofile (import_status& status) nfiles++; } - - data = new float[BLOCKSIZE * info.channels]; + data = new float[nframes * info.channels]; channel_data = new Sample * [ info.channels ]; for (n = 0; n < info.channels; ++n) { - channel_data[n] = new Sample[BLOCKSIZE]; + channel_data[n] = new Sample[nframes]; } so_far = 0; @@ -164,18 +208,19 @@ Session::import_audiofile (import_status& status) while (!status.cancel) { - long nread; + nframes_t nread; long x; long chn; - - if ((nread = sf_readf_float (in, data, BLOCKSIZE)) == 0) { + + if ((nread = importable->read (data, nframes)) == 0) { break; } /* de-interleave */ for (chn = 0; chn < info.channels; ++chn) { - for (x = chn, n = 0; n < nread; x += info.channels, ++n) { + + for (x = chn, n = 0; n < nframes; x += info.channels, ++n) { channel_data[chn][n] = (Sample) data[x]; } } @@ -183,11 +228,15 @@ Session::import_audiofile (import_status& status) /* flush to disk */ for (chn = 0; chn < info.channels; ++chn) { - newfiles[chn]->write (channel_data[chn], nread); + newfiles[chn]->write (channel_data[chn], nread / info.channels); } so_far += nread; - status.progress = so_far / (float) (info.frames * info.channels); + status.progress = so_far / (importable->ratio () * info.frames * info.channels); + } + + if (status.cancel) { + goto out; } if (status.multichan) { @@ -202,12 +251,9 @@ Session::import_audiofile (import_status& status) time (&xnow); now = localtime (&xnow); - if (status.cancel) { - goto out; - } - if (status.multichan) { /* all sources are used in a single multichannel region */ + for (n = 0; n < nfiles && !status.cancel; ++n) { /* flush the final length to the header */ newfiles[n]->update_header(0, *now, xnow); @@ -275,116 +321,57 @@ Session::import_audiofile (import_status& status) } } - if (tmp_convert_file.length()) { - unlink(tmp_convert_file.c_str()); + if (importable) { + delete importable; } - - sf_close (in); + + sf_close (in); status.done = true; + return ret; } -string -Session::build_tmp_convert_name(string infile) +nframes_t +ResampledImportableSource::read (Sample* output, nframes_t nframes) { - string tmp_name(_path + "/." + Glib::path_get_basename (infile.c_str()) + "XXXXXX"); - char* tmp = new char[tmp_name.length() + 1]; - tmp_name.copy(tmp, string::npos); - tmp[tmp_name.length()] = 0; - mkstemp(tmp); - string outfile = tmp; - delete [] tmp; + /* If the input buffer is empty, refill it. */ - return outfile; -} + if (src_data.input_frames == 0) { -bool -Session::sample_rate_convert (import_status& status, string infile, string& outfile) -{ - float input [BLOCKSIZE] ; - float output [BLOCKSIZE] ; - - SF_INFO sf_info; - SRC_STATE* src_state ; - SRC_DATA src_data ; - int err ; - sf_count_t output_count = 0 ; - sf_count_t input_count = 0; - - SNDFILE* in = sf_open(infile.c_str(), SFM_READ, &sf_info); - if (!in) { - error << string_compose(_("Import/SRC: could not open input file: %1"), outfile) << endmsg; - return false; - } - sf_count_t total_input_frames = sf_info.frames; - - outfile = build_tmp_convert_name(infile); - SNDFILE* out = sf_open(outfile.c_str(), SFM_RDWR, &sf_info); - if (!out) { - error << string_compose(_("Import/SRC: could not open output file: %1"), outfile) << endmsg; - return false; - } - - sf_seek (in, 0, SEEK_SET) ; - sf_seek (out, 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 ; - return false ; - } - - src_data.end_of_input = 0 ; /* Set this later. */ + src_data.input_frames = ImportableSource::read (input, BLOCKSIZE); - /* Start with zero to force load in while loop. */ - src_data.input_frames = 0 ; - src_data.data_in = input ; + /* The last read will not be a full buffer, so set end_of_input. */ - src_data.src_ratio = (1.0 * frame_rate()) / sf_info.samplerate ; - - src_data.data_out = output ; - src_data.output_frames = BLOCKSIZE / sf_info.channels ; - - while (!status.cancel) { - /* If the input buffer is empty, refill it. */ - if (src_data.input_frames == 0) { - src_data.input_frames = sf_readf_float (in, input, BLOCKSIZE / sf_info.channels) ; - src_data.data_in = input ; - - /* The last read will not be a full buffer, so snd_of_input. */ - if (src_data.input_frames < (int)BLOCKSIZE / sf_info.channels) { - src_data.end_of_input = SF_TRUE ; - } - } - - if ((err = src_process (src_state, &src_data))) { - error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ; - return false ; - } - - /* Terminate if at end */ - if (src_data.end_of_input && src_data.output_frames_gen == 0) { - break ; - } + if ((nframes_t) src_data.input_frames < BLOCKSIZE) { + src_data.end_of_input = SF_TRUE ; + } - /* Write output. */ - sf_writef_float (out, output, src_data.output_frames_gen) ; - output_count += src_data.output_frames_gen ; - input_count += src_data.input_frames_used; + src_data.input_frames /= sf_info->channels; + src_data.data_in = input ; + } + + src_data.data_out = output; - src_data.data_in += src_data.input_frames_used * sf_info.channels ; - src_data.input_frames -= src_data.input_frames_used ; - - status.progress = (float) input_count / total_input_frames; + if (!src_data.end_of_input) { + src_data.output_frames = nframes / sf_info->channels ; + } else { + src_data.output_frames = src_data.input_frames; } - src_state = src_delete (src_state) ; - sf_close(in); - sf_close(out); - - if (status.cancel) { - return false; - } else { - return true ; + if ((err = src_process (src_state, &src_data))) { + error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ; + return false ; + } + + /* 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 nframes; } + -- cgit v1.2.3