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.hpp 4.4KB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #pragma once
  2. #include <speex/speex_resampler.h>
  3. #include <dsp/common.hpp>
  4. #include <dsp/ringbuffer.hpp>
  5. #include <dsp/fir.hpp>
  6. #include <dsp/window.hpp>
  7. namespace rack {
  8. namespace dsp {
  9. /** Resamples by a fixed rational factor. */
  10. template <int MAX_CHANNELS>
  11. struct SampleRateConverter {
  12. SpeexResamplerState* st = NULL;
  13. int channels = MAX_CHANNELS;
  14. int quality = SPEEX_RESAMPLER_QUALITY_DEFAULT;
  15. int inRate = 44100;
  16. int outRate = 44100;
  17. SampleRateConverter() {
  18. refreshState();
  19. }
  20. ~SampleRateConverter() {
  21. if (st) {
  22. speex_resampler_destroy(st);
  23. }
  24. }
  25. /** Sets the number of channels to actually process. This can be at most MAX_CHANNELS. */
  26. void setChannels(int channels) {
  27. assert(channels <= MAX_CHANNELS);
  28. if (channels == this->channels)
  29. return;
  30. this->channels = channels;
  31. refreshState();
  32. }
  33. /** From 0 (worst, fastest) to 10 (best, slowest) */
  34. void setQuality(int quality) {
  35. if (quality == this->quality)
  36. return;
  37. this->quality = quality;
  38. refreshState();
  39. }
  40. void setRates(int inRate, int outRate) {
  41. if (inRate == this->inRate && outRate == this->outRate)
  42. return;
  43. this->inRate = inRate;
  44. this->outRate = outRate;
  45. refreshState();
  46. }
  47. void refreshState() {
  48. if (st) {
  49. speex_resampler_destroy(st);
  50. st = NULL;
  51. }
  52. if (channels > 0 && inRate != outRate) {
  53. int err;
  54. st = speex_resampler_init(channels, inRate, outRate, quality, &err);
  55. assert(st);
  56. assert(err == RESAMPLER_ERR_SUCCESS);
  57. speex_resampler_set_input_stride(st, MAX_CHANNELS);
  58. speex_resampler_set_output_stride(st, MAX_CHANNELS);
  59. }
  60. }
  61. /** `in` and `out` are interlaced with the number of channels */
  62. void process(const Frame<MAX_CHANNELS>* in, int* inFrames, Frame<MAX_CHANNELS>* out, int* outFrames) {
  63. assert(in);
  64. assert(inFrames);
  65. assert(out);
  66. assert(outFrames);
  67. if (st) {
  68. // Resample each channel at a time
  69. spx_uint32_t inLen = 0;
  70. spx_uint32_t outLen = 0;
  71. for (int i = 0; i < channels; i++) {
  72. inLen = *inFrames;
  73. outLen = *outFrames;
  74. int err = speex_resampler_process_float(st, i, ((const float*) in) + i, &inLen, ((float*) out) + i, &outLen);
  75. assert(err == RESAMPLER_ERR_SUCCESS);
  76. }
  77. *inFrames = inLen;
  78. *outFrames = outLen;
  79. }
  80. else {
  81. // Simply copy the buffer without conversion
  82. int frames = std::min(*inFrames, *outFrames);
  83. std::memcpy(out, in, frames * sizeof(Frame<MAX_CHANNELS>));
  84. *inFrames = frames;
  85. *outFrames = frames;
  86. }
  87. }
  88. };
  89. /** Downsamples by an integer factor. */
  90. template <int OVERSAMPLE, int QUALITY, typename T = float>
  91. struct Decimator {
  92. T inBuffer[OVERSAMPLE * QUALITY];
  93. float kernel[OVERSAMPLE * QUALITY];
  94. int inIndex;
  95. Decimator(float cutoff = 0.9f) {
  96. boxcarLowpassIR(kernel, OVERSAMPLE * QUALITY, cutoff * 0.5f / OVERSAMPLE);
  97. blackmanHarrisWindow(kernel, OVERSAMPLE * QUALITY);
  98. reset();
  99. }
  100. void reset() {
  101. inIndex = 0;
  102. std::memset(inBuffer, 0, sizeof(inBuffer));
  103. }
  104. /** `in` must be length OVERSAMPLE */
  105. T process(T* in) {
  106. // Copy input to buffer
  107. std::memcpy(&inBuffer[inIndex], in, OVERSAMPLE * sizeof(T));
  108. // Advance index
  109. inIndex += OVERSAMPLE;
  110. inIndex %= OVERSAMPLE * QUALITY;
  111. // Perform naive convolution
  112. T out = 0.f;
  113. for (int i = 0; i < OVERSAMPLE * QUALITY; i++) {
  114. int index = inIndex - 1 - i;
  115. index = (index + OVERSAMPLE * QUALITY) % (OVERSAMPLE * QUALITY);
  116. out += kernel[i] * inBuffer[index];
  117. }
  118. return out;
  119. }
  120. };
  121. /** Upsamples by an integer factor. */
  122. template <int OVERSAMPLE, int QUALITY>
  123. struct Upsampler {
  124. float inBuffer[QUALITY];
  125. float kernel[OVERSAMPLE * QUALITY];
  126. int inIndex;
  127. Upsampler(float cutoff = 0.9f) {
  128. boxcarLowpassIR(kernel, OVERSAMPLE * QUALITY, cutoff * 0.5f / OVERSAMPLE);
  129. blackmanHarrisWindow(kernel, OVERSAMPLE * QUALITY);
  130. reset();
  131. }
  132. void reset() {
  133. inIndex = 0;
  134. std::memset(inBuffer, 0, sizeof(inBuffer));
  135. }
  136. /** `out` must be length OVERSAMPLE */
  137. void process(float in, float* out) {
  138. // Zero-stuff input buffer
  139. inBuffer[inIndex] = OVERSAMPLE * in;
  140. // Advance index
  141. inIndex++;
  142. inIndex %= QUALITY;
  143. // Naively convolve each sample
  144. // TODO replace with polyphase filter hierarchy
  145. for (int i = 0; i < OVERSAMPLE; i++) {
  146. float y = 0.f;
  147. for (int j = 0; j < QUALITY; j++) {
  148. int index = inIndex - 1 - j;
  149. index = (index + QUALITY) % QUALITY;
  150. int kernelIndex = OVERSAMPLE * j + i;
  151. y += kernel[kernelIndex] * inBuffer[index];
  152. }
  153. out[i] = y;
  154. }
  155. }
  156. };
  157. } // namespace dsp
  158. } // namespace rack