Merged with trunk R920.
[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     $Id$
19 */
20
21 #include <cerrno>
22 #include <climits>
23
24 #include <pwd.h>
25 #include <sys/utsname.h>
26
27 #include <glibmm/miscutils.h>
28
29 #include <ardour/sndfilesource.h>
30
31 #include "i18n.h"
32
33 using namespace std;
34 using namespace ARDOUR;
35 using namespace PBD;
36
37 SndFileSource::SndFileSource (Session& s, const XMLNode& node)
38         : AudioFileSource (s, node)
39 {
40         init (_name);
41
42         if (open()) {
43                 throw failed_constructor ();
44         }
45
46         if (_build_peakfiles) {
47                 if (initialize_peakfile (false, _path)) {
48                         sf_close (sf);
49                         sf = 0;
50                         throw failed_constructor ();
51                 }
52         }
53 }
54
55 SndFileSource::SndFileSource (Session& s, string idstr, Flag flags)
56                                         /* files created this way are never writable or removable */
57         : AudioFileSource (s, idstr, Flag (flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy)))
58 {
59         init (idstr);
60
61         if (open()) {
62                 throw failed_constructor ();
63         }
64
65         if (!(_flags & NoPeakFile) && _build_peakfiles) {
66                 if (initialize_peakfile (false, _path)) {
67                         sf_close (sf);
68                         sf = 0;
69                         throw failed_constructor ();
70                 }
71         }
72 }
73
74 SndFileSource::SndFileSource (Session& s, string idstr, SampleFormat sfmt, HeaderFormat hf, jack_nframes_t rate, Flag flags)
75         : AudioFileSource (s, idstr, flags, sfmt, hf)
76 {
77         int fmt = 0;
78
79         init (idstr);
80
81         switch (hf) {
82         case CAF:
83                 fmt = SF_FORMAT_CAF;
84                 _flags = Flag (_flags & ~Broadcast);
85                 break;
86
87         case AIFF:
88                 fmt = SF_FORMAT_AIFF;
89                 _flags = Flag (_flags & ~Broadcast);
90                 break;
91
92         case BWF:
93                 fmt = SF_FORMAT_WAV;
94                 _flags = Flag (_flags | Broadcast);
95                 break;
96
97         case WAVE:
98                 fmt = SF_FORMAT_WAV;
99                 _flags = Flag (_flags & ~Broadcast);
100                 break;
101
102         case WAVE64:
103                 fmt = SF_FORMAT_W64;
104                 _flags = Flag (_flags & ~Broadcast);
105                 break;
106
107         default:
108                 fatal << string_compose (_("programming error: %1"), X_("unsupported audio header format requested")) << endmsg;
109                 /*NOTREACHED*/
110                 break;
111
112         }
113
114         switch (sfmt) {
115         case FormatFloat:
116                 fmt |= SF_FORMAT_FLOAT;
117                 break;
118
119         case FormatInt24:
120                 fmt |= SF_FORMAT_PCM_24;
121                 break;
122         }
123         
124         _info.channels = 1;
125         _info.samplerate = rate;
126         _info.format = fmt;
127
128         if (open()) {
129                 throw failed_constructor();
130         }
131
132         if (writable() && (_flags & Broadcast)) {
133
134                 _broadcast_info = new SF_BROADCAST_INFO;
135                 memset (_broadcast_info, 0, sizeof (*_broadcast_info));
136                 
137                 snprintf (_broadcast_info->description, sizeof (_broadcast_info->description), "BWF %s", _name.c_str());
138                 
139                 struct utsname utsinfo;
140
141                 if (uname (&utsinfo)) {
142                         error << string_compose(_("FileSource: cannot get host information for BWF header (%1)"), strerror(errno)) << endmsg;
143                         return;
144                 }
145                 
146                 snprintf (_broadcast_info->originator, sizeof (_broadcast_info->originator), "ardour:%s:%s:%s:%s:%s)", 
147                           Glib::get_real_name().c_str(),
148                           utsinfo.nodename,
149                           utsinfo.sysname,
150                           utsinfo.release,
151                           utsinfo.version);
152                 
153                 _broadcast_info->version = 1;  
154                 _broadcast_info->time_reference_low = 0;  
155                 _broadcast_info->time_reference_high = 0;  
156                 
157                 /* XXX do something about this field */
158                 
159                 snprintf (_broadcast_info->umid, sizeof (_broadcast_info->umid), "%s", "fnord");
160                 
161                 /* coding history is added by libsndfile */
162
163                 if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (_broadcast_info)) != SF_TRUE) {
164                         char errbuf[256];
165                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
166                         error << string_compose (_("cannot set broadcast info for audio file %1 (%2); dropping broadcast info for this file"), _path, errbuf) << endmsg;
167                         _flags = Flag (_flags & ~Broadcast);
168                         delete _broadcast_info;
169                         _broadcast_info = 0;
170                 }
171                 
172         }
173         
174         if (!(_flags & NoPeakFile) && _build_peakfiles) {
175                 if (initialize_peakfile (true, _path)) {
176                         sf_close (sf);
177                         sf = 0;
178                         throw failed_constructor ();
179                 }
180         }
181 }
182
183 void 
184 SndFileSource::init (const string& idstr)
185 {
186         string::size_type pos;
187         string file;
188
189         interleave_buf = 0;
190         interleave_bufsize = 0;
191         sf = 0;
192         _broadcast_info = 0;
193
194         if ((pos = idstr.find_last_of (':')) == string::npos) {
195                 channel = 0;
196                 _name = Glib::path_get_basename (idstr);
197         } else {
198                 channel = atoi (idstr.substr (pos+1).c_str());
199                 _name = Glib::path_get_basename (idstr.substr (0, pos));
200         }
201
202         /* although libsndfile says we don't need to set this,
203            valgrind and source code shows us that we do.
204         */
205
206         memset (&_info, 0, sizeof(_info));
207 }
208
209 int
210 SndFileSource::open ()
211 {
212         if ((sf = sf_open (_path.c_str(), (writable() ? SFM_RDWR : SFM_READ), &_info)) == 0) {
213                 char errbuf[256];
214                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
215                 error << string_compose(_("SndFileSource: cannot open file \"%1\" for %2 (%3)"), 
216                                         _path, (writable() ? "read+write" : "reading"), errbuf) << endmsg;
217                 return -1;
218         }
219
220         if (channel >= _info.channels) {
221                 error << string_compose(_("SndFileSource: file only contains %1 channels; %2 is invalid as a channel number"), _info.channels, channel) << endmsg;
222                 sf_close (sf);
223                 sf = 0;
224                 return -1;
225         }
226
227         _length = _info.frames;
228
229         _broadcast_info = new SF_BROADCAST_INFO;
230         memset (_broadcast_info, 0, sizeof (*_broadcast_info));
231         
232         /* lookup broadcast info */
233         
234         if (sf_command (sf, SFC_GET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
235
236                 /* if the file has data but no broadcast info, then clearly, there is no broadcast info */
237
238                 if (_length) {
239                         delete _broadcast_info;
240                         _broadcast_info = 0;
241                         _flags = Flag (_flags & ~Broadcast);
242                 }
243
244                 set_timeline_position (header_position_offset);
245
246         } else {
247         
248                 /* XXX 64 bit alert: when JACK switches to a 64 bit frame count, this needs to use the high bits
249                    of the time reference.
250                 */
251
252                 set_timeline_position ( _broadcast_info->time_reference_low );
253         }
254
255         if (writable()) {
256                 sf_command (sf, SFC_SET_UPDATE_HEADER_AUTO, 0, SF_FALSE);
257         }
258
259         return 0;
260 }
261
262 SndFileSource::~SndFileSource ()
263 {
264         GoingAway (); /* EMIT SIGNAL */
265
266         if (sf) {
267                 sf_close (sf);
268                 sf = 0;
269         }
270
271         if (interleave_buf) {
272                 delete [] interleave_buf;
273         }
274
275         if (_broadcast_info) {
276                 delete _broadcast_info;
277         }
278 }
279
280 float
281 SndFileSource::sample_rate () const 
282 {
283         return _info.samplerate;
284 }
285
286 jack_nframes_t
287 SndFileSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const
288 {
289         int32_t nread;
290         float *ptr;
291         uint32_t real_cnt;
292         jack_nframes_t file_cnt;
293
294         //destructive (tape) tracks need to offset reads and writes by the timeline position
295         if (_flags && ARDOUR::Destructive == ARDOUR::Destructive) {
296                 start -= timeline_position;
297         }
298
299         if (start > _length) {
300
301                 /* read starts beyond end of data, just memset to zero */
302                 
303                 file_cnt = 0;
304
305         } else if (start + cnt > _length) {
306                 
307                 /* read ends beyond end of data, read some, memset the rest */
308                 
309                 file_cnt = _length - start;
310
311         } else {
312                 
313                 /* read is entirely within data */
314
315                 file_cnt = cnt;
316         }
317         
318         if (file_cnt) {
319
320                 if (sf_seek (sf, (sf_count_t) start, SEEK_SET|SFM_READ) != (sf_count_t) start) {
321                         char errbuf[256];
322                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
323                         error << string_compose(_("SndFileSource: could not seek to frame %1 within %2 (%3)"), start, _name.substr (1), errbuf) << endmsg;
324                         return 0;
325                 }
326                 
327                 if (_info.channels == 1) {
328                         jack_nframes_t ret = sf_read_float (sf, dst, file_cnt);
329                         _read_data_count = cnt * sizeof(float);
330                         return ret;
331                 }
332         }
333
334         if (file_cnt != cnt) {
335                 jack_nframes_t delta = cnt - file_cnt;
336                 memset (dst+file_cnt, 0, sizeof (Sample) * delta);
337         }
338
339         real_cnt = cnt * _info.channels;
340
341         if (interleave_bufsize < real_cnt) {
342                 
343                 if (interleave_buf) {
344                         delete [] interleave_buf;
345                 }
346                 interleave_bufsize = real_cnt;
347                 interleave_buf = new float[interleave_bufsize];
348         }
349         
350         nread = sf_read_float (sf, interleave_buf, real_cnt);
351         ptr = interleave_buf + channel;
352         nread /= _info.channels;
353         
354         /* stride through the interleaved data */
355         
356         for (int32_t n = 0; n < nread; ++n) {
357                 dst[n] = *ptr;
358                 ptr += _info.channels;
359         }
360
361         _read_data_count = cnt * sizeof(float);
362                 
363         return nread;
364 }
365
366 jack_nframes_t 
367 SndFileSource::write_unlocked (Sample *data, jack_nframes_t cnt)
368 {
369         if (!writable()) {
370                 return 0;
371         }
372
373         if (_info.channels != 1) {
374                 fatal << string_compose (_("programming error: %1 %2"), X_("SndFileSource::write called on non-mono file"), _path) << endmsg;
375                 /*NOTREACHED*/
376                 return 0;
377         }
378         
379         jack_nframes_t oldlen;
380         int32_t frame_pos = _length;
381         
382         if (write_float (data, frame_pos, cnt) != cnt) {
383                 return 0;
384         }
385
386         oldlen = _length;
387         update_length (oldlen, cnt);
388
389         if (_build_peakfiles) {
390                 PeakBuildRecord *pbr = 0;
391                 
392                 if (pending_peak_builds.size()) {
393                                 pbr = pending_peak_builds.back();
394                         }
395                         
396                         if (pbr && pbr->frame + pbr->cnt == oldlen) {
397                                 
398                                 /* the last PBR extended to the start of the current write,
399                                    so just extend it again.
400                                 */
401
402                                 pbr->cnt += cnt;
403                         } else {
404                                 pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
405                         }
406                         
407                         _peaks_built = false;
408         }
409         
410         
411         if (_build_peakfiles) {
412                 queue_for_peaks (this);
413         }
414
415         _write_data_count = cnt;
416         
417         return cnt;
418 }
419
420 int
421 SndFileSource::update_header (jack_nframes_t when, struct tm& now, time_t tnow)
422 {       
423         set_timeline_position (when);
424
425         if (_flags & Broadcast) {
426                 if (setup_broadcast_info (when, now, tnow)) {
427                         return -1;
428                 }
429         } 
430
431         return flush_header ();
432 }
433
434 int
435 SndFileSource::flush_header ()
436 {
437         if (!writable() || (sf == 0)) {
438                 return -1;
439         }
440
441         return (sf_command (sf, SFC_UPDATE_HEADER_NOW, 0, 0) != SF_TRUE);
442 }
443
444 int
445 SndFileSource::setup_broadcast_info (jack_nframes_t when, struct tm& now, time_t tnow)
446 {
447         if (!writable()) {
448                 return -1;
449         }
450
451         if (!(_flags & Broadcast)) {
452                 return 0;
453         }
454
455         /* random code is 9 digits */
456         
457         int random_code = random() % 999999999;
458         
459         snprintf (_broadcast_info->originator_reference, sizeof (_broadcast_info->originator_reference), "%2s%3s%12s%02d%02d%02d%9d",
460                   bwf_country_code,
461                   bwf_organization_code,
462                   bwf_serial_number,
463                   now.tm_hour,
464                   now.tm_min,
465                   now.tm_sec,
466                   random_code);
467         
468         snprintf (_broadcast_info->origination_date, sizeof (_broadcast_info->origination_date), "%4d-%02d-%02d",
469                   1900 + now.tm_year,
470                   now.tm_mon,
471                   now.tm_mday);
472         
473         snprintf (_broadcast_info->origination_time, sizeof (_broadcast_info->origination_time), "%02d:%02d:%02d",
474                   now.tm_hour,
475                   now.tm_min,
476                   now.tm_sec);
477
478         /* now update header position taking header offset into account */
479         
480         set_header_timeline_position ();
481
482         if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
483                 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
484                 _flags = Flag (_flags & ~Broadcast);
485                 delete _broadcast_info;
486                 _broadcast_info = 0;
487                 return -1;
488         }
489
490         return 0;
491 }
492
493 void
494 SndFileSource::set_header_timeline_position ()
495 {
496         if (!(_flags & Broadcast)) {
497                 return;
498         }
499
500         _broadcast_info->time_reference_high = (timeline_position >> 32);
501         _broadcast_info->time_reference_low = (timeline_position & 0xffffffff);
502
503         if (sf_command (sf, SFC_SET_BROADCAST_INFO, _broadcast_info, sizeof (*_broadcast_info)) != SF_TRUE) {
504                 error << string_compose (_("cannot set broadcast info for audio file %1; Dropping broadcast info for this file"), _path) << endmsg;
505                 _flags = Flag (_flags & ~Broadcast);
506                 delete _broadcast_info;
507                 _broadcast_info = 0;
508         }
509
510         
511
512 }
513
514 jack_nframes_t
515 SndFileSource::write_float (Sample* data, jack_nframes_t frame_pos, jack_nframes_t cnt)
516 {
517         if (sf_seek (sf, frame_pos, SEEK_SET|SFM_WRITE) != frame_pos) {
518                 error << string_compose (_("%1: cannot seek to %2"), _path, frame_pos) << endmsg;
519                 return 0;
520         }
521         
522         if (sf_writef_float (sf, data, cnt) != (ssize_t) cnt) {
523                 return 0;
524         }
525         
526         return cnt;
527 }
528
529 jack_nframes_t
530 SndFileSource::natural_position() const
531 {
532         return timeline_position;
533 }