ardour
import.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000 Paul Davis
3 
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.
8 
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.
13 
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.
17 
18 */
19 
20 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
23 
24 #include <cstdio>
25 #include <cstdlib>
26 #include <string>
27 #include <climits>
28 #include <cerrno>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <time.h>
32 #include <stdint.h>
33 
34 #include <sndfile.h>
35 #include <samplerate.h>
36 
37 #include <glib/gstdio.h>
38 #include <glibmm.h>
39 
40 #include <boost/scoped_array.hpp>
41 #include <boost/shared_array.hpp>
42 
43 #include "pbd/basename.h"
44 #include "pbd/convert.h"
45 
46 #include "evoral/SMF.hpp"
47 
48 #include "ardour/analyser.h"
49 #include "ardour/ardour.h"
51 #include "ardour/audioengine.h"
52 #include "ardour/audioregion.h"
53 #include "ardour/import_status.h"
54 #include "ardour/region_factory.h"
57 #include "ardour/session.h"
59 #include "ardour/smf_source.h"
60 #include "ardour/sndfile_helpers.h"
62 #include "ardour/sndfilesource.h"
63 #include "ardour/source_factory.h"
64 #include "ardour/tempo.h"
65 
66 #ifdef HAVE_COREAUDIO
67 #include "ardour/caimportable.h"
68 #endif
69 
70 #include "i18n.h"
71 
72 using namespace std;
73 using namespace ARDOUR;
74 using namespace PBD;
75 
77 open_importable_source (const string& path, framecnt_t samplerate, ARDOUR::SrcQuality quality)
78 {
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()
82  */
83 
84  try {
86 
87  if (source->samplerate() == samplerate) {
88  return source;
89  }
90 
91  /* rewrap as a resampled source */
92 
93  return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
94  }
95 
96  catch (...) {
97 
98 #ifdef HAVE_COREAUDIO
99 
100  /* libsndfile failed, see if we can use CoreAudio to handle the IO */
101 
102  CAImportableSource* src = new CAImportableSource(path);
104 
105  if (source->samplerate() == samplerate) {
106  return source;
107  }
108 
109  /* rewrap as a resampled source */
110 
111  return boost::shared_ptr<ImportableSource>(new ResampledImportableSource(source, samplerate, quality));
112 
113 #else
114  throw; // rethrow
115 #endif
116 
117  }
118 }
119 
120 vector<string>
121 Session::get_paths_for_new_sources (bool /*allow_replacing*/, const string& import_file_path, uint32_t channels)
122 {
123  vector<string> new_paths;
124  const string basename = basename_nosuffix (import_file_path);
125 
126  for (uint32_t n = 0; n < channels; ++n) {
127 
128  const DataType type = SMFSource::safe_midi_file_extension (import_file_path) ? DataType::MIDI : DataType::AUDIO;
129  string filepath;
130 
131  switch (type) {
132  case DataType::MIDI:
133  if (channels > 1) {
134  string mchn_name = string_compose ("%1-t%2", basename, n);
135  filepath = new_midi_source_path (mchn_name);
136  } else {
137  filepath = new_midi_source_path (basename);
138  }
139  break;
140  case DataType::AUDIO:
141  filepath = new_audio_source_path (basename, channels, n, false, false);
142  break;
143  }
144 
145  if (filepath.empty()) {
146  error << string_compose (_("Cannot find new filename for imported file %1"), import_file_path) << endmsg;
147  return vector<string>();
148  }
149 
150  new_paths.push_back (filepath);
151  }
152 
153  return new_paths;
154 }
155 
156 static bool
157 map_existing_mono_sources (const vector<string>& new_paths, Session& /*sess*/,
158  uint32_t /*samplerate*/, vector<boost::shared_ptr<Source> >& newfiles, Session *session)
159 {
160  for (vector<string>::const_iterator i = new_paths.begin();
161  i != new_paths.end(); ++i)
162  {
164 
165  if (source == 0) {
166  error << string_compose(_("Could not find a source for %1 even though we are updating this file!"), (*i)) << endl;
167  return false;
168  }
169 
170  newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
171  }
172  return true;
173 }
174 
175 static bool
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)
180 {
181  for (vector<string>::const_iterator i = new_paths.begin(); i != new_paths.end(); ++i) {
182 
184 
185  try {
186  const DataType type = SMFSource::safe_midi_file_extension (*i) ? DataType::MIDI : DataType::AUDIO;
187 
188  source = SourceFactory::createWritable (type, sess,
189  i->c_str(),
190  false, // destructive
191  samplerate);
192  }
193 
194  catch (const failed_constructor& err) {
195  error << string_compose (_("Unable to create file %1 during import"), *i) << endmsg;
196  return false;
197  }
198 
199  newfiles.push_back(boost::dynamic_pointer_cast<Source>(source));
200 
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.
203  */
204 
206  if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
207  afs->set_timeline_position(timeline_position);
208  }
209  }
210  return true;
211 }
212 
213 static string
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 */)
219 {
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);
225  }
226 
227  return string_compose (_("Copying %1"), Glib::path_get_basename (path));
228 }
229 
230 static void
232  vector<boost::shared_ptr<Source> >& newfiles)
233 {
234  const framecnt_t nframes = ResampledImportableSource::blocksize;
236  uint32_t channels = source->channels();
237  if (channels == 0) {
238  return;
239  }
240 
241  boost::scoped_array<float> data(new float[nframes * channels]);
242  vector<boost::shared_array<Sample> > channel_data;
243 
244  for (uint32_t n = 0; n < channels; ++n) {
245  channel_data.push_back(boost::shared_array<Sample>(new Sample[nframes]));
246  }
247 
248  float gain = 1;
249 
251  assert (s);
252 
253  status.progress = 0.0f;
254  float progress_multiplier = 1;
255  float progress_base = 0;
256 
257  if (!source->clamped_at_unity() && s->clamped_at_unity()) {
258 
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.
262  */
263 
264  float peak = 0;
265  uint32_t read_count = 0;
266 
267  while (!status.cancel) {
268  framecnt_t const nread = source->read (data.get(), nframes);
269  if (nread == 0) {
270  break;
271  }
272 
273  peak = compute_peak (data.get(), nread, peak);
274 
275  read_count += nread;
276  status.progress = 0.5 * read_count / (source->ratio() * source->length() * channels);
277  }
278 
279  if (peak >= 1) {
280  /* we are out of range: compute a gain to fix it */
281  gain = (1 - FLT_EPSILON) / peak;
282  }
283 
284  source->seek (0);
285  progress_multiplier = 0.5;
286  progress_base = 0.5;
287  }
288 
289  framecnt_t read_count = 0;
290 
291  while (!status.cancel) {
292 
293  framecnt_t nread, nfread;
294  uint32_t x;
295  uint32_t chn;
296 
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)
304  afs->flush ();
305 #endif
306  break;
307  }
308 
309  if (gain != 1) {
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);
312  }
313 
314  nfread = nread / channels;
315 
316  /* de-interleave */
317 
318  for (chn = 0; chn < channels; ++chn) {
319 
320  framecnt_t n;
321  for (x = chn, n = 0; n < nfread; x += channels, ++n) {
322  channel_data[chn][n] = (Sample) data[x];
323  }
324  }
325 
326  /* flush to disk */
327 
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);
331  }
332  }
333 
334  read_count += nread;
335  status.progress = progress_base + progress_multiplier * read_count / (source->ratio () * source->length() * channels);
336  }
337 }
338 
339 static void
341  vector<boost::shared_ptr<Source> >& newfiles)
342 {
343  uint32_t buf_size = 4;
344  uint8_t* buf = (uint8_t*) malloc (buf_size);
345 
346  status.progress = 0.0f;
347 
348  assert (newfiles.size() == source->num_tracks());
349 
350  try {
351  vector<boost::shared_ptr<Source> >::iterator s = newfiles.begin();
352 
353  for (unsigned i = 1; i <= source->num_tracks(); ++i) {
354 
356 
357  Glib::Threads::Mutex::Lock source_lock(smfs->mutex());
358 
359  smfs->drop_model (source_lock);
360  source->seek_to_track (i);
361 
362  uint64_t t = 0;
363  uint32_t delta_t = 0;
364  uint32_t size = 0;
365  bool first = true;
366 
367  while (!status.cancel) {
368  gint note_id_ignored; // imported files either don't have NoteID's or we ignore them.
369 
370  size = buf_size;
371 
372  int ret = source->read_event (&delta_t, &size, &buf, &note_id_ignored);
373 
374  if (size > buf_size) {
375  buf_size = size;
376  }
377 
378  if (ret < 0) { // EOT
379  break;
380  }
381 
382  t += delta_t;
383 
384  if (ret == 0) { // Meta
385  continue;
386  }
387 
388  if (first) {
389  smfs->mark_streaming_write_started (source_lock);
390  first = false;
391  }
392 
393  smfs->append_event_beats(
394  source_lock,
396  0,
397  Evoral::Beats::ticks_at_rate(t, source->ppqn()),
398  size,
399  buf));
400 
401  if (status.progress < 0.99) {
402  status.progress += 0.01;
403  }
404  }
405 
406  if (!first) {
407 
408  /* we wrote something */
409 
410  const framepos_t pos = 0;
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);
415 
416  if (status.cancel) {
417  break;
418  }
419  } else {
420  info << string_compose (_("Track %1 of %2 contained no usable MIDI data"), i, source->num_tracks()) << endmsg;
421  }
422 
423  ++s; // next source
424  }
425 
426  } catch (exception& e) {
427  error << string_compose (_("MIDI file could not be written (best guess: %1)"), e.what()) << endmsg;
428  }
429 
430  if (buf) {
431  free (buf);
432  }
433 }
434 
435 static void
437 {
439 
440  fs->DropReferences ();
441 
442  if (fs) {
443  ::g_unlink (fs->path().c_str());
444  }
445 }
446 
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.
451 void
452 Session::import_files (ImportStatus& status)
453 {
454  typedef vector<boost::shared_ptr<Source> > Sources;
455  Sources all_new_sources;
458  uint32_t channels = 0;
459 
460  status.sources.clear ();
461 
462  for (vector<string>::iterator p = status.paths.begin();
463  p != status.paths.end() && !status.cancel;
464  ++p)
465  {
467  std::auto_ptr<Evoral::SMF> smf_reader;
468  const DataType type = SMFSource::safe_midi_file_extension (*p) ? DataType::MIDI : DataType::AUDIO;
469 
470  if (type == DataType::AUDIO) {
471  try {
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;
477  return;
478  }
479 
480  } else {
481  try {
482  smf_reader = std::auto_ptr<Evoral::SMF>(new Evoral::SMF());
483  smf_reader->open(*p);
484  channels = smf_reader->num_tracks();
485  } catch (...) {
486  error << _("Import: error opening MIDI file") << endmsg;
487  status.done = status.cancel = true;
488  return;
489  }
490  }
491 
492  if (channels == 0) {
493  error << _("Import: file contains no channels.") << endmsg;
494  continue;
495  }
496 
497  vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source, *p, channels);
498  Sources newfiles;
499  framepos_t natural_position = source ? source->natural_position() : 0;
500 
501 
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);
505  } else {
506  status.cancel = !create_mono_sources_for_writing (new_paths, *this, frame_rate(), newfiles, natural_position);
507  }
508 
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));
511 
512  if (status.cancel) {
513  break;
514  }
515 
516  for (Sources::iterator i = newfiles.begin(); i != newfiles.end(); ++i) {
517  if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*i)) != 0) {
519  }
520  }
521 
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);
529  }
530 
531  ++status.current;
532  status.progress = 0;
533  }
534 
535  if (!status.cancel) {
536  struct tm* now;
537  time_t xnow;
538  time (&xnow);
539  now = localtime (&xnow);
540  status.freeze = true;
541 
542  /* flush the final length(s) to the header(s) */
543 
544  for (Sources::iterator x = all_new_sources.begin(); x != all_new_sources.end(); ) {
545 
546  if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*x)) != 0) {
547  afs->update_header((*x)->natural_position(), *now, xnow);
549 
550  /* now that there is data there, requeue the file for analysis */
551 
552  if (Config->get_auto_analyse_audio()) {
553  Analyser::queue_source_for_analysis (boost::static_pointer_cast<Source>(*x), false);
554  }
555  }
556 
557  /* imported, copied files cannot be written or removed
558  */
559 
561  if (fs) {
562  /* Only audio files should be marked as
563  immutable - we may need to rewrite MIDI
564  files at any time.
565  */
566  if (boost::dynamic_pointer_cast<AudioFileSource> (fs)) {
567  fs->mark_immutable ();
568  } else {
570  }
571  fs->mark_nonremovable ();
572  }
573 
574  /* don't create tracks for empty MIDI sources (channels) */
575 
576  if ((smfs = boost::dynamic_pointer_cast<SMFSource>(*x)) != 0 && smfs->is_empty()) {
577  x = all_new_sources.erase(x);
578  } else {
579  ++x;
580  }
581  }
582 
583  /* save state so that we don't lose these new Sources */
584 
585  save_state (_name);
586 
587  std::copy (all_new_sources.begin(), all_new_sources.end(), std::back_inserter(status.sources));
588  } else {
589  try {
590  std::for_each (all_new_sources.begin(), all_new_sources.end(), remove_file_source);
591  } catch (...) {
592  error << _("Failed to remove some files after failed/cancelled import operation") << endmsg;
593  }
594 
595  }
596 
597  status.done = true;
598 }
599 
std::string doing_what
Definition: import_status.h:36
LIBPBD_API Transmitter fatal
bool is_empty() const
Definition: OldSMF.hpp:39
int read_event(uint32_t *delta_t, uint32_t *size, uint8_t **buf) const
Definition: OldSMF.cpp:212
PBD::Signal0< void > DropReferences
Definition: destructible.h:34
virtual void flush()=0
int prepare_for_peakfile_writes()
Definition: audiosource.cc:738
static void remove_file_source(boost::shared_ptr< Source > source)
Definition: import.cc:436
Session & session() const
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
void mark_immutable_except_write()
Definition: file_source.cc:524
static bool create_mono_sources_for_writing(const vector< string > &new_paths, Session &sess, uint32_t samplerate, vector< boost::shared_ptr< Source > > &newfiles, framepos_t timeline_position)
Definition: import.cc:176
virtual void update_length(framecnt_t)
Definition: midi_source.cc:175
static bool map_existing_mono_sources(const vector< string > &new_paths, Session &, uint32_t, vector< boost::shared_ptr< Source > > &newfiles, Session *session)
Definition: import.cc:157
TempoMap & tempo_map()
Definition: session.h:596
LIBARDOUR_API compute_peak_t compute_peak
Definition: globals.cc:129
tuple f
Definition: signals.py:35
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
LIBARDOUR_API PBD::PropertyDescriptor< bool > gain
Definition: route_group.cc:44
virtual float ratio() const
static void write_audio_data_to_new_files(ImportableSource *source, ImportStatus &status, vector< boost::shared_ptr< Source > > &newfiles)
Definition: import.cc:231
static string compose_status_message(const string &path, uint32_t file_samplerate, uint32_t session_samplerate, uint32_t, uint32_t)
Definition: import.cc:214
SrcQuality
Definition: types.h:522
void drop_model(const Glib::Threads::Mutex::Lock &lock)
Definition: midi_source.cc:415
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
uint16_t ppqn() const
Definition: OldSMF.hpp:38
volatile bool freeze
Definition: import_status.h:42
boost::shared_ptr< AudioFileSource > audio_source_by_path_and_channel(const std::string &, uint16_t) const
Definition: session.cc:3684
#define _(Text)
Definition: i18n.h:11
virtual void set_timeline_position(framepos_t pos)
Definition: source.cc:264
int64_t framecnt_t
Definition: types.h:76
static Beats ticks_at_rate(uint64_t ticks, uint32_t ppqn)
Definition: Beats.hpp:58
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
float Sample
Definition: types.h:54
virtual framecnt_t read(Sample *buffer, framecnt_t nframes)=0
uint16_t num_tracks() const
Definition: SMF.cpp:44
virtual bool clamped_at_unity() const =0
Definition: amp.h:29
virtual uint32_t channels() const =0
Beats round_up_to_beat() const
Definition: Beats.hpp:67
void done_with_peakfile_writes(bool done=true)
Definition: audiosource.cc:748
int seek_to_track(int track)
Definition: SMF.cpp:61
virtual void seek(framepos_t pos)=0
int64_t framepos_t
Definition: types.h:66
void mark_streaming_write_completed(const Lock &lock)
Definition: smf_source.cc:536
T * get() const
Definition: shared_ptr.hpp:268
LIBPBD_API Transmitter info
void append_event_beats(const Lock &lock, const Evoral::Event< Evoral::Beats > &ev)
Definition: smf_source.cc:393
Glib::Threads::Mutex & mutex()
Definition: source.h:105
LIBPBD_API Glib::ustring basename_nosuffix(Glib::ustring)
const std::string & path() const
Definition: file_source.h:49
virtual void mark_streaming_write_started(const Lock &lock)
Definition: midi_source.cc:307
virtual bool clamped_at_unity() const =0
virtual framecnt_t length() const =0
virtual framepos_t natural_position() const =0
LIBARDOUR_API PBD::PropertyDescriptor< Evoral::Beats > length_beats
Definition: midi_region.cc:57
Definition: debug.h:30
virtual framecnt_t write(Sample *src, framecnt_t cnt)
Definition: audiosource.cc:321
static void write_midi_data_to_new_files(Evoral::SMF *source, ImportStatus &status, vector< boost::shared_ptr< Source > > &newfiles)
Definition: import.cc:340
LIBARDOUR_API apply_gain_to_buffer_t apply_gain_to_buffer
Definition: globals.cc:131
std::vector< std::string > paths
Definition: import_status.h:43
virtual framecnt_t samplerate() const =0
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
virtual int update_header(framepos_t when, struct tm &, time_t)=0
static boost::shared_ptr< ImportableSource > open_importable_source(const string &path, framecnt_t samplerate, ARDOUR::SrcQuality quality)
Definition: import.cc:77
framecnt_t samplerate() const