fix up BWF creation; make CoreAudioSource work; add CAImportable; refactor SourceFact...
[ardour.git] / libs / ardour / audiofilesource.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 <vector>
21
22 #include <sys/time.h>
23 #include <sys/stat.h>
24 #include <stdio.h> // for rename(), sigh
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <errno.h>
28
29 #include <pbd/convert.h>
30 #include <pbd/basename.h>
31 #include <pbd/mountpoint.h>
32 #include <pbd/pathscanner.h>
33 #include <pbd/stl_delete.h>
34 #include <pbd/strsplit.h>
35 #include <pbd/shortpath.h>
36 #include <pbd/enumwriter.h>
37
38 #include <sndfile.h>
39
40 #include <glibmm/miscutils.h>
41 #include <glibmm/fileutils.h>
42 #include <glibmm/thread.h>
43
44 #include <ardour/audiofilesource.h>
45 #include <ardour/sndfile_helpers.h>
46 #include <ardour/sndfilesource.h>
47 #include <ardour/session.h>
48 #include <ardour/source_factory.h>
49
50 // if these headers come before sigc++ is included
51 // the parser throws ObjC++ errors. (nil is a keyword)
52 #ifdef HAVE_COREAUDIO 
53 #include <ardour/coreaudiosource.h>
54 #include <AudioToolbox/ExtendedAudioFile.h>
55 #include <AudioToolbox/AudioFormat.h>
56 #endif // HAVE_COREAUDIO
57
58 #include "i18n.h"
59
60 using namespace ARDOUR;
61 using namespace PBD;
62 using namespace Glib;
63
64 ustring AudioFileSource::peak_dir = "";
65 ustring AudioFileSource::search_path;
66
67 sigc::signal<void> AudioFileSource::HeaderPositionOffsetChanged;
68 uint64_t           AudioFileSource::header_position_offset = 0;
69
70 /* XXX maybe this too */
71 char   AudioFileSource::bwf_serial_number[13] = "000000000000";
72
73 struct SizedSampleBuffer {
74     nframes_t size;
75     Sample* buf;
76
77     SizedSampleBuffer (nframes_t sz) : size (sz) { 
78             buf = new Sample[size];
79     }
80
81     ~SizedSampleBuffer() {
82             delete [] buf;
83     }
84 };
85
86 Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
87
88 AudioFileSource::AudioFileSource (Session& s, ustring path, Flag flags)
89         : AudioSource (s, path), _flags (flags),
90           _channel (0)
91 {
92         /* constructor used for existing external to session files. file must exist already */
93         _is_embedded = AudioFileSource::determine_embeddedness (path);
94
95         if (init (path, true)) {
96                 throw failed_constructor ();
97         }
98
99 }
100
101 AudioFileSource::AudioFileSource (Session& s, ustring path, Flag flags, SampleFormat samp_format, HeaderFormat hdr_format)
102         : AudioSource (s, path), _flags (flags),
103           _channel (0)
104 {
105         /* constructor used for new internal-to-session files. file cannot exist */
106         _is_embedded = false;
107
108         if (init (path, false)) {
109                 throw failed_constructor ();
110         }
111 }
112
113 AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
114         : AudioSource (s, node), _flags (Flag (Writable|CanRename))
115           /* _channel is set in set_state() or init() */
116 {
117         /* constructor used for existing internal-to-session files. file must exist */
118
119         if (set_state (node)) {
120                 throw failed_constructor ();
121         }
122
123         string foo = _name;
124         
125         if (init (foo, must_exist)) {
126                 throw failed_constructor ();
127         }
128 }
129
130 AudioFileSource::~AudioFileSource ()
131 {
132         if (removable()) {
133                 unlink (_path.c_str());
134                 unlink (peakpath.c_str());
135         }
136 }
137
138 bool
139 AudioFileSource::determine_embeddedness (ustring path)
140 {
141         return (path.find("/") == 0);
142 }
143
144 bool
145 AudioFileSource::removable () const
146 {
147         return (_flags & Removable) && ((_flags & RemoveAtDestroy) || ((_flags & RemovableIfEmpty) && length() == 0));
148 }
149
150 int
151 AudioFileSource::init (ustring pathstr, bool must_exist)
152 {
153         _length = 0;
154         timeline_position = 0;
155         _peaks_built = false;
156
157         if (!find (pathstr, must_exist, file_is_new, _channel)) {
158                 throw non_existent_source ();
159         }
160
161         if (file_is_new && must_exist) {
162                 return -1;
163         }
164
165         return 0;
166 }
167
168
169 ustring
170 AudioFileSource::peak_path (ustring audio_path)
171 {
172         ustring base;
173
174         base = PBD::basename_nosuffix (audio_path);
175         base += '%';
176         base += (char) ('A' + _channel);
177
178         return _session.peak_path (base);
179 }
180
181 ustring
182 AudioFileSource::find_broken_peakfile (ustring peak_path, ustring audio_path)
183 {
184         ustring str;
185
186         /* check for the broken location in use by 2.0 for several months */
187         
188         str = broken_peak_path (audio_path);
189         
190         if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
191                 
192                 if (is_embedded()) {
193                         
194                         /* it would be nice to rename it but the nature of 
195                            the bug means that we can't reliably use it.
196                         */
197                         
198                         peak_path = str;
199                         
200                 } else {
201                         /* all native files are mono, so we can just rename
202                            it.
203                         */
204                         ::rename (str.c_str(), peak_path.c_str());
205                 }
206                 
207         } else {
208                 /* Nasty band-aid for older sessions that were created before we
209                    used libsndfile for all audio files.
210                 */
211                 
212                 
213                 str = old_peak_path (audio_path);       
214                 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
215                         peak_path = str;
216                 }
217         }
218
219         return peak_path;
220 }
221
222 ustring
223 AudioFileSource::broken_peak_path (ustring audio_path)
224 {
225         ustring res;
226
227         res = _session.peak_dir ();
228         res += PBD::basename_nosuffix (audio_path);
229         res += ".peak";
230
231         return res;
232 }
233
234 ustring
235 AudioFileSource::old_peak_path (ustring audio_path)
236 {
237         /* XXX hardly bombproof! fix me */
238
239         struct stat stat_file;
240         struct stat stat_mount;
241
242         ustring mp = mountpoint (audio_path);
243
244         stat (audio_path.c_str(), &stat_file);
245         stat (mp.c_str(), &stat_mount);
246
247         char buf[32];
248 #ifdef __APPLE__
249         snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
250 #else
251         snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
252 #endif
253
254         ustring res = peak_dir;
255         res += buf;
256
257         return res;
258 }
259
260 bool
261 AudioFileSource::get_soundfile_info (ustring path, SoundFileInfo& _info, string& error_msg)
262 {
263 #ifdef HAVE_COREAUDIO
264         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
265                 return true;
266         }
267 #endif // HAVE_COREAUDIO
268
269         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
270                 return true;
271         }
272
273         return false;
274 }
275
276 XMLNode&
277 AudioFileSource::get_state ()
278 {
279         XMLNode& root (AudioSource::get_state());
280         char buf[32];
281         root.add_property (X_("flags"), enum_2_string (_flags));
282         snprintf (buf, sizeof (buf), "%u", _channel);
283         root.add_property (X_("channel"), buf);
284         return root;
285 }
286
287 int
288 AudioFileSource::set_state (const XMLNode& node)
289 {
290         const XMLProperty* prop;
291
292         if (AudioSource::set_state (node)) {
293                 return -1;
294         }
295
296         if ((prop = node.property (X_("flags"))) != 0) {
297                 _flags = Flag (string_2_enum (prop->value(), _flags));
298         } else {
299                 _flags = Flag (0);
300
301         }
302
303         if ((prop = node.property (X_("channel"))) != 0) {
304                 _channel = atoi (prop->value());
305         } else {
306                 _channel = 0;
307         }
308
309         if ((prop = node.property (X_("name"))) != 0) {
310                 _is_embedded = AudioFileSource::determine_embeddedness (prop->value());
311         } else {
312                 _is_embedded = false;
313         }
314
315         if ((prop = node.property (X_("destructive"))) != 0) {
316                 /* old style, from the period when we had DestructiveFileSource */
317                 _flags = Flag (_flags | Destructive);
318         }
319
320         return 0;
321 }
322
323 void
324 AudioFileSource::mark_for_remove ()
325 {
326         // This operation is not allowed for sources for destructive tracks or embedded files.
327         // Fortunately mark_for_remove() is never called for embedded files. This function
328         // must be fixed if that ever happens.
329         if (_flags & Destructive) {
330                 return;
331         }
332
333         _flags = Flag (_flags | Removable | RemoveAtDestroy);
334 }
335
336 void
337 AudioFileSource::mark_streaming_write_completed ()
338 {
339         if (!writable()) {
340                 return;
341         }
342
343         /* XXX notice that we're readers of _peaks_built
344            but we must hold a solid lock on PeaksReady.
345         */
346
347         Glib::Mutex::Lock lm (_lock);
348         
349         if (_peaks_built) {
350                 PeaksReady (); /* EMIT SIGNAL */
351         }
352 }
353
354 void
355 AudioFileSource::mark_take (ustring id)
356 {
357         if (writable()) {
358                 _take_id = id;
359         }
360 }
361
362 int
363 AudioFileSource::move_to_trash (const ustring& trash_dir_name)
364 {
365         if (is_embedded()) {
366                 cerr << "tried to move an embedded region to trash" << endl;
367                 return -1;
368         }
369
370         ustring newpath;
371
372         if (!writable()) {
373                 return -1;
374         }
375
376         /* don't move the file across filesystems, just
377            stick it in the `trash_dir_name' directory
378            on whichever filesystem it was already on.
379         */
380         
381         newpath = Glib::path_get_dirname (_path);
382         newpath = Glib::path_get_dirname (newpath); 
383
384         cerr << "from " << _path << " dead dir looks like " << newpath << endl;
385
386         newpath += '/';
387         newpath += trash_dir_name;
388         newpath += '/';
389         newpath += Glib::path_get_basename (_path);
390
391         if (access (newpath.c_str(), F_OK) == 0) {
392
393                 /* the new path already exists, try versioning */
394                 
395                 char buf[PATH_MAX+1];
396                 int version = 1;
397                 ustring newpath_v;
398
399                 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
400                 newpath_v = buf;
401
402                 while (access (newpath_v.c_str(), F_OK) == 0 && version < 999) {
403                         snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
404                         newpath_v = buf;
405                 }
406                 
407                 if (version == 999) {
408                         error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
409                                           newpath)
410                               << endmsg;
411                 } else {
412                         newpath = newpath_v;
413                 }
414
415         } else {
416
417                 /* it doesn't exist, or we can't read it or something */
418
419         }
420
421         if (::rename (_path.c_str(), newpath.c_str()) != 0) {
422                 error << string_compose (_("cannot rename audio file source from %1 to %2 (%3)"),
423                                   _path, newpath, strerror (errno))
424                       << endmsg;
425                 return -1;
426         }
427
428         if (::unlink (peakpath.c_str()) != 0) {
429                 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
430                                   peakpath, _path, strerror (errno))
431                       << endmsg;
432                 /* try to back out */
433                 rename (newpath.c_str(), _path.c_str());
434                 return -1;
435         }
436             
437         _path = newpath;
438         peakpath = "";
439         
440         /* file can not be removed twice, since the operation is not idempotent */
441
442         _flags = Flag (_flags & ~(RemoveAtDestroy|Removable|RemovableIfEmpty));
443
444         return 0;
445 }
446
447 bool
448 AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew, uint16_t& chan)
449 {
450         ustring::size_type pos;
451         bool ret = false;
452
453         isnew = false;
454
455         if (pathstr[0] != '/') {
456
457                 /* non-absolute pathname: find pathstr in search path */
458
459                 vector<ustring> dirs;
460                 int cnt;
461                 ustring fullpath;
462                 ustring keeppath;
463
464                 if (search_path.length() == 0) {
465                         error << _("FileSource: search path not set") << endmsg;
466                         goto out;
467                 }
468
469                 split (search_path, dirs, ':');
470
471                 cnt = 0;
472                 
473                 for (vector<ustring>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
474
475                         fullpath = *i;
476                         if (fullpath[fullpath.length()-1] != '/') {
477                                 fullpath += '/';
478                         }
479
480                         fullpath += pathstr;
481
482                         /* i (paul) made a nasty design error by using ':' as a special character in
483                            Ardour 0.99 .. this hack tries to make things sort of work.
484                         */
485                         
486                         if ((pos = pathstr.find_last_of (':')) != ustring::npos) {
487                                 
488                                 if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
489
490                                         /* its a real file, no problem */
491                                         
492                                         keeppath = fullpath;
493                                         ++cnt;
494
495                                 } else {
496                                         
497                                         if (must_exist) {
498                                                 
499                                                 /* might be an older session using file:channel syntax. see if the version
500                                                    without the :suffix exists
501                                                  */
502                                                 
503                                                 ustring shorter = pathstr.substr (0, pos);
504                                                 fullpath = *i;
505
506                                                 if (fullpath[fullpath.length()-1] != '/') {
507                                                         fullpath += '/';
508                                                 }
509
510                                                 fullpath += shorter;
511
512                                                 if (Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
513                                                         chan = atoi (pathstr.substr (pos+1));
514                                                         pathstr = shorter;
515                                                         keeppath = fullpath;
516                                                         ++cnt;
517                                                 } 
518                                                 
519                                         } else {
520                                                 
521                                                 /* new derived file (e.g. for timefx) being created in a newer session */
522                                                 
523                                         }
524                                 }
525
526                         } else {
527
528                                 if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
529                                         keeppath = fullpath;
530                                         ++cnt;
531                                 } 
532                         }
533                 }
534
535                 if (cnt > 1) {
536
537                         error << string_compose (_("FileSource: \"%1\" is ambigous when searching %2\n\t"), pathstr, search_path) << endmsg;
538                         goto out;
539
540                 } else if (cnt == 0) {
541
542                         if (must_exist) {
543                                 error << string_compose(_("Filesource: cannot find required file (%1): while searching %2"), pathstr, search_path) << endmsg;
544                                 goto out;
545                         } else {
546                                 isnew = true;
547                         }
548                 }
549
550                 _name = pathstr;
551                 _path = keeppath;
552                 ret = true;
553
554         } else {
555                 
556                 /* external files and/or very very old style sessions include full paths */
557
558                 /* ugh, handle ':' situation */
559
560                 if ((pos = pathstr.find_last_of (':')) != ustring::npos) {
561                         
562                         ustring shorter = pathstr.substr (0, pos);
563
564                         if (Glib::file_test (shorter, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
565                                 chan = atoi (pathstr.substr (pos+1));
566                                 pathstr = shorter;
567                         }
568                 }
569                 
570                 _path = pathstr;
571
572                 if (is_embedded()) {
573                         _name = pathstr;
574                 } else {
575                         _name = pathstr.substr (pathstr.find_last_of ('/') + 1);
576                 }
577
578                 if (!Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
579
580                         /* file does not exist or we cannot read it */
581                         
582                         if (must_exist) {
583                                 error << string_compose(_("Filesource: cannot find required file (%1): %2"), _path, strerror (errno)) << endmsg;
584                                 goto out;
585                         }
586                         
587                         if (errno != ENOENT) {
588                                 error << string_compose(_("Filesource: cannot check for existing file (%1): %2"), _path, strerror (errno)) << endmsg;
589                                 goto out;
590                         }
591                         
592                         /* a new file */
593
594                         isnew = true;
595                         ret = true;
596
597                 } else {
598                         
599                         /* already exists */
600
601                         ret = true;
602
603                 }
604         }
605         
606   out:
607         return ret;
608 }
609
610 void
611 AudioFileSource::set_search_path (ustring p)
612 {
613         search_path = p;
614 }
615
616 void
617 AudioFileSource::set_header_position_offset (nframes_t offset)
618 {
619         header_position_offset = offset;
620         HeaderPositionOffsetChanged ();
621 }
622
623 void
624 AudioFileSource::set_timeline_position (int64_t pos)
625 {
626         timeline_position = pos;
627 }
628
629 void
630 AudioFileSource::set_allow_remove_if_empty (bool yn)
631 {
632         if (!writable()) {
633                 return;
634         }
635
636         if (yn) {
637                 _flags = Flag (_flags | RemovableIfEmpty);
638         } else {
639                 _flags = Flag (_flags & ~RemovableIfEmpty);
640         }
641 }
642
643 int
644 AudioFileSource::set_name (ustring newname, bool destructive)
645 {
646         Glib::Mutex::Lock lm (_lock);
647         ustring oldpath = _path;
648         ustring newpath = Session::change_audio_path_by_name (oldpath, _name, newname, destructive);
649
650         if (newpath.empty()) {
651                 error << string_compose (_("programming error: %1"), "cannot generate a changed audio path") << endmsg;
652                 return -1;
653         }
654
655         // Test whether newpath exists, if yes notify the user but continue. 
656         if (access(newpath.c_str(),F_OK) == 0) {
657                 error << _("Programming error! Ardour tried to rename a file over another file! It's safe to continue working, but please report this to the developers.") << endmsg;
658                 return -1;
659         }
660
661         if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
662                 error << string_compose (_("cannot rename audio file %1 to %2"), _name, newpath) << endmsg;
663                 return -1;
664         }
665
666         _name = Glib::path_get_basename (newpath);
667         _path = newpath;
668
669         return rename_peakfile (peak_path (_path));
670 }
671
672 bool
673 AudioFileSource::is_empty (Session& s, ustring path)
674 {
675         SoundFileInfo info;
676         string err;
677         
678         if (!get_soundfile_info (path, info, err)) {
679                 /* dangerous: we can't get info, so assume that its not empty */
680                 return false; 
681         }
682
683         return info.length == 0;
684 }
685
686 int
687 AudioFileSource::setup_peakfile ()
688 {
689         if (!(_flags & NoPeakFile)) {
690                 return initialize_peakfile (file_is_new, _path);
691         } else {
692                 return 0;
693         }
694 }
695
696 bool
697 AudioFileSource::safe_file_extension(ustring file)
698 {
699         return !(file.rfind(".wav") == ustring::npos &&
700                 file.rfind(".aiff")== ustring::npos &&
701                 file.rfind(".caf")== ustring::npos &&
702                 file.rfind(".aif") == ustring::npos &&
703                 file.rfind(".amb") == ustring::npos &&
704                 file.rfind(".snd") == ustring::npos &&
705                 file.rfind(".au")  == ustring::npos &&
706                 file.rfind(".raw") == ustring::npos &&
707                 file.rfind(".sf")  == ustring::npos &&
708                 file.rfind(".cdr") == ustring::npos &&
709                 file.rfind(".smp") == ustring::npos &&
710                 file.rfind(".maud")== ustring::npos &&
711                 file.rfind(".vwe") == ustring::npos &&
712                 file.rfind(".paf") == ustring::npos &&
713 #ifdef HAVE_FLAC
714                 file.rfind(".flac")== ustring::npos &&
715 #endif // HAVE_FLAC
716 #ifdef HAVE_COREAUDIO
717                 file.rfind(".mp3") == ustring::npos &&
718                 file.rfind(".aac") == ustring::npos &&
719                 file.rfind(".mp4") == ustring::npos &&
720 #endif // HAVE_COREAUDIO
721                 file.rfind(".voc") == ustring::npos);
722 }
723
724 void
725 AudioFileSource::mark_immutable ()
726 {
727         /* destructive sources stay writable, and their other flags don't
728            change.
729         */
730
731         if (!(_flags & Destructive)) {
732                 _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
733         }
734 }
735
736
737 Sample*
738 AudioFileSource::get_interleave_buffer (nframes_t size)
739 {
740         SizedSampleBuffer* ssb;
741
742         if ((ssb = thread_interleave_buffer.get()) == 0) {
743                 ssb = new SizedSampleBuffer (size);
744                 thread_interleave_buffer.set (ssb);
745         }
746
747         if (ssb->size < size) {
748                 ssb = new SizedSampleBuffer (size);
749                 thread_interleave_buffer.set (ssb);
750         }
751
752         return ssb->buf;
753 }