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.

208 lines
5.7KB

  1. // Copyright (C) 2020 Tyler Coy
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. #pragma once
  16. #include <rack.hpp>
  17. namespace streams
  18. {
  19. template <int num_inputs, int num_outputs, int block_size, int buffer_size>
  20. class SRCResampler
  21. {
  22. public:
  23. void Init(int outer_sample_rate, int inner_sample_rate, int quality)
  24. {
  25. input_src.setRates(outer_sample_rate, inner_sample_rate);
  26. output_src.setRates(inner_sample_rate, outer_sample_rate);
  27. input_src.setQuality(quality);
  28. output_src.setQuality(quality);
  29. Reset();
  30. }
  31. void Reset(void)
  32. {
  33. input_src.refreshState();
  34. output_src.refreshState();
  35. input_buffer.clear();
  36. output_buffer.clear();
  37. }
  38. using InputFrame = dsp::Frame<num_inputs>;
  39. using OutputFrame = dsp::Frame<num_outputs>;
  40. template <typename F>
  41. OutputFrame Process(InputFrame& input_frame, F callback)
  42. {
  43. if (!input_buffer.full())
  44. {
  45. input_buffer.push(input_frame);
  46. }
  47. if (output_buffer.empty())
  48. {
  49. // Resample input buffer
  50. InputFrame input_frames[block_size] = {};
  51. int in_len = input_buffer.size();
  52. int out_len = block_size;
  53. input_src.process(
  54. input_buffer.startData(), &in_len,
  55. input_frames, &out_len);
  56. input_buffer.startIncr(in_len);
  57. // Process the resampled signal
  58. // We might not fill all of the input buffer if there is a
  59. // deficiency, but this cannot be avoided due to imprecisions
  60. // between the input and output SRC.
  61. OutputFrame output_frames[block_size];
  62. callback(output_frames, input_frames);
  63. // Resample output buffer
  64. in_len = block_size;
  65. out_len = output_buffer.capacity();
  66. output_src.process(
  67. output_frames, &in_len,
  68. output_buffer.endData(), &out_len);
  69. output_buffer.endIncr(out_len);
  70. }
  71. // Set output
  72. OutputFrame output_frame = {};
  73. if (!output_buffer.empty())
  74. {
  75. output_frame = output_buffer.shift();
  76. }
  77. return output_frame;
  78. }
  79. protected:
  80. dsp::SampleRateConverter<num_inputs> input_src;
  81. dsp::SampleRateConverter<num_outputs> output_src;
  82. dsp::DoubleRingBuffer<InputFrame, buffer_size> input_buffer;
  83. dsp::DoubleRingBuffer<OutputFrame, buffer_size> output_buffer;
  84. };
  85. template <int num_inputs, int num_outputs, int block_size, int buffer_size>
  86. class InterpolatingResampler
  87. {
  88. public:
  89. void Init(int outer_sample_rate, int inner_sample_rate, int quality)
  90. {
  91. (void)quality;
  92. ratio_ = inner_sample_rate * 1.f / outer_sample_rate;
  93. ratio_inverse_ = 1.f / ratio_;
  94. }
  95. void Reset(void)
  96. {
  97. in_buffer_.clear();
  98. out_buffer_.clear();
  99. out_buffer_.endIncr(block_size);
  100. in_phase_ = 1.f;
  101. prev_input_ = {};
  102. prev_output_ = {};
  103. next_output_ = {};
  104. }
  105. using InputFrame = dsp::Frame<num_inputs>;
  106. using OutputFrame = dsp::Frame<num_outputs>;
  107. template <typename F>
  108. OutputFrame Process(InputFrame& input_frame, F callback)
  109. {
  110. int pushed = -in_buffer_.size();
  111. while (in_phase_ <= 1.f)
  112. {
  113. // Resample and push into input buffer
  114. auto input = CrossfadeFrame(prev_input_, input_frame, in_phase_);
  115. in_buffer_.push(input);
  116. in_phase_ += ratio_inverse_;
  117. }
  118. in_phase_ -= 1.f;
  119. prev_input_ = input_frame;
  120. pushed += in_buffer_.size();
  121. // Process the resampled signal
  122. while (in_buffer_.size() >= block_size)
  123. {
  124. callback(out_buffer_.endData(), in_buffer_.startData());
  125. in_buffer_.startIncr(block_size);
  126. out_buffer_.endIncr(block_size);
  127. }
  128. // Resample from output buffer
  129. float phase = clamp(1.f - in_phase_ * ratio_, 0.f, 1.f);
  130. while (pushed--)
  131. {
  132. prev_output_ = next_output_;
  133. next_output_ = out_buffer_.shift();
  134. }
  135. return CrossfadeFrame(prev_output_, next_output_, phase);
  136. }
  137. protected:
  138. float ratio_;
  139. float ratio_inverse_;
  140. dsp::DoubleRingBuffer<InputFrame, buffer_size> in_buffer_;
  141. dsp::DoubleRingBuffer<OutputFrame, buffer_size> out_buffer_;
  142. float in_phase_;
  143. InputFrame prev_input_;
  144. OutputFrame prev_output_;
  145. OutputFrame next_output_;
  146. template <typename T>
  147. T Crossfade(T a, T b, float x)
  148. {
  149. return a + (b - a) * x;
  150. }
  151. InputFrame CrossfadeFrame(InputFrame a, InputFrame b, float x)
  152. {
  153. InputFrame result;
  154. for (int i = 0; i < num_inputs; i++)
  155. {
  156. result.samples[i] = Crossfade(a.samples[i], b.samples[i], x);
  157. }
  158. return result;
  159. }
  160. OutputFrame CrossfadeFrame(OutputFrame a, OutputFrame b, float x)
  161. {
  162. OutputFrame result;
  163. for (int i = 0; i < num_outputs; i++)
  164. {
  165. result.samples[i] = Crossfade(a.samples[i], b.samples[i], x);
  166. }
  167. return result;
  168. }
  169. };
  170. }