2 #include "vorbisfile.hpp"
7 #include "vorbis/vorbisfile.h"
12 static int seek(void *user_data
, ogg_int64_t offset
, int whence
)
14 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
17 if(whence
== SEEK_CUR
)
18 stream
->seekg(offset
, std::ios_base::cur
);
19 else if(whence
== SEEK_SET
)
20 stream
->seekg(offset
, std::ios_base::beg
);
21 else if(whence
== SEEK_END
)
22 stream
->seekg(offset
, std::ios_base::end
);
26 return stream
->tellg();
29 static size_t read(void *ptr
, size_t size
, size_t nmemb
, void *user_data
)
31 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
34 stream
->read(static_cast<char*>(ptr
), nmemb
*size
);
35 size_t ret
= stream
->gcount();
39 static long tell(void *user_data
)
41 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
43 return stream
->tellg();
46 static int close(void*)
52 class VorbisFileDecoder
: public Decoder
{
53 UniquePtr
<std::istream
> mFile
;
55 UniquePtr
<OggVorbis_File
> mOggFile
;
56 vorbis_info
*mVorbisInfo
;
59 ChannelConfig mChannelConfig
;
62 VorbisFileDecoder(UniquePtr
<std::istream
> file
, UniquePtr
<OggVorbis_File
> oggfile
, vorbis_info
*vorbisinfo
, ChannelConfig sconfig
)
63 : mFile(std::move(file
)), mOggFile(std::move(oggfile
)), mVorbisInfo(vorbisinfo
)
64 , mOggBitstream(0), mChannelConfig(sconfig
)
66 ~VorbisFileDecoder() override final
;
68 ALuint
getFrequency() const override final
;
69 ChannelConfig
getChannelConfig() const override final
;
70 SampleType
getSampleType() const override final
;
72 uint64_t getLength() const override final
;
73 uint64_t getPosition() const override final
;
74 bool seek(uint64_t pos
) override final
;
76 std::pair
<uint64_t,uint64_t> getLoopPoints() const override final
;
78 ALuint
read(ALvoid
*ptr
, ALuint count
) override final
;
81 VorbisFileDecoder::~VorbisFileDecoder()
83 ov_clear(mOggFile
.get());
87 ALuint
VorbisFileDecoder::getFrequency() const
89 return mVorbisInfo
->rate
;
92 ChannelConfig
VorbisFileDecoder::getChannelConfig() const
94 return mChannelConfig
;
97 SampleType
VorbisFileDecoder::getSampleType() const
99 return SampleType::Int16
;
103 uint64_t VorbisFileDecoder::getLength() const
105 ogg_int64_t len
= ov_pcm_total(mOggFile
.get(), -1);
106 return std::max
<ogg_int64_t
>(len
, 0);
109 uint64_t VorbisFileDecoder::getPosition() const
111 ogg_int64_t pos
= ov_pcm_tell(mOggFile
.get());
112 return std::max
<ogg_int64_t
>(pos
, 0);
115 bool VorbisFileDecoder::seek(uint64_t pos
)
117 return ov_pcm_seek(mOggFile
.get(), pos
) == 0;
120 std::pair
<uint64_t,uint64_t> VorbisFileDecoder::getLoopPoints() const
122 return std::make_pair(0, 0);
125 ALuint
VorbisFileDecoder::read(ALvoid
*ptr
, ALuint count
)
128 ALshort
*samples
= (ALshort
*)ptr
;
131 int len
= (count
-total
) * mVorbisInfo
->channels
* 2;
132 #ifdef __BIG_ENDIAN__
133 long got
= ov_read(mOggFile
.get(), reinterpret_cast<char*>(samples
), len
, 1, 2, 1, &mOggBitstream
);
135 long got
= ov_read(mOggFile
.get(), reinterpret_cast<char*>(samples
), len
, 0, 2, 1, &mOggBitstream
);
141 got
/= mVorbisInfo
->channels
;
145 // 1, 2, and 4 channel files decode into the same channel order as
146 // OpenAL, however 6 (5.1), 7 (6.1), and 8 (7.1) channel files need to be
148 if(mChannelConfig
== ChannelConfig::X51
)
150 samples
= (ALshort
*)ptr
;
151 for(ALuint i
= 0;i
< total
;++i
)
153 // OpenAL : FL, FR, FC, LFE, RL, RR
154 // Vorbis : FL, FC, FR, RL, RR, LFE
155 std::swap(samples
[i
*6 + 1], samples
[i
*6 + 2]);
156 std::swap(samples
[i
*6 + 3], samples
[i
*6 + 5]);
157 std::swap(samples
[i
*6 + 4], samples
[i
*6 + 5]);
160 else if(mChannelConfig
== ChannelConfig::X61
)
162 samples
= (ALshort
*)ptr
;
163 for(ALuint i
= 0;i
< total
;++i
)
165 // OpenAL : FL, FR, FC, LFE, RC, SL, SR
166 // Vorbis : FL, FC, FR, SL, SR, RC, LFE
167 std::swap(samples
[i
*7 + 1], samples
[i
*7 + 2]);
168 std::swap(samples
[i
*7 + 3], samples
[i
*7 + 6]);
169 std::swap(samples
[i
*7 + 4], samples
[i
*7 + 5]);
170 std::swap(samples
[i
*7 + 5], samples
[i
*7 + 6]);
173 else if(mChannelConfig
== ChannelConfig::X71
)
175 samples
= (ALshort
*)ptr
;
176 for(ALuint i
= 0;i
< total
;++i
)
178 // OpenAL : FL, FR, FC, LFE, RL, RR, SL, SR
179 // Vorbis : FL, FC, FR, SL, SR, RL, RR, LFE
180 std::swap(samples
[i
*8 + 1], samples
[i
*8 + 2]);
181 std::swap(samples
[i
*8 + 3], samples
[i
*8 + 7]);
182 std::swap(samples
[i
*8 + 4], samples
[i
*8 + 5]);
183 std::swap(samples
[i
*8 + 5], samples
[i
*8 + 6]);
184 std::swap(samples
[i
*8 + 6], samples
[i
*8 + 7]);
192 SharedPtr
<Decoder
> VorbisFileDecoderFactory::createDecoder(UniquePtr
<std::istream
> &file
)
194 static const ov_callbacks streamIO
= {
195 read
, seek
, close
, tell
198 vorbis_info
*vorbisinfo
= nullptr;
199 auto oggfile
= MakeUnique
<OggVorbis_File
>();
200 if(ov_open_callbacks(file
.get(), oggfile
.get(), NULL
, 0, streamIO
) != 0)
203 vorbisinfo
= ov_info(oggfile
.get(), -1);
206 ov_clear(oggfile
.get());
210 ChannelConfig channels
= ChannelConfig::Mono
;
211 if(vorbisinfo
->channels
== 1)
212 channels
= ChannelConfig::Mono
;
213 else if(vorbisinfo
->channels
== 2)
214 channels
= ChannelConfig::Stereo
;
215 else if(vorbisinfo
->channels
== 4)
216 channels
= ChannelConfig::Quad
;
217 else if(vorbisinfo
->channels
== 6)
218 channels
= ChannelConfig::X51
;
219 else if(vorbisinfo
->channels
== 7)
220 channels
= ChannelConfig::X61
;
221 else if(vorbisinfo
->channels
== 8)
222 channels
= ChannelConfig::X71
;
225 ov_clear(oggfile
.get());
229 return MakeShared
<VorbisFileDecoder
>(
230 std::move(file
), std::move(oggfile
), vorbisinfo
, channels