add new sigc++2 directory
[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                 _name = pathstr;
547                 _path = keeppath;
548                 ret = true;
549
550         } else {
551                 
552                 /* external files and/or very very old style sessions include full paths */
553
554                 /* ugh, handle ':' situation */
555
556                 if ((pos = pathstr.find_last_of (':')) != ustring::npos) {
557                         
558                         ustring shorter = pathstr.substr (0, pos);
559
560                         if (Glib::file_test (shorter, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
561                                 chan = atoi (pathstr.substr (pos+1));
562                                 pathstr = shorter;
563                         }
564                 }
565                 
566                 _path = pathstr;
567
568                 if (is_embedded()) {
569                         _name = pathstr;
570                 } else {
571                         _name = pathstr.substr (pathstr.find_last_of ('/') + 1);
572                 }
573
574                 if (!Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
575
576                         /* file does not exist or we cannot read it */
577                         
578                         if (must_exist) {
579                                 error << string_compose(_("Filesource: cannot find required file (%1): %2"), _path, strerror (errno)) << endmsg;
580                                 goto out;
581                         }
582                         
583                         if (errno != ENOENT) {
584                                 error << string_compose(_("Filesource: cannot check for existing file (%1): %2"), _path, strerror (errno)) << endmsg;
585                                 goto out;
586                         }
587                         
588                         /* a new file */
589
590                         isnew = true;
591                         ret = true;
592
593                 } else {
594                         
595                         /* already exists */
596
597                         ret = true;
598
599                 }
600         }
601         
602   out:
603         return ret;
604 }
605
606 void
607 AudioFileSource::set_search_path (ustring p)
608 {
609         search_path = p;
610 }
611
612 void
613 AudioFileSource::set_header_position_offset (nframes_t offset)
614 {
615         header_position_offset = offset;
616         HeaderPositionOffsetChanged ();
617 }
618
619 void
620 AudioFileSource::set_timeline_position (int64_t pos)
621 {
622         timeline_position = pos;
623 }
624
625 void
626 AudioFileSource::set_allow_remove_if_empty (bool yn)
627 {
628         if (!writable()) {
629                 return;
630         }
631
632         if (yn) {
633                 _flags = Flag (_flags | RemovableIfEmpty);
634         } else {
635                 _flags = Flag (_flags & ~RemovableIfEmpty);
636         }
637 }
638
639 int
640 AudioFileSource::set_source_name (ustring newname, bool destructive)
641 {
642         Glib::Mutex::Lock lm (_lock);
643         ustring oldpath = _path;
644         ustring newpath = Session::change_audio_path_by_name (oldpath, _name, newname, destructive);
645
646         if (newpath.empty()) {
647                 error << string_compose (_("programming error: %1"), "cannot generate a changed audio path") << endmsg;
648                 return -1;
649         }
650
651         // Test whether newpath exists, if yes notify the user but continue. 
652         if (access(newpath.c_str(),F_OK) == 0) {
653                 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;
654                 return -1;
655         }
656
657         if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
658                 error << string_compose (_("cannot rename audio file %1 to %2"), _name, newpath) << endmsg;
659                 return -1;
660         }
661
662         _name = Glib::path_get_basename (newpath);
663         _path = newpath;
664
665         return rename_peakfile (peak_path (_path));
666 }
667
668 bool
669 AudioFileSource::is_empty (Session& s, ustring path)
670 {
671         SoundFileInfo info;
672         string err;
673         
674         if (!get_soundfile_info (path, info, err)) {
675                 /* dangerous: we can't get info, so assume that its not empty */
676                 return false; 
677         }
678
679         return info.length == 0;
680 }
681
682 int
683 AudioFileSource::setup_peakfile ()
684 {
685         if (!(_flags & NoPeakFile)) {
686                 return initialize_peakfile (file_is_new, _path);
687         } else {
688                 return 0;
689         }
690 }
691
692 bool
693 AudioFileSource::safe_file_extension(ustring file)
694 {
695         const char* suffixes[] = {
696                 ".wav", ".WAV",
697                 ".aiff", ".AIFF",
698                 ".caf", ".CAF",
699                 ".aif", ".AIF",
700                 ".amb", ".AMB",
701                 ".snd", ".SND",
702                 ".au", ".AU",
703                 ".raw", ".RAW",
704                 ".sf", ".SF",
705                 ".cdr", ".CDR",
706                 ".smp", ".SMP",
707                 ".maud", ".MAUD",
708                 ".vwe", ".VWE",
709                 ".paf", ".PAF",
710                 ".voc", ".VOC",
711 #ifdef HAVE_FLAC
712                 ".flac", ".FLAC",
713 #endif // HAVE_FLAC
714 #ifdef HAVE_COREAUDIO
715                 ".mp3", ".MP3",
716                 ".aac", ".AAC",
717                 ".mp4", ".MP4",
718 #endif // HAVE_COREAUDIO
719         };
720
721         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
722                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
723                         return true;
724                 }
725         }
726
727         return false;
728 }
729
730 void
731 AudioFileSource::mark_immutable ()
732 {
733         /* destructive sources stay writable, and their other flags don't
734            change.
735         */
736
737         if (!(_flags & Destructive)) {
738                 _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename));
739         }
740 }
741
742
743 Sample*
744 AudioFileSource::get_interleave_buffer (nframes_t size)
745 {
746         SizedSampleBuffer* ssb;
747
748         if ((ssb = thread_interleave_buffer.get()) == 0) {
749                 ssb = new SizedSampleBuffer (size);
750                 thread_interleave_buffer.set (ssb);
751         }
752
753         if (ssb->size < size) {
754                 ssb = new SizedSampleBuffer (size);
755                 thread_interleave_buffer.set (ssb);
756         }
757
758         return ssb->buf;
759 }