1 /*
2  * IntMixer.h
3  * ----------
4  * Purpose: Fixed point mixer classes
5  * Notes  : (currently none)
6  * Authors: Olivier Lapicque
7  *          OpenMPT Devs
8  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
9  */
10 
11 
12 #pragma once
13 
14 #include "openmpt/all/BuildSettings.hpp"
15 
16 #include "Resampler.h"
17 #include "MixerInterface.h"
18 #include "Paula.h"
19 
20 OPENMPT_NAMESPACE_BEGIN
21 
22 template<int channelsOut, int channelsIn, typename out, typename in, size_t mixPrecision>
23 struct IntToIntTraits : public MixerTraits<channelsOut, channelsIn, out, in>
24 {
25 	typedef MixerTraits<channelsOut, channelsIn, out, in> base_t;
26 	typedef typename base_t::input_t input_t;
27 	typedef typename base_t::output_t output_t;
28 
ConvertIntToIntTraits29 	static MPT_CONSTEXPRINLINE output_t Convert(const input_t x)
30 	{
31 		static_assert(std::numeric_limits<input_t>::is_integer, "Input must be integer");
32 		static_assert(std::numeric_limits<output_t>::is_integer, "Output must be integer");
33 		static_assert(sizeof(out) * 8 >= mixPrecision, "Mix precision is higher than output type can handle");
34 		static_assert(sizeof(in) * 8 <= mixPrecision, "Mix precision is lower than input type");
35 		return static_cast<output_t>(x) * (1<<(mixPrecision - sizeof(in) * 8));
36 	}
37 };
38 
39 typedef IntToIntTraits<2, 1, mixsample_t, int8,  16> Int8MToIntS;
40 typedef IntToIntTraits<2, 1, mixsample_t, int16, 16> Int16MToIntS;
41 typedef IntToIntTraits<2, 2, mixsample_t, int8,  16> Int8SToIntS;
42 typedef IntToIntTraits<2, 2, mixsample_t, int16, 16> Int16SToIntS;
43 
44 
45 //////////////////////////////////////////////////////////////////////////
46 // Interpolation templates
47 
48 
49 template<class Traits>
50 struct AmigaBlepInterpolation
51 {
52 	SamplePosition subIncrement;
53 	Paula::State *paula;
54 	const Paula::BlepArray *WinSincIntegral;
55 	int numSteps;
56 
StartAmigaBlepInterpolation57 	MPT_FORCEINLINE void Start(ModChannel &chn, const CResampler &resampler)
58 	{
59 		paula = &chn.paulaState;
60 		numSteps = paula->numSteps;
61 		WinSincIntegral = &resampler.blepTables.GetAmigaTable(resampler.m_Settings.emulateAmiga, chn.dwFlags[CHN_AMIGAFILTER]);
62 		if(numSteps)
63 			subIncrement = chn.increment / numSteps;
64 	}
65 
EndAmigaBlepInterpolation66 	MPT_FORCEINLINE void End(const ModChannel &) { }
67 
operatorAmigaBlepInterpolation68 	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
69 	{
70 		SamplePosition pos(0, posLo);
71 		// First, process steps of full length (one Amiga clock interval)
72 		for(int step = numSteps; step > 0; step--)
73 		{
74 			typename Traits::output_t inSample = 0;
75 			int32 posInt = pos.GetInt() * Traits::numChannelsIn;
76 			for(int32 i = 0; i < Traits::numChannelsIn; i++)
77 				inSample += Traits::Convert(inBuffer[posInt + i]);
78 			paula->InputSample(static_cast<int16>(inSample / (4 * Traits::numChannelsIn)));
79 			paula->Clock(Paula::MINIMUM_INTERVAL);
80 			pos += subIncrement;
81 		}
82 		paula->remainder += paula->stepRemainder;
83 
84 		// Now, process any remaining integer clock amount < MINIMUM_INTERVAL
85 		uint32 remainClocks = paula->remainder.GetInt();
86 		if(remainClocks)
87 		{
88 			typename Traits::output_t inSample = 0;
89 			int32 posInt = pos.GetInt() * Traits::numChannelsIn;
90 			for(int32 i = 0; i < Traits::numChannelsIn; i++)
91 				inSample += Traits::Convert(inBuffer[posInt + i]);
92 			paula->InputSample(static_cast<int16>(inSample / (4 * Traits::numChannelsIn)));
93 			paula->Clock(remainClocks);
94 			paula->remainder.RemoveInt();
95 		}
96 
97 		auto out = paula->OutputSample(*WinSincIntegral);
98 		for(int i = 0; i < Traits::numChannelsOut; i++)
99 			outSample[i] = out;
100 	}
101 };
102 
103 
104 template<class Traits>
105 struct LinearInterpolation
106 {
StartLinearInterpolation107 	MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { }
108 
EndLinearInterpolation109 	MPT_FORCEINLINE void End(const ModChannel &) { }
110 
operatorLinearInterpolation111 	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
112 	{
113 		static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
114 		const typename Traits::output_t fract = posLo >> 18u;
115 
116 		for(int i = 0; i < Traits::numChannelsIn; i++)
117 		{
118 			typename Traits::output_t srcVol = Traits::Convert(inBuffer[i]);
119 			typename Traits::output_t destVol = Traits::Convert(inBuffer[i + Traits::numChannelsIn]);
120 
121 			outSample[i] = srcVol + ((fract * (destVol - srcVol)) / 16384);
122 		}
123 	}
124 };
125 
126 
127 template<class Traits>
128 struct FastSincInterpolation
129 {
StartFastSincInterpolation130 	MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &) { }
EndFastSincInterpolation131 	MPT_FORCEINLINE void End(const ModChannel &) { }
132 
operatorFastSincInterpolation133 	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
134 	{
135 		static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
136 		const int16 *lut = CResampler::FastSincTable + ((posLo >> 22) & 0x3FC);
137 
138 		for(int i = 0; i < Traits::numChannelsIn; i++)
139 		{
140 			outSample[i] =
141 				 (lut[0] * Traits::Convert(inBuffer[i - Traits::numChannelsIn])
142 				+ lut[1] * Traits::Convert(inBuffer[i])
143 				+ lut[2] * Traits::Convert(inBuffer[i + Traits::numChannelsIn])
144 				+ lut[3] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn])) / 16384;
145 		}
146 	}
147 };
148 
149 
150 template<class Traits>
151 struct PolyphaseInterpolation
152 {
153 	const SINC_TYPE *sinc;
154 
StartPolyphaseInterpolation155 	MPT_FORCEINLINE void Start(const ModChannel &chn, const CResampler &resampler)
156 	{
157 		#ifdef MODPLUG_TRACKER
158 			// Otherwise causes "warning C4100: 'resampler' : unreferenced formal parameter"
159 			// because all 3 tables are static members.
160 			// #pragma warning fails with this templated case for unknown reasons.
161 			MPT_UNREFERENCED_PARAMETER(resampler);
162 		#endif // MODPLUG_TRACKER
163 		sinc = (((chn.increment > SamplePosition(0x130000000ll)) || (chn.increment < SamplePosition(-0x130000000ll))) ?
164 			(((chn.increment > SamplePosition(0x180000000ll)) || (chn.increment < SamplePosition(-0x180000000ll))) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc);
165 	}
166 
EndPolyphaseInterpolation167 	MPT_FORCEINLINE void End(const ModChannel &) { }
168 
operatorPolyphaseInterpolation169 	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
170 	{
171 		static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
172 		const SINC_TYPE *lut = sinc + ((posLo >> (32 - SINC_PHASES_BITS)) & SINC_MASK) * SINC_WIDTH;
173 
174 		for(int i = 0; i < Traits::numChannelsIn; i++)
175 		{
176 			outSample[i] =
177 				 (lut[0] * Traits::Convert(inBuffer[i - 3 * Traits::numChannelsIn])
178 				+ lut[1] * Traits::Convert(inBuffer[i - 2 * Traits::numChannelsIn])
179 				+ lut[2] * Traits::Convert(inBuffer[i - Traits::numChannelsIn])
180 				+ lut[3] * Traits::Convert(inBuffer[i])
181 				+ lut[4] * Traits::Convert(inBuffer[i + Traits::numChannelsIn])
182 				+ lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn])
183 				+ lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn])
184 				+ lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn])) / (1 << SINC_QUANTSHIFT);
185 		}
186 	}
187 };
188 
189 
190 template<class Traits>
191 struct FIRFilterInterpolation
192 {
193 	const int16 *WFIRlut;
194 
StartFIRFilterInterpolation195 	MPT_FORCEINLINE void Start(const ModChannel &, const CResampler &resampler)
196 	{
197 		WFIRlut = resampler.m_WindowedFIR.lut;
198 	}
199 
EndFIRFilterInterpolation200 	MPT_FORCEINLINE void End(const ModChannel &) { }
201 
operatorFIRFilterInterpolation202 	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
203 	{
204 		static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
205 		const int16 * const lut = WFIRlut + ((((posLo >> 16) + WFIR_FRACHALVE) >> WFIR_FRACSHIFT) & WFIR_FRACMASK);
206 
207 		for(int i = 0; i < Traits::numChannelsIn; i++)
208 		{
209 			typename Traits::output_t vol1 =
210 				  (lut[0] * Traits::Convert(inBuffer[i - 3 * Traits::numChannelsIn]))
211 				+ (lut[1] * Traits::Convert(inBuffer[i - 2 * Traits::numChannelsIn]))
212 				+ (lut[2] * Traits::Convert(inBuffer[i - Traits::numChannelsIn]))
213 				+ (lut[3] * Traits::Convert(inBuffer[i]));
214 			typename Traits::output_t vol2 =
215 				  (lut[4] * Traits::Convert(inBuffer[i + 1 * Traits::numChannelsIn]))
216 				+ (lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn]))
217 				+ (lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn]))
218 				+ (lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn]));
219 			outSample[i] = ((vol1 / 2) + (vol2 / 2)) / (1 << (WFIR_16BITSHIFT - 1));
220 		}
221 	}
222 };
223 
224 
225 //////////////////////////////////////////////////////////////////////////
226 // Mixing templates (add sample to stereo mix)
227 
228 template<class Traits>
229 struct NoRamp
230 {
231 	typename Traits::output_t lVol, rVol;
232 
StartNoRamp233 	MPT_FORCEINLINE void Start(const ModChannel &chn)
234 	{
235 		lVol = chn.leftVol;
236 		rVol = chn.rightVol;
237 	}
238 
EndNoRamp239 	MPT_FORCEINLINE void End(const ModChannel &) { }
240 };
241 
242 
243 struct Ramp
244 {
245 	int32 lRamp, rRamp;
246 
StartRamp247 	MPT_FORCEINLINE void Start(const ModChannel &chn)
248 	{
249 		lRamp = chn.rampLeftVol;
250 		rRamp = chn.rampRightVol;
251 	}
252 
EndRamp253 	MPT_FORCEINLINE void End(ModChannel &chn)
254 	{
255 		chn.rampLeftVol = lRamp; chn.leftVol = lRamp >> VOLUMERAMPPRECISION;
256 		chn.rampRightVol = rRamp; chn.rightVol = rRamp >> VOLUMERAMPPRECISION;
257 	}
258 };
259 
260 
261 // Legacy optimization: If chn.nLeftVol == chn.nRightVol, save one multiplication instruction
262 template<class Traits>
263 struct MixMonoFastNoRamp : public NoRamp<Traits>
264 {
265 	typedef NoRamp<Traits> base_t;
operatorMixMonoFastNoRamp266 	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
267 	{
268 		typename Traits::output_t vol = outSample[0] * base_t::lVol;
269 		for(int i = 0; i < Traits::numChannelsOut; i++)
270 		{
271 			outBuffer[i] += vol;
272 		}
273 	}
274 };
275 
276 
277 template<class Traits>
278 struct MixMonoNoRamp : public NoRamp<Traits>
279 {
280 	typedef NoRamp<Traits> base_t;
operatorMixMonoNoRamp281 	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
282 	{
283 		outBuffer[0] += outSample[0] * base_t::lVol;
284 		outBuffer[1] += outSample[0] * base_t::rVol;
285 	}
286 };
287 
288 
289 template<class Traits>
290 struct MixMonoRamp : public Ramp
291 {
operatorMixMonoRamp292 	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const MPT_RESTRICT outBuffer)
293 	{
294 		lRamp += chn.leftRamp;
295 		rRamp += chn.rightRamp;
296 		outBuffer[0] += outSample[0] * (lRamp >> VOLUMERAMPPRECISION);
297 		outBuffer[1] += outSample[0] * (rRamp >> VOLUMERAMPPRECISION);
298 	}
299 };
300 
301 
302 template<class Traits>
303 struct MixStereoNoRamp : public NoRamp<Traits>
304 {
305 	typedef NoRamp<Traits> base_t;
operatorMixStereoNoRamp306 	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
307 	{
308 		outBuffer[0] += outSample[0] * base_t::lVol;
309 		outBuffer[1] += outSample[1] * base_t::rVol;
310 	}
311 };
312 
313 
314 template<class Traits>
315 struct MixStereoRamp : public Ramp
316 {
operatorMixStereoRamp317 	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const MPT_RESTRICT outBuffer)
318 	{
319 		lRamp += chn.leftRamp;
320 		rRamp += chn.rightRamp;
321 		outBuffer[0] += outSample[0] * (lRamp >> VOLUMERAMPPRECISION);
322 		outBuffer[1] += outSample[1] * (rRamp >> VOLUMERAMPPRECISION);
323 	}
324 };
325 
326 
327 //////////////////////////////////////////////////////////////////////////
328 // Filter templates
329 
330 
331 template<class Traits>
332 struct NoFilter
333 {
StartNoFilter334 	MPT_FORCEINLINE void Start(const ModChannel &) { }
EndNoFilter335 	MPT_FORCEINLINE void End(const ModChannel &) { }
336 
operatorNoFilter337 	MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &, const ModChannel &) { }
338 };
339 
340 
341 // Resonant filter
342 template<class Traits>
343 struct ResonantFilter
344 {
345 	// Filter history
346 	typename Traits::output_t fy[Traits::numChannelsIn][2];
347 
StartResonantFilter348 	MPT_FORCEINLINE void Start(const ModChannel &chn)
349 	{
350 		for(int i = 0; i < Traits::numChannelsIn; i++)
351 		{
352 			fy[i][0] = chn.nFilter_Y[i][0];
353 			fy[i][1] = chn.nFilter_Y[i][1];
354 		}
355 	}
356 
EndResonantFilter357 	MPT_FORCEINLINE void End(ModChannel &chn)
358 	{
359 		for(int i = 0; i < Traits::numChannelsIn; i++)
360 		{
361 			chn.nFilter_Y[i][0] = fy[i][0];
362 			chn.nFilter_Y[i][1] = fy[i][1];
363 		}
364 	}
365 
366 	// To avoid a precision loss in the state variables especially with quiet samples at low cutoff and high mix rate, we pre-amplify the sample.
367 #define MIXING_FILTER_PREAMP 256
368 	// Filter values are clipped to double the input range
369 #define ClipFilter(x) Clamp<typename Traits::output_t, typename Traits::output_t>(x, int16_min * 2 * MIXING_FILTER_PREAMP, int16_max * 2 * MIXING_FILTER_PREAMP)
370 
operatorResonantFilter371 	MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const ModChannel &chn)
372 	{
373 		static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
374 
375 		for(int i = 0; i < Traits::numChannelsIn; i++)
376 		{
377 			const auto inputAmp = outSample[i] * MIXING_FILTER_PREAMP;
378 			typename Traits::output_t val = static_cast<typename Traits::output_t>(mpt::rshift_signed(
379 				Util::mul32to64(inputAmp, chn.nFilter_A0) +
380 				Util::mul32to64(ClipFilter(fy[i][0]), chn.nFilter_B0) +
381 				Util::mul32to64(ClipFilter(fy[i][1]), chn.nFilter_B1) +
382 				(1 << (MIXING_FILTER_PRECISION - 1)), MIXING_FILTER_PRECISION));
383 			fy[i][1] = fy[i][0];
384 			fy[i][0] = val - (inputAmp & chn.nFilter_HP);
385 			outSample[i] = val / MIXING_FILTER_PREAMP;
386 		}
387 	}
388 
389 #undef ClipFilter
390 };
391 
392 
393 OPENMPT_NAMESPACE_END
394