Make MAX_RESAMPLER_PADDING specify the total padding
[openal-soft.git] / alc / converter.cpp
blob553bad58eb63f6d38221b94931720c284bd7d94f
2 #include "config.h"
4 #include "converter.h"
6 #include <algorithm>
7 #include <cstdint>
8 #include <iterator>
10 #include "AL/al.h"
12 #include "albyte.h"
13 #include "alu.h"
14 #include "fpu_modes.h"
15 #include "mixer/defs.h"
18 namespace {
20 /* Base template left undefined. Should be marked =delete, but Clang 3.8.1
21 * chokes on that given the inline specializations.
23 template<DevFmtType T>
24 inline ALfloat LoadSample(typename DevFmtTypeTraits<T>::Type val) noexcept;
26 template<> inline ALfloat LoadSample<DevFmtByte>(DevFmtTypeTraits<DevFmtByte>::Type val) noexcept
27 { return val * (1.0f/128.0f); }
28 template<> inline ALfloat LoadSample<DevFmtShort>(DevFmtTypeTraits<DevFmtShort>::Type val) noexcept
29 { return val * (1.0f/32768.0f); }
30 template<> inline ALfloat LoadSample<DevFmtInt>(DevFmtTypeTraits<DevFmtInt>::Type val) noexcept
31 { return static_cast<float>(val) * (1.0f/2147483648.0f); }
32 template<> inline ALfloat LoadSample<DevFmtFloat>(DevFmtTypeTraits<DevFmtFloat>::Type val) noexcept
33 { return val; }
35 template<> inline ALfloat LoadSample<DevFmtUByte>(DevFmtTypeTraits<DevFmtUByte>::Type val) noexcept
36 { return LoadSample<DevFmtByte>(static_cast<ALbyte>(val - 128)); }
37 template<> inline ALfloat LoadSample<DevFmtUShort>(DevFmtTypeTraits<DevFmtUShort>::Type val) noexcept
38 { return LoadSample<DevFmtShort>(static_cast<ALshort>(val - 32768)); }
39 template<> inline ALfloat LoadSample<DevFmtUInt>(DevFmtTypeTraits<DevFmtUInt>::Type val) noexcept
40 { return LoadSample<DevFmtInt>(static_cast<ALint>(val - 2147483648u)); }
43 template<DevFmtType T>
44 inline void LoadSampleArray(ALfloat *RESTRICT dst, const void *src, const size_t srcstep,
45 const size_t samples) noexcept
47 using SampleType = typename DevFmtTypeTraits<T>::Type;
49 const SampleType *ssrc = static_cast<const SampleType*>(src);
50 for(size_t i{0u};i < samples;i++)
51 dst[i] = LoadSample<T>(ssrc[i*srcstep]);
54 void LoadSamples(ALfloat *dst, const ALvoid *src, const size_t srcstep, const DevFmtType srctype,
55 const size_t samples) noexcept
57 #define HANDLE_FMT(T) \
58 case T: LoadSampleArray<T>(dst, src, srcstep, samples); break
59 switch(srctype)
61 HANDLE_FMT(DevFmtByte);
62 HANDLE_FMT(DevFmtUByte);
63 HANDLE_FMT(DevFmtShort);
64 HANDLE_FMT(DevFmtUShort);
65 HANDLE_FMT(DevFmtInt);
66 HANDLE_FMT(DevFmtUInt);
67 HANDLE_FMT(DevFmtFloat);
69 #undef HANDLE_FMT
73 template<DevFmtType T>
74 inline typename DevFmtTypeTraits<T>::Type StoreSample(ALfloat) noexcept;
76 template<> inline ALfloat StoreSample<DevFmtFloat>(ALfloat val) noexcept
77 { return val; }
78 template<> inline ALint StoreSample<DevFmtInt>(ALfloat val) noexcept
79 { return fastf2i(clampf(val*2147483648.0f, -2147483648.0f, 2147483520.0f)); }
80 template<> inline ALshort StoreSample<DevFmtShort>(ALfloat val) noexcept
81 { return static_cast<ALshort>(fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f))); }
82 template<> inline ALbyte StoreSample<DevFmtByte>(ALfloat val) noexcept
83 { return static_cast<ALbyte>(fastf2i(clampf(val*128.0f, -128.0f, 127.0f))); }
85 /* Define unsigned output variations. */
86 template<> inline ALuint StoreSample<DevFmtUInt>(ALfloat val) noexcept
87 { return static_cast<ALuint>(StoreSample<DevFmtInt>(val)) + 2147483648u; }
88 template<> inline ALushort StoreSample<DevFmtUShort>(ALfloat val) noexcept
89 { return static_cast<ALushort>(StoreSample<DevFmtShort>(val) + 32768); }
90 template<> inline ALubyte StoreSample<DevFmtUByte>(ALfloat val) noexcept
91 { return static_cast<ALubyte>(StoreSample<DevFmtByte>(val) + 128); }
93 template<DevFmtType T>
94 inline void StoreSampleArray(void *dst, const ALfloat *RESTRICT src, const size_t dststep,
95 const size_t samples) noexcept
97 using SampleType = typename DevFmtTypeTraits<T>::Type;
99 SampleType *sdst = static_cast<SampleType*>(dst);
100 for(size_t i{0u};i < samples;i++)
101 sdst[i*dststep] = StoreSample<T>(src[i]);
105 void StoreSamples(ALvoid *dst, const ALfloat *src, const size_t dststep, const DevFmtType dsttype,
106 const size_t samples) noexcept
108 #define HANDLE_FMT(T) \
109 case T: StoreSampleArray<T>(dst, src, dststep, samples); break
110 switch(dsttype)
112 HANDLE_FMT(DevFmtByte);
113 HANDLE_FMT(DevFmtUByte);
114 HANDLE_FMT(DevFmtShort);
115 HANDLE_FMT(DevFmtUShort);
116 HANDLE_FMT(DevFmtInt);
117 HANDLE_FMT(DevFmtUInt);
118 HANDLE_FMT(DevFmtFloat);
120 #undef HANDLE_FMT
124 template<DevFmtType T>
125 void Mono2Stereo(ALfloat *RESTRICT dst, const void *src, const size_t frames) noexcept
127 using SampleType = typename DevFmtTypeTraits<T>::Type;
129 const SampleType *ssrc = static_cast<const SampleType*>(src);
130 for(size_t i{0u};i < frames;i++)
131 dst[i*2 + 1] = dst[i*2 + 0] = LoadSample<T>(ssrc[i]) * 0.707106781187f;
134 template<DevFmtType T>
135 void Stereo2Mono(ALfloat *RESTRICT dst, const void *src, const size_t frames) noexcept
137 using SampleType = typename DevFmtTypeTraits<T>::Type;
139 const SampleType *ssrc = static_cast<const SampleType*>(src);
140 for(size_t i{0u};i < frames;i++)
141 dst[i] = (LoadSample<T>(ssrc[i*2 + 0])+LoadSample<T>(ssrc[i*2 + 1])) *
142 0.707106781187f;
145 } // namespace
147 SampleConverterPtr CreateSampleConverter(DevFmtType srcType, DevFmtType dstType, size_t numchans,
148 ALuint srcRate, ALuint dstRate, Resampler resampler)
150 if(numchans < 1 || srcRate < 1 || dstRate < 1)
151 return nullptr;
153 SampleConverterPtr converter{new (FamCount{numchans}) SampleConverter{numchans}};
154 converter->mSrcType = srcType;
155 converter->mDstType = dstType;
156 converter->mSrcTypeSize = BytesFromDevFmt(srcType);
157 converter->mDstTypeSize = BytesFromDevFmt(dstType);
159 converter->mSrcPrepCount = 0;
160 converter->mFracOffset = 0;
162 /* Have to set the mixer FPU mode since that's what the resampler code expects. */
163 FPUCtl mixer_mode{};
164 auto step = static_cast<ALuint>(
165 mind(srcRate*double{FRACTIONONE}/dstRate + 0.5, MAX_PITCH*FRACTIONONE));
166 converter->mIncrement = maxu(step, 1);
167 if(converter->mIncrement == FRACTIONONE)
168 converter->mResample = Resample_<CopyTag,CTag>;
169 else
170 converter->mResample = PrepareResampler(resampler, converter->mIncrement,
171 &converter->mState);
173 return converter;
176 ALuint SampleConverter::availableOut(ALuint srcframes) const
178 ALint prepcount{mSrcPrepCount};
179 if(prepcount < 0)
181 /* Negative prepcount means we need to skip that many input samples. */
182 if(static_cast<ALuint>(-prepcount) >= srcframes)
183 return 0;
184 srcframes -= static_cast<ALuint>(-prepcount);
185 prepcount = 0;
188 if(srcframes < 1)
190 /* No output samples if there's no input samples. */
191 return 0;
194 if(prepcount < MAX_RESAMPLER_PADDING
195 && static_cast<ALuint>(MAX_RESAMPLER_PADDING - prepcount) >= srcframes)
197 /* Not enough input samples to generate an output sample. */
198 return 0;
201 auto DataSize64 = static_cast<uint64_t>(prepcount);
202 DataSize64 += srcframes;
203 DataSize64 -= MAX_RESAMPLER_PADDING;
204 DataSize64 <<= FRACTIONBITS;
205 DataSize64 -= mFracOffset;
207 /* If we have a full prep, we can generate at least one sample. */
208 return static_cast<ALuint>(clampu64((DataSize64 + mIncrement-1)/mIncrement, 1, BUFFERSIZE));
211 ALuint SampleConverter::convert(const ALvoid **src, ALuint *srcframes, ALvoid *dst, ALuint dstframes)
213 const ALuint SrcFrameSize{static_cast<ALuint>(mChan.size()) * mSrcTypeSize};
214 const ALuint DstFrameSize{static_cast<ALuint>(mChan.size()) * mDstTypeSize};
215 const ALuint increment{mIncrement};
216 auto SamplesIn = static_cast<const al::byte*>(*src);
217 ALuint NumSrcSamples{*srcframes};
219 FPUCtl mixer_mode{};
220 ALuint pos{0};
221 while(pos < dstframes && NumSrcSamples > 0)
223 ALint prepcount{mSrcPrepCount};
224 if(prepcount < 0)
226 /* Negative prepcount means we need to skip that many input samples. */
227 if(static_cast<ALuint>(-prepcount) >= NumSrcSamples)
229 mSrcPrepCount = static_cast<ALint>(NumSrcSamples) + prepcount;
230 NumSrcSamples = 0;
231 break;
233 SamplesIn += SrcFrameSize*static_cast<ALuint>(-prepcount);
234 NumSrcSamples -= static_cast<ALuint>(-prepcount);
235 mSrcPrepCount = 0;
236 continue;
238 ALuint toread{minu(NumSrcSamples, BUFFERSIZE - MAX_RESAMPLER_PADDING)};
240 if(prepcount < MAX_RESAMPLER_PADDING
241 && static_cast<ALuint>(MAX_RESAMPLER_PADDING - prepcount) >= toread)
243 /* Not enough input samples to generate an output sample. Store
244 * what we're given for later.
246 for(size_t chan{0u};chan < mChan.size();chan++)
247 LoadSamples(&mChan[chan].PrevSamples[prepcount], SamplesIn + mSrcTypeSize*chan,
248 mChan.size(), mSrcType, toread);
250 mSrcPrepCount = prepcount + static_cast<ALint>(toread);
251 NumSrcSamples = 0;
252 break;
255 ALfloat *RESTRICT SrcData{mSrcSamples};
256 ALfloat *RESTRICT DstData{mDstSamples};
257 ALuint DataPosFrac{mFracOffset};
258 auto DataSize64 = static_cast<uint64_t>(prepcount);
259 DataSize64 += toread;
260 DataSize64 -= MAX_RESAMPLER_PADDING;
261 DataSize64 <<= FRACTIONBITS;
262 DataSize64 -= DataPosFrac;
264 /* If we have a full prep, we can generate at least one sample. */
265 auto DstSize = static_cast<ALuint>(
266 clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE));
267 DstSize = minu(DstSize, dstframes-pos);
269 for(size_t chan{0u};chan < mChan.size();chan++)
271 const al::byte *SrcSamples{SamplesIn + mSrcTypeSize*chan};
272 al::byte *DstSamples = static_cast<al::byte*>(dst) + mDstTypeSize*chan;
274 /* Load the previous samples into the source data first, then the
275 * new samples from the input buffer.
277 std::copy_n(mChan[chan].PrevSamples, prepcount, SrcData);
278 LoadSamples(SrcData + prepcount, SrcSamples, mChan.size(), mSrcType, toread);
280 /* Store as many prep samples for next time as possible, given the
281 * number of output samples being generated.
283 ALuint SrcDataEnd{(DstSize*increment + DataPosFrac)>>FRACTIONBITS};
284 if(SrcDataEnd >= static_cast<ALuint>(prepcount)+toread)
285 std::fill(std::begin(mChan[chan].PrevSamples),
286 std::end(mChan[chan].PrevSamples), 0.0f);
287 else
289 const size_t len{minz(al::size(mChan[chan].PrevSamples),
290 static_cast<ALuint>(prepcount)+toread-SrcDataEnd)};
291 std::copy_n(SrcData+SrcDataEnd, len, mChan[chan].PrevSamples);
292 std::fill(std::begin(mChan[chan].PrevSamples)+len,
293 std::end(mChan[chan].PrevSamples), 0.0f);
296 /* Now resample, and store the result in the output buffer. */
297 const ALfloat *ResampledData{mResample(&mState, SrcData+(MAX_RESAMPLER_PADDING>>1),
298 DataPosFrac, increment, {DstData, DstSize})};
300 StoreSamples(DstSamples, ResampledData, mChan.size(), mDstType, DstSize);
303 /* Update the number of prep samples still available, as well as the
304 * fractional offset.
306 DataPosFrac += increment*DstSize;
307 mSrcPrepCount = mini(prepcount + static_cast<ALint>(toread - (DataPosFrac>>FRACTIONBITS)),
308 MAX_RESAMPLER_PADDING);
309 mFracOffset = DataPosFrac & FRACTIONMASK;
311 /* Update the src and dst pointers in case there's still more to do. */
312 SamplesIn += SrcFrameSize*(DataPosFrac>>FRACTIONBITS);
313 NumSrcSamples -= minu(NumSrcSamples, (DataPosFrac>>FRACTIONBITS));
315 dst = static_cast<al::byte*>(dst) + DstFrameSize*DstSize;
316 pos += DstSize;
319 *src = SamplesIn;
320 *srcframes = NumSrcSamples;
322 return pos;
326 void ChannelConverter::convert(const ALvoid *src, ALfloat *dst, ALuint frames) const
328 if(mSrcChans == DevFmtStereo && mDstChans == DevFmtMono)
330 switch(mSrcType)
332 #define HANDLE_FMT(T) case T: Stereo2Mono<T>(dst, src, frames); break
333 HANDLE_FMT(DevFmtByte);
334 HANDLE_FMT(DevFmtUByte);
335 HANDLE_FMT(DevFmtShort);
336 HANDLE_FMT(DevFmtUShort);
337 HANDLE_FMT(DevFmtInt);
338 HANDLE_FMT(DevFmtUInt);
339 HANDLE_FMT(DevFmtFloat);
340 #undef HANDLE_FMT
343 else if(mSrcChans == DevFmtMono && mDstChans == DevFmtStereo)
345 switch(mSrcType)
347 #define HANDLE_FMT(T) case T: Mono2Stereo<T>(dst, src, frames); break
348 HANDLE_FMT(DevFmtByte);
349 HANDLE_FMT(DevFmtUByte);
350 HANDLE_FMT(DevFmtShort);
351 HANDLE_FMT(DevFmtUShort);
352 HANDLE_FMT(DevFmtInt);
353 HANDLE_FMT(DevFmtUInt);
354 HANDLE_FMT(DevFmtFloat);
355 #undef HANDLE_FMT
358 else
359 LoadSamples(dst, src, 1u, mSrcType, frames * ChannelsFromDevFmt(mSrcChans, 0));