Remove the source files which got transferred to libpbd
[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
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 (
53                 Source::Writable |
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
78 /** Constructor for existing external-to-session files.
79     Files created this way are never writable or removable 
80 */
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
104 /** This constructor is used to construct new internal-to-session files, 
105     not open existing ones. 
106 */
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 write_unlocked() as needed
184                  */
185         }
186 }
187
188 /** Constructor to be called for recovering files being used for
189  * capture. They are in-session, they already exist, they should not
190  * be writable. They are an odd hybrid (from a constructor point of
191  * view) of the previous two constructors.
192  */
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
217 SndFileSource::init_sndfile ()
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()) {
226                 xfade_buf = new Sample[xfade_frames];
227                 _timeline_position = header_position_offset;
228         }
229
230         AudioFileSource::HeaderPositionOffsetChanged.connect_same_thread (header_position_connection, boost::bind (&SndFileSource::handle_header_position_change, this));
231 }
232
233 int
234 SndFileSource::open ()
235 {
236         string path_to_open;
237
238         if (_sndfile) {
239                 return 0;
240         }
241         
242 #ifdef PLATFORM_WINDOWS
243         path_to_open = Glib::locale_from_utf8(_path);
244 #else
245         path_to_open = _path;
246 #endif
247
248         _sndfile = sf_open (path_to_open.c_str(), writable() ? SFM_RDWR : SFM_READ, &_info);
249
250         if (_sndfile == 0) {
251                 char errbuf[1024];
252                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
253 #ifndef HAVE_COREAUDIO
254                 /* if we have CoreAudio, we will be falling back to that if libsndfile fails,
255                    so we don't want to see this message.
256                 */
257
258                 cerr << "failed to open " << path_to_open << " with name " << _name << endl;
259
260                 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"),
261                                         path_to_open, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
262 #endif
263                 return -1;
264         }
265
266         if (_channel >= _info.channels) {
267 #ifndef HAVE_COREAUDIO
268                 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
269 #endif
270                 sf_close (_sndfile);
271                 _sndfile = 0;
272                 return -1;
273         }
274
275         _length = _info.frames;
276
277         if (!_broadcast_info) {
278                 _broadcast_info = new BroadcastInfo;
279         }
280
281         bool bwf_info_exists = _broadcast_info->load_from_file (_sndfile);
282
283         if (_file_is_new && _length == 0 && writable() && !bwf_info_exists) {
284                 /* newly created files will not have a BWF header at this point in time.
285                  * Import will have called Source::set_timeline_position() if one exists
286                  * in the original. */
287                 header_position_offset = _timeline_position;
288         }
289
290         /* Set our timeline position to either the time reference from a BWF header or the current
291            start of the session.
292         */
293         set_timeline_position (bwf_info_exists ? _broadcast_info->get_time_reference() : header_position_offset);
294
295         if (_length != 0 && !bwf_info_exists) {
296                 delete _broadcast_info;
297                 _broadcast_info = 0;
298                 _flags = Flag (_flags & ~Broadcast);
299         } 
300
301         /* Set the broadcast flag if the BWF info is already there. We need
302          * this when recovering or using existing files.
303          */
304         
305         if (bwf_info_exists) {
306                 _flags = Flag (_flags | Broadcast);
307         }
308
309         if (writable()) {
310                 sf_command (_sndfile, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
311
312                 if (_flags & Broadcast) {
313
314                         if (!_broadcast_info) {
315                                 _broadcast_info = new BroadcastInfo;
316                         }
317
318                         _broadcast_info->set_from_session (_session, header_position_offset);
319                         _broadcast_info->set_description (string_compose ("BWF %1", _name));
320
321                         if (!_broadcast_info->write_to_file (_sndfile)) {
322                                 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
323                                                          path_to_open, _broadcast_info->get_error())
324                                       << endmsg;
325                                 _flags = Flag (_flags & ~Broadcast);
326                                 delete _broadcast_info;
327                                 _broadcast_info = 0;
328                         }
329                 }
330         }
331         
332         return 0;
333 }
334
335 SndFileSource::~SndFileSource ()
336 {
337         if (_sndfile) {
338                 sf_close (_sndfile);
339                 _sndfile = 0;
340         }
341         delete _broadcast_info;
342         delete [] xfade_buf;
343 }
344
345 float
346 SndFileSource::sample_rate () const
347 {
348         return _info.samplerate;
349 }
350
351 framecnt_t
352 SndFileSource::read_unlocked (Sample *dst, framepos_t start, framecnt_t cnt) const
353 {
354         assert (cnt >= 0);
355         
356         int32_t nread;
357         float *ptr;
358         uint32_t real_cnt;
359         framepos_t file_cnt;
360
361         if (writable() && !_sndfile) {
362                 /* file has not been opened yet - nothing written to it */
363                 memset (dst, 0, sizeof (Sample) * cnt);
364                 return cnt;
365         }
366
367         if (_sndfile == 0) {
368                 error << string_compose (_("could not allocate file %1 for reading."), _path) << endmsg;
369                 return 0;
370         }
371
372         if (start > _length) {
373
374                 /* read starts beyond end of data, just memset to zero */
375
376                 file_cnt = 0;
377
378         } else if (start + cnt > _length) {
379
380                 /* read ends beyond end of data, read some, memset the rest */
381
382                 file_cnt = _length - start;
383
384         } else {
385
386                 /* read is entirely within data */
387
388                 file_cnt = cnt;
389         }
390
391         assert (file_cnt >= 0);
392
393         if (file_cnt != cnt) {
394                 framepos_t delta = cnt - file_cnt;
395                 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
396         }
397
398         if (file_cnt) {
399
400                 if (sf_seek (_sndfile, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
401                         char errbuf[256];
402                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
403                         error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.val().substr (1), errbuf) << endmsg;
404                         return 0;
405                 }
406
407                 if (_info.channels == 1) {
408                         framecnt_t ret = sf_read_float (_sndfile, dst, file_cnt);
409                         if (ret != file_cnt) {
410                                 char errbuf[256];
411                                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
412                                 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;
413                         }
414                         return ret;
415                 }
416         }
417
418         real_cnt = cnt * _info.channels;
419
420         Sample* interleave_buf = get_interleave_buffer (real_cnt);
421
422         nread = sf_read_float (_sndfile, interleave_buf, real_cnt);
423         ptr = interleave_buf + _channel;
424         nread /= _info.channels;
425
426         /* stride through the interleaved data */
427
428         for (int32_t n = 0; n < nread; ++n) {
429                 dst[n] = *ptr;
430                 ptr += _info.channels;
431         }
432
433         return nread;
434 }
435
436 framecnt_t
437 SndFileSource::write_unlocked (Sample *data, framecnt_t cnt)
438 {
439         if (open()) {
440                 return 0; // failure
441         }
442
443         if (destructive()) {
444                 return destructive_write_unlocked (data, cnt);
445         } else {
446                 return nondestructive_write_unlocked (data, cnt);
447         }
448 }
449
450 framecnt_t
451 SndFileSource::nondestructive_write_unlocked (Sample *data, framecnt_t cnt)
452 {
453         if (!writable()) {
454                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
455                 return 0;
456         }
457
458         if (_info.channels != 1) {
459                 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
460                 abort(); /*NOTREACHED*/
461                 return 0;
462         }
463
464         int32_t frame_pos = _length;
465
466         if (write_float (data, frame_pos, cnt) != cnt) {
467                 return 0;
468         }
469
470         update_length (_length + cnt);
471
472         if (_build_peakfiles) {
473                 compute_and_write_peaks (data, frame_pos, cnt, false, true);
474         }
475
476         return cnt;
477 }
478
479 framecnt_t
480 SndFileSource::destructive_write_unlocked (Sample* data, framecnt_t cnt)
481 {
482         if (!writable()) {
483                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
484                 return 0;
485         }
486
487         if (_capture_start && _capture_end) {
488
489                 /* start and end of capture both occur within the data we are writing,
490                    so do both crossfades.
491                 */
492
493                 _capture_start = false;
494                 _capture_end = false;
495
496                 /* move to the correct location place */
497                 file_pos = capture_start_frame - _timeline_position;
498
499                 // split cnt in half
500                 framecnt_t subcnt = cnt / 2;
501                 framecnt_t ofilepos = file_pos;
502
503                 // fade in
504                 if (crossfade (data, subcnt, 1) != subcnt) {
505                         return 0;
506                 }
507
508                 file_pos += subcnt;
509                 Sample * tmpdata = data + subcnt;
510
511                 // fade out
512                 subcnt = cnt - subcnt;
513                 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
514                         return 0;
515                 }
516
517                 file_pos = ofilepos; // adjusted below
518
519         } else if (_capture_start) {
520
521                 /* start of capture both occur within the data we are writing,
522                    so do the fade in
523                 */
524
525                 _capture_start = false;
526                 _capture_end = false;
527
528                 /* move to the correct location place */
529                 file_pos = capture_start_frame - _timeline_position;
530
531                 if (crossfade (data, cnt, 1) != cnt) {
532                         return 0;
533                 }
534
535         } else if (_capture_end) {
536
537                 /* end of capture both occur within the data we are writing,
538                    so do the fade out
539                 */
540
541                 _capture_start = false;
542                 _capture_end = false;
543
544                 if (crossfade (data, cnt, 0) != cnt) {
545                         return 0;
546                 }
547
548         } else {
549
550                 /* in the middle of recording */
551
552                 if (write_float (data, file_pos, cnt) != cnt) {
553                         return 0;
554                 }
555         }
556
557         update_length (file_pos + cnt);
558
559         if (_build_peakfiles) {
560                 compute_and_write_peaks (data, file_pos, cnt, false, true);
561         }
562
563         file_pos += cnt;
564
565         return cnt;
566 }
567
568 int
569 SndFileSource::update_header (framepos_t when, struct tm& now, time_t tnow)
570 {
571         set_timeline_position (when);
572
573         if (_flags & Broadcast) {
574                 if (setup_broadcast_info (when, now, tnow)) {
575                         return -1;
576                 }
577         }
578
579         return flush_header ();
580 }
581
582 int
583 SndFileSource::flush_header ()
584 {
585         if (!writable()) {
586                 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
587                 return -1;
588         }
589
590         if (_sndfile == 0) {
591                 error << string_compose (_("could not allocate file %1 to write header"), _path) << endmsg;
592                 return -1;
593         }
594
595         int const r = sf_command (_sndfile, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE;
596
597         return r;
598 }
599
600 void
601 SndFileSource::flush ()
602 {
603         if (!writable()) {
604                 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
605                 return;
606         }
607
608         if (_sndfile == 0) {
609                 error << string_compose (_("could not allocate file %1 to flush contents"), _path) << endmsg;
610                 return;
611         }
612
613         // Hopefully everything OK
614         sf_write_sync (_sndfile);
615 }
616
617 int
618 SndFileSource::setup_broadcast_info (framepos_t /*when*/, struct tm& now, time_t /*tnow*/)
619 {
620         if (!writable()) {
621                 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
622                 return -1;
623         }
624
625         if (!_sndfile) {
626                 warning << string_compose (_("attempt to set BWF info for an un-opened audio file source (%1)"), _path) << endmsg;
627                 return -1;
628         }
629
630         if (!(_flags & Broadcast) || !_broadcast_info) {
631                 return 0;
632         }
633
634         _broadcast_info->set_originator_ref_from_session (_session);
635         _broadcast_info->set_origination_time (&now);
636
637         /* now update header position taking header offset into account */
638
639         set_header_timeline_position ();
640
641         if (!_broadcast_info->write_to_file (_sndfile)) {
642                 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
643                                            _path, _broadcast_info->get_error())
644                       << endmsg;
645                 _flags = Flag (_flags & ~Broadcast);
646                 delete _broadcast_info;
647                 _broadcast_info = 0;
648         }
649
650         return 0;
651 }
652
653 void
654 SndFileSource::set_header_timeline_position ()
655 {
656         if (!(_flags & Broadcast)) {
657                 return;
658         }
659
660         _broadcast_info->set_time_reference (_timeline_position);
661
662         if (_sndfile == 0 || !_broadcast_info->write_to_file (_sndfile)) {
663                 error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"),
664                                            _path, _broadcast_info->get_error())
665                       << endmsg;
666                 _flags = Flag (_flags & ~Broadcast);
667                 delete _broadcast_info;
668                 _broadcast_info = 0;
669         }
670 }
671
672 framecnt_t
673 SndFileSource::write_float (Sample* data, framepos_t frame_pos, framecnt_t cnt)
674 {
675         if (_sndfile == 0 || sf_seek (_sndfile, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
676                 char errbuf[256];
677                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
678                 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3)"), _path, frame_pos, errbuf) << endmsg;
679                 return 0;
680         }
681
682         if (sf_writef_float (_sndfile, data, cnt) != (ssize_t) cnt) {
683                 return 0;
684         }
685
686         return cnt;
687 }
688
689 framepos_t
690 SndFileSource::natural_position() const
691 {
692         return _timeline_position;
693 }
694
695 bool
696 SndFileSource::set_destructive (bool yn)
697 {
698         if (yn) {
699                 _flags = Flag (_flags | Writable | Destructive);
700                 if (!xfade_buf) {
701                         xfade_buf = new Sample[xfade_frames];
702                 }
703                 clear_capture_marks ();
704                 _timeline_position = header_position_offset;
705         } else {
706                 _flags = Flag (_flags & ~Destructive);
707                 _timeline_position = 0;
708                 /* leave xfade buf alone in case we need it again later */
709         }
710
711         return true;
712 }
713
714 void
715 SndFileSource::clear_capture_marks ()
716 {
717         _capture_start = false;
718         _capture_end = false;
719 }
720
721 /** @param pos Capture start position in session frames */
722 void
723 SndFileSource::mark_capture_start (framepos_t pos)
724 {
725         if (destructive()) {
726                 if (pos < _timeline_position) {
727                         _capture_start = false;
728                 } else {
729                         _capture_start = true;
730                         capture_start_frame = pos;
731                 }
732         }
733 }
734
735 void
736 SndFileSource::mark_capture_end()
737 {
738         if (destructive()) {
739                 _capture_end = true;
740         }
741 }
742
743 framecnt_t
744 SndFileSource::crossfade (Sample* data, framecnt_t cnt, int fade_in)
745 {
746         framecnt_t xfade = min (xfade_frames, cnt);
747         framecnt_t nofade = cnt - xfade;
748         Sample* fade_data = 0;
749         framepos_t fade_position = 0; // in frames
750         ssize_t retval;
751         framecnt_t file_cnt;
752
753         if (fade_in) {
754                 fade_position = file_pos;
755                 fade_data = data;
756         } else {
757                 fade_position = file_pos + nofade;
758                 fade_data = data + nofade;
759         }
760
761         if (fade_position > _length) {
762
763                 /* read starts beyond end of data, just memset to zero */
764
765                 file_cnt = 0;
766
767         } else if (fade_position + xfade > _length) {
768
769                 /* read ends beyond end of data, read some, memset the rest */
770
771                 file_cnt = _length - fade_position;
772
773         } else {
774
775                 /* read is entirely within data */
776
777                 file_cnt = xfade;
778         }
779
780         if (file_cnt) {
781
782                 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
783                         if (retval >= 0 && errno == EAGAIN) {
784                                 /* XXX - can we really trust that errno is meaningful here?  yes POSIX, i'm talking to you.
785                                  * short or no data there */
786                                 memset (xfade_buf, 0, xfade * sizeof(Sample));
787                         } else {
788                                 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
789                                 return 0;
790                         }
791                 }
792         }
793
794         if (file_cnt != xfade) {
795                 framecnt_t delta = xfade - file_cnt;
796                 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
797         }
798
799         if (nofade && !fade_in) {
800                 if (write_float (data, file_pos, nofade) != nofade) {
801                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
802                         return 0;
803                 }
804         }
805
806         if (xfade == xfade_frames) {
807
808                 framecnt_t n;
809
810                 /* use the standard xfade curve */
811
812                 if (fade_in) {
813
814                         /* fade new material in */
815
816                         for (n = 0; n < xfade; ++n) {
817                                 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
818                         }
819
820                 } else {
821
822
823                         /* fade new material out */
824
825                         for (n = 0; n < xfade; ++n) {
826                                 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
827                         }
828                 }
829
830         } else if (xfade < xfade_frames) {
831
832                 std::vector<gain_t> in(xfade);
833                 std::vector<gain_t> out(xfade);
834
835                 /* short xfade, compute custom curve */
836
837                 compute_equal_power_fades (xfade, &in[0], &out[0]);
838
839                 for (framecnt_t n = 0; n < xfade; ++n) {
840                         xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);
841                 }
842
843         } else if (xfade) {
844
845                 /* long xfade length, has to be computed across several calls */
846
847         }
848
849         if (xfade) {
850                 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
851                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
852                         return 0;
853                 }
854         }
855
856         if (fade_in && nofade) {
857                 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
858                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
859                         return 0;
860                 }
861         }
862
863         return cnt;
864 }
865
866 framepos_t
867 SndFileSource::last_capture_start_frame () const
868 {
869         if (destructive()) {
870                 return capture_start_frame;
871         } else {
872                 return 0;
873         }
874 }
875
876 void
877 SndFileSource::handle_header_position_change ()
878 {
879         if (destructive()) {
880                 if ( _length != 0 ) {
881                         error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
882                         //in the future, pop up a dialog here that allows user to regenerate file with new start offset
883                 } else if (writable()) {
884                         _timeline_position = header_position_offset;
885                         set_header_timeline_position ();  //this will get flushed if/when the file is recorded to
886                 }
887         }
888 }
889
890 void
891 SndFileSource::setup_standard_crossfades (Session const & s, framecnt_t rate)
892 {
893         /* This static method is assumed to have been called by the Session
894            before any DFS's are created.
895         */
896
897         xfade_frames = (framecnt_t) floor ((s.config.get_destructive_xfade_msecs () / 1000.0) * rate);
898
899         delete [] out_coefficient;
900         delete [] in_coefficient;
901
902         out_coefficient = new gain_t[xfade_frames];
903         in_coefficient = new gain_t[xfade_frames];
904
905         compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
906 }
907
908 void
909 SndFileSource::set_timeline_position (framepos_t pos)
910 {
911         // destructive track timeline postion does not change
912         // except at instantion or when header_position_offset
913         // (session start) changes
914
915         if (!destructive()) {
916                 AudioFileSource::set_timeline_position (pos);
917         }
918 }
919
920 int
921 SndFileSource::get_soundfile_info (const string& path, SoundFileInfo& info, string& error_msg)
922 {
923         SNDFILE *sf;
924         SF_INFO sf_info;
925         BroadcastInfo binfo;
926
927         sf_info.format = 0; // libsndfile says to clear this before sf_open().
928
929         if ((sf = sf_open (const_cast<char*>(path.c_str()), SFM_READ, &sf_info)) == 0) {
930                 char errbuf[256];
931                 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
932                 return false;
933         }
934
935         info.samplerate  = sf_info.samplerate;
936         info.channels    = sf_info.channels;
937         info.length      = sf_info.frames;
938
939         string major = sndfile_major_format(sf_info.format);
940         string minor = sndfile_minor_format(sf_info.format);
941
942         if (major.length() + minor.length() < 16) { /* arbitrary */
943                 info.format_name = string_compose("%1/%2", major, minor);
944         } else {
945                 info.format_name = string_compose("%1\n%2", major, minor);
946         }
947
948         info.timecode = binfo.load_from_file (sf) ? binfo.get_time_reference() : 0;
949
950         sf_close (sf);
951
952         return true;
953 }
954
955 bool
956 SndFileSource::one_of_several_channels () const
957 {
958         return _info.channels > 1;
959 }
960
961 bool
962 SndFileSource::clamped_at_unity () const
963 {
964         int const type = _info.format & SF_FORMAT_TYPEMASK;
965         int const sub = _info.format & SF_FORMAT_SUBMASK;
966         /* XXX: this may not be the full list of formats that are unclamped */
967         return (sub != SF_FORMAT_FLOAT && sub != SF_FORMAT_DOUBLE && type != SF_FORMAT_OGG);
968 }
969
970 void
971 SndFileSource::file_closed ()
972 {
973         /* stupid libsndfile updated the headers on close,
974            so touch the peakfile if it exists and has data
975            to make sure its time is as new as the audio
976            file.
977         */
978
979         touch_peakfile ();
980 }
981
982 void
983 SndFileSource::set_path (const string& p)
984 {
985         FileSource::set_path (p);
986 }
987