Also check for libvorbisfile.dll and libvorbisidec.dll in Windows
[alure.git] / src / codec_vorbisfile.cpp
blob14cd55077f3b3d05329966ba6ad1574942e1fcfc
1 /*
2 * ALURE OpenAL utility library
3 * Copyright (c) 2009-2010 by Chris Robinson.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
24 #include "config.h"
26 #include "main.h"
28 #include <string.h>
29 #include <assert.h>
31 #include <istream>
33 #ifdef HAS_VORBISIDEC
34 #include <tremor/ivorbiscodec.h>
35 #include <tremor/ivorbisfile.h>
36 #else
37 #include <vorbis/vorbisfile.h>
38 #endif
41 #ifdef DYNLOAD
42 static void *vorbisfile_handle;
43 #define MAKE_FUNC(x) static typeof(x)* p##x
44 MAKE_FUNC(ov_clear);
45 MAKE_FUNC(ov_info);
46 MAKE_FUNC(ov_open_callbacks);
47 MAKE_FUNC(ov_pcm_seek);
48 MAKE_FUNC(ov_pcm_total);
49 MAKE_FUNC(ov_read);
50 #undef MAKE_FUNC
52 #define ov_clear pov_clear
53 #define ov_info pov_info
54 #define ov_open_callbacks pov_open_callbacks
55 #define ov_pcm_seek pov_pcm_seek
56 #define ov_pcm_total pov_pcm_total
57 #define ov_read pov_read
58 #else
59 #define vorbisfile_handle 1
60 #endif
63 struct oggStream : public alureStream {
64 private:
65 OggVorbis_File oggFile;
66 vorbis_info *oggInfo;
67 int oggBitstream;
68 ALenum format;
70 public:
71 #ifdef DYNLOAD
72 static void Init()
74 #ifdef HAS_VORBISIDEC
75 #ifdef _WIN32
76 #define VORBISFILE_LIB "vorbisidec.dll"
77 #define VORBISFILE_LIB2 "libvorbisidec.dll"
78 #elif defined(__APPLE__)
79 #define VORBISFILE_LIB "libvorbisidec.1.dylib"
80 #define VORBISFILE_LIB2 0
81 #else
82 #define VORBISFILE_LIB "libvorbisidec.so.1"
83 #define VORBISFILE_LIB2 0
84 #endif
85 #else
86 #ifdef _WIN32
87 #define VORBISFILE_LIB "vorbisfile.dll"
88 #define VORBISFILE_LIB2 "libvorbisfile.dll"
89 #elif defined(__APPLE__)
90 #define VORBISFILE_LIB "libvorbisfile.3.dylib"
91 #define VORBISFILE_LIB2 0
92 #else
93 #define VORBISFILE_LIB "libvorbisfile.so.3"
94 #define VORBISFILE_LIB2 0
95 #endif
96 #endif
97 vorbisfile_handle = OpenLib(VORBISFILE_LIB);
98 if(!vorbisfile_handle && VORBISFILE_LIB2)
99 vorbisfile_handle = OpenLib(VORBISFILE_LIB2);
100 if(!vorbisfile_handle) return;
102 LOAD_FUNC(vorbisfile_handle, ov_clear);
103 LOAD_FUNC(vorbisfile_handle, ov_info);
104 LOAD_FUNC(vorbisfile_handle, ov_open_callbacks);
105 LOAD_FUNC(vorbisfile_handle, ov_pcm_seek);
106 LOAD_FUNC(vorbisfile_handle, ov_pcm_total);
107 LOAD_FUNC(vorbisfile_handle, ov_read);
109 static void Deinit()
111 if(vorbisfile_handle)
112 CloseLib(vorbisfile_handle);
113 vorbisfile_handle = NULL;
115 #else
116 static void Init() { }
117 static void Deinit() { }
118 #endif
120 virtual bool IsValid()
121 { return oggInfo != NULL; }
123 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
125 if(format == AL_NONE)
126 format = GetSampleFormat(oggInfo->channels, 16, false);
127 *fmt = format;
128 *frequency = oggInfo->rate;
129 *blockalign = oggInfo->channels*2;
130 return true;
133 virtual ALuint GetData(ALubyte *data, ALuint bytes)
135 ALuint got = 0;
136 while(bytes > 0)
138 #ifdef HAS_VORBISIDEC
139 int res = ov_read(&oggFile, (char*)&data[got], bytes, &oggBitstream);
140 #else
141 int res = ov_read(&oggFile, (char*)&data[got], bytes, BigEndian?1:0, 2, 1, &oggBitstream);
142 #endif
143 if(res <= 0)
144 break;
145 bytes -= res;
146 got += res;
148 // 1, 2, and 4 channel files decode into the same channel order as
149 // OpenAL, however 6(5.1), 7(6.1), and 8(7.1) channel files need to be
150 // re-ordered
151 if(oggInfo->channels == 6)
153 ALshort *samples = (ALshort*)data;
154 for(ALuint i = 0;i < got/sizeof(ALshort);i+=6)
156 // OpenAL : FL, FR, FC, LFE, RL, RR
157 // Vorbis : FL, FC, FR, RL, RR, LFE
158 swap(samples[i+1], samples[i+2]);
159 swap(samples[i+3], samples[i+5]);
160 swap(samples[i+4], samples[i+5]);
163 else if(oggInfo->channels == 7)
165 ALshort *samples = (ALshort*)data;
166 for(ALuint i = 0;i < got/sizeof(ALshort);i+=7)
168 // OpenAL : FL, FR, FC, LFE, RC, SL, SR
169 // Vorbis : FL, FC, FR, SL, SR, RC, LFE
170 swap(samples[i+1], samples[i+2]);
171 swap(samples[i+3], samples[i+6]);
172 swap(samples[i+4], samples[i+6]);
173 swap(samples[i+5], samples[i+6]);
176 else if(oggInfo->channels == 8)
178 ALshort *samples = (ALshort*)data;
179 for(ALuint i = 0;i < got/sizeof(ALshort);i+=8)
181 // OpenAL : FL, FR, FC, LFE, RL, RR, SL, SR
182 // Vorbis : FL, FC, FR, SL, SR, RL, RR, LFE
183 swap(samples[i+1], samples[i+2]);
184 swap(samples[i+3], samples[i+7]);
185 swap(samples[i+4], samples[i+5]);
186 swap(samples[i+5], samples[i+6]);
187 swap(samples[i+6], samples[i+7]);
190 return got;
193 virtual bool Rewind()
195 if(ov_pcm_seek(&oggFile, 0) == 0)
196 return true;
198 SetError("Seek failed");
199 return false;
202 virtual alureInt64 GetLength()
204 ogg_int64_t len = ov_pcm_total(&oggFile, oggBitstream);
205 if(len < 0) return 0;
206 return len;
209 oggStream(std::istream *_fstream)
210 : alureStream(_fstream), oggInfo(NULL), oggBitstream(0), format(AL_NONE)
212 if(!vorbisfile_handle) return;
214 const ov_callbacks streamIO = {
215 read, seek, close, tell
218 if(ov_open_callbacks(this, &oggFile, NULL, 0, streamIO) == 0)
220 oggInfo = ov_info(&oggFile, -1);
221 if(!oggInfo)
222 ov_clear(&oggFile);
226 virtual ~oggStream()
228 if(oggInfo)
229 ov_clear(&oggFile);
230 oggInfo = NULL;
233 private:
234 // libVorbisFile iostream callbacks
235 static int seek(void *user_data, ogg_int64_t offset, int whence)
237 std::istream *stream = static_cast<oggStream*>(user_data)->fstream;
238 stream->clear();
240 if(whence == SEEK_CUR)
241 stream->seekg(offset, std::ios_base::cur);
242 else if(whence == SEEK_SET)
243 stream->seekg(offset, std::ios_base::beg);
244 else if(whence == SEEK_END)
245 stream->seekg(offset, std::ios_base::end);
246 else
247 return -1;
249 return stream->tellg();
252 static size_t read(void *ptr, size_t size, size_t nmemb, void *user_data)
254 std::istream *stream = static_cast<oggStream*>(user_data)->fstream;
255 stream->clear();
257 stream->read(static_cast<char*>(ptr), nmemb*size);
258 size_t ret = stream->gcount();
259 return ret/size;
262 static long tell(void *user_data)
264 std::istream *stream = static_cast<oggStream*>(user_data)->fstream;
265 stream->clear();
266 return stream->tellg();
269 static int close(void*)
271 return 0;
274 // Priority = 2, so it's preferred over libsndfile and libFLAC
275 static DecoderDecl<oggStream,2> oggStream_decoder;
276 Decoder &alure_init_vorbisfile(void)
277 { return oggStream_decoder; }