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