~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to libs/ardour/audiofilesource.cc

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

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