lots of fidgety work to get track renaming to work correctly now that we have to...
[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         snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, channel);
80
81         string res = peak_dir;
82         res += buf;
83
84         return res;
85 }
86
87 #ifdef HAVE_COREAUDIO
88
89 ExternalSource*
90 ExternalSource::create (const XMLNode& node)
91 {
92         ExternalSource* es = 0;
93
94         try {
95                 es = new CoreAudioSource (node);
96         } 
97         
98         catch (failed_constructor& err) {
99                 es = new SndFileSource (node);
100         }
101
102         es = new SndFileSource (node);
103
104         return es;
105 }
106
107 #else
108
109 ExternalSource*
110 ExternalSource::create (const XMLNode& node)
111 {
112         return new SndFileSource (node);
113 }
114
115 #endif // HAVE_COREAUDIO
116
117 #ifdef HAVE_COREAUDIO
118 ExternalSource*
119 ExternalSource::create (const string& idstr, bool build_peak)
120 {
121         ExternalSource* es = 0;
122
123         try {
124                 es = new CoreAudioSource (idstr, build_peak);
125         }
126
127         catch (failed_constructor& err) {
128                 es = new SndFileSource (idstr, build_peak);
129         }
130
131         return es;
132 }
133
134 #else
135
136 ExternalSource*
137 ExternalSource::create (const string& idstr, bool build_peak)
138 {
139         return new SndFileSource (idstr, build_peak);
140 }
141
142 #endif // HAVE_COREAUDIO
143
144 #ifdef HAVE_COREAUDIO
145 std::string 
146 CFStringRefToStdString(CFStringRef stringRef)
147 {
148         CFIndex size = 
149                 CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) , 
150                 kCFStringEncodingASCII);
151             char *buf = new char[size];
152         
153         std::string result;
154
155         if(CFStringGetCString(stringRef, buf, size, kCFStringEncodingASCII)) {
156             result = buf;
157         }
158         delete [] buf;
159         return result;
160 }
161 #endif // HAVE_COREAUDIO
162
163 bool
164 ExternalSource::get_soundfile_info (string path, SoundFileInfo& _info, string& error_msg)
165 {
166 #ifdef HAVE_COREAUDIO
167         OSStatus err = noErr;
168     FSRef ref; 
169         ExtAudioFileRef af = 0;
170         size_t size;
171     CFStringRef name;
172
173     err = FSPathMakeRef ((UInt8*)path.c_str(), &ref, 0);
174         if (err != noErr) {
175         ExtAudioFileDispose (af);
176                 goto libsndfile;
177         }
178
179         err = ExtAudioFileOpen(&ref, &af);
180         if (err != noErr) {
181         ExtAudioFileDispose (af);
182                 goto libsndfile;
183         }
184
185         AudioStreamBasicDescription absd;
186         memset(&absd, 0, sizeof(absd));
187         size = sizeof(AudioStreamBasicDescription);
188         err = ExtAudioFileGetProperty(af,
189                         kExtAudioFileProperty_FileDataFormat, &size, &absd);
190         if (err != noErr) {
191         ExtAudioFileDispose (af);
192                 goto libsndfile;
193         }
194
195         _info.samplerate = absd.mSampleRate;
196         _info.channels   = absd.mChannelsPerFrame;
197
198     size = sizeof(_info.length);
199     err = ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileLengthFrames, &size, &_info.length);
200     if (err != noErr) {
201         ExtAudioFileDispose (af);
202                 goto libsndfile;
203     }
204
205         size = sizeof(CFStringRef);
206         err = AudioFormatGetProperty(
207                         kAudioFormatProperty_FormatName, sizeof(absd), &absd, &size, &name);
208         if (err != noErr) {
209         ExtAudioFileDispose (af);
210                 goto libsndfile;
211         }
212
213         _info.format_name = CFStringRefToStdString(name);
214
215     ExtAudioFileDispose (af);
216         return true;
217         
218 libsndfile:
219 #endif // HAVE_COREAUDIO
220
221         SNDFILE *sf;
222         SF_INFO sf_info;
223
224         sf_info.format = 0; // libsndfile says to clear this before sf_open().
225
226         if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) { 
227                 char errbuf[256];
228                 error_msg = sf_error_str (0, errbuf, sizeof (errbuf) - 1);
229                 return false;
230         }
231
232         sf_close (sf);
233
234         _info.samplerate  = sf_info.samplerate;
235         _info.channels    = sf_info.channels;
236         _info.length      = sf_info.frames;
237         _info.format_name = string_compose("Format: %1, %2",
238                         sndfile_major_format(sf_info.format),
239                         sndfile_minor_format(sf_info.format));
240
241         return true;
242 }