PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
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.

Resampler.h 9.8KB

3 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /* Audio Library for Teensy 3.X
  2. * Copyright (c) 2019, Paul Stoffregen, paul@pjrc.com
  3. *
  4. * Development of this audio library was funded by PJRC.COM, LLC by sales of
  5. * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
  6. * open source software by purchasing Teensy or other PJRC products.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice, development funding notice, and this permission
  16. * notice shall be included in all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. /*
  27. by Alexander Walch
  28. */
  29. #ifndef resampler_h_
  30. #define resampler_h_
  31. #include "Arduino.h"
  32. //#define DEBUG_RESAMPLER //activates debug output
  33. #define MAX_FILTER_SAMPLES 40961 //=1024*20 +1
  34. #define NO_EXACT_KAISER_SAMPLES 1025
  35. #define MAX_HALF_FILTER_LENGTH 80
  36. #define MAX_NO_CHANNELS 8
  37. class Resampler {
  38. public:
  39. struct StepAdaptionParameters {
  40. StepAdaptionParameters(){}
  41. double alpha =0.2; //exponential smoothing parameter
  42. double maxAdaption = 0.01; //maximum relative allowed adaption of resampler step 0.01 = 1%
  43. double kp= 0.6;
  44. double ki=0.00012;
  45. double kd= 1.8;
  46. };
  47. Resampler(StepAdaptionParameters settings=StepAdaptionParameters());
  48. void reset();
  49. ///@param attenuation target attenuation [dB] of the anti-aliasing filter. Only used if newFs<fs. The attenuation can't be reached if the needed filter length exceeds 2*MAX_FILTER_SAMPLES+1
  50. ///@param minHalfFilterLength If newFs >= fs, the filter length of the resampling filter is 2*minHalfFilterLength+1. If fs y newFs the filter is maybe longer to reach the desired attenuation
  51. void configure(float fs, float newFs, float attenuation=100, int32_t minHalfFilterLength=20);
  52. ///@param input0 first input array/ channel
  53. ///@param input1 second input array/ channel
  54. ///@param inputLength length of each input array
  55. ///@param processedLength number of samples of the input that were resampled to fill the output array
  56. ///@param output0 first output array/ channel
  57. ///@param output1 second output array/ channel
  58. ///@param outputLength length of each output array
  59. ///@param outputCount number of samples of each output array, that were filled with data
  60. void resample(float* input0, float* input1, uint16_t inputLength, uint16_t& processedLength, float* output0, float* output1,uint16_t outputLength, uint16_t& outputCount);
  61. bool addToSampleDiff(double diff);
  62. double getXPos() const;
  63. double getStep() const;
  64. void addToPos(double val);
  65. void fixStep();
  66. bool initialized() const;
  67. //resampling NOCHANNELS channels. Performance is increased a lot if the number of channels is known at compile time -> the number of channels is a template argument
  68. template <uint8_t NOCHANNELS>
  69. inline void resample(float** inputs, uint16_t inputLength, uint16_t& processedLength, float** outputs, uint16_t outputLength, uint16_t& outputCount){
  70. outputCount=0;
  71. int32_t successorIndex=(int32_t)(ceil(_cPos)); //negative number -> currently the _buffer0 of the last iteration is used
  72. float* ip[NOCHANNELS];
  73. float* fPtr;
  74. float si0[NOCHANNELS];
  75. float* si0Ptr;
  76. float si1[NOCHANNELS];
  77. float* si1Ptr;
  78. while (floor(_cPos + _halfFilterLength) < inputLength && outputCount < outputLength){
  79. float dist=successorIndex-_cPos;
  80. float distScaled=dist*_overSamplingFactor;
  81. int32_t rightIndex=abs((int32_t)(ceil(distScaled))-_overSamplingFactor*_halfFilterLength);
  82. const int32_t indexData=successorIndex-_halfFilterLength;
  83. if (indexData>=0){
  84. for (uint8_t i =0; i< NOCHANNELS; i++){
  85. ip[i]=inputs[i]+indexData;
  86. }
  87. }
  88. else {
  89. for (uint8_t i =0; i< NOCHANNELS; i++){
  90. ip[i]=_buffer[i]+indexData+_filterLength;
  91. }
  92. }
  93. fPtr=filter+rightIndex;
  94. memset(si0, 0, NOCHANNELS*sizeof(float));
  95. if (rightIndex==_overSamplingFactor*_halfFilterLength){
  96. si1Ptr=si1;
  97. for (uint8_t i=0; i< NOCHANNELS; i++){
  98. *(si1Ptr++)=*ip[i]++**fPtr;
  99. }
  100. fPtr-=_overSamplingFactor;
  101. rightIndex=(int32_t)(ceil(distScaled))+_overSamplingFactor; //needed below
  102. }
  103. else {
  104. memset(si1, 0, NOCHANNELS*sizeof(float));
  105. rightIndex=(int32_t)(ceil(distScaled)); //needed below
  106. }
  107. for (uint16_t i =0 ; i<_halfFilterLength; i++){
  108. if(ip[0]==_endOfBuffer[0]){
  109. for (uint8_t i =0; i< NOCHANNELS; i++){
  110. ip[i]=inputs[i];
  111. }
  112. }
  113. const float fPtrSucc=*(fPtr+1);
  114. si0Ptr=si0;
  115. si1Ptr=si1;
  116. for (uint8_t i =0; i< NOCHANNELS; i++){
  117. *(si0Ptr++)+=*ip[i]*fPtrSucc;
  118. *(si1Ptr++)+=*ip[i]**fPtr;
  119. ++ip[i];
  120. }
  121. fPtr-=_overSamplingFactor;
  122. }
  123. fPtr=filter+rightIndex-1;
  124. for (uint16_t i =0 ; i<_halfFilterLength; i++){
  125. if(ip[0]==_endOfBuffer[0]){
  126. for (uint8_t i =0; i< NOCHANNELS; i++){
  127. ip[i]=inputs[i];
  128. }
  129. }
  130. const float fPtrSucc=*(fPtr+1);
  131. si0Ptr=si0;
  132. si1Ptr=si1;
  133. for (uint8_t i =0; i< NOCHANNELS; i++){
  134. *(si0Ptr++)+=*ip[i]**fPtr;
  135. *(si1Ptr++)+=*ip[i]*fPtrSucc;
  136. ++ip[i];
  137. }
  138. fPtr+=_overSamplingFactor;
  139. }
  140. const float w0=ceil(distScaled)-distScaled;
  141. const float w1=1.-w0;
  142. si0Ptr=si0;
  143. si1Ptr=si1;
  144. for (uint8_t i =0; i< NOCHANNELS; i++){
  145. *outputs[i]++=*(si0Ptr++)*w0 + *(si1Ptr++)*w1;
  146. }
  147. outputCount++;
  148. _cPos+=_stepAdapted;
  149. while (_cPos >successorIndex){
  150. successorIndex++;
  151. }
  152. }
  153. if(outputCount < outputLength){
  154. //ouput vector not full -> we ran out of input samples
  155. processedLength=inputLength;
  156. }
  157. else{
  158. processedLength=min(inputLength, (int16_t)floor(_cPos + _halfFilterLength));
  159. }
  160. //fill _buffer
  161. const int32_t indexData=processedLength-_filterLength;
  162. if (indexData>=0){
  163. const unsigned long long bytesToCopy= _filterLength*sizeof(float);
  164. float** inPtr=inputs;
  165. for (uint8_t i =0; i< NOCHANNELS; i++){
  166. memcpy((void *)_buffer[i], (void *)((*inPtr)+indexData), bytesToCopy);
  167. ++inPtr;
  168. }
  169. }
  170. else {
  171. float** inPtr=inputs;
  172. for (uint8_t i =0; i< NOCHANNELS; i++){
  173. float* b=_buffer[i];
  174. float* ip=b+indexData+_filterLength;
  175. for (uint16_t j =0; j< _filterLength; j++){
  176. if(ip==_endOfBuffer[i]){
  177. ip=*inPtr;
  178. }
  179. *b++ = *ip++;
  180. }
  181. ++inPtr;
  182. }
  183. }
  184. _cPos-=processedLength;
  185. if (_cPos < -_halfFilterLength){
  186. _cPos=-_halfFilterLength;
  187. }
  188. }
  189. private:
  190. void getKaiserExact(float beta);
  191. void setKaiserWindow(float beta, int32_t noSamples);
  192. void setFilter(int32_t halfFiltLength,int32_t overSampling, float cutOffFrequ, float kaiserBeta);
  193. float filter[MAX_FILTER_SAMPLES];
  194. double kaiserWindowSamples[NO_EXACT_KAISER_SAMPLES];
  195. double tempRes[NO_EXACT_KAISER_SAMPLES-1];
  196. double kaiserWindowXsq[NO_EXACT_KAISER_SAMPLES-1];
  197. float _buffer[MAX_NO_CHANNELS][MAX_HALF_FILTER_LENGTH*2];
  198. float* _endOfBuffer[MAX_NO_CHANNELS];
  199. int32_t _overSamplingFactor;
  200. int32_t _halfFilterLength;
  201. int32_t _filterLength;
  202. bool _initialized=false;
  203. const double _settledThrs = 1e-6;
  204. StepAdaptionParameters _settings;
  205. double _configuredStep;
  206. double _step;
  207. double _stepAdapted;
  208. double _cPos;
  209. double _sum;
  210. double _oldDiffs[2];
  211. };
  212. #endif