2 #include "opusfile.hpp"
15 static int read(void *user_data
, unsigned char *ptr
, int size
)
17 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
20 if(size
< 0 || !stream
->read(reinterpret_cast<char*>(ptr
), size
))
22 return stream
->gcount();
25 static int seek(void *user_data
, opus_int64 offset
, int whence
)
27 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
30 if(whence
== SEEK_CUR
)
31 stream
->seekg(offset
, std::ios_base::cur
);
32 else if(whence
== SEEK_SET
)
33 stream
->seekg(offset
, std::ios_base::beg
);
34 else if(whence
== SEEK_END
)
35 stream
->seekg(offset
, std::ios_base::end
);
39 return stream
->good() ? 0 : -1;
42 static opus_int64
tell(void *user_data
)
44 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
46 return stream
->tellg();
50 template<typename T
> struct OggTypeInfo
{ };
52 struct OggTypeInfo
<ogg_int16_t
>
54 template<typename
...Args
>
55 static int read(Args
&& ...args
)
56 { return op_read(std::forward
<Args
>(args
)...); }
59 struct OggTypeInfo
<float>
61 template<typename
...Args
>
62 static int read(Args
&& ...args
)
63 { return op_read_float(std::forward
<Args
>(args
)...); }
66 class OpusFileDecoder
: public Decoder
{
67 UniquePtr
<std::istream
> mFile
;
69 OggOpusFile
*mOggFile
;
72 ChannelConfig mChannelConfig
;
73 SampleType mSampleType
;
76 ALuint
do_read(T
*ptr
, ALuint count
)
80 int num_chans
= FramesToBytes(1, mChannelConfig
, SampleType::UInt8
);
83 if(num_chans
!= op_head(mOggFile
, -1)->channel_count
)
85 int len
= (count
-total
) * num_chans
;
87 long got
= OggTypeInfo
<T
>::read(mOggFile
, samples
, len
, &mOggBitstream
);
90 samples
+= got
*num_chans
;
94 // 1, 2, and 4 channel files decode into the same channel order as
95 // OpenAL, however 6 (5.1), 7 (6.1), and 8 (7.1) channel files need to be
97 if(mChannelConfig
== ChannelConfig::X51
)
100 for(ALuint i
= 0;i
< total
;++i
)
102 // OpenAL : FL, FR, FC, LFE, RL, RR
103 // Opus : FL, FC, FR, RL, RR, LFE
104 std::swap(samples
[i
*6 + 1], samples
[i
*6 + 2]);
105 std::swap(samples
[i
*6 + 3], samples
[i
*6 + 5]);
106 std::swap(samples
[i
*6 + 4], samples
[i
*6 + 5]);
109 else if(mChannelConfig
== ChannelConfig::X61
)
112 for(ALuint i
= 0;i
< total
;++i
)
114 // OpenAL : FL, FR, FC, LFE, RC, SL, SR
115 // Opus : FL, FC, FR, SL, SR, RC, LFE
116 std::swap(samples
[i
*7 + 1], samples
[i
*7 + 2]);
117 std::swap(samples
[i
*7 + 3], samples
[i
*7 + 6]);
118 std::swap(samples
[i
*7 + 4], samples
[i
*7 + 5]);
119 std::swap(samples
[i
*7 + 5], samples
[i
*7 + 6]);
122 else if(mChannelConfig
== ChannelConfig::X71
)
125 for(ALuint i
= 0;i
< total
;++i
)
127 // OpenAL : FL, FR, FC, LFE, RL, RR, SL, SR
128 // Opus : FL, FC, FR, SL, SR, RL, RR, LFE
129 std::swap(samples
[i
*8 + 1], samples
[i
*8 + 2]);
130 std::swap(samples
[i
*8 + 3], samples
[i
*8 + 7]);
131 std::swap(samples
[i
*8 + 4], samples
[i
*8 + 5]);
132 std::swap(samples
[i
*8 + 5], samples
[i
*8 + 6]);
133 std::swap(samples
[i
*8 + 6], samples
[i
*8 + 7]);
141 OpusFileDecoder(UniquePtr
<std::istream
> file
, OggOpusFile
*oggfile
, ChannelConfig sconfig
, SampleType stype
)
142 : mFile(std::move(file
)), mOggFile(oggfile
), mOggBitstream(0), mChannelConfig(sconfig
), mSampleType(stype
)
144 ~OpusFileDecoder() override final
;
146 ALuint
getFrequency() const override final
;
147 ChannelConfig
getChannelConfig() const override final
;
148 SampleType
getSampleType() const override final
;
150 uint64_t getLength() const override final
;
151 uint64_t getPosition() const override final
;
152 bool seek(uint64_t pos
) override final
;
154 std::pair
<uint64_t,uint64_t> getLoopPoints() const override final
;
156 ALuint
read(ALvoid
*ptr
, ALuint count
) override final
;
159 OpusFileDecoder::~OpusFileDecoder()
165 ALuint
OpusFileDecoder::getFrequency() const
167 // libopusfile always decodes to 48khz.
171 ChannelConfig
OpusFileDecoder::getChannelConfig() const
173 return mChannelConfig
;
176 SampleType
OpusFileDecoder::getSampleType() const
182 uint64_t OpusFileDecoder::getLength() const
184 ogg_int64_t len
= op_pcm_total(mOggFile
, -1);
185 return std::max
<ogg_int64_t
>(len
, 0);
188 uint64_t OpusFileDecoder::getPosition() const
190 ogg_int64_t pos
= op_pcm_tell(mOggFile
);
191 return std::max
<ogg_int64_t
>(pos
, 0);
194 bool OpusFileDecoder::seek(uint64_t pos
)
196 return op_pcm_seek(mOggFile
, pos
) == 0;
199 std::pair
<uint64_t,uint64_t> OpusFileDecoder::getLoopPoints() const
201 return std::make_pair(0, std::numeric_limits
<uint64_t>::max());
204 ALuint
OpusFileDecoder::read(ALvoid
*ptr
, ALuint count
)
206 if(mSampleType
== SampleType::Float32
)
207 return do_read
<float>(reinterpret_cast<float*>(ptr
), count
);
208 return do_read
<ogg_int16_t
>(reinterpret_cast<ogg_int16_t
*>(ptr
), count
);
212 SharedPtr
<Decoder
> OpusFileDecoderFactory::createDecoder(UniquePtr
<std::istream
> &file
)
214 static const OpusFileCallbacks streamIO
= {
215 read
, seek
, tell
, nullptr
218 OggOpusFile
*oggfile
= op_open_callbacks(file
.get(), &streamIO
, nullptr, 0, nullptr);
219 if(!oggfile
) return nullptr;
221 int num_chans
= op_head(oggfile
, -1)->channel_count
;
222 ChannelConfig channels
= ChannelConfig::Mono
;
224 channels
= ChannelConfig::Mono
;
225 else if(num_chans
== 2)
226 channels
= ChannelConfig::Stereo
;
227 else if(num_chans
== 4)
228 channels
= ChannelConfig::Quad
;
229 else if(num_chans
== 6)
230 channels
= ChannelConfig::X51
;
231 else if(num_chans
== 7)
232 channels
= ChannelConfig::X61
;
233 else if(num_chans
== 8)
234 channels
= ChannelConfig::X71
;
241 if(Context::GetCurrent().isSupported(channels
, SampleType::Float32
))
242 return MakeShared
<OpusFileDecoder
>(std::move(file
), oggfile
, channels
, SampleType::Float32
);
243 return MakeShared
<OpusFileDecoder
>(std::move(file
), oggfile
, channels
, SampleType::Int16
);