Remove the source's public update method
[alure.git] / src / decoders / vorbisfile.cpp
blob00fbb9c97404c195fdddd962e635c3393d526fad
2 #include "vorbisfile.hpp"
4 #include <stdexcept>
5 #include <iostream>
7 #include "vorbis/vorbisfile.h"
9 namespace alure
12 static int seek(void *user_data, ogg_int64_t offset, int whence)
14 std::istream *stream = static_cast<std::istream*>(user_data);
15 stream->clear();
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);
23 else
24 return -1;
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);
32 stream->clear();
34 stream->read(static_cast<char*>(ptr), nmemb*size);
35 size_t ret = stream->gcount();
36 return ret/size;
39 static long tell(void *user_data)
41 std::istream *stream = static_cast<std::istream*>(user_data);
42 stream->clear();
43 return stream->tellg();
46 static int close(void*)
48 return 0;
52 class VorbisFileDecoder : public Decoder {
53 UniquePtr<std::istream> mFile;
55 UniquePtr<OggVorbis_File> mOggFile;
56 vorbis_info *mVorbisInfo;
57 int mOggBitstream;
59 ChannelConfig mChannelConfig;
61 public:
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)
65 { }
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)
127 ALuint total = 0;
128 ALshort *samples = (ALshort*)ptr;
129 while(total < count)
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);
134 #else
135 long got = ov_read(mOggFile.get(), reinterpret_cast<char*>(samples), len, 0, 2, 1, &mOggBitstream);
136 #endif
137 if(got <= 0) break;
139 got /= 2;
140 samples += got;
141 got /= mVorbisInfo->channels;
142 total += got;
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
147 // re-ordered.
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]);
188 return total;
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)
201 return nullptr;
203 vorbisinfo = ov_info(oggfile.get(), -1);
204 if(!vorbisinfo)
206 ov_clear(oggfile.get());
207 return nullptr;
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;
223 else
225 ov_clear(oggfile.get());
226 return nullptr;
229 return MakeShared<VorbisFileDecoder>(
230 std::move(file), std::move(oggfile), vorbisinfo, channels