And a small libsndfile error.
[ardour.git] / libs / ardour / sndfile_helpers.cc
1 #include <map>
2 #include <vector>
3
4 #include <sndfile.h>
5 #include <ardour/sndfile_helpers.h>
6
7 #ifdef HAVE_COREAUDIO
8 #include <AudioToolbox/ExtendedAudioFile.h>
9 #include <AudioToolbox/AudioFormat.h>
10 #endif // HAVE_COREAUDIO
11
12 #include "i18n.h"
13
14 using std::map;
15 using namespace std;
16
17 const char * const sndfile_header_formats_strings[SNDFILE_HEADER_FORMATS+1] = {
18         N_("WAV"),
19         N_("AIFF"),
20         N_("raw (no header)"),
21         N_("PAF (Ensoniq Paris)"),
22         N_("AU (Sun/NeXT)"),
23         N_("IRCAM"),
24         N_("W64 (64 bit WAV)"),
25         0
26 };
27
28 const char* const sndfile_file_endings_strings[SNDFILE_HEADER_FORMATS+1] = {
29         N_(".wav"),
30         N_(".aiff"),
31         N_(".raw"),
32         N_(".paf"),
33         N_(".au"),
34         N_(".ircam"),
35         N_(".w64"),
36         0
37 };
38
39 int sndfile_header_formats[SNDFILE_HEADER_FORMATS] = {
40         SF_FORMAT_WAV,
41         SF_FORMAT_AIFF,
42         SF_FORMAT_RAW,
43         SF_FORMAT_PAF,
44         SF_FORMAT_AU,
45         SF_FORMAT_IRCAM,
46         SF_FORMAT_W64
47 };
48
49 const char * const sndfile_bitdepth_formats_strings[SNDFILE_BITDEPTH_FORMATS+1] = {
50         N_("16 bit"),
51         N_("24 bit"),
52         N_("32 bit"),
53         N_("8 bit"),
54         N_("float"),
55         0
56 };
57
58 int sndfile_bitdepth_formats[SNDFILE_BITDEPTH_FORMATS] = {
59         SF_FORMAT_PCM_16,
60         SF_FORMAT_PCM_24,
61         SF_FORMAT_PCM_32,
62         SF_FORMAT_PCM_S8,
63         SF_FORMAT_FLOAT
64 };
65
66 const char * const sndfile_endian_formats_strings[SNDFILE_ENDIAN_FORMATS+1] = {
67         N_("Little-endian (Intel)"),
68         N_("Big-endian (Mac)"),
69         0
70 };
71
72 int sndfile_endian_formats[SNDFILE_ENDIAN_FORMATS] = {
73         SF_ENDIAN_LITTLE,
74         SF_ENDIAN_BIG
75 };
76
77 int
78 sndfile_header_format_from_string (string str)
79 {
80         for (int n = 0; sndfile_header_formats_strings[n]; ++n) {
81                 if (str == sndfile_header_formats_strings[n]) {
82                         return sndfile_header_formats[n];
83                 }
84         }
85         return -1;
86 }
87
88 int
89 sndfile_bitdepth_format_from_string (string str)
90 {
91         for (int n = 0; sndfile_bitdepth_formats_strings[n]; ++n) {
92                 if (str == sndfile_bitdepth_formats_strings[n]) {
93                         return sndfile_bitdepth_formats[n];
94                 }
95         }
96         return -1;
97 }
98
99 int
100 sndfile_endian_format_from_string (string str)
101 {
102         for (int n = 0; sndfile_endian_formats_strings[n]; ++n) {
103                 if (str == sndfile_endian_formats_strings[n]) {
104                         return sndfile_endian_formats[n];
105                 }
106         }
107         return -1;
108 }
109
110 string
111 sndfile_file_ending_from_string (string str)
112 {
113         static vector<string> file_endings;
114
115         if (file_endings.empty()) {
116                 file_endings = internationalize((const char **) sndfile_file_endings_strings);
117         }
118
119         for (int n = 0; sndfile_header_formats_strings[n]; ++n) {
120                 if (str == sndfile_header_formats_strings[n]) {
121                         return file_endings[n];
122                 }
123         }
124         return 0;
125 }
126
127 int
128 sndfile_data_width (int format)
129 {
130         int tval = format & 0xf;
131
132         switch (tval) {
133           case SF_FORMAT_PCM_S8:
134           case SF_FORMAT_PCM_U8:
135                 return 8;
136           case SF_FORMAT_PCM_16:
137                 return 16;
138           case SF_FORMAT_PCM_24:
139                 return 24;
140           case SF_FORMAT_PCM_32:
141                 return 32;
142           case SF_FORMAT_FLOAT:
143                 return 1; // heh, heh
144           default:
145             // we don't handle anything else within ardour
146                 return 0;
147         }
148 }
149
150 string 
151 sndfile_major_format(int format)
152 {
153         static map<int, string> m;
154
155         if(m.empty()){
156                 SF_FORMAT_INFO format_info;
157                 int count;
158                 sf_command(0, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof (int));
159                 for (int i = 0; i < count; ++i){
160                         format_info.format = i;
161                         sf_command (0, SFC_GET_FORMAT_MAJOR, 
162                                         &format_info, sizeof (format_info));
163                         m[format_info.format & SF_FORMAT_TYPEMASK] = format_info.name;
164                 }
165         }
166         
167         map<int, string>::iterator p = m.find(format & SF_FORMAT_TYPEMASK);
168         if(p != m.end()){
169                 return m[format & SF_FORMAT_TYPEMASK];
170         } else {
171                 return "-Unknown-";
172         }
173 }
174
175 string
176 sndfile_minor_format(int format)
177 {
178         static map<int, string> m;
179
180         if(m.empty()){
181                 SF_FORMAT_INFO format_info;
182                 int count;
183                 sf_command(0, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int));
184                 for (int i = 0; i < count; ++i){
185                         format_info.format = i;
186                         sf_command (0, SFC_GET_FORMAT_SUBTYPE, 
187                                         &format_info, sizeof (format_info));
188                         m[format_info.format & SF_FORMAT_SUBMASK] = format_info.name;
189                 }
190         }
191         
192         map<int, string>::iterator p = m.find(format & SF_FORMAT_SUBMASK);
193         if(p != m.end()){
194                 return m[format & SF_FORMAT_SUBMASK];
195         } else {
196                 return "-Unknown-";
197         }
198 }
199
200 #ifdef HAVE_COREAUDIO
201 std::string 
202 CFStringRefToStdString(CFStringRef stringRef)
203 {
204         CFIndex size = 
205                 CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) , 
206                 kCFStringEncodingASCII);
207             char *buf = new char[size];
208         
209         std::string result;
210
211         if(CFStringGetCString(stringRef, buf, size, kCFStringEncodingASCII)) {
212             result = buf;
213         }
214         delete [] buf;
215         return result;
216 }
217 #endif // HAVE_COREAUDIO
218
219 bool
220 get_soundfile_info (string path, SoundFileInfo& _info)
221 {
222 #ifdef HAVE_COREAUDIO
223         OSStatus err = noErr;
224     FSRef ref; 
225         ExtAudioFileRef af = 0;
226         size_t size;
227     CFStringRef name;
228
229     err = FSPathMakeRef ((UInt8*)path.c_str(), &ref, 0);
230         if (err != noErr) {
231         ExtAudioFileDispose (af);
232                 goto libsndfile;
233         }
234
235         err = ExtAudioFileOpen(&ref, &af);
236         if (err != noErr) {
237         ExtAudioFileDispose (af);
238                 goto libsndfile;
239         }
240
241         AudioStreamBasicDescription absd;
242         memset(&absd, 0, sizeof(absd));
243         size = sizeof(AudioStreamBasicDescription);
244         err = ExtAudioFileGetProperty(af,
245                         kExtAudioFileProperty_FileDataFormat, &size, &absd);
246         if (err != noErr) {
247         ExtAudioFileDispose (af);
248                 goto libsndfile;
249         }
250
251         _info.samplerate = absd.mSampleRate;
252         _info.channels   = absd.mChannelsPerFrame;
253
254     size = sizeof(_info.length);
255     err = ExtAudioFileGetProperty(af, kExtAudioFileProperty_FileLengthFrames, &size, &_info.length);
256     if (err != noErr) {
257         ExtAudioFileDispose (af);
258                 goto libsndfile;
259     }
260
261         size = sizeof(CFStringRef);
262         err = AudioFormatGetProperty(
263                         kAudioFormatProperty_FormatName, sizeof(absd), &absd, &size, &name);
264         if (err != noErr) {
265         ExtAudioFileDispose (af);
266                 goto libsndfile;
267         }
268
269         _info.format_name = CFStringRefToStdString(name);
270
271     ExtAudioFileDispose (af);
272         return true;
273         
274 libsndfile:
275 #endif // HAVE_COREAUDIO
276
277         SNDFILE *sf;
278         SF_INFO sf_info;
279
280         sf_info.format = 0; // libsndfile says to clear this before sf_open().
281
282         if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) { 
283                 return false;
284         }
285
286         sf_close (sf);
287
288         _info.samplerate  = sf_info.samplerate;
289         _info.channels    = sf_info.channels;
290         _info.length      = sf_info.frames;
291         _info.format_name = string_compose("Format: %1, %2",
292                         sndfile_major_format(sf_info.format),
293                         sndfile_minor_format(sf_info.format));
294
295         return true;
296 }
297