Manually track the source decoder sample pos
[alure.git] / src / decoders / sndfile.cpp
blob8eca4f26c67b5bdf02bfbb8d3c3cb66b46488459
2 #include "sndfile.hpp"
4 #include <stdexcept>
5 #include <iostream>
7 #include "sndfile.h"
9 namespace alure
12 static sf_count_t get_filelen(void *user_data)
14 std::istream *file = reinterpret_cast<std::istream*>(user_data);
15 sf_count_t len = -1;
17 file->clear();
18 std::streampos pos = file->tellg();
19 if(pos != -1 && file->seekg(0, std::ios::end))
21 len = file->tellg();
22 file->seekg(pos);
24 return len;
27 static sf_count_t seek(sf_count_t offset, int whence, void *user_data)
29 std::istream *file = reinterpret_cast<std::istream*>(user_data);
31 file->clear();
32 if(!file->seekg(offset, std::ios::seekdir(whence)))
33 return -1;
34 return file->tellg();
37 static sf_count_t read(void *ptr, sf_count_t count, void *user_data)
39 std::istream *file = reinterpret_cast<std::istream*>(user_data);
41 file->clear();
42 file->read(reinterpret_cast<char*>(ptr), count);
43 return file->gcount();
46 static sf_count_t write(const void*, sf_count_t, void*)
48 return -1;
51 static sf_count_t tell(void *user_data)
53 std::istream *file = reinterpret_cast<std::istream*>(user_data);
55 file->clear();
56 return file->tellg();
60 class SndFileDecoder : public Decoder {
61 UniquePtr<std::istream> mFile;
63 SNDFILE *mSndFile;
64 SF_INFO mSndInfo;
66 ChannelConfig mChannelConfig;
67 SampleType mSampleType;
69 public:
70 SndFileDecoder(UniquePtr<std::istream> file, SNDFILE *sndfile, const SF_INFO sndinfo, ChannelConfig sconfig, SampleType stype)
71 : mFile(std::move(file)), mSndFile(sndfile), mSndInfo(sndinfo)
72 , mChannelConfig(sconfig), mSampleType(stype)
73 { }
74 ~SndFileDecoder() override final;
76 ALuint getFrequency() const override final;
77 ChannelConfig getChannelConfig() const override final;
78 SampleType getSampleType() const override final;
80 uint64_t getLength() const override final;
81 bool seek(uint64_t pos) override final;
83 std::pair<uint64_t,uint64_t> getLoopPoints() const override final;
85 ALuint read(ALvoid *ptr, ALuint count) override final;
88 SndFileDecoder::~SndFileDecoder()
90 sf_close(mSndFile);
91 mSndFile = 0;
95 ALuint SndFileDecoder::getFrequency() const
97 return mSndInfo.samplerate;
100 ChannelConfig SndFileDecoder::getChannelConfig() const
102 return mChannelConfig;
105 SampleType SndFileDecoder::getSampleType() const
107 return mSampleType;
111 uint64_t SndFileDecoder::getLength() const
113 return std::max<sf_count_t>(mSndInfo.frames, 0);
116 bool SndFileDecoder::seek(uint64_t pos)
118 sf_count_t newpos = sf_seek(mSndFile, pos, SEEK_SET);
119 if(newpos < 0) return false;
120 return true;
123 std::pair<uint64_t,uint64_t> SndFileDecoder::getLoopPoints() const
125 return std::make_pair(0, 0);
128 ALuint SndFileDecoder::read(ALvoid *ptr, ALuint count)
130 sf_count_t got = 0;
131 if(mSampleType == SampleType::Int16)
132 got = sf_readf_short(mSndFile, static_cast<short*>(ptr), count);
133 else if(mSampleType == SampleType::Float32)
134 got = sf_readf_float(mSndFile, static_cast<float*>(ptr), count);
135 return (ALuint)std::max<sf_count_t>(got, 0);
139 SharedPtr<Decoder> SndFileDecoderFactory::createDecoder(UniquePtr<std::istream> &file)
141 SF_VIRTUAL_IO vio = {
142 get_filelen, seek,
143 read, write, tell
145 SF_INFO sndinfo;
146 SNDFILE *sndfile = sf_open_virtual(&vio, SFM_READ, &sndinfo, file.get());
147 if(!sndfile) return nullptr;
149 ChannelConfig sconfig;
150 Vector<int> chanmap(sndinfo.channels);
151 if(sf_command(sndfile, SFC_GET_CHANNEL_MAP_INFO, &chanmap[0], chanmap.size()*sizeof(int)) == SF_TRUE)
153 auto matches = [](const Vector<int> &first, std::initializer_list<int> second) -> bool
155 if(first.size() != second.size())
156 return false;
157 return std::mismatch(first.begin(), first.end(), second.begin()).first == first.end();
160 if(matches(chanmap, {SF_CHANNEL_MAP_MONO}))
161 sconfig = ChannelConfig::Mono;
162 else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT}))
163 sconfig = ChannelConfig::Stereo;
164 else if(matches(chanmap, {SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}))
165 sconfig = ChannelConfig::Rear;
166 else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
167 SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}))
168 sconfig = ChannelConfig::Quad;
169 else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
170 SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
171 SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}) ||
172 matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
173 SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
174 SF_CHANNEL_MAP_SIDE_LEFT, SF_CHANNEL_MAP_SIDE_RIGHT}))
175 sconfig = ChannelConfig::X51;
176 else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
177 SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
178 SF_CHANNEL_MAP_REAR_CENTER, SF_CHANNEL_MAP_SIDE_LEFT,
179 SF_CHANNEL_MAP_SIDE_RIGHT}))
180 sconfig = ChannelConfig::X61;
181 else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
182 SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
183 SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT,
184 SF_CHANNEL_MAP_SIDE_LEFT, SF_CHANNEL_MAP_SIDE_RIGHT}))
185 sconfig = ChannelConfig::X71;
186 else if(matches(chanmap, {SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X,
187 SF_CHANNEL_MAP_AMBISONIC_B_Y}))
188 sconfig = ChannelConfig::BFormat2D;
189 else if(matches(chanmap, {SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X,
190 SF_CHANNEL_MAP_AMBISONIC_B_Y, SF_CHANNEL_MAP_AMBISONIC_B_Z}))
191 sconfig = ChannelConfig::BFormat3D;
192 else
194 sf_close(sndfile);
195 return nullptr;
198 else if(sf_command(sndfile, SFC_WAVEX_GET_AMBISONIC, 0, 0) == SF_AMBISONIC_B_FORMAT)
200 if(sndinfo.channels == 3)
201 sconfig = ChannelConfig::BFormat2D;
202 else if(sndinfo.channels == 4)
203 sconfig = ChannelConfig::BFormat3D;
204 else
206 sf_close(sndfile);
207 return nullptr;
210 else if(sndinfo.channels == 1)
211 sconfig = ChannelConfig::Mono;
212 else if(sndinfo.channels == 2)
213 sconfig = ChannelConfig::Stereo;
214 else
216 sf_close(sndfile);
217 return nullptr;
220 SampleType stype = SampleType::Int16;
221 switch(sndinfo.format&SF_FORMAT_SUBMASK)
223 case SF_FORMAT_FLOAT:
224 case SF_FORMAT_DOUBLE:
225 case SF_FORMAT_VORBIS:
226 if(Context::GetCurrent().isSupported(sconfig, SampleType::Float32))
228 stype = SampleType::Float32;
229 break;
231 /*fall-through*/
232 default:
233 stype = SampleType::Int16;
234 break;
237 return MakeShared<SndFileDecoder>(std::move(file), sndfile, sndinfo, sconfig, stype);