16 inline ALfloat
do_point(const InterpState
&, const ALfloat
*RESTRICT vals
, const ALuint
)
18 inline ALfloat
do_lerp(const InterpState
&, const ALfloat
*RESTRICT vals
, const ALuint frac
)
19 { return lerp(vals
[0], vals
[1], static_cast<float>(frac
)*(1.0f
/FRACTIONONE
)); }
20 inline ALfloat
do_cubic(const InterpState
&, const ALfloat
*RESTRICT vals
, const ALuint frac
)
21 { return cubic(vals
[0], vals
[1], vals
[2], vals
[3], static_cast<float>(frac
)*(1.0f
/FRACTIONONE
)); }
22 inline ALfloat
do_bsinc(const InterpState
&istate
, const ALfloat
*RESTRICT vals
, const ALuint frac
)
24 const size_t m
{istate
.bsinc
.m
};
26 // Calculate the phase index and factor.
27 #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
28 const ALuint pi
{frac
>> FRAC_PHASE_BITDIFF
};
29 const ALfloat pf
{static_cast<float>(frac
& ((1<<FRAC_PHASE_BITDIFF
)-1)) *
30 (1.0f
/(1<<FRAC_PHASE_BITDIFF
))};
31 #undef FRAC_PHASE_BITDIFF
33 const ALfloat
*fil
{istate
.bsinc
.filter
+ m
*pi
*4};
34 const ALfloat
*scd
{fil
+ m
};
35 const ALfloat
*phd
{scd
+ m
};
36 const ALfloat
*spd
{phd
+ m
};
38 // Apply the scale and phase interpolated filter.
40 for(size_t j_f
{0};j_f
< m
;j_f
++)
41 r
+= (fil
[j_f
] + istate
.bsinc
.sf
*scd
[j_f
] + pf
*(phd
[j_f
] + istate
.bsinc
.sf
*spd
[j_f
])) * vals
[j_f
];
44 inline ALfloat
do_fastbsinc(const InterpState
&istate
, const ALfloat
*RESTRICT vals
, const ALuint frac
)
46 const size_t m
{istate
.bsinc
.m
};
48 // Calculate the phase index and factor.
49 #define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
50 const ALuint pi
{frac
>> FRAC_PHASE_BITDIFF
};
51 const ALfloat pf
{static_cast<float>(frac
& ((1<<FRAC_PHASE_BITDIFF
)-1)) *
52 (1.0f
/(1<<FRAC_PHASE_BITDIFF
))};
53 #undef FRAC_PHASE_BITDIFF
55 const ALfloat
*fil
{istate
.bsinc
.filter
+ m
*pi
*4};
56 const ALfloat
*phd
{fil
+ m
*2};
58 // Apply the phase interpolated filter.
60 for(size_t j_f
{0};j_f
< m
;j_f
++)
61 r
+= (fil
[j_f
] + pf
*phd
[j_f
]) * vals
[j_f
];
65 using SamplerT
= ALfloat(const InterpState
&, const ALfloat
*RESTRICT
, const ALuint
);
66 template<SamplerT
&Sampler
>
67 const ALfloat
*DoResample(const InterpState
*state
, const ALfloat
*RESTRICT src
,
68 ALuint frac
, ALuint increment
, const al::span
<float> dst
)
70 const InterpState istate
{*state
};
71 auto proc_sample
= [&src
,&frac
,istate
,increment
]() -> ALfloat
73 const ALfloat ret
{Sampler(istate
, src
, frac
)};
76 src
+= frac
>>FRACTIONBITS
;
81 std::generate(dst
.begin(), dst
.end(), proc_sample
);
89 const ALfloat
*Resample_
<CopyTag
,CTag
>(const InterpState
*, const ALfloat
*RESTRICT src
, ALuint
,
90 ALuint
, const al::span
<float> dst
)
92 #if defined(HAVE_SSE) || defined(HAVE_NEON)
93 /* Avoid copying the source data if it's aligned like the destination. */
94 if((reinterpret_cast<intptr_t>(src
)&15) == (reinterpret_cast<intptr_t>(dst
.data())&15))
97 std::copy_n(src
, dst
.size(), dst
.begin());
102 const ALfloat
*Resample_
<PointTag
,CTag
>(const InterpState
*state
, const ALfloat
*RESTRICT src
,
103 ALuint frac
, ALuint increment
, const al::span
<float> dst
)
104 { return DoResample
<do_point
>(state
, src
, frac
, increment
, dst
); }
107 const ALfloat
*Resample_
<LerpTag
,CTag
>(const InterpState
*state
, const ALfloat
*RESTRICT src
,
108 ALuint frac
, ALuint increment
, const al::span
<float> dst
)
109 { return DoResample
<do_lerp
>(state
, src
, frac
, increment
, dst
); }
112 const ALfloat
*Resample_
<CubicTag
,CTag
>(const InterpState
*state
, const ALfloat
*RESTRICT src
,
113 ALuint frac
, ALuint increment
, const al::span
<float> dst
)
114 { return DoResample
<do_cubic
>(state
, src
-1, frac
, increment
, dst
); }
117 const ALfloat
*Resample_
<BSincTag
,CTag
>(const InterpState
*state
, const ALfloat
*RESTRICT src
,
118 ALuint frac
, ALuint increment
, const al::span
<float> dst
)
119 { return DoResample
<do_bsinc
>(state
, src
-state
->bsinc
.l
, frac
, increment
, dst
); }
122 const ALfloat
*Resample_
<FastBSincTag
,CTag
>(const InterpState
*state
, const ALfloat
*RESTRICT src
,
123 ALuint frac
, ALuint increment
, const al::span
<float> dst
)
124 { return DoResample
<do_fastbsinc
>(state
, src
-state
->bsinc
.l
, frac
, increment
, dst
); }
127 static inline void ApplyCoeffs(size_t /*Offset*/, float2
*RESTRICT Values
, const ALuint IrSize
,
128 const HrirArray
&Coeffs
, const ALfloat left
, const ALfloat right
)
131 for(ALuint c
{0};c
< IrSize
;++c
)
133 Values
[c
][0] += Coeffs
[c
][0] * left
;
134 Values
[c
][1] += Coeffs
[c
][1] * right
;
139 void MixHrtf_
<CTag
>(FloatBufferLine
&LeftOut
, FloatBufferLine
&RightOut
,
140 const ALfloat
*InSamples
, float2
*AccumSamples
, const size_t OutPos
, const ALuint IrSize
,
141 MixHrtfFilter
*hrtfparams
, const size_t BufferSize
)
143 MixHrtfBase
<ApplyCoeffs
>(LeftOut
, RightOut
, InSamples
, AccumSamples
, OutPos
, IrSize
,
144 hrtfparams
, BufferSize
);
148 void MixHrtfBlend_
<CTag
>(FloatBufferLine
&LeftOut
, FloatBufferLine
&RightOut
,
149 const ALfloat
*InSamples
, float2
*AccumSamples
, const size_t OutPos
, const ALuint IrSize
,
150 const HrtfFilter
*oldparams
, MixHrtfFilter
*newparams
, const size_t BufferSize
)
152 MixHrtfBlendBase
<ApplyCoeffs
>(LeftOut
, RightOut
, InSamples
, AccumSamples
, OutPos
, IrSize
,
153 oldparams
, newparams
, BufferSize
);
157 void MixDirectHrtf_
<CTag
>(FloatBufferLine
&LeftOut
, FloatBufferLine
&RightOut
,
158 const al::span
<const FloatBufferLine
> InSamples
, float2
*AccumSamples
, DirectHrtfState
*State
,
159 const size_t BufferSize
)
161 MixDirectHrtfBase
<ApplyCoeffs
>(LeftOut
, RightOut
, InSamples
, AccumSamples
, State
, BufferSize
);
166 void Mix_
<CTag
>(const al::span
<const float> InSamples
, const al::span
<FloatBufferLine
> OutBuffer
,
167 float *CurrentGains
, const float *TargetGains
, const size_t Counter
, const size_t OutPos
)
169 const ALfloat delta
{(Counter
> 0) ? 1.0f
/ static_cast<ALfloat
>(Counter
) : 0.0f
};
170 const bool reached_target
{InSamples
.size() >= Counter
};
171 const auto min_end
= reached_target
? InSamples
.begin() + Counter
: InSamples
.end();
172 for(FloatBufferLine
&output
: OutBuffer
)
174 ALfloat
*RESTRICT dst
{al::assume_aligned
<16>(output
.data()+OutPos
)};
175 ALfloat gain
{*CurrentGains
};
176 const ALfloat diff
{*TargetGains
- gain
};
178 auto in_iter
= InSamples
.begin();
179 if(std::fabs(diff
) > std::numeric_limits
<float>::epsilon())
181 const ALfloat step
{diff
* delta
};
182 ALfloat step_count
{0.0f
};
183 while(in_iter
!= min_end
)
185 *(dst
++) += *(in_iter
++) * (gain
+ step
*step_count
);
191 gain
+= step
*step_count
;
192 *CurrentGains
= gain
;
197 if(!(std::fabs(gain
) > GAIN_SILENCE_THRESHOLD
))
199 while(in_iter
!= InSamples
.end())
200 *(dst
++) += *(in_iter
++) * gain
;
204 /* Basically the inverse of the above. Rather than one input going to multiple
205 * outputs (each with its own gain), it's multiple inputs (each with its own
206 * gain) going to one output. This applies one row (vs one column) of a matrix
207 * transform. And as the matrices are more or less static once set up, no
208 * stepping is necessary.
211 void MixRow_
<CTag
>(const al::span
<float> OutBuffer
, const al::span
<const float> Gains
,
212 const float *InSamples
, const size_t InStride
)
214 for(const float gain
: Gains
)
216 const float *RESTRICT input
{InSamples
};
217 InSamples
+= InStride
;
219 if(!(std::fabs(gain
) > GAIN_SILENCE_THRESHOLD
))
222 auto do_mix
= [gain
](const float cur
, const float src
) noexcept
-> float
223 { return cur
+ src
*gain
; };
224 std::transform(OutBuffer
.begin(), OutBuffer
.end(), input
, OutBuffer
.begin(), do_mix
);