Fix typos in AU channel-count calc
[ardour.git] / libs / ardour / audiofilesource.cc
1 /*
2  * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
3  * Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2007-2017 Tim Mayberry <mojofunk@gmail.com>
5  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
6  * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #ifdef WAF_BUILD
24 #include "libardour-config.h"
25 #endif
26
27 #include <vector>
28
29 #include <sys/time.h>
30 #include <sys/stat.h>
31 #include <stdio.h> // for rename(), sigh
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <errno.h>
35
36 #include "pbd/gstdio_compat.h"
37 #include "pbd/convert.h"
38 #include "pbd/basename.h"
39 #include "pbd/file_utils.h"
40 #include "pbd/mountpoint.h"
41 #include "pbd/stl_delete.h"
42 #include "pbd/strsplit.h"
43 #include "pbd/shortpath.h"
44 #include "pbd/stacktrace.h"
45 #include "pbd/enumwriter.h"
46
47 #include <sndfile.h>
48
49 #include <glibmm/miscutils.h>
50 #include <glibmm/fileutils.h>
51 #include <glibmm/threads.h>
52
53 #include "ardour/audiofilesource.h"
54 #include "ardour/debug.h"
55 #include "ardour/sndfilesource.h"
56 #include "ardour/session.h"
57 #include "ardour/filename_extensions.h"
58
59 // if these headers come before sigc++ is included
60 // the parser throws ObjC++ errors. (nil is a keyword)
61 #ifdef HAVE_COREAUDIO
62 #include "ardour/coreaudiosource.h"
63 #include <AudioToolbox/ExtendedAudioFile.h>
64 #include <AudioToolbox/AudioFormat.h>
65 #endif // HAVE_COREAUDIO
66
67 #include "pbd/i18n.h"
68
69 using namespace std;
70 using namespace ARDOUR;
71 using namespace PBD;
72 using namespace Glib;
73
74 PBD::Signal0<void> AudioFileSource::HeaderPositionOffsetChanged;
75 samplecnt_t         AudioFileSource::header_position_offset = 0;
76
77 /* XXX maybe this too */
78 char AudioFileSource::bwf_serial_number[13] = "000000000000";
79
80 struct SizedSampleBuffer {
81         samplecnt_t size;
82         Sample* buf;
83
84         SizedSampleBuffer (samplecnt_t sz) : size (sz) {
85                 buf = new Sample[size];
86         }
87
88         ~SizedSampleBuffer() {
89                 delete [] buf;
90         }
91 };
92
93 Glib::Threads::Private<SizedSampleBuffer> thread_interleave_buffer;
94
95 /** Constructor used for existing external-to-session files. */
96 AudioFileSource::AudioFileSource (Session& s, const string& path, Source::Flag flags)
97         : Source (s, DataType::AUDIO, path, flags)
98         , AudioSource (s, path)
99           /* note that external files have their own path as "origin" */
100         , FileSource (s, DataType::AUDIO, path, path, flags)
101 {
102         if (init (_path, true)) {
103                 throw failed_constructor ();
104         }
105 }
106
107 /** Constructor used for new internal-to-session files. */
108 AudioFileSource::AudioFileSource (Session& s, const string& path, const string& origin, Source::Flag flags,
109                                   SampleFormat /*samp_format*/, HeaderFormat /*hdr_format*/)
110         : Source (s, DataType::AUDIO, path, flags)
111         , AudioSource (s, path)
112         , FileSource (s, DataType::AUDIO, path, origin, flags)
113 {
114         /* note that origin remains empty */
115
116         if (init (_path, false)) {
117                 throw failed_constructor ();
118         }
119 }
120
121 /** Constructor used for existing internal-to-session files during crash
122  * recovery. File must exist
123  */
124 AudioFileSource::AudioFileSource (Session& s, const string& path, Source::Flag flags, bool /* ignored-exists-for-prototype differentiation */)
125         : Source (s, DataType::AUDIO, path, flags)
126         , AudioSource (s, path)
127         , FileSource (s, DataType::AUDIO, path, string(), flags)
128 {
129         /* note that origin remains empty */
130
131         if (init (_path, true)) {
132                 throw failed_constructor ();
133         }
134 }
135
136
137 /** Constructor used for sources listed in session-files (XML)
138  * and missing sources (SilentFileSource).
139  *
140  * If _origin is an absolute path after ::set_state(), then the
141  * file is external to the session.
142  */
143 AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
144         : Source (s, node)
145         , AudioSource (s, node)
146         , FileSource (s, node, must_exist)
147 {
148         if (set_state (node, Stateful::loading_state_version)) {
149                 throw failed_constructor ();
150         }
151
152         if (Glib::path_is_absolute (_origin)) {
153                 _path = _origin;
154         }
155
156         if (init (_path, must_exist)) {
157                 throw failed_constructor ();
158         }
159 }
160
161 AudioFileSource::~AudioFileSource ()
162 {
163         DEBUG_TRACE (DEBUG::Destruction, string_compose ("AudioFileSource destructor %1, removable? %2\n", _path, removable()));
164         if (removable()) {
165                 ::g_unlink (_path.c_str());
166                 ::g_unlink (_peakpath.c_str());
167         }
168 }
169
170 int
171 AudioFileSource::init (const string& pathstr, bool must_exist)
172 {
173         return FileSource::init (pathstr, must_exist);
174 }
175
176 string
177 AudioFileSource::construct_peak_filepath (const string& audio_path, const bool in_session, const bool old_peak_name) const
178 {
179         string base;
180         if (old_peak_name) {
181                 base = audio_path.substr (0, audio_path.find_last_of ('.'));
182         } else {
183                 base = audio_path;
184         }
185         base += '%';
186         base += (char) ('A' + _channel);
187         return _session.construct_peak_filepath (base, in_session, old_peak_name);
188 }
189
190 bool
191 AudioFileSource::get_soundfile_info (const string& path, SoundFileInfo& _info, string& error_msg)
192 {
193         /* try sndfile first because it gets timecode info from .wav (BWF) if it exists,
194            which at present, ExtAudioFile from Apple seems unable to do.
195         */
196
197         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
198                 return true;
199         }
200
201 #ifdef HAVE_COREAUDIO
202         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
203                 return true;
204         }
205 #endif // HAVE_COREAUDIO
206
207         return false;
208 }
209
210 XMLNode&
211 AudioFileSource::get_state ()
212 {
213         XMLNode& root (AudioSource::get_state());
214         root.set_property (X_("channel"), _channel);
215         root.set_property (X_("origin"), _origin);
216         root.set_property (X_("gain"), _gain);
217         return root;
218 }
219
220 int
221 AudioFileSource::set_state (const XMLNode& node, int version)
222 {
223         if (Source::set_state (node, version)) {
224                 return -1;
225         }
226
227         if (AudioSource::set_state (node, version)) {
228                 return -1;
229         }
230
231         if (FileSource::set_state (node, version)) {
232                 return -1;
233         }
234
235         return 0;
236 }
237
238 void
239 AudioFileSource::mark_streaming_write_completed (const Lock& lock)
240 {
241         if (!writable()) {
242                 return;
243         }
244
245         AudioSource::mark_streaming_write_completed (lock);
246 }
247
248 int
249 AudioFileSource::move_dependents_to_trash()
250 {
251         return ::g_unlink (_peakpath.c_str());
252 }
253
254 void
255 AudioFileSource::set_header_position_offset (samplecnt_t offset)
256 {
257         header_position_offset = offset;
258         HeaderPositionOffsetChanged ();
259 }
260
261 bool
262 AudioFileSource::is_empty (Session& /*s*/, string path)
263 {
264         SoundFileInfo info;
265         string err;
266
267         if (!get_soundfile_info (path, info, err)) {
268                 /* dangerous: we can't get info, so assume that its not empty */
269                 return false;
270         }
271
272         return info.length == 0;
273 }
274
275 int
276 AudioFileSource::setup_peakfile ()
277 {
278         if (_session.deletion_in_progress()) {
279                 return 0;
280         }
281         if (!(_flags & NoPeakFile)) {
282                 return initialize_peakfile (_path, within_session());
283         } else {
284                 return 0;
285         }
286 }
287
288 void
289 AudioFileSource::set_gain (float g, bool temporarily)
290 {
291         if (_gain == g) {
292                 return;
293         }
294         _gain = g;
295         if (temporarily) {
296                 return;
297         }
298         close_peakfile();
299         setup_peakfile ();
300 }
301
302 bool
303 AudioFileSource::safe_audio_file_extension(const string& file)
304 {
305         const char* suffixes[] = {
306                 ".aif", ".AIF",
307                 ".aifc", ".AIFC",
308                 ".aiff", ".AIFF",
309                 ".amb", ".AMB",
310                 ".au", ".AU",
311                 ".caf", ".CAF",
312                 ".cdr", ".CDR",
313                 ".flac", ".FLAC",
314                 ".htk", ".HTK",
315                 ".iff", ".IFF",
316                 ".mat", ".MAT",
317                 ".oga", ".OGA",
318                 ".ogg", ".OGG",
319                 ".paf", ".PAF",
320                 ".pvf", ".PVF",
321                 ".sf", ".SF",
322                 ".smp", ".SMP",
323                 ".snd", ".SND",
324                 ".maud", ".MAUD",
325                 ".voc", ".VOC"
326                 ".vwe", ".VWE",
327                 ".w64", ".W64",
328                 ".wav", ".WAV",
329 #ifdef HAVE_COREAUDIO
330                 ".aac", ".AAC",
331                 ".adts", ".ADTS",
332                 ".ac3", ".AC3",
333                 ".amr", ".AMR",
334                 ".mpa", ".MPA",
335                 ".mpeg", ".MPEG",
336                 ".mp1", ".MP1",
337                 ".mp2", ".MP2",
338                 ".mp3", ".MP3",
339                 ".mp4", ".MP4",
340                 ".m4a", ".M4A",
341                 ".sd2", ".SD2", // libsndfile supports sd2 also, but the resource fork is required to open.
342 #endif // HAVE_COREAUDIO
343         };
344
345         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
346                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
347                         return true;
348                 }
349         }
350
351         return false;
352 }
353
354 Sample*
355 AudioFileSource::get_interleave_buffer (samplecnt_t size)
356 {
357         SizedSampleBuffer* ssb;
358
359         if ((ssb = thread_interleave_buffer.get()) == 0) {
360                 ssb = new SizedSampleBuffer (size);
361                 thread_interleave_buffer.set (ssb);
362         }
363
364         if (ssb->size < size) {
365                 ssb = new SizedSampleBuffer (size);
366                 thread_interleave_buffer.set (ssb);
367         }
368
369         return ssb->buf;
370 }
371