1 // sndfile helper functions
2 //
3 // Copyright (c) 2002 James McCartney. All rights reserved.
4 // Copyright (C) 2012 Tim Blechmann
5 // Copyright (C) 2017 Brian Heim
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; see the file COPYING. If not, write to
19 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 // Boston, MA 02111-1307, USA.
21
22 #pragma once
23
24 #include "SC_Errors.h"
25
26 #ifndef NO_LIBSNDFILE
27
28 // on Windows, enable Windows libsndfile prototypes in order to access sf_wchar_open.
29 // See sndfile.h, lines 739-752. Note that order matters: this has to be the first include of sndfile.h
30 # ifdef _WIN32
31 # include "SC_Codecvt.hpp" // utf8_cstr_to_utf16_wstring
32 # include <windows.h>
33 # define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
34 # endif // _WIN32
35 # include <sndfile.h>
36 # include <sndfile.hh>
37
38 # include "string.h"
39
40 # include <boost/algorithm/string/predicate.hpp> // iequals
41
42 using boost::iequals;
43
headerFormatFromString(const char * name)44 static inline int headerFormatFromString(const char* name) {
45 if (!name)
46 return SF_FORMAT_AIFF;
47 if (iequals(name, "AIFF"))
48 return SF_FORMAT_AIFF;
49 if (iequals(name, "AIFC"))
50 return SF_FORMAT_AIFF;
51 if (iequals(name, "RIFF"))
52 return SF_FORMAT_WAV;
53 if (iequals(name, "WAVEX"))
54 return SF_FORMAT_WAVEX;
55 if (iequals(name, "WAVE"))
56 return SF_FORMAT_WAV;
57 if (iequals(name, "WAV"))
58 return SF_FORMAT_WAV;
59 if (iequals(name, "Sun"))
60 return SF_FORMAT_AU;
61 if (iequals(name, "IRCAM"))
62 return SF_FORMAT_IRCAM;
63 if (iequals(name, "NeXT"))
64 return SF_FORMAT_AU;
65 if (iequals(name, "raw"))
66 return SF_FORMAT_RAW;
67 if (iequals(name, "MAT4"))
68 return SF_FORMAT_MAT4;
69 if (iequals(name, "MAT5"))
70 return SF_FORMAT_MAT5;
71 if (iequals(name, "PAF"))
72 return SF_FORMAT_PAF;
73 if (iequals(name, "SVX"))
74 return SF_FORMAT_SVX;
75 if (iequals(name, "NIST"))
76 return SF_FORMAT_NIST;
77 if (iequals(name, "VOC"))
78 return SF_FORMAT_VOC;
79 if (iequals(name, "W64"))
80 return SF_FORMAT_W64;
81 if (iequals(name, "PVF"))
82 return SF_FORMAT_PVF;
83 if (iequals(name, "XI"))
84 return SF_FORMAT_XI;
85 if (iequals(name, "HTK"))
86 return SF_FORMAT_HTK;
87 if (iequals(name, "SDS"))
88 return SF_FORMAT_SDS;
89 if (iequals(name, "AVR"))
90 return SF_FORMAT_AVR;
91 if (iequals(name, "SD2"))
92 return SF_FORMAT_SD2;
93 if (iequals(name, "FLAC"))
94 return SF_FORMAT_FLAC;
95 // TODO allow other platforms to know vorbis once libsndfile 1.0.18 is established
96 # if defined(__APPLE__) || defined(_WIN32) || LIBSNDFILE_1018
97 if (iequals(name, "vorbis"))
98 return SF_FORMAT_VORBIS;
99 # endif
100 if (iequals(name, "CAF"))
101 return SF_FORMAT_CAF;
102 if (iequals(name, "RF64"))
103 return SF_FORMAT_RF64;
104 return 0;
105 }
106
sampleFormatFromString(const char * name)107 static inline int sampleFormatFromString(const char* name) {
108 if (!name)
109 return SF_FORMAT_PCM_16;
110
111 size_t len = strlen(name);
112 if (len < 1)
113 return 0;
114
115 if (name[0] == 'u') {
116 if (len < 5)
117 return 0;
118 if (name[4] == '8')
119 return SF_FORMAT_PCM_U8; // uint8
120 return 0;
121 } else if (name[0] == 'i') {
122 if (len < 4)
123 return 0;
124 if (name[3] == '8')
125 return SF_FORMAT_PCM_S8; // int8
126 else if (name[3] == '1')
127 return SF_FORMAT_PCM_16; // int16
128 else if (name[3] == '2')
129 return SF_FORMAT_PCM_24; // int24
130 else if (name[3] == '3')
131 return SF_FORMAT_PCM_32; // int32
132 } else if (name[0] == 'f') {
133 return SF_FORMAT_FLOAT; // float
134 } else if (name[0] == 'd') {
135 return SF_FORMAT_DOUBLE; // double
136 } else if (name[0] == 'm' || name[0] == 'u') {
137 return SF_FORMAT_ULAW; // mulaw ulaw
138 } else if (name[0] == 'a') {
139 return SF_FORMAT_ALAW; // alaw
140 }
141 return 0;
142 }
143
sndfileFormatInfoFromStrings(struct SF_INFO * info,const char * headerFormatString,const char * sampleFormatString)144 static inline int sndfileFormatInfoFromStrings(struct SF_INFO* info, const char* headerFormatString,
145 const char* sampleFormatString) {
146 int headerFormat = headerFormatFromString(headerFormatString);
147 if (!headerFormat)
148 return kSCErr_Failed;
149
150 int sampleFormat = sampleFormatFromString(sampleFormatString);
151 if (!sampleFormat)
152 return kSCErr_Failed;
153
154 info->format = (unsigned int)(headerFormat | sampleFormat);
155 return kSCErr_None;
156 }
157
158 // ------------------------------ platform-specific functions ------------------------------
159 # ifdef _WIN32
160
sndfileOpen(LPCWSTR wpath,int mode,SF_INFO * sfinfo)161 inline SNDFILE* sndfileOpen(LPCWSTR wpath, int mode, SF_INFO* sfinfo) { return sf_wchar_open(wpath, mode, sfinfo); }
162
163 // This safely opens a sound file using a raw cstring on any platform
sndfileOpenFromCStr(const char * path,int mode,SF_INFO * sfinfo)164 inline SNDFILE* sndfileOpenFromCStr(const char* path, int mode, SF_INFO* sfinfo) {
165 // convert to wchar first
166 const std::wstring path_w = SC_Codecvt::utf8_cstr_to_utf16_wstring(path);
167 return sndfileOpen(path_w.c_str(), mode, sfinfo);
168 }
169
170 // Safely creates a handle using a raw cstring on any platform
makeSndfileHandle(const char * path,int mode=SFM_READ,int format=0,int channels=0,int samplerate=0)171 inline SndfileHandle makeSndfileHandle(const char* path, int mode = SFM_READ, int format = 0, int channels = 0,
172 int samplerate = 0) {
173 const std::wstring path_w = SC_Codecvt::utf8_cstr_to_utf16_wstring(path);
174 return SndfileHandle(path_w.c_str(), mode, format, channels, samplerate);
175 }
176
177 # else // not _WIN32
178
sndfileOpen(const char * path,int mode,SF_INFO * sfinfo)179 inline SNDFILE* sndfileOpen(const char* path, int mode, SF_INFO* sfinfo) { return sf_open(path, mode, sfinfo); }
180
181 // simple forward
sndfileOpenFromCStr(const char * path,int mode,SF_INFO * sfinfo)182 inline SNDFILE* sndfileOpenFromCStr(const char* path, int mode, SF_INFO* sfinfo) {
183 return sndfileOpen(path, mode, sfinfo);
184 }
185
186 // simple forward
makeSndfileHandle(const char * path,int mode=SFM_READ,int format=0,int channels=0,int samplerate=0)187 inline SndfileHandle makeSndfileHandle(const char* path, int mode = SFM_READ, int format = 0, int channels = 0,
188 int samplerate = 0) {
189 return SndfileHandle(path, mode, format, channels, samplerate);
190 }
191
192 # endif // _WIN32
193
194 #else // not NO_LIBSNDFILE
195
sndfileFormatInfoFromStrings(struct SF_INFO * info,const char * headerFormatString,const char * sampleFormatString)196 static inline int sndfileFormatInfoFromStrings(struct SF_INFO* info, const char* headerFormatString,
197 const char* sampleFormatString) {
198 return kSCErr_Failed;
199 }
200
201 #endif /* NO_LIBSNDFILE */
202