ardour
sndfilesource.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 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 <cstring>
25 #include <cerrno>
26 #include <climits>
27 #include <cstdarg>
28 
29 #include <sys/stat.h>
30 
31 #ifdef PLATFORM_WINDOWS
32 #include <glibmm/convert.h>
33 #endif
34 #include <glibmm/fileutils.h>
35 #include <glibmm/miscutils.h>
36 
37 #include "ardour/sndfilesource.h"
38 #include "ardour/sndfile_helpers.h"
39 #include "ardour/utils.h"
40 #include "ardour/session.h"
41 
42 #include "i18n.h"
43 
44 using namespace std;
45 using namespace ARDOUR;
46 using namespace PBD;
47 using std::string;
48 
49 gain_t* SndFileSource::out_coefficient = 0;
50 gain_t* SndFileSource::in_coefficient = 0;
51 framecnt_t SndFileSource::xfade_frames = 64;
52 const Source::Flag SndFileSource::default_writable_flags = Source::Flag (
54  Source::Removable |
55  Source::RemovableIfEmpty |
56  Source::CanRename );
57 
58 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
59  : Source(s, node)
60  , AudioFileSource (s, node)
61  , _sndfile (0)
62  , _broadcast_info (0)
63  , _capture_start (false)
64  , _capture_end (false)
65  , file_pos (0)
66  , xfade_buf (0)
67 {
68  init_sndfile ();
69 
70  assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
71  existence_check ();
72 
73  if (open()) {
74  throw failed_constructor ();
75  }
76 }
77 
81 SndFileSource::SndFileSource (Session& s, const string& path, int chn, Flag flags)
82  : Source(s, DataType::AUDIO, path, flags)
83  /* note that the origin of an external file is itself */
84  , AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
85  , _sndfile (0)
86  , _broadcast_info (0)
87  , _capture_start (false)
88  , _capture_end (false)
89  , file_pos (0)
90  , xfade_buf (0)
91 {
92  _channel = chn;
93 
94  init_sndfile ();
95 
96  assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
97  existence_check ();
98 
99  if (open()) {
100  throw failed_constructor ();
101  }
102 }
103 
107 SndFileSource::SndFileSource (Session& s, const string& path, const string& origin,
108  SampleFormat sfmt, HeaderFormat hf, framecnt_t rate, Flag flags)
109  : Source(s, DataType::AUDIO, path, flags)
110  , AudioFileSource (s, path, origin, flags, sfmt, hf)
111  , _sndfile (0)
112  , _broadcast_info (0)
113  , _capture_start (false)
114  , _capture_end (false)
115  , file_pos (0)
116  , xfade_buf (0)
117 {
118  int fmt = 0;
119 
120  init_sndfile ();
121 
122  assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
123  existence_check ();
124 
125  _file_is_new = true;
126 
127  switch (hf) {
128  case CAF:
129  fmt = SF_FORMAT_CAF;
130  _flags = Flag (_flags & ~Broadcast);
131  break;
132 
133  case AIFF:
134  fmt = SF_FORMAT_AIFF;
135  _flags = Flag (_flags & ~Broadcast);
136  break;
137 
138  case BWF:
139  fmt = SF_FORMAT_WAV;
140  _flags = Flag (_flags | Broadcast);
141  break;
142 
143  case WAVE:
144  fmt = SF_FORMAT_WAV;
145  _flags = Flag (_flags & ~Broadcast);
146  break;
147 
148  case WAVE64:
149  fmt = SF_FORMAT_W64;
150  _flags = Flag (_flags & ~Broadcast);
151  break;
152 
153  default:
154  fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
155  abort(); /*NOTREACHED*/
156  break;
157 
158  }
159 
160  switch (sfmt) {
161  case FormatFloat:
162  fmt |= SF_FORMAT_FLOAT;
163  break;
164 
165  case FormatInt24:
166  fmt |= SF_FORMAT_PCM_24;
167  break;
168 
169  case FormatInt16:
170  fmt |= SF_FORMAT_PCM_16;
171  break;
172  }
173 
174  _info.channels = 1;
175  _info.samplerate = rate;
176  _info.format = fmt;
177 
178  if (_flags & Destructive) {
179  if (open()) {
180  throw failed_constructor();
181  }
182  } else {
183  /* normal mode: do not open the file here - do that in {read,write}_unlocked() as needed
184  */
185  }
186 }
187 
193 SndFileSource::SndFileSource (Session& s, const string& path, int chn)
194  : Source (s, DataType::AUDIO, path, Flag (0))
195  /* the final boolean argument is not used, its value is irrelevant. see audiofilesource.h for explanation */
196  , AudioFileSource (s, path, Flag (0))
197  , _sndfile (0)
198  , _broadcast_info (0)
199  , _capture_start (false)
200  , _capture_end (false)
201  , file_pos (0)
202  , xfade_buf (0)
203 {
204  _channel = chn;
205 
206  init_sndfile ();
207 
208  assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
209  existence_check ();
210 
211  if (open()) {
212  throw failed_constructor ();
213  }
214 }
215 
216 void
218 {
219  /* although libsndfile says we don't need to set this,
220  valgrind and source code shows us that we do.
221  */
222 
223  memset (&_info, 0, sizeof(_info));
224 
225  if (destructive()) {
228  }
229 
231 }
232 
233 void
235 {
236  if (_sndfile) {
237  sf_close (_sndfile);
238  _sndfile = 0;
239  }
240 }
241 
242 int
244 {
245  string path_to_open;
246 
247  if (_sndfile) {
248  return 0;
249  }
250 
251 #ifdef PLATFORM_WINDOWS
252  path_to_open = Glib::locale_from_utf8(_path);
253 #else
254  path_to_open = _path;
255 #endif
256 
257  _sndfile = sf_open (path_to_open.c_str(), writable() ? SFM_RDWR : SFM_READ, &_info);
258 
259  if (_sndfile == 0) {
260  char errbuf[1024];
261  sf_error_str (0, errbuf, sizeof (errbuf) - 1);
262 #ifndef HAVE_COREAUDIO
263  /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
264  so we don't want to see this message.
265  */
266 
267  cerr << "failed to open " << path_to_open << " with name " << _name << endl;
268 
269  error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
270  path_to_open, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
271 #endif
272  return -1;
273  }
274 
275  if (_channel >= _info.channels) {
276 #ifndef HAVE_COREAUDIO
277  error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
278 #endif
279  sf_close (_sndfile);
280  _sndfile = 0;
281  return -1;
282  }
283 
284  _length = _info.frames;
285 
286  if (!_broadcast_info) {
288  }
289 
290  bool bwf_info_exists = _broadcast_info->load_from_file (_sndfile);
291 
292  if (_file_is_new && _length == 0 && writable() && !bwf_info_exists) {
293  /* newly created files will not have a BWF header at this point in time.
294  * Import will have called Source::set_timeline_position() if one exists
295  * in the original. */
297  }
298 
299  /* Set our timeline position to either the time reference from a BWF header or the current
300  start of the session.
301  */
302  set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
303 
304  if (_length != 0 && !bwf_info_exists) {
305  delete _broadcast_info;
306  _broadcast_info = 0;
307  _flags = Flag (_flags & ~Broadcast);
308  }
309 
310  /* Set the broadcast flag if the BWF info is already there. We need
311  * this when recovering or using existing files.
312  */
313 
314  if (bwf_info_exists) {
315  _flags = Flag (_flags | Broadcast);
316  }
317 
318  if (writable()) {
319  sf_command (_sndfile, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
320 
321  if (_flags & Broadcast) {
322 
323  if (!_broadcast_info) {
325  }
326 
328  _broadcast_info->set_description (string_compose ("BWF %1", _name));
329 
330  if (!_broadcast_info->write_to_file (_sndfile)) {
331  error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
332  path_to_open, _broadcast_info->get_error())
333  << endmsg;
334  _flags = Flag (_flags & ~Broadcast);
335  delete _broadcast_info;
336  _broadcast_info = 0;
337  }
338  }
339  }
340 
341  return 0;
342 }
343 
345 {
346  close ();
347  delete _broadcast_info;
348  delete [] xfade_buf;
349 }
350 
351 float
353 {
354  return _info.samplerate;
355 }
356 
359 {
360  assert (cnt >= 0);
361 
362  framecnt_t nread;
363  float *ptr;
364  framecnt_t real_cnt;
365  framepos_t file_cnt;
366 
367  if (writable() && !_sndfile) {
368  /* file has not been opened yet - nothing written to it */
369  memset (dst, 0, sizeof (Sample) * cnt);
370  return cnt;
371  }
372 
373  if (const_cast<SndFileSource*>(this)->open()) {
374  error << string_compose (_("could not open file %1 for reading."), _path) << endmsg;
375  return 0;
376  }
377 
378  if (start > _length) {
379 
380  /* read starts beyond end of data, just memset to zero */
381 
382  file_cnt = 0;
383 
384  } else if (start + cnt > _length) {
385 
386  /* read ends beyond end of data, read some, memset the rest */
387 
388  file_cnt = _length - start;
389 
390  } else {
391 
392  /* read is entirely within data */
393 
394  file_cnt = cnt;
395  }
396 
397  assert (file_cnt >= 0);
398 
399  if (file_cnt != cnt) {
400  framepos_t delta = cnt - file_cnt;
401  memset (dst+file_cnt, 0, sizeof (Sample) * delta);
402  }
403 
404  if (file_cnt) {
405 
406  if (sf_seek (_sndfile, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
407  char errbuf[256];
408  sf_error_str (0, errbuf, sizeof (errbuf) - 1);
409  error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
410  return 0;
411  }
412 
413  if (_info.channels == 1) {
414  framecnt_t ret = sf_read_float (_sndfile, dst, file_cnt);
415  if (ret != file_cnt) {
416  char errbuf[256];
417  sf_error_str (0, errbuf, sizeof (errbuf) - 1);
418  error << string_compose(_("SndFileSource: @ %1 could not read %2 within %3 (%4) (len = %5, ret was %6)"), start, file_cnt, _name.val().substr (1), errbuf, _length, ret) << endl;
419  }
420  return ret;
421  }
422  }
423 
424  real_cnt = cnt * _info.channels;
425 
426  Sample* interleave_buf = get_interleave_buffer (real_cnt);
427 
428  nread = sf_read_float (_sndfile, interleave_buf, real_cnt);
429  ptr = interleave_buf + _channel;
430  nread /= _info.channels;
431 
432  /* stride through the interleaved data */
433 
434  for (framecnt_t n = 0; n < nread; ++n) {
435  dst[n] = *ptr;
436  ptr += _info.channels;
437  }
438 
439  return nread;
440 }
441 
444 {
445  if (open()) {
446  return 0; // failure
447  }
448 
449  if (destructive()) {
450  return destructive_write_unlocked (data, cnt);
451  } else {
452  return nondestructive_write_unlocked (data, cnt);
453  }
454 }
455 
458 {
459  if (!writable()) {
460  warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
461  return 0;
462  }
463 
464  if (_info.channels != 1) {
465  fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
466  abort(); /*NOTREACHED*/
467  return 0;
468  }
469 
470  framepos_t frame_pos = _length;
471 
472  if (write_float (data, frame_pos, cnt) != cnt) {
473  return 0;
474  }
475 
476  update_length (_length + cnt);
477 
478  if (_build_peakfiles) {
479  compute_and_write_peaks (data, frame_pos, cnt, true, true);
480  }
481 
482  return cnt;
483 }
484 
487 {
488  if (!writable()) {
489  warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
490  return 0;
491  }
492 
493  if (_capture_start && _capture_end) {
494 
495  /* start and end of capture both occur within the data we are writing,
496  so do both crossfades.
497  */
498 
499  _capture_start = false;
500  _capture_end = false;
501 
502  /* move to the correct location place */
504 
505  // split cnt in half
506  framecnt_t subcnt = cnt / 2;
507  framecnt_t ofilepos = file_pos;
508 
509  // fade in
510  if (crossfade (data, subcnt, 1) != subcnt) {
511  return 0;
512  }
513 
514  file_pos += subcnt;
515  Sample * tmpdata = data + subcnt;
516 
517  // fade out
518  subcnt = cnt - subcnt;
519  if (crossfade (tmpdata, subcnt, 0) != subcnt) {
520  return 0;
521  }
522 
523  file_pos = ofilepos; // adjusted below
524 
525  } else if (_capture_start) {
526 
527  /* start of capture both occur within the data we are writing,
528  so do the fade in
529  */
530 
531  _capture_start = false;
532  _capture_end = false;
533 
534  /* move to the correct location place */
536 
537  if (crossfade (data, cnt, 1) != cnt) {
538  return 0;
539  }
540 
541  } else if (_capture_end) {
542 
543  /* end of capture both occur within the data we are writing,
544  so do the fade out
545  */
546 
547  _capture_start = false;
548  _capture_end = false;
549 
550  if (crossfade (data, cnt, 0) != cnt) {
551  return 0;
552  }
553 
554  } else {
555 
556  /* in the middle of recording */
557 
558  if (write_float (data, file_pos, cnt) != cnt) {
559  return 0;
560  }
561  }
562 
563  update_length (file_pos + cnt);
564 
565  if (_build_peakfiles) {
566  compute_and_write_peaks (data, file_pos, cnt, true, true);
567  }
568 
569  file_pos += cnt;
570 
571  return cnt;
572 }
573 
574 int
575 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
576 {
577  set_timeline_position (when);
578 
579  if (_flags & Broadcast) {
580  if (setup_broadcast_info (when, now, tnow)) {
581  return -1;
582  }
583  }
584 
585  return flush_header ();
586 }
587 
588 int
590 {
591  if (!writable()) {
592  warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
593  return -1;
594  }
595 
596  if (_sndfile == 0) {
597  error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
598  return -1;
599  }
600 
601  int const r = sf_command (_sndfile, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
602 
603  return r;
604 }
605 
606 void
608 {
609  if (!writable()) {
610  warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
611  return;
612  }
613 
614  if (_sndfile == 0) {
615  error << string_compose (_("could not allocate file %1 to flush contents"), _path) << endmsg;
616  return;
617  }
618 
619  // Hopefully everything OK
620  sf_write_sync (_sndfile);
621 }
622 
623 int
624 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
625 {
626  if (!writable()) {
627  warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
628  return -1;
629  }
630 
631  if (!_sndfile) {
632  warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
633  return -1;
634  }
635 
636  if (!(_flags & Broadcast) || !_broadcast_info) {
637  return 0;
638  }
639 
641  _broadcast_info->set_origination_time (&now);
642 
643  /* now update header position taking header offset into account */
644 
646 
647  return 0;
648 }
649 
650 void
652 {
653  if (!(_flags & Broadcast)) {
654  return;
655  }
656  assert (_broadcast_info);
657 
658  _broadcast_info->set_time_reference (_timeline_position);
659 
660  if (_sndfile == 0 || !_broadcast_info->write_to_file (_sndfile)) {
661  error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
662  _path, _broadcast_info->get_error())
663  << endmsg;
664  _flags = Flag (_flags & ~Broadcast);
665  delete _broadcast_info;
666  _broadcast_info = 0;
667  }
668 }
669 
672 {
673  if (_sndfile == 0 || sf_seek (_sndfile, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
674  char errbuf[256];
675  sf_error_str (0, errbuf, sizeof (errbuf) - 1);
676  error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3)"), _path, frame_pos, errbuf) << endmsg;
677  return 0;
678  }
679 
680  if (sf_writef_float (_sndfile, data, cnt) != (ssize_t) cnt) {
681  return 0;
682  }
683 
684  return cnt;
685 }
686 
689 {
690  return _timeline_position;
691 }
692 
693 bool
695 {
696  if (yn) {
697  _flags = Flag (_flags | Writable | Destructive);
698  if (!xfade_buf) {
700  }
703  } else {
704  _flags = Flag (_flags & ~Destructive);
705  _timeline_position = 0;
706  /* leave xfade buf alone in case we need it again later */
707  }
708 
709  return true;
710 }
711 
712 void
714 {
715  _capture_start = false;
716  _capture_end = false;
717 }
718 
720 void
722 {
723  if (destructive()) {
724  if (pos < _timeline_position) {
725  _capture_start = false;
726  } else {
727  _capture_start = true;
728  capture_start_frame = pos;
729  }
730  }
731 }
732 
733 void
735 {
736  if (destructive()) {
737  _capture_end = true;
738  }
739 }
740 
743 {
744  framecnt_t xfade = min (xfade_frames, cnt);
745  framecnt_t nofade = cnt - xfade;
746  Sample* fade_data = 0;
747  framepos_t fade_position = 0; // in frames
748  ssize_t retval;
749  framecnt_t file_cnt;
750 
751  if (fade_in) {
752  fade_position = file_pos;
753  fade_data = data;
754  } else {
755  fade_position = file_pos + nofade;
756  fade_data = data + nofade;
757  }
758 
759  if (fade_position > _length) {
760 
761  /* read starts beyond end of data, just memset to zero */
762 
763  file_cnt = 0;
764 
765  } else if (fade_position + xfade > _length) {
766 
767  /* read ends beyond end of data, read some, memset the rest */
768 
769  file_cnt = _length - fade_position;
770 
771  } else {
772 
773  /* read is entirely within data */
774 
775  file_cnt = xfade;
776  }
777 
778  if (file_cnt) {
779 
780  if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
781  if (retval >= 0 && errno == EAGAIN) {
782  /* XXX - can we really trust that errno is meaningful here? yes POSIX, i'm talking to you.
783  * short or no data there */
784  memset (xfade_buf, 0, xfade * sizeof(Sample));
785  } else {
786  error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
787  return 0;
788  }
789  }
790  }
791 
792  if (file_cnt != xfade) {
793  framecnt_t delta = xfade - file_cnt;
794  memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
795  }
796 
797  if (nofade && !fade_in) {
798  if (write_float (data, file_pos, nofade) != nofade) {
799  error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
800  return 0;
801  }
802  }
803 
804  if (xfade == xfade_frames) {
805 
806  framecnt_t n;
807 
808  /* use the standard xfade curve */
809 
810  if (fade_in) {
811 
812  /* fade new material in */
813 
814  for (n = 0; n < xfade; ++n) {
815  xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
816  }
817 
818  } else {
819 
820 
821  /* fade new material out */
822 
823  for (n = 0; n < xfade; ++n) {
824  xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
825  }
826  }
827 
828  } else if (xfade < xfade_frames) {
829 
830  std::vector<gain_t> in(xfade);
831  std::vector<gain_t> out(xfade);
832 
833  /* short xfade, compute custom curve */
834 
835  compute_equal_power_fades (xfade, &in[0], &out[0]);
836 
837  for (framecnt_t n = 0; n < xfade; ++n) {
838  xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
839  }
840 
841  } else if (xfade) {
842 
843  /* long xfade length, has to be computed across several calls */
844 
845  }
846 
847  if (xfade) {
848  if (write_float (xfade_buf, fade_position, xfade) != xfade) {
849  error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
850  return 0;
851  }
852  }
853 
854  if (fade_in && nofade) {
855  if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
856  error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
857  return 0;
858  }
859  }
860 
861  return cnt;
862 }
863 
866 {
867  if (destructive()) {
868  return capture_start_frame;
869  } else {
870  return 0;
871  }
872 }
873 
874 void
876 {
877  if (destructive()) {
878  if ( _length != 0 ) {
879  error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
880  //in the future, pop up a dialog here that allows user to regenerate file with new start offset
881  } else if (writable()) {
883  set_header_timeline_position (); //this will get flushed if/when the file is recorded to
884  }
885  }
886 }
887 
888 void
890 {
891  /* This static method is assumed to have been called by the Session
892  before any DFS's are created.
893  */
894 
895  xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
896 
897  delete [] out_coefficient;
898  delete [] in_coefficient;
899 
902 
904 }
905 
906 void
908 {
909  // destructive track timeline postion does not change
910  // except at instantion or when header_position_offset
911  // (session start) changes
912 
913  if (!destructive()) {
915  }
916 }
917 
918 int
919 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
920 {
921  SNDFILE *sf;
922  SF_INFO sf_info;
923  BroadcastInfo binfo;
924 
925  sf_info.format = 0; // libsndfile says to clear this before sf_open().
926 
927  if ((sf = sf_open (const_cast<char*>(path.c_str()), SFM_READ, &sf_info)) == 0) {
928  char errbuf[256];
929  error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
930  return false;
931  }
932 
933  info.samplerate = sf_info.samplerate;
934  info.channels = sf_info.channels;
935  info.length = sf_info.frames;
936 
937  string major = sndfile_major_format(sf_info.format);
938  string minor = sndfile_minor_format(sf_info.format);
939 
940  if (major.length() + minor.length() < 16) { /* arbitrary */
941  info.format_name = string_compose("%1/%2", major, minor);
942  } else {
943  info.format_name = string_compose("%1\n%2", major, minor);
944  }
945 
946  info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
947 
948  sf_close (sf);
949 
950  return true;
951 }
952 
953 bool
955 {
956  return _info.channels > 1;
957 }
958 
959 bool
961 {
962  int const type = _info.format & SF_FORMAT_TYPEMASK;
963  int const sub = _info.format & SF_FORMAT_SUBMASK;
964  /* XXX: this may not be the full list of formats that are unclamped */
965  return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
966 }
967 
968 void
970 {
971  /* stupid libsndfile updated the headers on close,
972  so touch the peakfile if it exists and has data
973  to make sure its time is as new as the audio
974  file.
975  */
976 
977  touch_peakfile ();
978 }
979 
980 void
981 SndFileSource::set_path (const string& p)
982 {
984 }
985 
Flag _flags
Definition: source.h:119
HeaderFormat
Definition: types.h:475
bool set_destructive(bool yn)
static int get_soundfile_info(const std::string &path, SoundFileInfo &_info, std::string &error_msg)
ARDOUR::Session & _session
LIBPBD_API Transmitter fatal
framecnt_t write_unlocked(Sample *dst, framecnt_t cnt)
void set_from_session(Session const &session, int64_t time_ref)
framecnt_t _length
Definition: audiosource.h:127
LIBARDOUR_API void compute_equal_power_fades(ARDOUR::framecnt_t nframes, float *in, float *out)
Definition: utils.cc:394
static bool _build_peakfiles
Definition: audiosource.h:110
std::string sndfile_minor_format(int)
std::string sndfile_major_format(int)
static gain_t * out_coefficient
static framecnt_t header_position_offset
static framecnt_t xfade_frames
Definition: sndfilesource.h:99
void set_originator_ref_from_session(Session const &)
T const & val() const
Definition: properties.h:96
static void setup_standard_crossfades(Session const &, framecnt_t sample_rate)
DataType type()
Definition: source.h:61
SndFileSource(Session &, const std::string &path, int chn, Flag flags)
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
framepos_t _timeline_position
Definition: source.h:121
float gain_t
Definition: types.h:58
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
SessionConfiguration config
Definition: session.h:866
framecnt_t write_float(Sample *data, framepos_t pos, framecnt_t cnt)
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
bool clamped_at_unity() const
#define origin
framepos_t last_capture_start_frame() const
void set_timeline_position(framepos_t)
#define _(Text)
Definition: i18n.h:11
void update_length(framecnt_t cnt)
Definition: audiosource.cc:167
bool destructive() const
Definition: source.h:82
virtual void set_timeline_position(framepos_t pos)
Definition: source.cc:264
#define X_(Text)
Definition: i18n.h:13
static gain_t * in_coefficient
int64_t framecnt_t
Definition: types.h:76
framecnt_t crossfade(Sample *data, framecnt_t cnt, int dir)
static PBD::Signal0< void > HeaderPositionOffsetChanged
float Sample
Definition: types.h:54
bool one_of_several_channels() const
framecnt_t destructive_write_unlocked(Sample *dst, framecnt_t cnt)
Definition: amp.h:29
LIBARDOUR_API PBD::PropertyDescriptor< boost::shared_ptr< AutomationList > > fade_in
Definition: audioregion.cc:67
framepos_t capture_start_frame
framecnt_t nondestructive_write_unlocked(Sample *dst, framecnt_t cnt)
std::string _path
Definition: file_source.h:107
void set_path(const std::string &p)
int64_t framepos_t
Definition: types.h:66
int setup_broadcast_info(framepos_t when, struct tm &, time_t)
PBD::Property< std::string > _name
LIBPBD_API Transmitter info
static Sample * get_interleave_buffer(framecnt_t size)
void handle_header_position_change()
void mark_capture_start(framepos_t)
Writable
Definition: selectable.h:36
SampleFormat
Definition: types.h:460
framepos_t natural_position() const
Definition: xml++.h:95
int update_header(framepos_t when, struct tm &, time_t)
Definition: debug.h:30
virtual void set_path(const std::string &)
Definition: file_source.cc:545
bool writable() const
Definition: source.cc:305
float sample_rate() const
BroadcastInfo * _broadcast_info
Definition: sndfilesource.h:90
int compute_and_write_peaks(Sample *buf, framecnt_t first_frame, framecnt_t cnt, bool force, bool intermediate_peaks_ready_signal)
Definition: audiosource.cc:766
PBD::ScopedConnection header_position_connection
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
framecnt_t read_unlocked(Sample *dst, framepos_t start, framecnt_t cnt) const