merge from 2.0-ongoing by hand, minus key binding editor
[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 #include <cerrno>
21 #include <climits>
22
23 #include <pwd.h>
24 #include <sys/utsname.h>
25 #include <sys/stat.h>
26
27 #include <glibmm/miscutils.h>
28 #include <glibmm/thread.h>
29 #include <ardour/sndfilesource.h>
30 #include <ardour/sndfile_helpers.h>
31 #include <ardour/utils.h>
32
33 #include "i18n.h"
34
35 using namespace std;
36 using namespace ARDOUR;
37 using namespace PBD;
38 using Glib::ustring;
39
40 gain_t* SndFileSource::out_coefficient = 0;
41 gain_t* SndFileSource::in_coefficient = 0;
42 nframes_t SndFileSource::xfade_frames = 64;
43 const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSource::Flag (AudioFileSource::Writable|
44                                                                                            AudioFileSource::Removable|
45                                                                                            AudioFileSource::RemovableIfEmpty|
46                                                                                            AudioFileSource::CanRename);
47
48 struct SizedSampleBuffer {
49     nframes_t size;
50     Sample* buf;
51
52     SizedSampleBuffer (nframes_t sz) : size (sz) { 
53             buf = new Sample[size];
54     }
55
56     ~SizedSampleBuffer() {
57             delete [] buf;
58     }
59 };
60
61 Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
62
63 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
64         : AudioFileSource (s, node)
65 {
66         init ();
67
68         if (open()) {
69                 throw failed_constructor ();
70         }
71 }
72
73 SndFileSource::SndFileSource (Session& s, ustring path, int chn, Flag flags)
74           /* files created this way are never writable or removable */
75         : AudioFileSource (s, path, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
76 {
77         _channel = chn;
78
79         init ();
80
81         if (open()) {
82                 throw failed_constructor ();
83         }
84 }
85
86 SndFileSource::SndFileSource (Session& s, ustring path, SampleFormat sfmt, HeaderFormat hf, nframes_t rate, Flag flags)
87         : AudioFileSource (s, path, flags, sfmt, hf)
88 {
89         int fmt = 0;
90
91         init ();
92
93         /* this constructor is used to construct new files, not open
94            existing ones.
95         */
96
97         file_is_new = true;
98         
99         switch (hf) {
100         case CAF:
101                 fmt = SF_FORMAT_CAF;
102                 _flags = Flag (_flags & ~Broadcast);
103                 break;
104
105         case AIFF:
106                 fmt = SF_FORMAT_AIFF;
107                 _flags = Flag (_flags & ~Broadcast);
108                 break;
109
110         case BWF:
111                 fmt = SF_FORMAT_WAV;
112                 _flags = Flag (_flags | Broadcast);
113                 break;
114
115         case WAVE:
116                 fmt = SF_FORMAT_WAV;
117                 _flags = Flag (_flags & ~Broadcast);
118                 break;
119
120         case WAVE64:
121                 fmt = SF_FORMAT_W64;
122                 _flags = Flag (_flags & ~Broadcast);
123                 break;
124
125         default:
126                 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
127                 /*NOTREACHED*/
128                 break;
129
130         }
131
132         switch (sfmt) {
133         case FormatFloat:
134                 fmt |= SF_FORMAT_FLOAT;
135                 break;
136
137         case FormatInt24:
138                 fmt |= SF_FORMAT_PCM_24;
139                 break;
140
141         case FormatInt16:
142                 fmt |= SF_FORMAT_PCM_16;
143                 break;
144         }
145         
146         _info.channels = 1;
147         _info.samplerate = rate;
148         _info.format = fmt;
149
150         if (open()) {
151                 throw failed_constructor();
152         }
153
154         if (writable() && (_flags & Broadcast)) {
155
156                 _broadcast_info = new SF_BROADCAST_INFO;
157                 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
158                 
159                 snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
160                 
161                 struct utsname utsinfo;
162
163                 if (uname (&utsinfo)) {
164                         error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg;
165                         return;
166                 }
167                 
168                 snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)", 
169                           Glib::get_real_name().c_str(),
170                           utsinfo.nodename,
171                           utsinfo.sysname,
172                           utsinfo.release,
173                           utsinfo.version);
174                 
175                 _broadcast_info->version = 1;  
176                 _broadcast_info->time_reference_low = 0;  
177                 _broadcast_info->time_reference_high = 0;  
178                 
179                 /* XXX do something about this field */
180                 
181                 snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
182                 
183                 /* coding history is added by libsndfile */
184
185                 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
186                         char errbuf[256];
187                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
188                         error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
189                         _flags = Flag (_flags & ~Broadcast);
190                         delete _broadcast_info;
191                         _broadcast_info = 0;
192                 }
193                 
194         }
195 }
196
197 void 
198 SndFileSource::init ()
199 {
200         ustring file;
201
202         // lets try to keep the object initalizations here at the top
203         xfade_buf = 0;
204         sf = 0;
205         _broadcast_info = 0;
206
207         if (is_embedded()) {
208                 _name = _path;
209         } else {
210                 _name = Glib::path_get_basename (_path);
211         }
212
213         /* although libsndfile says we don't need to set this,
214            valgrind and source code shows us that we do.
215         */
216
217         memset (&_info, 0, sizeof(_info));
218
219         _capture_start = false;
220         _capture_end = false;
221         file_pos = 0;
222
223         if (destructive()) {    
224                 xfade_buf = new Sample[xfade_frames];
225                 timeline_position = header_position_offset;
226         }
227
228         AudioFileSource::HeaderPositionOffsetChanged.connect (mem_fun (*this, &SndFileSource::handle_header_position_change));
229 }
230
231 int
232 SndFileSource::open ()
233 {
234         if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
235                 char errbuf[256];
236                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
237                 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"), 
238                                         _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
239                 return -1;
240         }
241
242         if (_channel >= _info.channels) {
243                 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, _channel) << endmsg;
244                 sf_close (sf);
245                 sf = 0;
246                 return -1;
247         }
248
249         _length = _info.frames;
250
251         _broadcast_info = new SF_BROADCAST_INFO;
252         memset (_broadcast_info, 0, sizeof (*_broadcast_info));
253         
254         bool timecode_info_exists;
255
256         set_timeline_position (get_timecode_info (sf, _broadcast_info, timecode_info_exists));
257
258         if (!timecode_info_exists) {
259                 delete _broadcast_info;
260                 _broadcast_info = 0;
261                 _flags = Flag (_flags & ~Broadcast);
262         }
263
264         if (writable()) {
265                 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
266         }
267
268         return 0;
269 }
270
271 SndFileSource::~SndFileSource ()
272 {
273         GoingAway (); /* EMIT SIGNAL */
274
275         if (sf) {
276                 sf_close (sf);
277                 sf = 0;
278
279                 /* stupid libsndfile updated the headers on close,
280                    so touch the peakfile if it exists and has data
281                    to make sure its time is as new as the audio
282                    file.
283                 */
284
285                 touch_peakfile ();
286         }
287
288         if (_broadcast_info) {
289                 delete _broadcast_info;
290         }
291
292         if (xfade_buf) {
293                 delete [] xfade_buf;
294         }
295 }
296
297 float
298 SndFileSource::sample_rate () const 
299 {
300         return _info.samplerate;
301 }
302
303 nframes_t
304 SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
305 {
306         int32_t nread;
307         float *ptr;
308         uint32_t real_cnt;
309         nframes_t file_cnt;
310
311         if (start > _length) {
312
313                 /* read starts beyond end of data, just memset to zero */
314                 
315                 file_cnt = 0;
316
317         } else if (start + cnt > _length) {
318                 
319                 /* read ends beyond end of data, read some, memset the rest */
320                 
321                 file_cnt = _length - start;
322
323         } else {
324                 
325                 /* read is entirely within data */
326
327                 file_cnt = cnt;
328         }
329         
330         if (file_cnt) {
331
332                 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
333                         char errbuf[256];
334                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
335                         error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
336                         return 0;
337                 }
338                 
339                 if (_info.channels == 1) {
340                         nframes_t ret = sf_read_float (sf, dst, file_cnt);
341                         _read_data_count = cnt * sizeof(float);
342                         return ret;
343                 }
344         }
345
346         if (file_cnt != cnt) {
347                 nframes_t delta = cnt - file_cnt;
348                 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
349         }
350
351         real_cnt = cnt * _info.channels;
352
353         Sample* interleave_buf = get_interleave_buffer (real_cnt);
354         
355         nread = sf_read_float (sf, interleave_buf, real_cnt);
356         ptr = interleave_buf + _channel;
357         nread /= _info.channels;
358         
359         /* stride through the interleaved data */
360         
361         for (int32_t n = 0; n < nread; ++n) {
362                 dst[n] = *ptr;
363                 ptr += _info.channels;
364         }
365
366         _read_data_count = cnt * sizeof(float);
367                 
368         return nread;
369 }
370
371 nframes_t 
372 SndFileSource::write_unlocked (Sample *data, nframes_t cnt)
373 {
374         if (destructive()) {
375                 return destructive_write_unlocked (data, cnt);
376         } else {
377                 return nondestructive_write_unlocked (data, cnt);
378         }
379 }
380
381 nframes_t 
382 SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
383 {
384         if (!writable()) {
385                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
386                 return 0;
387         }
388
389         if (_info.channels != 1) {
390                 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
391                 /*NOTREACHED*/
392                 return 0;
393         }
394         
395         nframes_t oldlen;
396         int32_t frame_pos = _length;
397
398         if (write_float (data, frame_pos, cnt) != cnt) {
399                 return 0;
400         }
401
402         oldlen = _length;
403         update_length (oldlen, cnt);
404
405         if (_build_peakfiles) {
406                 compute_and_write_peaks (data, frame_pos, cnt, false, true);
407         }
408
409         _write_data_count = cnt;
410         
411         return cnt;
412 }
413
414 nframes_t
415 SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
416 {
417         nframes_t old_file_pos;
418
419         if (!writable()) {
420                 warning << string_compose (_("attempt to write a non-writable audio file source (%1)"), _path) << endmsg;
421                 return 0;
422         }
423
424         if (_capture_start && _capture_end) {
425
426                 /* start and end of capture both occur within the data we are writing,
427                    so do both crossfades.
428                 */
429
430                 _capture_start = false;
431                 _capture_end = false;
432                 
433                 /* move to the correct location place */
434                 file_pos = capture_start_frame - timeline_position;
435                 
436                 // split cnt in half
437                 nframes_t subcnt = cnt / 2;
438                 nframes_t ofilepos = file_pos;
439                 
440                 // fade in
441                 if (crossfade (data, subcnt, 1) != subcnt) {
442                         return 0;
443                 }
444                 
445                 file_pos += subcnt;
446                 Sample * tmpdata = data + subcnt;
447                 
448                 // fade out
449                 subcnt = cnt - subcnt;
450                 if (crossfade (tmpdata, subcnt, 0) != subcnt) {
451                         return 0;
452                 }
453                 
454                 file_pos = ofilepos; // adjusted below
455
456         } else if (_capture_start) {
457
458                 /* start of capture both occur within the data we are writing,
459                    so do the fade in
460                 */
461
462                 _capture_start = false;
463                 _capture_end = false;
464                 
465                 /* move to the correct location place */
466                 file_pos = capture_start_frame - timeline_position;
467
468                 if (crossfade (data, cnt, 1) != cnt) {
469                         return 0;
470                 }
471                 
472         } else if (_capture_end) {
473
474                 /* end of capture both occur within the data we are writing,
475                    so do the fade out
476                 */
477
478                 _capture_start = false;
479                 _capture_end = false;
480                 
481                 if (crossfade (data, cnt, 0) != cnt) {
482                         return 0;
483                 }
484
485         } else {
486
487                 /* in the middle of recording */
488
489                 if (write_float (data, file_pos, cnt) != cnt) {
490                         return 0;
491                 }
492         }
493
494         old_file_pos = file_pos;
495         update_length (file_pos, cnt);
496
497         if (_build_peakfiles) {
498                 compute_and_write_peaks (data, file_pos, cnt, false, true);
499         }
500
501         file_pos += cnt;
502         
503         return cnt;
504 }
505
506 int
507 SndFileSource::update_header (nframes_t when, struct tm& now, time_t tnow)
508 {       
509         set_timeline_position (when);
510
511         if (_flags & Broadcast) {
512                 if (setup_broadcast_info (when, now, tnow)) {
513                         return -1;
514                 }
515         } 
516
517         return flush_header ();
518 }
519
520 int
521 SndFileSource::flush_header ()
522 {
523         if (!writable() || (sf == 0)) {
524                 warning << string_compose (_("attempt to flush a non-writable audio file source (%1)"), _path) << endmsg;
525                 return -1;
526         }
527         return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
528 }
529
530 int
531 SndFileSource::setup_broadcast_info (nframes_t when, struct tm& now, time_t tnow)
532 {
533         if (!writable()) {
534                 warning << string_compose (_("attempt to store broadcast info in a non-writable audio file source (%1)"), _path) << endmsg;
535                 return -1;
536         }
537
538         if (!(_flags & Broadcast)) {
539                 return 0;
540         }
541
542         /* random code is 9 digits */
543         
544         int random_code = random() % 999999999;
545         
546         snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
547                   Config->get_bwf_country_code().c_str(),
548                   Config->get_bwf_organization_code().c_str(),
549                   bwf_serial_number,
550                   now.tm_hour,
551                   now.tm_min,
552                   now.tm_sec,
553                   random_code);
554         
555         snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
556                   1900 + now.tm_year,
557                   now.tm_mon,
558                   now.tm_mday);
559         
560         snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
561                   now.tm_hour,
562                   now.tm_min,
563                   now.tm_sec);
564
565         /* now update header position taking header offset into account */
566         
567         set_header_timeline_position ();
568
569         if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
570                 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
571                 _flags = Flag (_flags & ~Broadcast);
572                 delete _broadcast_info;
573                 _broadcast_info = 0;
574                 return -1;
575         }
576
577         return 0;
578 }
579
580 void
581 SndFileSource::set_header_timeline_position ()
582 {
583         if (!(_flags & Broadcast)) {
584                 return;
585         }
586
587         _broadcast_info->time_reference_high = (timeline_position >> 32);
588         _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
589
590         if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
591                 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
592                 _flags = Flag (_flags & ~Broadcast);
593                 delete _broadcast_info;
594                 _broadcast_info = 0;
595         }
596 }
597
598 nframes_t
599 SndFileSource::write_float (Sample* data, nframes_t frame_pos, nframes_t cnt)
600 {
601         if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) < 0) {
602                 char errbuf[256];
603                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
604                 error << string_compose (_("%1: cannot seek to %2 (libsndfile error: %3"), _path, frame_pos, errbuf) << endmsg;
605                 return 0;
606         }
607         
608         if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
609                 return 0;
610         }
611         
612         return cnt;
613 }
614
615 nframes_t
616 SndFileSource::natural_position() const
617 {
618         return timeline_position;
619 }
620
621 bool
622 SndFileSource::set_destructive (bool yn)
623 {
624         if (yn) {
625                 _flags = Flag (_flags | Destructive);
626                 if (!xfade_buf) {
627                         xfade_buf = new Sample[xfade_frames];
628                 }
629                 clear_capture_marks ();
630                 timeline_position = header_position_offset;
631         } else {
632                 _flags = Flag (_flags & ~Destructive);
633                 timeline_position = 0;
634                 /* leave xfade buf alone in case we need it again later */
635         }
636
637         return true;
638 }
639
640 void
641 SndFileSource::clear_capture_marks ()
642 {
643         _capture_start = false;
644         _capture_end = false;
645 }       
646
647 void
648 SndFileSource::mark_capture_start (nframes_t pos)
649 {
650         if (destructive()) {
651                 if (pos < timeline_position) {
652                         _capture_start = false;
653                 } else {
654                         _capture_start = true;
655                         capture_start_frame = pos;
656                 }
657         }
658 }
659
660 void
661 SndFileSource::mark_capture_end()
662 {
663         if (destructive()) {
664                 _capture_end = true;
665         }
666 }
667
668 nframes_t
669 SndFileSource::crossfade (Sample* data, nframes_t cnt, int fade_in)
670 {
671         nframes_t xfade = min (xfade_frames, cnt);
672         nframes_t nofade = cnt - xfade;
673         Sample* fade_data = 0;
674         nframes_t fade_position = 0; // in frames
675         ssize_t retval;
676         nframes_t file_cnt;
677
678         if (fade_in) {
679                 fade_position = file_pos;
680                 fade_data = data;
681         } else {
682                 fade_position = file_pos + nofade;
683                 fade_data = data + nofade;
684         }
685
686         if (fade_position > _length) {
687                 
688                 /* read starts beyond end of data, just memset to zero */
689                 
690                 file_cnt = 0;
691
692         } else if (fade_position + xfade > _length) {
693                 
694                 /* read ends beyond end of data, read some, memset the rest */
695                 
696                 file_cnt = _length - fade_position;
697
698         } else {
699                 
700                 /* read is entirely within data */
701
702                 file_cnt = xfade;
703         }
704
705         if (file_cnt) {
706                 
707                 if ((retval = read_unlocked (xfade_buf, fade_position, file_cnt)) != (ssize_t) file_cnt) {
708                         if (retval >= 0 && errno == EAGAIN) {
709                                 /* XXX - can we really trust that errno is meaningful here?  yes POSIX, i'm talking to you.
710                                  * short or no data there */
711                                 memset (xfade_buf, 0, xfade * sizeof(Sample));
712                         } else {
713                                 error << string_compose(_("SndFileSource: \"%1\" bad read retval: %2 of %5 (%3: %4)"), _path, retval, errno, strerror (errno), xfade) << endmsg;
714                                 return 0;
715                         }
716                 }
717         } 
718
719         if (file_cnt != xfade) {
720                 nframes_t delta = xfade - file_cnt;
721                 memset (xfade_buf+file_cnt, 0, sizeof (Sample) * delta);
722         }
723         
724         if (nofade && !fade_in) {
725                 if (write_float (data, file_pos, nofade) != nofade) {
726                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
727                         return 0;
728                 }
729         }
730
731         if (xfade == xfade_frames) {
732
733                 nframes_t n;
734
735                 /* use the standard xfade curve */
736                 
737                 if (fade_in) {
738
739                         /* fade new material in */
740                         
741                         for (n = 0; n < xfade; ++n) {
742                                 xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (fade_data[n] * in_coefficient[n]);
743                         }
744
745                 } else {
746
747
748                         /* fade new material out */
749                         
750                         for (n = 0; n < xfade; ++n) {
751                                 xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (fade_data[n] * out_coefficient[n]);
752                         }
753                 }
754
755         } else if (xfade < xfade_frames) {
756
757                 gain_t in[xfade];
758                 gain_t out[xfade];
759
760                 /* short xfade, compute custom curve */
761
762                 compute_equal_power_fades (xfade, in, out);
763
764                 for (nframes_t n = 0; n < xfade; ++n) {
765                         xfade_buf[n] = (xfade_buf[n] * out[n]) + (fade_data[n] * in[n]);                
766                 }
767
768         } else if (xfade) {
769
770                 /* long xfade length, has to be computed across several calls */
771
772         }
773
774         if (xfade) {
775                 if (write_float (xfade_buf, fade_position, xfade) != xfade) {
776                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
777                         return 0;
778                 }
779         }
780         
781         if (fade_in && nofade) {
782                 if (write_float (data + xfade, file_pos + xfade, nofade) != nofade) {
783                         error << string_compose(_("SndFileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
784                         return 0;
785                 }
786         }
787
788         return cnt;
789 }
790
791 nframes_t
792 SndFileSource::last_capture_start_frame () const
793 {
794         if (destructive()) {
795                 return capture_start_frame;
796         } else {
797                 return 0;
798         }
799 }
800
801 void
802 SndFileSource::handle_header_position_change ()
803 {
804         if (destructive()) {
805                 if ( _length != 0 ) {
806                         error << string_compose(_("Filesource: start time is already set for existing file (%1): Cannot change start time."), _path ) << endmsg;
807                         //in the future, pop up a dialog here that allows user to regenerate file with new start offset
808                 } else if (writable()) {
809                         timeline_position = header_position_offset;
810                         set_header_timeline_position ();  //this will get flushed if/when the file is recorded to
811                 }
812         }
813 }
814
815 void
816 SndFileSource::setup_standard_crossfades (nframes_t rate)
817 {
818         /* This static method is assumed to have been called by the Session
819            before any DFS's are created.
820         */
821
822         xfade_frames = (nframes_t) floor ((Config->get_destructive_xfade_msecs () / 1000.0) * rate);
823
824         if (out_coefficient) {
825                 delete [] out_coefficient;
826         }
827
828         if (in_coefficient) {
829                 delete [] in_coefficient;
830         }
831
832         out_coefficient = new gain_t[xfade_frames];
833         in_coefficient = new gain_t[xfade_frames];
834
835         compute_equal_power_fades (xfade_frames, in_coefficient, out_coefficient);
836 }
837
838 void
839 SndFileSource::set_timeline_position (int64_t pos)
840 {
841         // destructive track timeline postion does not change
842         // except at instantion or when header_position_offset 
843         // (session start) changes
844
845         if (!destructive()) {
846                 AudioFileSource::set_timeline_position (pos);
847         } 
848 }
849
850 int
851 SndFileSource::get_soundfile_info (const ustring& path, SoundFileInfo& info, string& error_msg)
852 {
853         SNDFILE *sf;
854         SF_INFO sf_info;
855         SF_BROADCAST_INFO binfo;
856         bool timecode_exists;
857
858         sf_info.format = 0; // libsndfile says to clear this before sf_open().
859
860         if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) { 
861                 char errbuf[256];
862                 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
863                 return false;
864         }
865
866         info.samplerate  = sf_info.samplerate;
867         info.channels    = sf_info.channels;
868         info.length      = sf_info.frames;
869         info.format_name = string_compose("Format: %1, %2",
870                                            sndfile_major_format(sf_info.format),
871                                            sndfile_minor_format(sf_info.format));
872
873         memset (&binfo, 0, sizeof (binfo));
874         info.timecode  = get_timecode_info (sf, &binfo, timecode_exists);
875
876         if (!timecode_exists) {
877                 info.timecode = 0;
878         }
879         
880         sf_close (sf);
881
882         return true;
883 }
884
885 int64_t
886 SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists)
887 {
888         if (sf_command (sf, SFC_GET_BROADCAST_INFO, binfo, sizeof (*binfo)) != SF_TRUE) {
889                 exists = false;
890                 return (header_position_offset);
891         } 
892         
893         /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
894            of the time reference.
895         */
896         
897         exists = true;
898         int64_t ret = (uint32_t) binfo->time_reference_high;
899         ret <<= 32;
900         ret |= (uint32_t) binfo->time_reference_low;
901         return ret;
902 }
903
904 bool
905 SndFileSource::one_of_several_channels () const
906 {
907         return _info.channels > 1;
908 }
909
910 Sample*
911 SndFileSource::get_interleave_buffer (nframes_t size)
912 {
913         SizedSampleBuffer* ssb;
914
915         if ((ssb = thread_interleave_buffer.get()) == 0) {
916                 ssb = new SizedSampleBuffer (size);
917                 thread_interleave_buffer.set (ssb);
918         }
919
920         if (ssb->size < size) {
921                 ssb = new SizedSampleBuffer (size);
922                 thread_interleave_buffer.set (ssb);
923         }
924
925         return ssb->buf;
926 }