Remove most using declarations from header files.
[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 std;
62 using namespace ARDOUR;
63 using namespace PBD;
64 using namespace Glib;
65
66 ustring AudioFileSource::peak_dir = "";
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. */
90 AudioFileSource::AudioFileSource (Session& s, const ustring& path, bool embedded, Source::Flag flags)
91         : Source (s, DataType::AUDIO, path, flags)
92         , AudioSource (s, path)
93         , FileSource (s, DataType::AUDIO, path, embedded, flags)
94 {
95         if (init (path, true)) {
96                 throw failed_constructor ();
97         }
98 }
99
100 /** Constructor used for new internal-to-session files. */
101 AudioFileSource::AudioFileSource (Session& s, const ustring& path, bool embedded, Source::Flag flags,
102                 SampleFormat samp_format, HeaderFormat hdr_format)
103         : Source (s, DataType::AUDIO, path, flags)
104         , AudioSource (s, path)
105         , FileSource (s, DataType::AUDIO, path, embedded, flags)
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         : Source (s, node)
117         , AudioSource (s, node)
118         , FileSource (s, node, must_exist)
119 {
120         if (set_state (node)) {
121                 throw failed_constructor ();
122         }
123
124         if (init (_name, must_exist)) {
125                 throw failed_constructor ();
126         }
127 }
128
129 AudioFileSource::~AudioFileSource ()
130 {
131         if (removable()) {
132                 unlink (_path.c_str());
133                 unlink (peakpath.c_str());
134         }
135 }
136
137 int
138 AudioFileSource::init (const ustring& pathstr, bool must_exist)
139 {
140         _peaks_built = false;
141         return FileSource::init (pathstr, must_exist);
142 }
143
144 ustring
145 AudioFileSource::peak_path (ustring audio_path)
146 {
147         ustring base;
148
149         base = PBD::basename_nosuffix (audio_path);
150         base += '%';
151         base += (char) ('A' + _channel);
152
153         return _session.peak_path (base);
154 }
155
156 ustring
157 AudioFileSource::find_broken_peakfile (ustring peak_path, ustring audio_path)
158 {
159         ustring str;
160
161         /* check for the broken location in use by 2.0 for several months */
162         
163         str = broken_peak_path (audio_path);
164         
165         if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
166                 
167                 if (is_embedded()) {
168                         
169                         /* it would be nice to rename it but the nature of 
170                            the bug means that we can't reliably use it.
171                         */
172                         
173                         peak_path = str;
174                         
175                 } else {
176                         /* all native files are mono, so we can just rename
177                            it.
178                         */
179                         ::rename (str.c_str(), peak_path.c_str());
180                 }
181                 
182         } else {
183                 /* Nasty band-aid for older sessions that were created before we
184                    used libsndfile for all audio files.
185                 */
186                 
187                 
188                 str = old_peak_path (audio_path);       
189                 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
190                         peak_path = str;
191                 }
192         }
193
194         return peak_path;
195 }
196
197 ustring
198 AudioFileSource::broken_peak_path (ustring audio_path)
199 {
200         return _session.peak_path (audio_path);
201 }
202
203 ustring
204 AudioFileSource::old_peak_path (ustring audio_path)
205 {
206         /* XXX hardly bombproof! fix me */
207
208         struct stat stat_file;
209         struct stat stat_mount;
210
211         ustring mp = mountpoint (audio_path);
212
213         stat (audio_path.c_str(), &stat_file);
214         stat (mp.c_str(), &stat_mount);
215
216         char buf[32];
217 #ifdef __APPLE__
218         snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
219 #else
220         snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
221 #endif
222
223         ustring res = peak_dir;
224         res += buf;
225         res += peakfile_suffix;
226
227         return res;
228 }
229
230 bool
231 AudioFileSource::get_soundfile_info (ustring path, SoundFileInfo& _info, string& error_msg)
232 {
233 #ifdef HAVE_COREAUDIO
234         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
235                 return true;
236         }
237 #endif // HAVE_COREAUDIO
238
239         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
240                 return true;
241         }
242
243         return false;
244 }
245
246 XMLNode&
247 AudioFileSource::get_state ()
248 {
249         XMLNode& root (AudioSource::get_state());
250         char buf[32];
251         snprintf (buf, sizeof (buf), "%u", _channel);
252         root.add_property (X_("channel"), buf);
253         return root;
254 }
255
256 int
257 AudioFileSource::set_state (const XMLNode& node)
258 {
259         if (Source::set_state (node)) {
260                 return -1;
261         }
262
263         if (AudioSource::set_state (node)) {
264                 return -1;
265         }
266         
267         if (FileSource::set_state (node)) {
268                 return -1;
269         }
270
271         return 0;
272 }
273
274 void
275 AudioFileSource::mark_streaming_write_completed ()
276 {
277         if (!writable()) {
278                 return;
279         }
280         
281         /* XXX notice that we're readers of _peaks_built
282            but we must hold a solid lock on PeaksReady.
283         */
284
285         Glib::Mutex::Lock lm (_lock);
286
287         if (_peaks_built) {
288                 PeaksReady (); /* EMIT SIGNAL */
289         }
290 }
291
292 int
293 AudioFileSource::move_dependents_to_trash()
294 {
295         return ::unlink (peakpath.c_str());
296 }
297
298 void
299 AudioFileSource::set_header_position_offset (nframes_t offset)
300 {
301         header_position_offset = offset;
302         HeaderPositionOffsetChanged ();
303 }
304
305 bool
306 AudioFileSource::is_empty (Session& s, ustring path)
307 {
308         SoundFileInfo info;
309         string err;
310         
311         if (!get_soundfile_info (path, info, err)) {
312                 /* dangerous: we can't get info, so assume that its not empty */
313                 return false; 
314         }
315
316         return info.length == 0;
317 }
318
319 int
320 AudioFileSource::setup_peakfile ()
321 {
322         if (!(_flags & NoPeakFile)) {
323                 return initialize_peakfile (_file_is_new, _path);
324         } else {
325                 return 0;
326         }
327 }
328
329 bool
330 AudioFileSource::safe_audio_file_extension(const ustring& file)
331 {
332         const char* suffixes[] = {
333                 ".wav", ".WAV",
334                 ".aiff", ".AIFF",
335                 ".caf", ".CAF",
336                 ".aif", ".AIF",
337                 ".amb", ".AMB",
338                 ".snd", ".SND",
339                 ".au", ".AU",
340                 ".raw", ".RAW",
341                 ".sf", ".SF",
342                 ".cdr", ".CDR",
343                 ".smp", ".SMP",
344                 ".maud", ".MAUD",
345                 ".vwe", ".VWE",
346                 ".paf", ".PAF",
347                 ".voc", ".VOC",
348 #ifdef HAVE_FLAC
349                 ".flac", ".FLAC",
350 #endif // HAVE_FLAC
351 #ifdef HAVE_COREAUDIO
352                 ".mp3", ".MP3",
353                 ".aac", ".AAC",
354                 ".mp4", ".MP4",
355 #endif // HAVE_COREAUDIO
356         };
357
358         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
359                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
360                         return true;
361                 }
362         }
363
364         return false;
365 }
366
367 Sample*
368 AudioFileSource::get_interleave_buffer (nframes_t size)
369 {
370         SizedSampleBuffer* ssb;
371
372         if ((ssb = thread_interleave_buffer.get()) == 0) {
373                 ssb = new SizedSampleBuffer (size);
374                 thread_interleave_buffer.set (ssb);
375         }
376
377         if (ssb->size < size) {
378                 ssb = new SizedSampleBuffer (size);
379                 thread_interleave_buffer.set (ssb);
380         }
381
382         return ssb->buf;
383 }