IntMixer.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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. #pragma once
  11. #include "openmpt/all/BuildSettings.hpp"
  12. #include "Resampler.h"
  13. #include "MixerInterface.h"
  14. #include "Paula.h"
  15. OPENMPT_NAMESPACE_BEGIN
  16. template<int channelsOut, int channelsIn, typename out, typename in, size_t mixPrecision>
  17. struct IntToIntTraits : public MixerTraits<channelsOut, channelsIn, out, in>
  18. {
  19. typedef MixerTraits<channelsOut, channelsIn, out, in> base_t;
  20. typedef typename base_t::input_t input_t;
  21. typedef typename base_t::output_t output_t;
  22. static MPT_CONSTEXPRINLINE output_t Convert(const input_t x)
  23. {
  24. static_assert(std::numeric_limits<input_t>::is_integer, "Input must be integer");
  25. static_assert(std::numeric_limits<output_t>::is_integer, "Output must be integer");
  26. static_assert(sizeof(out) * 8 >= mixPrecision, "Mix precision is higher than output type can handle");
  27. static_assert(sizeof(in) * 8 <= mixPrecision, "Mix precision is lower than input type");
  28. return static_cast<output_t>(x) * (1<<(mixPrecision - sizeof(in) * 8));
  29. }
  30. };
  31. typedef IntToIntTraits<2, 1, mixsample_t, int8, 16> Int8MToIntS;
  32. typedef IntToIntTraits<2, 1, mixsample_t, int16, 16> Int16MToIntS;
  33. typedef IntToIntTraits<2, 2, mixsample_t, int8, 16> Int8SToIntS;
  34. typedef IntToIntTraits<2, 2, mixsample_t, int16, 16> Int16SToIntS;
  35. //////////////////////////////////////////////////////////////////////////
  36. // Interpolation templates
  37. template<class Traits>
  38. struct AmigaBlepInterpolation
  39. {
  40. SamplePosition subIncrement;
  41. Paula::State &paula;
  42. const Paula::BlepArray &WinSincIntegral;
  43. const int numSteps;
  44. unsigned int remainingSamples = 0;
  45. MPT_FORCEINLINE AmigaBlepInterpolation(ModChannel &chn, const CResampler &resampler, unsigned int numSamples)
  46. : paula{chn.paulaState}
  47. , WinSincIntegral{resampler.blepTables.GetAmigaTable(resampler.m_Settings.emulateAmiga, chn.dwFlags[CHN_AMIGAFILTER])}
  48. , numSteps{chn.paulaState.numSteps}
  49. {
  50. if(numSteps)
  51. {
  52. subIncrement = chn.increment / numSteps;
  53. // May we read past the start or end of sample if we do partial sample increments?
  54. // If that's the case, don't apply any sub increments on the source sample if we reached the last output sample
  55. // Note that this should only happen with notes well outside the Amiga note range, e.g. in software-mixed formats like MED
  56. const int32 targetPos = (chn.position + chn.increment * numSamples).GetInt();
  57. if(static_cast<SmpLength>(targetPos) > chn.nLength)
  58. remainingSamples = numSamples;
  59. }
  60. }
  61. MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
  62. {
  63. if(--remainingSamples == 0)
  64. subIncrement = {};
  65. SamplePosition pos(0, posLo);
  66. // First, process steps of full length (one Amiga clock interval)
  67. for(int step = numSteps; step > 0; step--)
  68. {
  69. typename Traits::output_t inSample = 0;
  70. int32 posInt = pos.GetInt() * Traits::numChannelsIn;
  71. for(int32 i = 0; i < Traits::numChannelsIn; i++)
  72. inSample += Traits::Convert(inBuffer[posInt + i]);
  73. paula.InputSample(static_cast<int16>(inSample / (4 * Traits::numChannelsIn)));
  74. paula.Clock(Paula::MINIMUM_INTERVAL);
  75. pos += subIncrement;
  76. }
  77. paula.remainder += paula.stepRemainder;
  78. // Now, process any remaining integer clock amount < MINIMUM_INTERVAL
  79. uint32 remainClocks = paula.remainder.GetInt();
  80. if(remainClocks)
  81. {
  82. typename Traits::output_t inSample = 0;
  83. int32 posInt = pos.GetInt() * Traits::numChannelsIn;
  84. for(int32 i = 0; i < Traits::numChannelsIn; i++)
  85. inSample += Traits::Convert(inBuffer[posInt + i]);
  86. paula.InputSample(static_cast<int16>(inSample / (4 * Traits::numChannelsIn)));
  87. paula.Clock(remainClocks);
  88. paula.remainder.RemoveInt();
  89. }
  90. auto out = paula.OutputSample(WinSincIntegral);
  91. for(int i = 0; i < Traits::numChannelsOut; i++)
  92. outSample[i] = out;
  93. }
  94. };
  95. template<class Traits>
  96. struct LinearInterpolation
  97. {
  98. MPT_FORCEINLINE LinearInterpolation(const ModChannel &, const CResampler &, unsigned int) { }
  99. MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
  100. {
  101. static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
  102. const typename Traits::output_t fract = posLo >> 18u;
  103. for(int i = 0; i < Traits::numChannelsIn; i++)
  104. {
  105. typename Traits::output_t srcVol = Traits::Convert(inBuffer[i]);
  106. typename Traits::output_t destVol = Traits::Convert(inBuffer[i + Traits::numChannelsIn]);
  107. outSample[i] = srcVol + ((fract * (destVol - srcVol)) / 16384);
  108. }
  109. }
  110. };
  111. template<class Traits>
  112. struct FastSincInterpolation
  113. {
  114. MPT_FORCEINLINE FastSincInterpolation(const ModChannel &, const CResampler &, unsigned int) { }
  115. MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
  116. {
  117. static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
  118. const int16 *lut = CResampler::FastSincTable + ((posLo >> 22) & 0x3FC);
  119. for(int i = 0; i < Traits::numChannelsIn; i++)
  120. {
  121. outSample[i] =
  122. (lut[0] * Traits::Convert(inBuffer[i - Traits::numChannelsIn])
  123. + lut[1] * Traits::Convert(inBuffer[i])
  124. + lut[2] * Traits::Convert(inBuffer[i + Traits::numChannelsIn])
  125. + lut[3] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn])) / 16384;
  126. }
  127. }
  128. };
  129. template<class Traits>
  130. struct PolyphaseInterpolation
  131. {
  132. const SINC_TYPE *sinc;
  133. MPT_FORCEINLINE PolyphaseInterpolation(const ModChannel &chn, const CResampler &resampler, unsigned int)
  134. {
  135. #ifdef MODPLUG_TRACKER
  136. // Otherwise causes "warning C4100: 'resampler' : unreferenced formal parameter"
  137. // because all 3 tables are static members.
  138. // #pragma warning fails with this templated case for unknown reasons.
  139. MPT_UNREFERENCED_PARAMETER(resampler);
  140. #endif // MODPLUG_TRACKER
  141. sinc = (((chn.increment > SamplePosition(0x130000000ll)) || (chn.increment < SamplePosition(-0x130000000ll))) ?
  142. (((chn.increment > SamplePosition(0x180000000ll)) || (chn.increment < SamplePosition(-0x180000000ll))) ? resampler.gDownsample2x : resampler.gDownsample13x) : resampler.gKaiserSinc);
  143. }
  144. MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
  145. {
  146. static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
  147. const SINC_TYPE *lut = sinc + ((posLo >> (32 - SINC_PHASES_BITS)) & SINC_MASK) * SINC_WIDTH;
  148. for(int i = 0; i < Traits::numChannelsIn; i++)
  149. {
  150. outSample[i] =
  151. (lut[0] * Traits::Convert(inBuffer[i - 3 * Traits::numChannelsIn])
  152. + lut[1] * Traits::Convert(inBuffer[i - 2 * Traits::numChannelsIn])
  153. + lut[2] * Traits::Convert(inBuffer[i - Traits::numChannelsIn])
  154. + lut[3] * Traits::Convert(inBuffer[i])
  155. + lut[4] * Traits::Convert(inBuffer[i + Traits::numChannelsIn])
  156. + lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn])
  157. + lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn])
  158. + lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn])) / (1 << SINC_QUANTSHIFT);
  159. }
  160. }
  161. };
  162. template<class Traits>
  163. struct FIRFilterInterpolation
  164. {
  165. const int16 *WFIRlut;
  166. MPT_FORCEINLINE FIRFilterInterpolation(const ModChannel &, const CResampler &resampler, unsigned int)
  167. {
  168. WFIRlut = resampler.m_WindowedFIR.lut;
  169. }
  170. MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const typename Traits::input_t * const MPT_RESTRICT inBuffer, const uint32 posLo)
  171. {
  172. static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
  173. const int16 * const lut = WFIRlut + ((((posLo >> 16) + WFIR_FRACHALVE) >> WFIR_FRACSHIFT) & WFIR_FRACMASK);
  174. for(int i = 0; i < Traits::numChannelsIn; i++)
  175. {
  176. typename Traits::output_t vol1 =
  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. typename Traits::output_t vol2 =
  182. (lut[4] * Traits::Convert(inBuffer[i + 1 * Traits::numChannelsIn]))
  183. + (lut[5] * Traits::Convert(inBuffer[i + 2 * Traits::numChannelsIn]))
  184. + (lut[6] * Traits::Convert(inBuffer[i + 3 * Traits::numChannelsIn]))
  185. + (lut[7] * Traits::Convert(inBuffer[i + 4 * Traits::numChannelsIn]));
  186. outSample[i] = ((vol1 / 2) + (vol2 / 2)) / (1 << (WFIR_16BITSHIFT - 1));
  187. }
  188. }
  189. };
  190. //////////////////////////////////////////////////////////////////////////
  191. // Mixing templates (add sample to stereo mix)
  192. template<class Traits>
  193. struct NoRamp
  194. {
  195. typename Traits::output_t lVol, rVol;
  196. MPT_FORCEINLINE NoRamp(const ModChannel &chn)
  197. {
  198. lVol = chn.leftVol;
  199. rVol = chn.rightVol;
  200. }
  201. };
  202. struct Ramp
  203. {
  204. ModChannel &channel;
  205. int32 lRamp, rRamp;
  206. MPT_FORCEINLINE Ramp(ModChannel &chn)
  207. : channel{chn}
  208. {
  209. lRamp = chn.rampLeftVol;
  210. rRamp = chn.rampRightVol;
  211. }
  212. MPT_FORCEINLINE ~Ramp()
  213. {
  214. channel.rampLeftVol = lRamp; channel.leftVol = lRamp >> VOLUMERAMPPRECISION;
  215. channel.rampRightVol = rRamp; channel.rightVol = rRamp >> VOLUMERAMPPRECISION;
  216. }
  217. };
  218. // Legacy optimization: If chn.nLeftVol == chn.nRightVol, save one multiplication instruction
  219. template<class Traits>
  220. struct MixMonoFastNoRamp : public NoRamp<Traits>
  221. {
  222. typedef NoRamp<Traits> base_t;
  223. MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
  224. {
  225. typename Traits::output_t vol = outSample[0] * base_t::lVol;
  226. for(int i = 0; i < Traits::numChannelsOut; i++)
  227. {
  228. outBuffer[i] += vol;
  229. }
  230. }
  231. };
  232. template<class Traits>
  233. struct MixMonoNoRamp : public NoRamp<Traits>
  234. {
  235. typedef NoRamp<Traits> base_t;
  236. MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
  237. {
  238. outBuffer[0] += outSample[0] * base_t::lVol;
  239. outBuffer[1] += outSample[0] * base_t::rVol;
  240. }
  241. };
  242. template<class Traits>
  243. struct MixMonoRamp : public Ramp
  244. {
  245. MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const MPT_RESTRICT outBuffer)
  246. {
  247. lRamp += chn.leftRamp;
  248. rRamp += chn.rightRamp;
  249. outBuffer[0] += outSample[0] * (lRamp >> VOLUMERAMPPRECISION);
  250. outBuffer[1] += outSample[0] * (rRamp >> VOLUMERAMPPRECISION);
  251. }
  252. };
  253. template<class Traits>
  254. struct MixStereoNoRamp : public NoRamp<Traits>
  255. {
  256. typedef NoRamp<Traits> base_t;
  257. MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &, typename Traits::output_t * const MPT_RESTRICT outBuffer)
  258. {
  259. outBuffer[0] += outSample[0] * base_t::lVol;
  260. outBuffer[1] += outSample[1] * base_t::rVol;
  261. }
  262. };
  263. template<class Traits>
  264. struct MixStereoRamp : public Ramp
  265. {
  266. MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &outSample, const ModChannel &chn, typename Traits::output_t * const MPT_RESTRICT outBuffer)
  267. {
  268. lRamp += chn.leftRamp;
  269. rRamp += chn.rightRamp;
  270. outBuffer[0] += outSample[0] * (lRamp >> VOLUMERAMPPRECISION);
  271. outBuffer[1] += outSample[1] * (rRamp >> VOLUMERAMPPRECISION);
  272. }
  273. };
  274. //////////////////////////////////////////////////////////////////////////
  275. // Filter templates
  276. template<class Traits>
  277. struct NoFilter
  278. {
  279. MPT_FORCEINLINE NoFilter(const ModChannel &) { }
  280. MPT_FORCEINLINE void operator() (const typename Traits::outbuf_t &, const ModChannel &) { }
  281. };
  282. // Resonant filter
  283. template<class Traits>
  284. struct ResonantFilter
  285. {
  286. ModChannel &channel;
  287. // Filter history
  288. typename Traits::output_t fy[Traits::numChannelsIn][2];
  289. MPT_FORCEINLINE ResonantFilter(ModChannel &chn)
  290. : channel{chn}
  291. {
  292. for(int i = 0; i < Traits::numChannelsIn; i++)
  293. {
  294. fy[i][0] = chn.nFilter_Y[i][0];
  295. fy[i][1] = chn.nFilter_Y[i][1];
  296. }
  297. }
  298. MPT_FORCEINLINE ~ResonantFilter()
  299. {
  300. for(int i = 0; i < Traits::numChannelsIn; i++)
  301. {
  302. channel.nFilter_Y[i][0] = fy[i][0];
  303. channel.nFilter_Y[i][1] = fy[i][1];
  304. }
  305. }
  306. // 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.
  307. #define MIXING_FILTER_PREAMP 256
  308. // Filter values are clipped to double the input range
  309. #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)
  310. MPT_FORCEINLINE void operator() (typename Traits::outbuf_t &outSample, const ModChannel &chn)
  311. {
  312. static_assert(static_cast<int>(Traits::numChannelsIn) <= static_cast<int>(Traits::numChannelsOut), "Too many input channels");
  313. for(int i = 0; i < Traits::numChannelsIn; i++)
  314. {
  315. const auto inputAmp = outSample[i] * MIXING_FILTER_PREAMP;
  316. typename Traits::output_t val = static_cast<typename Traits::output_t>(mpt::rshift_signed(
  317. Util::mul32to64(inputAmp, chn.nFilter_A0) +
  318. Util::mul32to64(ClipFilter(fy[i][0]), chn.nFilter_B0) +
  319. Util::mul32to64(ClipFilter(fy[i][1]), chn.nFilter_B1) +
  320. (1 << (MIXING_FILTER_PRECISION - 1)), MIXING_FILTER_PRECISION));
  321. fy[i][1] = fy[i][0];
  322. fy[i][0] = val - (inputAmp & chn.nFilter_HP);
  323. outSample[i] = val / MIXING_FILTER_PREAMP;
  324. }
  325. }
  326. #undef ClipFilter
  327. };
  328. OPENMPT_NAMESPACE_END