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 bool seek(uint64_t pos
) override final
;
75 std::pair
<uint64_t,uint64_t> getLoopPoints() const override final
;
77 ALuint
read(ALvoid
*ptr
, ALuint count
) override final
;
80 VorbisFileDecoder::~VorbisFileDecoder()
82 ov_clear(mOggFile
.get());
86 ALuint
VorbisFileDecoder::getFrequency() const
88 return mVorbisInfo
->rate
;
91 ChannelConfig
VorbisFileDecoder::getChannelConfig() const
93 return mChannelConfig
;
96 SampleType
VorbisFileDecoder::getSampleType() const
98 return SampleType::Int16
;
102 uint64_t VorbisFileDecoder::getLength() const
104 ogg_int64_t len
= ov_pcm_total(mOggFile
.get(), -1);
105 return std::max
<ogg_int64_t
>(len
, 0);
108 bool VorbisFileDecoder::seek(uint64_t pos
)
110 return ov_pcm_seek(mOggFile
.get(), pos
) == 0;
113 std::pair
<uint64_t,uint64_t> VorbisFileDecoder::getLoopPoints() const
115 return std::make_pair(0, 0);
118 ALuint
VorbisFileDecoder::read(ALvoid
*ptr
, ALuint count
)
121 ALshort
*samples
= (ALshort
*)ptr
;
124 int len
= (count
-total
) * mVorbisInfo
->channels
* 2;
125 #ifdef __BIG_ENDIAN__
126 long got
= ov_read(mOggFile
.get(), reinterpret_cast<char*>(samples
), len
, 1, 2, 1, &mOggBitstream
);
128 long got
= ov_read(mOggFile
.get(), reinterpret_cast<char*>(samples
), len
, 0, 2, 1, &mOggBitstream
);
134 got
/= mVorbisInfo
->channels
;
138 // 1, 2, and 4 channel files decode into the same channel order as
139 // OpenAL, however 6 (5.1), 7 (6.1), and 8 (7.1) channel files need to be
141 if(mChannelConfig
== ChannelConfig::X51
)
143 samples
= (ALshort
*)ptr
;
144 for(ALuint i
= 0;i
< total
;++i
)
146 // OpenAL : FL, FR, FC, LFE, RL, RR
147 // Vorbis : FL, FC, FR, RL, RR, LFE
148 std::swap(samples
[i
*6 + 1], samples
[i
*6 + 2]);
149 std::swap(samples
[i
*6 + 3], samples
[i
*6 + 5]);
150 std::swap(samples
[i
*6 + 4], samples
[i
*6 + 5]);
153 else if(mChannelConfig
== ChannelConfig::X61
)
155 samples
= (ALshort
*)ptr
;
156 for(ALuint i
= 0;i
< total
;++i
)
158 // OpenAL : FL, FR, FC, LFE, RC, SL, SR
159 // Vorbis : FL, FC, FR, SL, SR, RC, LFE
160 std::swap(samples
[i
*7 + 1], samples
[i
*7 + 2]);
161 std::swap(samples
[i
*7 + 3], samples
[i
*7 + 6]);
162 std::swap(samples
[i
*7 + 4], samples
[i
*7 + 5]);
163 std::swap(samples
[i
*7 + 5], samples
[i
*7 + 6]);
166 else if(mChannelConfig
== ChannelConfig::X71
)
168 samples
= (ALshort
*)ptr
;
169 for(ALuint i
= 0;i
< total
;++i
)
171 // OpenAL : FL, FR, FC, LFE, RL, RR, SL, SR
172 // Vorbis : FL, FC, FR, SL, SR, RL, RR, LFE
173 std::swap(samples
[i
*8 + 1], samples
[i
*8 + 2]);
174 std::swap(samples
[i
*8 + 3], samples
[i
*8 + 7]);
175 std::swap(samples
[i
*8 + 4], samples
[i
*8 + 5]);
176 std::swap(samples
[i
*8 + 5], samples
[i
*8 + 6]);
177 std::swap(samples
[i
*8 + 6], samples
[i
*8 + 7]);
185 SharedPtr
<Decoder
> VorbisFileDecoderFactory::createDecoder(UniquePtr
<std::istream
> &file
)
187 static const ov_callbacks streamIO
= {
188 read
, seek
, close
, tell
191 vorbis_info
*vorbisinfo
= nullptr;
192 auto oggfile
= MakeUnique
<OggVorbis_File
>();
193 if(ov_open_callbacks(file
.get(), oggfile
.get(), NULL
, 0, streamIO
) != 0)
196 vorbisinfo
= ov_info(oggfile
.get(), -1);
199 ov_clear(oggfile
.get());
203 ChannelConfig channels
= ChannelConfig::Mono
;
204 if(vorbisinfo
->channels
== 1)
205 channels
= ChannelConfig::Mono
;
206 else if(vorbisinfo
->channels
== 2)
207 channels
= ChannelConfig::Stereo
;
208 else if(vorbisinfo
->channels
== 4)
209 channels
= ChannelConfig::Quad
;
210 else if(vorbisinfo
->channels
== 6)
211 channels
= ChannelConfig::X51
;
212 else if(vorbisinfo
->channels
== 7)
213 channels
= ChannelConfig::X61
;
214 else if(vorbisinfo
->channels
== 8)
215 channels
= ChannelConfig::X71
;
218 ov_clear(oggfile
.get());
222 return MakeShared
<VorbisFileDecoder
>(
223 std::move(file
), std::move(oggfile
), vorbisinfo
, channels