X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fimport.cc;h=bd6351cf0558be969e3844a143a40a6de4d99b1f;hb=badc087263990ecf360792c10e4d9f2d60828d43;hp=5fbd4e075006e918364674065e5ca6e4800a10ed;hpb=c268314b64c2235b0d69c3854e303accd2cad4d9;p=ardour.git diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc index 5fbd4e0750..bd6351cf05 100644 --- a/libs/ardour/import.cc +++ b/libs/ardour/import.cc @@ -32,35 +32,33 @@ #include #include +#include #include #include +#include #include #include #include #include #include #include - +#include #include "i18n.h" using namespace ARDOUR; using namespace PBD; -#define BLOCKSIZE 4096U - int Session::import_audiofile (import_status& status) { SNDFILE *in; vector > newfiles; - SourceList sources; SF_INFO info; float *data = 0; Sample **channel_data = 0; - long nfiles = 0; - long n; + int nfiles = 0; string basepath; string sounds_dir; nframes_t so_far; @@ -68,183 +66,167 @@ Session::import_audiofile (import_status& status) int ret = -1; vector new_paths; struct tm* now; - string tmp_convert_file; - - 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; - } 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; - } - } - } - - for (n = 0; n < info.channels; ++n) { - newfiles.push_back (boost::shared_ptr()); - } + ImportableSource* importable = 0; + const nframes_t nframes = ResampledImportableSource::blocksize; + uint32_t cnt = 1; - sounds_dir = discover_best_sound_dir (); - basepath = PBD::basename_nosuffix (status.paths.front()); + status.sources.clear (); + + for (vector::iterator p = status.paths.begin(); p != status.paths.end(); ++p, ++cnt) { - for (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()); + } + + 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%lu.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 (::access (buf, F_OK) == 0) { + 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 (SourceFactory::createWritable (*this, buf, false, frame_rate())); - } + try { + newfiles[n] = boost::dynamic_pointer_cast (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[BLOCKSIZE * info.channels]; - channel_data = new Sample * [ 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]; - } + 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) { + } - long nread; - long x; - long chn; + status.progress = 0.0; - if ((nread = sf_readf_float (in, data, BLOCKSIZE)) == 0) { - break; - } + while (!status.cancel) { + + nframes_t nread, nfread; + long x; + long chn; + + if ((nread = importable->read (data, nframes)) == 0) { + break; + } + nfread = nread / info.channels; - /* de-interleave */ + /* de-interleave */ - for (chn = 0; chn < info.channels; ++chn) { - for (x = chn, n = 0; n < nread; x += info.channels, ++n) { - channel_data[chn][n] = (Sample) data[x]; + 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]; + } } - } - /* flush to disk */ + /* flush to disk */ - for (chn = 0; chn < info.channels; ++chn) { - newfiles[chn]->write (channel_data[chn], nread); + 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 / (float) (info.frames * info.channels); - } + 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.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); - sources.push_back(newfiles[n]); - } - - bool strip_paired_suffixes = (newfiles.size() > 1); - - boost::shared_ptr r (boost::dynamic_pointer_cast - (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 (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. + /* flush the final length(s) to the header(s) */ - 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 - (RegionFactory::create (boost::static_pointer_cast (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(*x)->update_header(0, *now, xnow); + boost::dynamic_pointer_cast(*x)->done_with_peakfile_writes (); } - + /* save state so that we don't lose these new Sources */ if (!status.cancel) { @@ -260,7 +242,7 @@ Session::import_audiofile (import_status& status) } if (channel_data) { - for (n = 0; n < info.channels; ++n) { + for (int n = 0; n < info.channels; ++n) { delete [] channel_data[n]; } delete [] channel_data; @@ -268,123 +250,19 @@ Session::import_audiofile (import_status& status) if (status.cancel) { - status.new_regions.clear (); + status.sources.clear (); for (vector::iterator i = new_paths.begin(); i != new_paths.end(); ++i) { unlink ((*i).c_str()); } } - if (tmp_convert_file.length()) { - unlink(tmp_convert_file.c_str()); + if (importable) { + delete importable; } - - sf_close (in); - status.done = true; - return ret; -} - -string -Session::build_tmp_convert_name(string infile) -{ - 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; - - return outfile; -} -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. */ - - /* Start with zero to force load in while loop. */ - src_data.input_frames = 0 ; - src_data.data_in = 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 ; - } - - /* 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.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; - } - - src_state = src_delete (src_state) ; - sf_close(in); - sf_close(out); + sf_close (in); + status.done = true; - if (status.cancel) { - return false; - } else { - return true ; - } + return ret; }