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
}};
28 static sf_count_t
get_filelen(void *user_data
)
30 std::istream
*file
= reinterpret_cast<std::istream
*>(user_data
);
34 std::streampos pos
= file
->tellg();
35 if(pos
!= -1 && file
->seekg(0, std::ios::end
))
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
);
48 if(!file
->seekg(offset
, std::ios::seekdir(whence
)))
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
);
58 file
->read(reinterpret_cast<char*>(ptr
), count
);
59 return file
->gcount();
62 static sf_count_t
write(const void*, sf_count_t
, void*)
67 static sf_count_t
tell(void *user_data
)
69 std::istream
*file
= reinterpret_cast<std::istream
*>(user_data
);
76 class SndFileDecoder final
: public Decoder
{
77 UniquePtr
<std::istream
> mFile
;
79 SNDFILE
*mSndFile
{nullptr};
82 ChannelConfig mChannelConfig
{ChannelConfig::Mono
};
83 SampleType mSampleType
{SampleType::UInt8
};
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
)
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()
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
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;
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
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
= {
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())
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
;
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
;
212 else if(sndinfo
.channels
== 1)
213 sconfig
= ChannelConfig::Mono
;
214 else if(sndinfo
.channels
== 2)
215 sconfig
= ChannelConfig::Stereo
;
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
;
235 stype
= SampleType::Int16
;
239 return MakeShared
<SndFileDecoder
>(std::move(file
), sndfile
, sndinfo
, sconfig
, stype
);