Add stem export dialog and make all different export dialogs save their config to...
[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 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
23
24 #include <vector>
25
26 #include <sys/time.h>
27 #include <sys/stat.h>
28 #include <stdio.h> // for rename(), sigh
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32
33 #include "pbd/convert.h"
34 #include "pbd/basename.h"
35 #include "pbd/mountpoint.h"
36 #include "pbd/stl_delete.h"
37 #include "pbd/strsplit.h"
38 #include "pbd/shortpath.h"
39 #include "pbd/enumwriter.h"
40
41 #include <sndfile.h>
42
43 #include <glibmm/miscutils.h>
44 #include <glibmm/fileutils.h>
45 #include <glibmm/thread.h>
46
47 #include "ardour/audiofilesource.h"
48 #include "ardour/debug.h"
49 #include "ardour/sndfile_helpers.h"
50 #include "ardour/sndfilesource.h"
51 #include "ardour/session.h"
52 #include "ardour/session_directory.h"
53 #include "ardour/source_factory.h"
54 #include "ardour/filename_extensions.h"
55
56 // if these headers come before sigc++ is included
57 // the parser throws ObjC++ errors. (nil is a keyword)
58 #ifdef HAVE_COREAUDIO
59 #include "ardour/coreaudiosource.h"
60 #include <AudioToolbox/ExtendedAudioFile.h>
61 #include <AudioToolbox/AudioFormat.h>
62 #endif // HAVE_COREAUDIO
63
64 #include "i18n.h"
65
66 using namespace std;
67 using namespace ARDOUR;
68 using namespace PBD;
69 using namespace Glib;
70
71 string AudioFileSource::peak_dir = "";
72
73 PBD::Signal0<void> AudioFileSource::HeaderPositionOffsetChanged;
74 uint64_t           AudioFileSource::header_position_offset = 0;
75
76 /* XXX maybe this too */
77 char AudioFileSource::bwf_serial_number[13] = "000000000000";
78
79 struct SizedSampleBuffer {
80         framecnt_t size;
81         Sample* buf;
82
83         SizedSampleBuffer (framecnt_t sz) : size (sz) {
84                 buf = new Sample[size];
85         }
86
87         ~SizedSampleBuffer() {
88                 delete [] buf;
89         }
90 };
91
92 Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
93
94 /** Constructor used for existing external-to-session files. */
95 AudioFileSource::AudioFileSource (Session& s, const string& path, Source::Flag flags)
96         : Source (s, DataType::AUDIO, path, flags)
97         , AudioSource (s, path)
98           /* note that external files have their own path as "origin" */
99         , FileSource (s, DataType::AUDIO, path, path, flags)
100 {
101         /* note that origin remains empty */
102
103         if (init (_path, true)) {
104                 throw failed_constructor ();
105         }
106         cerr << "audiofile source created with path " << path << endl;
107 }
108
109 /** Constructor used for new internal-to-session files. */
110 AudioFileSource::AudioFileSource (Session& s, const string& path, const string& origin, Source::Flag flags,
111                                   SampleFormat /*samp_format*/, HeaderFormat /*hdr_format*/)
112         : Source (s, DataType::AUDIO, path, flags)
113         , AudioSource (s, path)
114         , FileSource (s, DataType::AUDIO, path, origin, flags)
115 {
116         /* note that origin remains empty */
117
118         if (init (_path, false)) {
119                 throw failed_constructor ();
120         }
121 }
122
123 /** Constructor used for existing internal-to-session files via XML.  File must exist. */
124 AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
125         : Source (s, node)
126         , AudioSource (s, node)
127         , FileSource (s, node, must_exist)
128 {
129         if (set_state (node, Stateful::loading_state_version)) {
130                 throw failed_constructor ();
131         }
132         
133         if (init (_path, must_exist)) {
134                 throw failed_constructor ();
135         }
136 }
137
138 AudioFileSource::~AudioFileSource ()
139 {
140         DEBUG_TRACE (DEBUG::Destruction, string_compose ("AudioFileSource destructor %1, removable? %2\n", _path, removable()));
141         if (removable()) {
142                 unlink (_path.c_str());
143                 unlink (peakpath.c_str());
144         }
145 }
146
147 int
148 AudioFileSource::init (const string& pathstr, bool must_exist)
149 {
150         return FileSource::init (pathstr, must_exist);
151 }
152
153 string
154 AudioFileSource::peak_path (string audio_path)
155 {
156         string base;
157
158         base = PBD::basename_nosuffix (audio_path);
159         base += '%';
160         base += (char) ('A' + _channel);
161
162         return _session.peak_path (base);
163 }
164
165 string
166 AudioFileSource::find_broken_peakfile (string peak_path, string audio_path)
167 {
168         string str;
169
170         /* check for the broken location in use by 2.0 for several months */
171
172         str = broken_peak_path (audio_path);
173
174         if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
175
176                 if (!within_session()) {
177
178                         /* it would be nice to rename it but the nature of
179                            the bug means that we can't reliably use it.
180                         */
181
182                         peak_path = str;
183
184                 } else {
185                         /* all native files are mono, so we can just rename
186                            it.
187                         */
188                         ::rename (str.c_str(), peak_path.c_str());
189                 }
190
191         } else {
192                 /* Nasty band-aid for older sessions that were created before we
193                    used libsndfile for all audio files.
194                 */
195
196
197                 str = old_peak_path (audio_path);
198                 if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
199                         peak_path = str;
200                 }
201         }
202
203         return peak_path;
204 }
205
206 string
207 AudioFileSource::broken_peak_path (string audio_path)
208 {
209         return _session.peak_path (basename_nosuffix (audio_path));
210 }
211
212 string
213 AudioFileSource::old_peak_path (string audio_path)
214 {
215         /* XXX hardly bombproof! fix me */
216
217         struct stat stat_file;
218         struct stat stat_mount;
219
220         string mp = mountpoint (audio_path);
221
222         stat (audio_path.c_str(), &stat_file);
223         stat (mp.c_str(), &stat_mount);
224
225         char buf[32];
226 #ifdef __APPLE__
227         snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
228 #else
229         snprintf (buf, sizeof (buf), "%" PRId64 "-%" PRId64 "-%d.peak", (int64_t) stat_mount.st_ino, (int64_t) stat_file.st_ino, _channel);
230 #endif
231
232         string res = peak_dir;
233         res += buf;
234         res += peakfile_suffix;
235
236         return res;
237 }
238
239 bool
240 AudioFileSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg)
241 {
242         /* try sndfile first because it gets timecode info from .wav (BWF) if it exists,
243            which at present, ExtAudioFile from Apple seems unable to do.
244         */
245
246         if (SndFileSource::get_soundfile_info (path, _info, error_msg) != 0) {
247                 return true;
248         }
249         
250 #ifdef HAVE_COREAUDIO
251         if (CoreAudioSource::get_soundfile_info (path, _info, error_msg) == 0) {
252                 return true;
253         }
254 #endif // HAVE_COREAUDIO
255
256         return false;
257 }
258
259 XMLNode&
260 AudioFileSource::get_state ()
261 {
262         XMLNode& root (AudioSource::get_state());
263         char buf[32];
264         snprintf (buf, sizeof (buf), "%u", _channel);
265         root.add_property (X_("channel"), buf);
266         root.add_property (X_("origin"), _origin);
267         return root;
268 }
269
270 int
271 AudioFileSource::set_state (const XMLNode& node, int version)
272 {
273         if (Source::set_state (node, version)) {
274                 return -1;
275         }
276
277         if (AudioSource::set_state (node, version)) {
278                 return -1;
279         }
280
281         if (FileSource::set_state (node, version)) {
282                 return -1;
283         }
284
285         return 0;
286 }
287
288 void
289 AudioFileSource::mark_streaming_write_completed ()
290 {
291         if (!writable()) {
292                 return;
293         }
294
295         AudioSource::mark_streaming_write_completed ();
296 }
297
298 int
299 AudioFileSource::move_dependents_to_trash()
300 {
301         return ::unlink (peakpath.c_str());
302 }
303
304 void
305 AudioFileSource::set_header_position_offset (framecnt_t offset)
306 {
307         header_position_offset = offset;
308         HeaderPositionOffsetChanged ();
309 }
310
311 bool
312 AudioFileSource::is_empty (Session& /*s*/, string path)
313 {
314         SoundFileInfo info;
315         string err;
316
317         if (!get_soundfile_info (path, info, err)) {
318                 /* dangerous: we can't get info, so assume that its not empty */
319                 return false;
320         }
321
322         return info.length == 0;
323 }
324
325 int
326 AudioFileSource::setup_peakfile ()
327 {
328         if (!(_flags & NoPeakFile)) {
329                 return initialize_peakfile (_file_is_new, _path);
330         } else {
331                 return 0;
332         }
333 }
334
335 bool
336 AudioFileSource::safe_audio_file_extension(const string& file)
337 {
338         const char* suffixes[] = {
339                 ".aif", ".AIF",
340                 ".aifc", ".AIFC",
341                 ".aiff", ".AIFF",
342                 ".amb", ".AMB",
343                 ".au", ".AU",
344                 ".caf", ".CAF",
345                 ".cdr", ".CDR",
346                 ".flac", ".FLAC",
347                 ".htk", ".HTK",
348                 ".iff", ".IFF",
349                 ".mat", ".MAT",
350                 ".oga", ".OGA",
351                 ".ogg", ".OGG",
352                 ".paf", ".PAF",
353                 ".pvf", ".PVF",
354                 ".sf", ".SF",
355                 ".smp", ".SMP",
356                 ".snd", ".SND",
357                 ".maud", ".MAUD",
358                 ".voc", ".VOC"
359                 ".vwe", ".VWE",
360                 ".w64", ".W64",
361                 ".wav", ".WAV",
362 #ifdef HAVE_COREAUDIO
363                 ".aac", ".AAC",
364                 ".adts", ".ADTS",
365                 ".ac3", ".AC3",
366                 ".amr", ".AMR",
367                 ".mpa", ".MPA",
368                 ".mpeg", ".MPEG",
369                 ".mp1", ".MP1",
370                 ".mp2", ".MP2",
371                 ".mp3", ".MP3",
372                 ".mp4", ".MP4",
373                 ".m4a", ".M4A",
374                 ".sd2", ".SD2",         // libsndfile supports sd2 also, but the resource fork is required to open.
375 #endif // HAVE_COREAUDIO
376         };
377
378         for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
379                 if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
380                         return true;
381                 }
382         }
383
384         return false;
385 }
386
387 Sample*
388 AudioFileSource::get_interleave_buffer (framecnt_t size)
389 {
390         SizedSampleBuffer* ssb;
391
392         if ((ssb = thread_interleave_buffer.get()) == 0) {
393                 ssb = new SizedSampleBuffer (size);
394                 thread_interleave_buffer.set (ssb);
395         }
396
397         if (ssb->size < size) {
398                 ssb = new SizedSampleBuffer (size);
399                 thread_interleave_buffer.set (ssb);
400         }
401
402         return ssb->buf;
403 }