Initialize member variables when declaring them for private classes
[alure.git] / src / decoders / sndfile.cpp
blob3f4753faad7036e89ff466f4f2bfb717da230dae
2 #include "sndfile.hpp"
4 #include <stdexcept>
5 #include <iostream>
7 #include "sndfile.h"
9 namespace
12 constexpr alure::Array<int,1> CHANNELS_MONO {{SF_CHANNEL_MAP_MONO}};
13 constexpr alure::Array<int,2> CHANNELS_STEREO {{SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT}};
14 constexpr alure::Array<int,2> CHANNELS_REAR {{SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}};
15 constexpr alure::Array<int,4> CHANNELS_QUAD {{SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}};
16 constexpr alure::Array<int,6> CHANNELS_5DOT1 {{SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_SIDE_LEFT, SF_CHANNEL_MAP_SIDE_RIGHT}};
17 constexpr alure::Array<int,6> CHANNELS_5DOT1_REAR{{SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT}};
18 constexpr alure::Array<int,7> CHANNELS_6DOT1 {{SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_CENTER, SF_CHANNEL_MAP_SIDE_LEFT, SF_CHANNEL_MAP_SIDE_RIGHT}};
19 constexpr alure::Array<int,8> CHANNELS_7DOT1 {{SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_SIDE_LEFT, SF_CHANNEL_MAP_SIDE_RIGHT}};
20 constexpr alure::Array<int,3> CHANNELS_BFORMAT2D {{SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X, SF_CHANNEL_MAP_AMBISONIC_B_Y}};
21 constexpr alure::Array<int,4> CHANNELS_BFORMAT3D {{SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X, SF_CHANNEL_MAP_AMBISONIC_B_Y, SF_CHANNEL_MAP_AMBISONIC_B_Z}};
25 namespace alure
28 static sf_count_t get_filelen(void *user_data)
30 std::istream *file = reinterpret_cast<std::istream*>(user_data);
31 sf_count_t len = -1;
33 file->clear();
34 std::streampos pos = file->tellg();
35 if(pos != -1 && file->seekg(0, std::ios::end))
37 len = file->tellg();
38 file->seekg(pos);
40 return len;
43 static sf_count_t seek(sf_count_t offset, int whence, void *user_data)
45 std::istream *file = reinterpret_cast<std::istream*>(user_data);
47 file->clear();
48 if(!file->seekg(offset, std::ios::seekdir(whence)))
49 return -1;
50 return file->tellg();
53 static sf_count_t read(void *ptr, sf_count_t count, void *user_data)
55 std::istream *file = reinterpret_cast<std::istream*>(user_data);
57 file->clear();
58 file->read(reinterpret_cast<char*>(ptr), count);
59 return file->gcount();
62 static sf_count_t write(const void*, sf_count_t, void*)
64 return -1;
67 static sf_count_t tell(void *user_data)
69 std::istream *file = reinterpret_cast<std::istream*>(user_data);
71 file->clear();
72 return file->tellg();
76 class SndFileDecoder final : public Decoder {
77 UniquePtr<std::istream> mFile;
79 SNDFILE *mSndFile{nullptr};
80 SF_INFO mSndInfo;
82 ChannelConfig mChannelConfig{ChannelConfig::Mono};
83 SampleType mSampleType{SampleType::UInt8};
85 public:
86 SndFileDecoder(UniquePtr<std::istream> file, SNDFILE *sndfile, const SF_INFO &sndinfo, ChannelConfig sconfig, SampleType stype) noexcept
87 : mFile(std::move(file)), mSndFile(sndfile), mSndInfo(sndinfo)
88 , mChannelConfig(sconfig), mSampleType(stype)
89 { }
90 ~SndFileDecoder() override;
92 ALuint getFrequency() const noexcept override;
93 ChannelConfig getChannelConfig() const noexcept override;
94 SampleType getSampleType() const noexcept override;
96 uint64_t getLength() const noexcept override;
97 bool seek(uint64_t pos) noexcept override;
99 std::pair<uint64_t,uint64_t> getLoopPoints() const noexcept override;
101 ALuint read(ALvoid *ptr, ALuint count) noexcept override;
104 SndFileDecoder::~SndFileDecoder()
106 sf_close(mSndFile);
107 mSndFile = 0;
111 ALuint SndFileDecoder::getFrequency() const noexcept
113 return mSndInfo.samplerate;
116 ChannelConfig SndFileDecoder::getChannelConfig() const noexcept
118 return mChannelConfig;
121 SampleType SndFileDecoder::getSampleType() const noexcept
123 return mSampleType;
127 uint64_t SndFileDecoder::getLength() const noexcept
129 return std::max<sf_count_t>(mSndInfo.frames, 0);
132 bool SndFileDecoder::seek(uint64_t pos) noexcept
134 sf_count_t newpos = sf_seek(mSndFile, pos, SEEK_SET);
135 if(newpos < 0) return false;
136 return true;
139 std::pair<uint64_t,uint64_t> SndFileDecoder::getLoopPoints() const noexcept
141 return std::make_pair(0, 0);
144 ALuint SndFileDecoder::read(ALvoid *ptr, ALuint count) noexcept
146 sf_count_t got = 0;
147 if(mSampleType == SampleType::Int16)
148 got = sf_readf_short(mSndFile, static_cast<short*>(ptr), count);
149 else if(mSampleType == SampleType::Float32)
150 got = sf_readf_float(mSndFile, static_cast<float*>(ptr), count);
151 return (ALuint)std::max<sf_count_t>(got, 0);
155 SharedPtr<Decoder> SndFileDecoderFactory::createDecoder(UniquePtr<std::istream> &file) noexcept
157 SF_VIRTUAL_IO vio = {
158 get_filelen, seek,
159 read, write, tell
161 SF_INFO sndinfo;
162 SNDFILE *sndfile = sf_open_virtual(&vio, SFM_READ, &sndinfo, file.get());
163 if(!sndfile) return nullptr;
165 ChannelConfig sconfig;
166 Vector<int> chanmap(sndinfo.channels);
167 if(sf_command(sndfile, SFC_GET_CHANNEL_MAP_INFO, chanmap.data(), chanmap.size()*sizeof(int)) == SF_TRUE)
169 auto matches = [](const Vector<int> &first, ArrayView<int> second) -> bool
171 if(first.size() != second.size())
172 return false;
173 return std::equal(first.begin(), first.end(), second.begin());
176 if(matches(chanmap, CHANNELS_MONO))
177 sconfig = ChannelConfig::Mono;
178 else if(matches(chanmap, CHANNELS_STEREO))
179 sconfig = ChannelConfig::Stereo;
180 else if(matches(chanmap, CHANNELS_REAR))
181 sconfig = ChannelConfig::Rear;
182 else if(matches(chanmap, CHANNELS_QUAD))
183 sconfig = ChannelConfig::Quad;
184 else if(matches(chanmap, CHANNELS_5DOT1) || matches(chanmap, CHANNELS_5DOT1_REAR))
185 sconfig = ChannelConfig::X51;
186 else if(matches(chanmap, CHANNELS_6DOT1))
187 sconfig = ChannelConfig::X61;
188 else if(matches(chanmap, CHANNELS_7DOT1))
189 sconfig = ChannelConfig::X71;
190 else if(matches(chanmap, CHANNELS_BFORMAT2D))
191 sconfig = ChannelConfig::BFormat2D;
192 else if(matches(chanmap, CHANNELS_BFORMAT3D))
193 sconfig = ChannelConfig::BFormat3D;
194 else
196 sf_close(sndfile);
197 return nullptr;
200 else if(sf_command(sndfile, SFC_WAVEX_GET_AMBISONIC, nullptr, 0) == SF_AMBISONIC_B_FORMAT)
202 if(sndinfo.channels == 3)
203 sconfig = ChannelConfig::BFormat2D;
204 else if(sndinfo.channels == 4)
205 sconfig = ChannelConfig::BFormat3D;
206 else
208 sf_close(sndfile);
209 return nullptr;
212 else if(sndinfo.channels == 1)
213 sconfig = ChannelConfig::Mono;
214 else if(sndinfo.channels == 2)
215 sconfig = ChannelConfig::Stereo;
216 else
218 sf_close(sndfile);
219 return nullptr;
222 SampleType stype = SampleType::Int16;
223 switch(sndinfo.format&SF_FORMAT_SUBMASK)
225 case SF_FORMAT_FLOAT:
226 case SF_FORMAT_DOUBLE:
227 case SF_FORMAT_VORBIS:
228 if(Context::GetCurrent().isSupported(sconfig, SampleType::Float32))
230 stype = SampleType::Float32;
231 break;
233 /*fall-through*/
234 default:
235 stype = SampleType::Int16;
236 break;
239 return MakeShared<SndFileDecoder>(std::move(file), sndfile, sndinfo, sconfig, stype);