You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ovCResampler.h 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. #pragma once
  2. #include <vector>
  3. #include <algorithm>
  4. #include <cassert>
  5. #include <cstdint>
  6. #include <r8brain/CDSPResampler.h>
  7. namespace Common {
  8. namespace Resampler {
  9. enum class EResamplerStoreModes { ChannelWise, SampleWise };
  10. template <class TFloat, EResamplerStoreModes TStoreMode>
  11. class TResampler
  12. {
  13. public:
  14. class ICallback
  15. {
  16. public:
  17. virtual ~ICallback() { }
  18. virtual void processResampler(const TFloat* pSample, const size_t nChannel) const = 0;
  19. };
  20. private:
  21. TResampler(const TResampler<TFloat, TStoreMode>&) = default;
  22. public:
  23. /// <summary> Constructor, with default values for real-time processing. </summary>
  24. TResampler()
  25. {
  26. this->clear();
  27. switch (TStoreMode)
  28. {
  29. case EResamplerStoreModes::ChannelWise:
  30. m_fpResample = &TResampler<TFloat, TStoreMode>::resampleChannelWise;
  31. m_fpResampleDirect = &TResampler<TFloat, TStoreMode>::resampleChannelWise;
  32. break;
  33. case EResamplerStoreModes::SampleWise:
  34. m_fpResample = &TResampler<TFloat, TStoreMode>::resampleSampleWise;
  35. m_fpResampleDirect = &TResampler<TFloat, TStoreMode>::resampleSampleWise;
  36. break;
  37. default:
  38. assert(false);
  39. }
  40. }
  41. virtual ~TResampler() { this->clear(); }
  42. void clear()
  43. {
  44. for (size_t j = 0; j < m_resamplers.size(); ++j) { delete m_resamplers[j]; }
  45. m_resamplers.clear();
  46. m_nChannel = 0;
  47. m_iSampling = 0;
  48. m_oSampling = 0;
  49. m_nFractionalDelayFilterSample = 6;
  50. m_iMaxNSampleIn = 1024;
  51. m_transitionBandPercent = 45;
  52. m_stopBandAttenuation = 49;
  53. }
  54. /// <summary> Specifies the number of samples (taps) each fractional delay filter should have.\n
  55. ///
  56. /// This must be an even value.To achieve a higher resampling precision,
  57. /// the oversampling should be used in the first place instead of using a higher FractionalDelayFilterSampleCount value.
  58. /// The lower this value is the lower the signal - to - noise performance of the interpolator will be.
  59. /// Each FractionalDelayFilterSampleCount decrease by 2 decreases SNR by approximately 12 to 14 decibels. </summary>
  60. /// <param name="n">The fractional delay (Between 6 and 30, and default = 6).</param>
  61. /// <returns> <c>true</c> if even and between 6 and 30, <c>false</c> otherwise. </returns>
  62. /// <remarks>For real-time processing, n = 6. </remarks>
  63. bool setFractionalDelayFilterSampleCount(const int n = 6)
  64. {
  65. if (n < 6 || 30 < n || n % 2 == 1) { return false; } // false if odd value
  66. m_nFractionalDelayFilterSample = n;
  67. return true;
  68. }
  69. /// <summary> Maximal planned length of the input buffer (in samples) that will be passed to the resampler.
  70. /// Input buffers longer than this value should never be supplied to the resampler.
  71. /// The resampler relies on this value as it allocates intermediate buffers. </summary>
  72. /// <param name="n">The maximal input sample count.</param>
  73. /// <returns> <c>true</c> if between 8 and 2048, <c>false</c> otherwise. </returns>
  74. /// <remarks> Note that the resampler may use the input buffer itself for intermediate sample data storage. </remarks>
  75. bool setMaxNSampleIn(const int n = 8)
  76. {
  77. if (n < 8 || 2048 < n) { return false; }
  78. m_iMaxNSampleIn = n;
  79. return true;
  80. }
  81. /// <summary> Transition band, in percent of the spectral space of the input signal
  82. /// (or the output signal if downsampling is performed) between filter's -3 dB point and the Nyquist frequency. </summary>
  83. /// <param name="n">The Transition band (Between 0.5% and 45%, and default = 10.).</param>
  84. /// <returns> <c>true</c> if between 0.5 and 45, <c>false</c> otherwise. </returns>
  85. /// <remarks>For real-time processing, n = 45. </remarks>
  86. bool setTransitionBand(const double n = 10)
  87. {
  88. if (n < r8b::CDSPFIRFilter::getLPMinTransBand() || r8b::CDSPFIRFilter::getLPMaxTransBand() < n) { return false; }
  89. m_transitionBandPercent = n;
  90. return true;
  91. }
  92. /// <summary> Stop-band attenuation in decibel.\n
  93. ///
  94. /// The general formula is 6.02 * Bits + 40, where "Bits" is the bit resolution(e.g. 16, 24),
  95. /// "40" is an added resolution for stationary signals, this value can be decreased to 20 to 10
  96. /// if the signal being resampled is mostly non - stationary(e.g.impulse response). </summary>
  97. /// <param name="n">The Stop-band attenuation in decibel (Between 49 and 218, and default = 49 is given by the general formula).</param>
  98. /// <returns> <c>true</c> if between 49 and 218, <c>false</c> otherwise. </returns>
  99. /// <remarks>For real-time processing, n = 49. </remarks>
  100. bool setStopBandAttenuation(const double n = 49)
  101. {
  102. if (n < r8b::CDSPFIRFilter::getLPMinAtten() || r8b::CDSPFIRFilter::getLPMaxAtten() < n) { return false; }
  103. m_stopBandAttenuation = n;
  104. return true;
  105. }
  106. /// <summary> This fonction initializes the vector of Resampler, using the number of channels, the input and the output sampling rates. </summary>
  107. /// <param name="nChannel"> The number of channel. </param>
  108. /// <param name="iSampling"> The input sampling. </param>
  109. /// <param name="oSampling"> The output sampling. </param>
  110. /// <returns> <c>true</c> if success, <c>false</c> otherwise. </returns>
  111. bool reset(const size_t nChannel, const size_t iSampling, const size_t oSampling)
  112. {
  113. if (nChannel == 0 || iSampling == 0 || oSampling == 0) { return false; }
  114. m_iSampling = iSampling;
  115. m_oSampling = oSampling;
  116. m_nChannel = nChannel;
  117. for (size_t i = 0; i < m_resamplers.size(); ++i) { delete m_resamplers[i]; }
  118. m_resamplers.clear();
  119. m_resamplers.resize(m_nChannel);
  120. const double in = double(iSampling), out = double(oSampling);
  121. const double stopBandAttenuation = m_stopBandAttenuation == 0
  122. ? std::min(6.02 * m_nFractionalDelayFilterSample + 40, r8b::CDSPFIRFilter::getLPMaxAtten())
  123. : m_stopBandAttenuation;
  124. #define NEW_SAMPLER(Len, Fracs)\
  125. new r8b::CDSPResampler<r8b::CDSPFracInterpolator<Len, Fracs>>(in, out, m_iMaxNSampleIn,\
  126. m_transitionBandPercent, stopBandAttenuation,r8b::EDSPFilterPhaseResponse(0), false)
  127. for (size_t j = 0; j < m_nChannel; ++j)
  128. {
  129. switch (m_nFractionalDelayFilterSample) // it defines iFractionalDelayPositionCount
  130. {
  131. case 6:
  132. m_resamplers[j] = NEW_SAMPLER(6, 11);
  133. break;
  134. case 8:
  135. m_resamplers[j] = NEW_SAMPLER(8, 17);
  136. break;
  137. case 10:
  138. m_resamplers[j] = NEW_SAMPLER(10, 23);
  139. break;
  140. case 12:
  141. m_resamplers[j] = NEW_SAMPLER(12, 41);
  142. break;
  143. case 14:
  144. //stopBandAttenuation = 109.56;
  145. m_resamplers[j] = NEW_SAMPLER(14, 67);
  146. break;
  147. case 16:
  148. m_resamplers[j] = NEW_SAMPLER(16, 97);
  149. break;
  150. case 18:
  151. //stopBandAttenuation = 136.45;
  152. m_resamplers[j] = NEW_SAMPLER(18, 137);
  153. break;
  154. case 20:
  155. m_resamplers[j] = NEW_SAMPLER(20, 211);
  156. break;
  157. case 22:
  158. m_resamplers[j] = NEW_SAMPLER(22, 353);
  159. break;
  160. case 24:
  161. //stopBandAttenuation = 180.15;
  162. m_resamplers[j] = NEW_SAMPLER(24, 673);
  163. break;
  164. case 26:
  165. m_resamplers[j] = NEW_SAMPLER(26, 1051);
  166. break;
  167. case 28:
  168. m_resamplers[j] = NEW_SAMPLER(28, 1733);
  169. break;
  170. case 30:
  171. m_resamplers[j] = NEW_SAMPLER(30, 2833);
  172. break;
  173. default:
  174. return false;
  175. }
  176. }
  177. #undef NEW_SAMPLER(Len, Fracs)
  178. return true;
  179. }
  180. /// <summary> Gets the latency.\n
  181. ///
  182. /// This value is usually zero if the DSP processor "consumes" the latency automatically. (from CDSPProcessor.h) </summary>
  183. /// <returns> Latency. </returns>
  184. virtual int getLatency() const { return m_resamplers[0]->getLatency(); }
  185. /// <summary> Gets the Fractional latency.
  186. ///
  187. /// Fractional latency, in samples, which is present in the output signal.
  188. /// This value is usually zero if a linear - phase filtering is used.
  189. /// With minimum - phase filters in use, this value can be non - zero even if the getLatency() function returns zero. (from CDSPProcessor.h)
  190. /// </summary>
  191. /// <returns></returns>
  192. /// <returns> Fractionnal Latency. </returns>
  193. virtual double getLatencyFrac() const { return m_resamplers[0]->getLatencyFrac(); }
  194. /// <summary> Gets the cumulative number of samples that should be passed to *this object before the actual output starts.
  195. /// This value includes latencies induced by all processors which run after *this processor in chain. </summary>
  196. /// <param name="nextInLen"> The number of input samples required before the output starts on the next resampling step. (from CDSPProcessor.h) </param>
  197. /// <returns> the cumulative number of samples. </returns>
  198. virtual int getInLenBeforeOutStart(const int nextInLen) const { return m_resamplers[0]->getInLenBeforeOutStart(nextInLen); }
  199. /// <summary> Gets the maximal length of the output buffer required when processing the "maxInLen" number of input samples. </summary>
  200. /// <param name="maxInLen"> The number of samples planned to process at once, at most. (from CDSPProcessor.h). </param>
  201. /// <returns> The length. </returns>
  202. virtual int getMaxOutLen(const int maxInLen) const { return m_resamplers[0]->getMaxOutLen(maxInLen); }
  203. double getBuiltInLatency() const { return (m_iSampling != 0) ? (1.0 * m_resamplers[0]->getInLenBeforeOutStart(0) / m_iSampling) : 0.0; }
  204. size_t resample(const ICallback& callback, const TFloat* iSample, const size_t nInSample) { return (this->*m_fpResample)(callback, iSample, nInSample); }
  205. size_t downsample(const ICallback& callback, const TFloat* iSample, const size_t nInSample) { return (this->*m_fpResample)(callback, iSample, nInSample); }
  206. private:
  207. /// <summary> This function resamples the signal assuming the input samples are ordered this way :
  208. /// - sample 1 of channel 1, sample 1 of channel 2, ..., sample 1 of channel nChannel,
  209. /// - sample 2 of channel 1, sample 2 of channel 2, ..., sample 2 of channel nChannel,
  210. /// - ...
  211. /// - sample nInSample of channel 1, sample nInSample of channel 2, ..., sample nInSample of channel nChannel,\n
  212. ///
  213. /// This is convenient for resampling at the acquisition level. </summary>
  214. /// <param name="callback">The callback.</param>
  215. /// <param name="iSample">The input sample.</param>
  216. /// <param name="nInSample">The n input sample.</param>
  217. /// <returns> the number of sample process in last channel. </returns>
  218. size_t resampleChannelWise(const ICallback& callback, const TFloat* iSample, const size_t nInSample)
  219. {
  220. int nI = 0;
  221. bool isFirstChannel = true;
  222. std::vector<double> iBuffers(nInSample);
  223. std::vector<TFloat> oBuffers;
  224. for (size_t j = 0; j < m_nChannel; ++j)
  225. {
  226. for (size_t k = 0; k < nInSample; ++k) { iBuffers[k] = double(iSample[k * m_nChannel + j]); }
  227. double* resamplerOutputBuffer;
  228. nI = m_resamplers[j]->process(&iBuffers[0], int(nInSample), resamplerOutputBuffer);
  229. if (isFirstChannel)
  230. {
  231. oBuffers.resize(nI * m_nChannel);
  232. isFirstChannel = false;
  233. }
  234. for (int k = 0; k < nI; ++k) { oBuffers[k * m_nChannel + j] = TFloat(resamplerOutputBuffer[k]); }
  235. }
  236. for (int k = 0; k < nI; ++k) { callback.processResampler(&oBuffers[k * m_nChannel], m_nChannel); }
  237. return nI;
  238. }
  239. /// <summary> This function resamples the signal assuming the input samples are ordered this way :
  240. /// - sample 1 of channel 1, sample 2 of channel 1, ..., sample nInSample of channel 1,
  241. /// - sample 1 of channel 2, sample 2 of channel 2, ..., sample nInSample of channel 2,
  242. /// - ...
  243. /// - sample 1 of channel nChannel, sample 2 of channel nChannel, ..., sample nInSample of channel nChannel,
  244. ///
  245. /// This is convenient for resampling at the signal-processing level. </summary>
  246. /// <param name="callback">The callback.</param>
  247. /// <param name="iSample">The input sample.</param>
  248. /// <param name="nInSample">The n input sample.</param>
  249. /// <returns> the number of sample process in last channel. </returns>
  250. size_t resampleSampleWise(const ICallback& callback, const TFloat* iSample, const size_t nInSample)
  251. {
  252. int nI = 0;
  253. bool isFirstChannel = true;
  254. std::vector<double> iBuffers(nInSample);
  255. std::vector<TFloat> oBuffers;
  256. for (size_t j = 0; j < m_nChannel; ++j)
  257. {
  258. for (size_t k = 0; k < nInSample; ++k) { iBuffers[k] = double(iSample[j * nInSample + k]); }
  259. double* resamplerOutputBuffer;
  260. nI = m_resamplers[j]->process(&iBuffers[0], int(nInSample), resamplerOutputBuffer);
  261. if (isFirstChannel)
  262. {
  263. oBuffers.resize(nI * m_nChannel);
  264. isFirstChannel = false;
  265. }
  266. for (int k = 0; k < nI; ++k) { oBuffers[k * m_nChannel + j] = TFloat(resamplerOutputBuffer[k]); }
  267. }
  268. for (int k = 0; k < nI; ++k) { callback.processResampler(&oBuffers[k * m_nChannel], m_nChannel); }
  269. return nI;
  270. }
  271. protected:
  272. /// <summary> Trivial channel wise callback implementation. </summary>
  273. class CCallbackChannelWise final : public ICallback
  274. {
  275. public:
  276. CCallbackChannelWise(TFloat* oSample) : m_OutputSample(oSample) { }
  277. void processResampler(const TFloat* sample, const size_t nChannel) const override
  278. {
  279. for (size_t i = 0; i < nChannel; ++i)
  280. {
  281. *m_OutputSample = *sample;
  282. ++m_OutputSample;
  283. ++sample;
  284. }
  285. }
  286. mutable TFloat* m_OutputSample;
  287. };
  288. /// <summary> Trivial sample wise callback implementation. </summary>
  289. class CCallbackSampleWise final : public ICallback
  290. {
  291. public:
  292. CCallbackSampleWise(TFloat* oSample, const size_t nOutSample) : m_OutputSample(oSample), m_NOutputSample(nOutSample) { }
  293. void processResampler(const TFloat* sample, const size_t nChannel) const override
  294. {
  295. for (size_t i = 0; i < nChannel; ++i) { m_OutputSample[i * m_NOutputSample + m_OutputSampleIdx] = sample[i]; }
  296. m_OutputSampleIdx++;
  297. m_OutputSampleIdx %= m_NOutputSample;
  298. }
  299. TFloat* const m_OutputSample;
  300. size_t m_NOutputSample = 0;
  301. mutable size_t m_OutputSampleIdx = 0;
  302. };
  303. size_t resampleChannelWise(TFloat* oSample, const TFloat* iSample, const size_t nInSample, const size_t /*nOutSample*/)
  304. {
  305. return this->resample(CCallbackChannelWise(oSample), iSample, nInSample);
  306. }
  307. size_t resampleSampleWise(TFloat* oSample, const TFloat* iSample, const size_t nInSample, const size_t nOutSample)
  308. {
  309. return this->resample(CCallbackSampleWise(oSample, nOutSample), iSample, nInSample);
  310. }
  311. public:
  312. size_t resample(TFloat* oSample, const TFloat* iSample, const size_t nInSample, const size_t nOutSample = 1)
  313. {
  314. return (this->*m_fpResampleDirect)(oSample, iSample, nInSample, nOutSample);
  315. }
  316. size_t downsample(TFloat* oSample, const TFloat* iSample, const size_t nInSample, const size_t nOutSample = 1)
  317. {
  318. return resample(oSample, iSample, nInSample, nOutSample);
  319. }
  320. protected:
  321. size_t m_nChannel = 0;
  322. size_t m_iSampling = 0;
  323. size_t m_oSampling = 0;
  324. int m_nFractionalDelayFilterSample = 6;
  325. int m_iMaxNSampleIn = 1024;
  326. double m_transitionBandPercent = 45;
  327. double m_stopBandAttenuation = 49;
  328. std::vector<r8b::CDSPProcessor*> m_resamplers;
  329. size_t (TResampler<TFloat, TStoreMode>::*m_fpResample)(const ICallback& callback, const TFloat* iSample, const size_t nInSample);
  330. size_t (TResampler<TFloat, TStoreMode>::*m_fpResampleDirect)(TFloat* oSample, const TFloat* iSample, const size_t nInSample, const size_t nOutSample);
  331. };
  332. typedef TResampler<float, EResamplerStoreModes::SampleWise> CResamplerSf;
  333. typedef TResampler<float, EResamplerStoreModes::ChannelWise> CResamplerCf;
  334. typedef TResampler<double, EResamplerStoreModes::SampleWise> CResamplerSd;
  335. typedef TResampler<double, EResamplerStoreModes::ChannelWise> CResamplerCd;
  336. typedef TResampler<float, EResamplerStoreModes::SampleWise> CDownsamplerSf;
  337. typedef TResampler<float, EResamplerStoreModes::ChannelWise> CDownsamplerCf;
  338. typedef TResampler<double, EResamplerStoreModes::SampleWise> CDownsamplerSd;
  339. typedef TResampler<double, EResamplerStoreModes::ChannelWise> CDownsamplerCd;
  340. } // namespace Resampler
  341. } // namespace Common