9 #include "mixer/defs.h"
14 /* Base template left undefined. Should be marked =delete, but Clang 3.8.1
15 * chokes on that given the inline specializations.
17 template<DevFmtType T
>
18 inline ALfloat
LoadSample(typename DevFmtTypeTraits
<T
>::Type val
);
20 template<> inline ALfloat LoadSample
<DevFmtByte
>(DevFmtTypeTraits
<DevFmtByte
>::Type val
)
21 { return val
* (1.0f
/128.0f
); }
22 template<> inline ALfloat LoadSample
<DevFmtShort
>(DevFmtTypeTraits
<DevFmtShort
>::Type val
)
23 { return val
* (1.0f
/32768.0f
); }
24 template<> inline ALfloat LoadSample
<DevFmtInt
>(DevFmtTypeTraits
<DevFmtInt
>::Type val
)
25 { return (val
>>7) * (1.0f
/16777216.0f
); }
26 template<> inline ALfloat LoadSample
<DevFmtFloat
>(DevFmtTypeTraits
<DevFmtFloat
>::Type val
)
29 template<> inline ALfloat LoadSample
<DevFmtUByte
>(DevFmtTypeTraits
<DevFmtUByte
>::Type val
)
30 { return LoadSample
<DevFmtByte
>(val
- 128); }
31 template<> inline ALfloat LoadSample
<DevFmtUShort
>(DevFmtTypeTraits
<DevFmtUShort
>::Type val
)
32 { return LoadSample
<DevFmtByte
>(val
- 32768); }
33 template<> inline ALfloat LoadSample
<DevFmtUInt
>(DevFmtTypeTraits
<DevFmtUInt
>::Type val
)
34 { return LoadSample
<DevFmtByte
>(val
- 2147483648u); }
37 template<DevFmtType T
>
38 inline void LoadSampleArray(ALfloat
*RESTRICT dst
, const void *src
, ALint srcstep
, ALsizei samples
)
40 using SampleType
= typename DevFmtTypeTraits
<T
>::Type
;
42 const SampleType
*ssrc
= static_cast<const SampleType
*>(src
);
43 for(ALsizei i
{0};i
< samples
;i
++)
44 dst
[i
] = LoadSample
<T
>(ssrc
[i
*srcstep
]);
47 void LoadSamples(ALfloat
*dst
, const ALvoid
*src
, ALint srcstep
, enum DevFmtType srctype
,
50 #define HANDLE_FMT(T) \
51 case T: LoadSampleArray<T>(dst, src, srcstep, samples); break
54 HANDLE_FMT(DevFmtByte
);
55 HANDLE_FMT(DevFmtUByte
);
56 HANDLE_FMT(DevFmtShort
);
57 HANDLE_FMT(DevFmtUShort
);
58 HANDLE_FMT(DevFmtInt
);
59 HANDLE_FMT(DevFmtUInt
);
60 HANDLE_FMT(DevFmtFloat
);
66 template<DevFmtType T
>
67 inline typename DevFmtTypeTraits
<T
>::Type
StoreSample(ALfloat
);
69 template<> inline ALfloat StoreSample
<DevFmtFloat
>(ALfloat val
)
71 template<> inline ALint StoreSample
<DevFmtInt
>(ALfloat val
)
72 { return fastf2i(clampf(val
*16777216.0f
, -16777216.0f
, 16777215.0f
))<<7; }
73 template<> inline ALshort StoreSample
<DevFmtShort
>(ALfloat val
)
74 { return fastf2i(clampf(val
*32768.0f
, -32768.0f
, 32767.0f
)); }
75 template<> inline ALbyte StoreSample
<DevFmtByte
>(ALfloat val
)
76 { return fastf2i(clampf(val
*128.0f
, -128.0f
, 127.0f
)); }
78 /* Define unsigned output variations. */
79 template<> inline ALuint StoreSample
<DevFmtUInt
>(ALfloat val
)
80 { return StoreSample
<DevFmtInt
>(val
) + 2147483648u; }
81 template<> inline ALushort StoreSample
<DevFmtUShort
>(ALfloat val
)
82 { return StoreSample
<DevFmtShort
>(val
) + 32768; }
83 template<> inline ALubyte StoreSample
<DevFmtUByte
>(ALfloat val
)
84 { return StoreSample
<DevFmtByte
>(val
) + 128; }
86 template<DevFmtType T
>
87 inline void StoreSampleArray(void *dst
, const ALfloat
*RESTRICT src
, ALint dststep
,
90 using SampleType
= typename DevFmtTypeTraits
<T
>::Type
;
92 SampleType
*sdst
= static_cast<SampleType
*>(dst
);
93 for(ALsizei i
{0};i
< samples
;i
++)
94 sdst
[i
*dststep
] = StoreSample
<T
>(src
[i
]);
98 void StoreSamples(ALvoid
*dst
, const ALfloat
*src
, ALint dststep
, enum DevFmtType dsttype
, ALsizei samples
)
100 #define HANDLE_FMT(T) \
101 case T: StoreSampleArray<T>(dst, src, dststep, samples); break
104 HANDLE_FMT(DevFmtByte
);
105 HANDLE_FMT(DevFmtUByte
);
106 HANDLE_FMT(DevFmtShort
);
107 HANDLE_FMT(DevFmtUShort
);
108 HANDLE_FMT(DevFmtInt
);
109 HANDLE_FMT(DevFmtUInt
);
110 HANDLE_FMT(DevFmtFloat
);
116 template<DevFmtType T
>
117 void Mono2Stereo(ALfloat
*RESTRICT dst
, const void *src
, ALsizei frames
)
119 using SampleType
= typename DevFmtTypeTraits
<T
>::Type
;
121 const SampleType
*ssrc
= static_cast<const SampleType
*>(src
);
122 for(ALsizei i
{0};i
< frames
;i
++)
123 dst
[i
*2 + 1] = dst
[i
*2 + 0] = LoadSample
<T
>(ssrc
[i
]) * 0.707106781187f
;
126 template<DevFmtType T
>
127 void Stereo2Mono(ALfloat
*RESTRICT dst
, const void *src
, ALsizei frames
)
129 using SampleType
= typename DevFmtTypeTraits
<T
>::Type
;
131 const SampleType
*ssrc
= static_cast<const SampleType
*>(src
);
132 for(ALsizei i
{0};i
< frames
;i
++)
133 dst
[i
] = (LoadSample
<T
>(ssrc
[i
*2 + 0])+LoadSample
<T
>(ssrc
[i
*2 + 1])) *
139 SampleConverter
*CreateSampleConverter(enum DevFmtType srcType
, enum DevFmtType dstType
,
140 ALsizei numchans
, ALsizei srcRate
, ALsizei dstRate
,
143 if(numchans
<= 0 || srcRate
<= 0 || dstRate
<= 0)
146 size_t alloc_size
{FAM_SIZE(SampleConverter
, Chan
, numchans
)};
147 auto converter
= new (al_calloc(16, alloc_size
)) SampleConverter
{};
148 converter
->mSrcType
= srcType
;
149 converter
->mDstType
= dstType
;
150 converter
->mNumChannels
= numchans
;
151 converter
->mSrcTypeSize
= BytesFromDevFmt(srcType
);
152 converter
->mDstTypeSize
= BytesFromDevFmt(dstType
);
154 converter
->mSrcPrepCount
= 0;
155 converter
->mFracOffset
= 0;
157 /* Have to set the mixer FPU mode since that's what the resampler code expects. */
159 auto step
= static_cast<ALsizei
>(
160 mind((ALdouble
)srcRate
/dstRate
*FRACTIONONE
+ 0.5, MAX_PITCH
*FRACTIONONE
));
161 converter
->mIncrement
= maxi(step
, 1);
162 if(converter
->mIncrement
== FRACTIONONE
)
163 converter
->mResample
= Resample_copy_C
;
166 if(resampler
== BSinc24Resampler
)
167 BsincPrepare(converter
->mIncrement
, &converter
->mState
.bsinc
, &bsinc24
);
168 else if(resampler
== BSinc12Resampler
)
169 BsincPrepare(converter
->mIncrement
, &converter
->mState
.bsinc
, &bsinc12
);
170 converter
->mResample
= SelectResampler(resampler
);
176 void DestroySampleConverter(SampleConverter
**converter
)
181 *converter
= nullptr;
186 ALsizei
SampleConverterAvailableOut(SampleConverter
*converter
, ALsizei srcframes
)
188 ALint prepcount
{converter
->mSrcPrepCount
};
191 /* Negative prepcount means we need to skip that many input samples. */
192 if(-prepcount
>= srcframes
)
194 srcframes
+= prepcount
;
200 /* No output samples if there's no input samples. */
204 if(prepcount
< MAX_RESAMPLE_PADDING
*2 &&
205 MAX_RESAMPLE_PADDING
*2 - prepcount
>= srcframes
)
207 /* Not enough input samples to generate an output sample. */
211 ALsizei increment
{converter
->mIncrement
};
212 ALsizei DataPosFrac
{converter
->mFracOffset
};
213 auto DataSize64
= static_cast<ALuint64
>(prepcount
);
214 DataSize64
+= srcframes
;
215 DataSize64
-= MAX_RESAMPLE_PADDING
*2;
216 DataSize64
<<= FRACTIONBITS
;
217 DataSize64
-= DataPosFrac
;
219 /* If we have a full prep, we can generate at least one sample. */
220 return (ALsizei
)clampu64((DataSize64
+ increment
-1)/increment
, 1, BUFFERSIZE
);
223 ALsizei
SampleConverterInput(SampleConverter
*converter
, const ALvoid
**src
, ALsizei
*srcframes
, ALvoid
*dst
, ALsizei dstframes
)
225 const ALsizei SrcFrameSize
{converter
->mNumChannels
* converter
->mSrcTypeSize
};
226 const ALsizei DstFrameSize
{converter
->mNumChannels
* converter
->mDstTypeSize
};
227 const ALsizei increment
{converter
->mIncrement
};
228 auto SamplesIn
= static_cast<const ALbyte
*>(*src
);
229 ALsizei NumSrcSamples
{*srcframes
};
233 while(pos
< dstframes
&& NumSrcSamples
> 0)
235 ALint prepcount
{converter
->mSrcPrepCount
};
238 /* Negative prepcount means we need to skip that many input samples. */
239 if(-prepcount
>= NumSrcSamples
)
241 converter
->mSrcPrepCount
= prepcount
+ NumSrcSamples
;
245 SamplesIn
+= SrcFrameSize
*-prepcount
;
246 NumSrcSamples
+= prepcount
;
247 converter
->mSrcPrepCount
= 0;
250 ALint toread
{mini(NumSrcSamples
, BUFFERSIZE
- MAX_RESAMPLE_PADDING
*2)};
252 if(prepcount
< MAX_RESAMPLE_PADDING
*2 &&
253 MAX_RESAMPLE_PADDING
*2 - prepcount
>= toread
)
255 /* Not enough input samples to generate an output sample. Store
256 * what we're given for later.
258 for(ALsizei chan
{0};chan
< converter
->mNumChannels
;chan
++)
259 LoadSamples(&converter
->Chan
[chan
].mPrevSamples
[prepcount
],
260 SamplesIn
+ converter
->mSrcTypeSize
*chan
,
261 converter
->mNumChannels
, converter
->mSrcType
, toread
264 converter
->mSrcPrepCount
= prepcount
+ toread
;
269 ALfloat
*RESTRICT SrcData
{converter
->mSrcSamples
};
270 ALfloat
*RESTRICT DstData
{converter
->mDstSamples
};
271 ALsizei DataPosFrac
{converter
->mFracOffset
};
272 auto DataSize64
= static_cast<ALuint64
>(prepcount
);
273 DataSize64
+= toread
;
274 DataSize64
-= MAX_RESAMPLE_PADDING
*2;
275 DataSize64
<<= FRACTIONBITS
;
276 DataSize64
-= DataPosFrac
;
278 /* If we have a full prep, we can generate at least one sample. */
279 auto DstSize
= static_cast<ALsizei
>(
280 clampu64((DataSize64
+ increment
-1)/increment
, 1, BUFFERSIZE
));
281 DstSize
= mini(DstSize
, dstframes
-pos
);
283 for(ALsizei chan
{0};chan
< converter
->mNumChannels
;chan
++)
285 const ALbyte
*SrcSamples
= SamplesIn
+ converter
->mSrcTypeSize
*chan
;
286 ALbyte
*DstSamples
= (ALbyte
*)dst
+ converter
->mDstTypeSize
*chan
;
288 /* Load the previous samples into the source data first, then the
289 * new samples from the input buffer.
291 std::copy_n(converter
->Chan
[chan
].mPrevSamples
, prepcount
, SrcData
);
292 LoadSamples(SrcData
+ prepcount
, SrcSamples
,
293 converter
->mNumChannels
, converter
->mSrcType
, toread
296 /* Store as many prep samples for next time as possible, given the
297 * number of output samples being generated.
299 ALsizei SrcDataEnd
{(DstSize
*increment
+ DataPosFrac
)>>FRACTIONBITS
};
300 if(SrcDataEnd
>= prepcount
+toread
)
301 std::fill(std::begin(converter
->Chan
[chan
].mPrevSamples
),
302 std::end(converter
->Chan
[chan
].mPrevSamples
), 0.0f
);
305 size_t len
= mini(MAX_RESAMPLE_PADDING
*2, prepcount
+toread
-SrcDataEnd
);
306 std::copy_n(SrcData
+SrcDataEnd
, len
, converter
->Chan
[chan
].mPrevSamples
);
307 std::fill(std::begin(converter
->Chan
[chan
].mPrevSamples
)+len
,
308 std::end(converter
->Chan
[chan
].mPrevSamples
), 0.0f
);
311 /* Now resample, and store the result in the output buffer. */
312 const ALfloat
*ResampledData
{converter
->mResample(&converter
->mState
,
313 SrcData
+MAX_RESAMPLE_PADDING
, DataPosFrac
, increment
,
317 StoreSamples(DstSamples
, ResampledData
, converter
->mNumChannels
,
318 converter
->mDstType
, DstSize
);
321 /* Update the number of prep samples still available, as well as the
324 DataPosFrac
+= increment
*DstSize
;
325 converter
->mSrcPrepCount
= mini(prepcount
+ toread
- (DataPosFrac
>>FRACTIONBITS
),
326 MAX_RESAMPLE_PADDING
*2);
327 converter
->mFracOffset
= DataPosFrac
& FRACTIONMASK
;
329 /* Update the src and dst pointers in case there's still more to do. */
330 SamplesIn
+= SrcFrameSize
*(DataPosFrac
>>FRACTIONBITS
);
331 NumSrcSamples
-= mini(NumSrcSamples
, (DataPosFrac
>>FRACTIONBITS
));
333 dst
= (ALbyte
*)dst
+ DstFrameSize
*DstSize
;
338 *srcframes
= NumSrcSamples
;
344 ChannelConverter
*CreateChannelConverter(DevFmtType srcType
, DevFmtChannels srcChans
, DevFmtChannels dstChans
)
346 if(srcChans
!= dstChans
&& !((srcChans
== DevFmtMono
&& dstChans
== DevFmtStereo
) ||
347 (srcChans
== DevFmtStereo
&& dstChans
== DevFmtMono
)))
350 return new ChannelConverter
{srcType
, srcChans
, dstChans
};
353 void DestroyChannelConverter(ChannelConverter
**converter
)
358 *converter
= nullptr;
362 void ChannelConverterInput(ChannelConverter
*converter
, const ALvoid
*src
, ALfloat
*dst
, ALsizei frames
)
364 if(converter
->mSrcChans
== converter
->mDstChans
)
366 LoadSamples(dst
, src
, 1, converter
->mSrcType
,
367 frames
*ChannelsFromDevFmt(converter
->mSrcChans
, 0));
371 if(converter
->mSrcChans
== DevFmtStereo
&& converter
->mDstChans
== DevFmtMono
)
373 switch(converter
->mSrcType
)
375 #define HANDLE_FMT(T) case T: Stereo2Mono<T>(dst, src, frames); break
376 HANDLE_FMT(DevFmtByte
);
377 HANDLE_FMT(DevFmtUByte
);
378 HANDLE_FMT(DevFmtShort
);
379 HANDLE_FMT(DevFmtUShort
);
380 HANDLE_FMT(DevFmtInt
);
381 HANDLE_FMT(DevFmtUInt
);
382 HANDLE_FMT(DevFmtFloat
);
386 else /*if(converter->mSrcChans == DevFmtMono && converter->mDstChans == DevFmtStereo)*/
388 switch(converter
->mSrcType
)
390 #define HANDLE_FMT(T) case T: Mono2Stereo<T>(dst, src, frames); break
391 HANDLE_FMT(DevFmtByte
);
392 HANDLE_FMT(DevFmtUByte
);
393 HANDLE_FMT(DevFmtShort
);
394 HANDLE_FMT(DevFmtUShort
);
395 HANDLE_FMT(DevFmtInt
);
396 HANDLE_FMT(DevFmtUInt
);
397 HANDLE_FMT(DevFmtFloat
);