12 static sf_count_t
get_filelen(void *user_data
)
14 std::istream
*file
= reinterpret_cast<std::istream
*>(user_data
);
18 std::streampos pos
= file
->tellg();
19 if(pos
!= -1 && file
->seekg(0, std::ios::end
))
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
);
32 if(!file
->seekg(offset
, std::ios::seekdir(whence
)))
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
);
42 file
->read(reinterpret_cast<char*>(ptr
), count
);
43 return file
->gcount();
46 static sf_count_t
write(const void*, sf_count_t
, void*)
51 static sf_count_t
tell(void *user_data
)
53 std::istream
*file
= reinterpret_cast<std::istream
*>(user_data
);
60 class SndFileDecoder final
: public Decoder
{
61 UniquePtr
<std::istream
> mFile
;
66 ChannelConfig mChannelConfig
;
67 SampleType mSampleType
;
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
)
74 ~SndFileDecoder() override
;
76 ALuint
getFrequency() const override
;
77 ChannelConfig
getChannelConfig() const override
;
78 SampleType
getSampleType() const override
;
80 uint64_t getLength() const override
;
81 bool seek(uint64_t pos
) override
;
83 std::pair
<uint64_t,uint64_t> getLoopPoints() const override
;
85 ALuint
read(ALvoid
*ptr
, ALuint count
) override
;
88 SndFileDecoder::~SndFileDecoder()
95 ALuint
SndFileDecoder::getFrequency() const
97 return mSndInfo
.samplerate
;
100 ChannelConfig
SndFileDecoder::getChannelConfig() const
102 return mChannelConfig
;
105 SampleType
SndFileDecoder::getSampleType() const
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;
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
)
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
= {
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
.data(), 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())
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
;
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
;
210 else if(sndinfo
.channels
== 1)
211 sconfig
= ChannelConfig::Mono
;
212 else if(sndinfo
.channels
== 2)
213 sconfig
= ChannelConfig::Stereo
;
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
;
233 stype
= SampleType::Int16
;
237 return MakeShared
<SndFileDecoder
>(std::move(file
), sndfile
, sndinfo
, sconfig
, stype
);