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