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
34 #include <tremor/ivorbiscodec.h>
35 #include <tremor/ivorbisfile.h>
37 #include <vorbis/vorbisfile.h>
42 static void *vorbisfile_handle
;
43 #define MAKE_FUNC(x) static typeof(x)* p##x
46 MAKE_FUNC(ov_open_callbacks
);
47 MAKE_FUNC(ov_pcm_seek
);
48 MAKE_FUNC(ov_pcm_total
);
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
59 #define vorbisfile_handle 1
63 struct oggStream
: public alureStream
{
65 OggVorbis_File oggFile
;
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
82 #define VORBISFILE_LIB "libvorbisidec.so.1"
83 #define VORBISFILE_LIB2 0
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
93 #define VORBISFILE_LIB "libvorbisfile.so.3"
94 #define VORBISFILE_LIB2 0
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
);
111 if(vorbisfile_handle
)
112 CloseLib(vorbisfile_handle
);
113 vorbisfile_handle
= NULL
;
116 static void Init() { }
117 static void Deinit() { }
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);
128 *frequency
= oggInfo
->rate
;
129 *blockalign
= oggInfo
->channels
*2;
133 virtual ALuint
GetData(ALubyte
*data
, ALuint bytes
)
138 #ifdef HAS_VORBISIDEC
139 int res
= ov_read(&oggFile
, (char*)&data
[got
], bytes
, &oggBitstream
);
141 int res
= ov_read(&oggFile
, (char*)&data
[got
], bytes
, BigEndian
?1:0, 2, 1, &oggBitstream
);
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
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]);
193 virtual bool Rewind()
195 if(ov_pcm_seek(&oggFile
, 0) == 0)
198 SetError("Seek failed");
202 virtual alureInt64
GetLength()
204 ogg_int64_t len
= ov_pcm_total(&oggFile
, oggBitstream
);
205 if(len
< 0) return 0;
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);
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
;
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
);
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
;
257 stream
->read(static_cast<char*>(ptr
), nmemb
*size
);
258 size_t ret
= stream
->gcount();
262 static long tell(void *user_data
)
264 std::istream
*stream
= static_cast<oggStream
*>(user_data
)->fstream
;
266 return stream
->tellg();
269 static int close(void*)
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
; }