Check for and read float samples from opusfile and sndfile
[alure.git] / src / decoders / sndfile.cpp
bloba94ec5596359ca0ac85f53e83b0468d9155aab9f
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 uint64_t getPosition() const override final;
82 bool seek(uint64_t pos) override final;
84 std::pair<uint64_t,uint64_t> getLoopPoints() const override final;
86 ALuint read(ALvoid *ptr, ALuint count) override final;
89 SndFileDecoder::~SndFileDecoder()
91 sf_close(mSndFile);
92 mSndFile = 0;
96 ALuint SndFileDecoder::getFrequency() const
98 return mSndInfo.samplerate;
101 ChannelConfig SndFileDecoder::getChannelConfig() const
103 return mChannelConfig;
106 SampleType SndFileDecoder::getSampleType() const
108 return mSampleType;
112 uint64_t SndFileDecoder::getLength() const
114 return std::max<sf_count_t>(mSndInfo.frames, 0);
117 uint64_t SndFileDecoder::getPosition() const
119 sf_count_t pos = sf_seek(mSndFile, 0, SEEK_CUR);
120 return std::max<sf_count_t>(pos, 0);
123 bool SndFileDecoder::seek(uint64_t pos)
125 sf_count_t newpos = sf_seek(mSndFile, pos, SEEK_SET);
126 if(newpos < 0) return false;
127 return true;
130 std::pair<uint64_t,uint64_t> SndFileDecoder::getLoopPoints() const
132 return std::make_pair(0, 0);
135 ALuint SndFileDecoder::read(ALvoid *ptr, ALuint count)
137 sf_count_t got = 0;
138 if(mSampleType == SampleType::Int16)
139 got = sf_readf_short(mSndFile, static_cast<short*>(ptr), count);
140 else if(mSampleType == SampleType::Float32)
141 got = sf_readf_float(mSndFile, static_cast<float*>(ptr), count);
142 return (ALuint)std::max<sf_count_t>(got, 0);
146 SharedPtr<Decoder> SndFileDecoderFactory::createDecoder(UniquePtr<std::istream> &file)
148 SF_VIRTUAL_IO vio = {
149 get_filelen, seek,
150 read, write, tell
152 SF_INFO sndinfo;
153 SNDFILE *sndfile = sf_open_virtual(&vio, SFM_READ, &sndinfo, file.get());
154 if(!sndfile) return nullptr;
156 ChannelConfig sconfig;
157 Vector<int> chanmap(sndinfo.channels);
158 if(sf_command(sndfile, SFC_GET_CHANNEL_MAP_INFO, &chanmap[0], chanmap.size()*sizeof(int)) == SF_TRUE)
160 auto matches = [](const Vector<int> &first, std::initializer_list<int> second) -> bool
162 if(first.size() != second.size())
163 return false;
164 return std::mismatch(first.begin(), first.end(), second.begin()).first == first.end();
167 if(matches(chanmap, {SF_CHANNEL_MAP_MONO}))
168 sconfig = ChannelConfig::Mono;
169 else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT}))
170 sconfig = ChannelConfig::Stereo;
171 else if(matches(chanmap, {SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}))
172 sconfig = ChannelConfig::Rear;
173 else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
174 SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}))
175 sconfig = ChannelConfig::Quad;
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_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}) ||
179 matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
180 SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
181 SF_CHANNEL_MAP_SIDE_LEFT, SF_CHANNEL_MAP_SIDE_RIGHT}))
182 sconfig = ChannelConfig::X51;
183 else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
184 SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
185 SF_CHANNEL_MAP_REAR_CENTER, SF_CHANNEL_MAP_SIDE_LEFT,
186 SF_CHANNEL_MAP_SIDE_RIGHT}))
187 sconfig = ChannelConfig::X61;
188 else if(matches(chanmap, {SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT,
189 SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE,
190 SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT,
191 SF_CHANNEL_MAP_SIDE_LEFT, SF_CHANNEL_MAP_SIDE_RIGHT}))
192 sconfig = ChannelConfig::X71;
193 else if(matches(chanmap, {SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X,
194 SF_CHANNEL_MAP_AMBISONIC_B_Y}))
195 sconfig = ChannelConfig::BFormat2D;
196 else if(matches(chanmap, {SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X,
197 SF_CHANNEL_MAP_AMBISONIC_B_Y, SF_CHANNEL_MAP_AMBISONIC_B_Z}))
198 sconfig = ChannelConfig::BFormat3D;
199 else
201 sf_close(sndfile);
202 return nullptr;
205 else if(sf_command(sndfile, SFC_WAVEX_GET_AMBISONIC, 0, 0) == SF_AMBISONIC_B_FORMAT)
207 if(sndinfo.channels == 3)
208 sconfig = ChannelConfig::BFormat2D;
209 else if(sndinfo.channels == 4)
210 sconfig = ChannelConfig::BFormat3D;
211 else
213 sf_close(sndfile);
214 return nullptr;
217 else if(sndinfo.channels == 1)
218 sconfig = ChannelConfig::Mono;
219 else if(sndinfo.channels == 2)
220 sconfig = ChannelConfig::Stereo;
221 else
223 sf_close(sndfile);
224 return nullptr;
227 SampleType stype = SampleType::Int16;
228 switch(sndinfo.format&SF_FORMAT_SUBMASK)
230 case SF_FORMAT_FLOAT:
231 case SF_FORMAT_DOUBLE:
232 case SF_FORMAT_VORBIS:
233 if(Context::GetCurrent().isSupported(sconfig, SampleType::Float32))
235 stype = SampleType::Float32;
236 break;
238 /*fall-through*/
239 default:
240 stype = SampleType::Int16;
241 break;
244 return MakeShared<SndFileDecoder>(std::move(file), sndfile, sndinfo, sconfig, stype);