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