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