(Messy merge fixes)
[ardour.git] / libs / ardour / externalsource.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 <sys/stat.h>
21 #include <unistd.h>
22 #include <sys/time.h>
23
24 #include <sndfile.h>
25
26 #include <pbd/mountpoint.h>
27 #include <ardour/externalsource.h>
28 #include <ardour/sndfilesource.h>
29 #include <ardour/sndfile_helpers.h>
30
31 // if these headers come before sigc++ is included
32 // the parser throws ObjC++ errors. (nil is a keyword)
33 #ifdef HAVE_COREAUDIO 
34 #include <ardour/coreaudio_source.h>
35 #include <AudioToolbox/ExtendedAudioFile.h>
36 #include <AudioToolbox/AudioFormat.h>
37 #endif // HAVE_COREAUDIO
38
39 #include "i18n.h"
40
41 using namespace ARDOUR;
42
43 string ExternalSource::peak_dir = "";
44
45 ExternalSource::ExternalSource (const XMLNode& node)
46         : Source (node)
47 {
48 }
49
50 ExternalSource::ExternalSource (const string& idstr, bool build_peak)
51         : Source(build_peak)
52 {
53 }
54
55 ExternalSource::~ExternalSource ()
56 {
57 }
58
59 jack_nframes_t
60 ExternalSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const
61 {
62         return read (dst, start, cnt, workbuf);
63 }
64
65 string
66 ExternalSource::peak_path (string audio_path)
67 {
68         /* XXX hardly bombproof! fix me */
69
70         struct stat stat_file;
71         struct stat stat_mount;
72
73         string mp = mountpoint (audio_path);
74
75         stat (audio_path.c_str(), &stat_file);
76         stat (mp.c_str(), &stat_mount);
77
78         char buf[32];
79 #ifdef __APPLE__
80         snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, channel);
81 #else
82         snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, channel);
83 #endif
84
85         string res = peak_dir;
86         res += buf;
87
88         return res;
89 }
90
91 #ifdef HAVE_COREAUDIO
92
93 ExternalSource*
94 ExternalSource::create (const XMLNode& node)
95 {
96         ExternalSource* es = 0;
97
98         try {
99                 es = new CoreAudioSource (node);
100         } 
101         
102         catch (failed_constructor& err) {
103                 es = new SndFileSource (node);
104         }
105
106         es = new SndFileSource (node);
107
108         return es;
109 }
110
111 #else
112
113 ExternalSource*
114 ExternalSource::create (const XMLNode& node)
115 {
116         return new SndFileSource (node);
117 }
118
119 #endif // HAVE_COREAUDIO
120
121 #ifdef HAVE_COREAUDIO
122 ExternalSource*
123 ExternalSource::create (const string& idstr, bool build_peak)
124 {
125         ExternalSource* es = 0;
126
127         try {
128                 es = new CoreAudioSource (idstr, build_peak);
129         }
130
131         catch (failed_constructor& err) {
132                 es = new SndFileSource (idstr, build_peak);
133         }
134
135         return es;
136 }
137
138 #else
139
140 ExternalSource*
141 ExternalSource::create (const string& idstr, bool build_peak)
142 {
143         return new SndFileSource (idstr, build_peak);
144 }
145
146 #endif // HAVE_COREAUDIO
147
148 #ifdef HAVE_COREAUDIO
149 std::string 
150 CFStringRefToStdString(CFStringRef stringRef)
151 {
152         CFIndex size = 
153                 CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) , 
154                 kCFStringEncodingASCII);
155             char *buf = new char[size];
156         
157         std::string result;
158
159         if(CFStringGetCString(stringRef, buf, size, kCFStringEncodingASCII)) {
160             result = buf;
161         }
162         delete [] buf;
163         return result;
164 }
165 #endif // HAVE_COREAUDIO
166
167 bool
168 ExternalSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg)
169 {
170 #ifdef HAVE_COREAUDIO
171         OSStatus err = noErr;
172     FSRef ref; 
173         ExtAudioFileRef af = 0;
174         size_t size;
175     CFStringRef name;
176
177     err = FSPathMakeRef ((UInt8*)path.c_str(), &ref, 0);
178         if (err != noErr) {
179         ExtAudioFileDispose (af);
180                 goto libsndfile;
181         }
182
183         err = ExtAudioFileOpen(&ref, &af);
184         if (err != noErr) {
185         ExtAudioFileDispose (af);
186                 goto libsndfile;
187         }
188
189         AudioStreamBasicDescription absd;
190         memset(&absd, 0, sizeof(absd));
191         size = sizeof(AudioStreamBasicDescription);
192         err = ExtAudioFileGetProperty(af,
193                         kExtAudioFileProperty_FileDataFormat, &size, &absd);
194         if (err != noErr) {
195         ExtAudioFileDispose (af);
196                 goto libsndfile;
197         }
198
199         _info.samplerate = absd.mSampleRate;
200         _info.channels   = absd.mChannelsPerFrame;
201
202     size = sizeof(_info.length);
203     err = ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileLengthFrames, &size, &_info.length);
204     if (err != noErr) {
205         ExtAudioFileDispose (af);
206                 goto libsndfile;
207     }
208
209         size = sizeof(CFStringRef);
210         err = AudioFormatGetProperty(
211                         kAudioFormatProperty_FormatName, sizeof(absd), &absd, &size, &name);
212         if (err != noErr) {
213         ExtAudioFileDispose (af);
214                 goto libsndfile;
215         }
216
217         _info.format_name = CFStringRefToStdString(name);
218
219     ExtAudioFileDispose (af);
220         return true;
221         
222 libsndfile:
223 #endif // HAVE_COREAUDIO
224
225         SNDFILE *sf;
226         SF_INFO sf_info;
227
228         sf_info.format = 0; // libsndfile says to clear this before sf_open().
229
230         if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) { 
231                 char errbuf[256];
232                 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
233                 return false;
234         }
235
236         sf_close (sf);
237
238         _info.samplerate  = sf_info.samplerate;
239         _info.channels    = sf_info.channels;
240         _info.length      = sf_info.frames;
241         _info.format_name = string_compose("Format: %1, %2",
242                         sndfile_major_format(sf_info.format),
243                         sndfile_minor_format(sf_info.format));
244
245         return true;
246 }