Remove the DYNLOAD option. It's buggy and causes problems.
[alure.git] / src / codec_vorbisfile.cpp
blob06e911b467ee60e67c6c5029196564c99d8d7acc
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 struct oggStream : public alureStream {
42 private:
43 OggVorbis_File oggFile;
44 vorbis_info *oggInfo;
45 int oggBitstream;
46 ALenum format;
48 public:
49 static void Init() { }
50 static void Deinit() { }
52 virtual bool IsValid()
53 { return oggInfo != NULL; }
55 virtual bool GetFormat(ALenum *fmt, ALuint *frequency, ALuint *blockalign)
57 if(format == AL_NONE)
58 format = GetSampleFormat(oggInfo->channels, 16, false);
59 *fmt = format;
60 *frequency = oggInfo->rate;
61 *blockalign = oggInfo->channels*2;
62 return true;
65 virtual ALuint GetData(ALubyte *data, ALuint bytes)
67 ALuint got = 0;
68 while(bytes > 0)
70 #ifdef HAS_VORBISIDEC
71 int res = ov_read(&oggFile, (char*)&data[got], bytes, &oggBitstream);
72 #else
73 int res = ov_read(&oggFile, (char*)&data[got], bytes, BigEndian?1:0, 2, 1, &oggBitstream);
74 #endif
75 if(res <= 0)
76 break;
77 bytes -= res;
78 got += res;
80 // 1, 2, and 4 channel files decode into the same channel order as
81 // OpenAL, however 6(5.1), 7(6.1), and 8(7.1) channel files need to be
82 // re-ordered
83 if(oggInfo->channels == 6)
85 ALshort *samples = (ALshort*)data;
86 for(ALuint i = 0;i < got/sizeof(ALshort);i+=6)
88 // OpenAL : FL, FR, FC, LFE, RL, RR
89 // Vorbis : FL, FC, FR, RL, RR, LFE
90 swap(samples[i+1], samples[i+2]);
91 swap(samples[i+3], samples[i+5]);
92 swap(samples[i+4], samples[i+5]);
95 else if(oggInfo->channels == 7)
97 ALshort *samples = (ALshort*)data;
98 for(ALuint i = 0;i < got/sizeof(ALshort);i+=7)
100 // OpenAL : FL, FR, FC, LFE, RC, SL, SR
101 // Vorbis : FL, FC, FR, SL, SR, RC, LFE
102 swap(samples[i+1], samples[i+2]);
103 swap(samples[i+3], samples[i+6]);
104 swap(samples[i+4], samples[i+6]);
105 swap(samples[i+5], samples[i+6]);
108 else if(oggInfo->channels == 8)
110 ALshort *samples = (ALshort*)data;
111 for(ALuint i = 0;i < got/sizeof(ALshort);i+=8)
113 // OpenAL : FL, FR, FC, LFE, RL, RR, SL, SR
114 // Vorbis : FL, FC, FR, SL, SR, RL, RR, LFE
115 swap(samples[i+1], samples[i+2]);
116 swap(samples[i+3], samples[i+7]);
117 swap(samples[i+4], samples[i+5]);
118 swap(samples[i+5], samples[i+6]);
119 swap(samples[i+6], samples[i+7]);
122 return got;
125 virtual bool Rewind()
127 if(ov_pcm_seek(&oggFile, 0) == 0)
128 return true;
130 SetError("Seek failed");
131 return false;
134 virtual alureInt64 GetLength()
136 ogg_int64_t len = ov_pcm_total(&oggFile, oggBitstream);
137 if(len < 0) return 0;
138 return len;
141 oggStream(std::istream *_fstream)
142 : alureStream(_fstream), oggInfo(NULL), oggBitstream(0), format(AL_NONE)
144 const ov_callbacks streamIO = {
145 read, seek, close, tell
148 if(ov_open_callbacks(this, &oggFile, NULL, 0, streamIO) == 0)
150 oggInfo = ov_info(&oggFile, -1);
151 if(!oggInfo)
152 ov_clear(&oggFile);
156 virtual ~oggStream()
158 if(oggInfo)
159 ov_clear(&oggFile);
160 oggInfo = NULL;
163 private:
164 // libVorbisFile iostream callbacks
165 static int seek(void *user_data, ogg_int64_t offset, int whence)
167 std::istream *stream = static_cast<oggStream*>(user_data)->fstream;
168 stream->clear();
170 if(whence == SEEK_CUR)
171 stream->seekg(offset, std::ios_base::cur);
172 else if(whence == SEEK_SET)
173 stream->seekg(offset, std::ios_base::beg);
174 else if(whence == SEEK_END)
175 stream->seekg(offset, std::ios_base::end);
176 else
177 return -1;
179 return stream->tellg();
182 static size_t read(void *ptr, size_t size, size_t nmemb, void *user_data)
184 std::istream *stream = static_cast<oggStream*>(user_data)->fstream;
185 stream->clear();
187 stream->read(static_cast<char*>(ptr), nmemb*size);
188 size_t ret = stream->gcount();
189 return ret/size;
192 static long tell(void *user_data)
194 std::istream *stream = static_cast<oggStream*>(user_data)->fstream;
195 stream->clear();
196 return stream->tellg();
199 static int close(void*)
201 return 0;
204 // Priority = 2, so it's preferred over libsndfile and libFLAC
205 static DecoderDecl<oggStream,2> oggStream_decoder;
206 Decoder &alure_init_vorbisfile(void)
207 { return oggStream_decoder; }