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