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.

238 lines
8.0KB

  1. // Mutable Instruments Streams emulation for VCV Rack
  2. // Copyright (C) 2020 Tyler Coy
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. #pragma once
  17. #include <cmath>
  18. #include <rack.hpp>
  19. #include "resampler.hpp"
  20. #include "analog_engine.hpp"
  21. #include "digital_engine.hpp"
  22. namespace streams
  23. {
  24. using namespace rack;
  25. class StreamsEngine
  26. {
  27. public:
  28. struct ChannelFrame
  29. {
  30. // Parameters
  31. float shape_knob;
  32. float mod_knob;
  33. float level_mod_knob;
  34. float response_knob;
  35. bool function_button;
  36. // Inputs
  37. float excite_in;
  38. float signal_in;
  39. float level_cv;
  40. bool signal_in_connected;
  41. bool level_cv_connected;
  42. // Outputs
  43. float signal_out;
  44. // Lights
  45. float led_green[4];
  46. float led_red[4];
  47. };
  48. struct Frame
  49. {
  50. ChannelFrame ch1;
  51. ChannelFrame ch2;
  52. bool metering_button;
  53. bool lights_updated;
  54. };
  55. StreamsEngine()
  56. {
  57. Reset();
  58. SetSampleRate(1.f);
  59. }
  60. void Reset(void)
  61. {
  62. adc_lpf_.reset();
  63. resampler_.Reset();
  64. analog_engine_.Reset();
  65. digital_engine_.Reset();
  66. adc_feedback_[0] = 0.f;
  67. adc_feedback_[1] = 0.f;
  68. }
  69. void SetSampleRate(float sample_rate)
  70. {
  71. adc_lpf_.setCutoffFreq(kAdcFilterCutoff / sample_rate);
  72. resampler_.Init(sample_rate, DigitalEngine::kSampleRate, 0);
  73. analog_engine_.SetSampleRate(sample_rate);
  74. }
  75. void Randomize(void)
  76. {
  77. digital_engine_.Randomize();
  78. }
  79. void ApplySettings(const UiSettings& settings)
  80. {
  81. digital_engine_.ApplySettings(settings);
  82. }
  83. const UiSettings& ui_settings(void)
  84. {
  85. return digital_engine_.ui_settings();
  86. }
  87. void SyncUI(const StreamsEngine& other)
  88. {
  89. digital_engine_.SyncUI(other.digital_engine_);
  90. }
  91. void Process(Frame& frame)
  92. {
  93. frame.lights_updated = false;
  94. float ch1_signal_in = frame.ch1.signal_in_connected ?
  95. frame.ch1.signal_in : kSignalInNormalV;
  96. float ch2_signal_in = frame.ch2.signal_in_connected ?
  97. frame.ch2.signal_in : kSignalInNormalV;
  98. float ch1_level_cv = frame.ch1.level_cv_connected ?
  99. frame.ch1.level_cv : kLevelNormalV;
  100. float ch2_level_cv = frame.ch2.level_cv_connected ?
  101. frame.ch2.level_cv : kLevelNormalV;
  102. Rsmp::InputFrame d_input;
  103. d_input.samples[0] = ch1_signal_in;
  104. d_input.samples[1] = ch2_signal_in;
  105. d_input.samples[2] = frame.ch1.excite_in;
  106. d_input.samples[3] = frame.ch2.excite_in;
  107. d_input.samples[4] = adc_feedback_[0];
  108. d_input.samples[5] = adc_feedback_[1];
  109. auto adc_input = simd::float_4::load(d_input.samples);
  110. adc_lpf_.process(adc_input);
  111. adc_input = adc_lpf_.lowpass();
  112. adc_input = kAdcFilterOffset + adc_input * kAdcFilterGain;
  113. adc_input.store(d_input.samples);
  114. DigitalEngine::Frame<kBlockSize> d_frame;
  115. Rsmp::OutputFrame d_output = resampler_.Process(d_input,
  116. [&](Rsmp::OutputFrame* output, const Rsmp::InputFrame* input)
  117. {
  118. d_frame.ch1.shape_knob = frame.ch1.shape_knob;
  119. d_frame.ch1.mod_knob = frame.ch1.mod_knob;
  120. d_frame.ch1.level_mod_knob = frame.ch1.level_mod_knob;
  121. d_frame.ch1.response_knob = frame.ch1.response_knob;
  122. d_frame.ch2.shape_knob = frame.ch2.shape_knob;
  123. d_frame.ch2.mod_knob = frame.ch2.mod_knob;
  124. d_frame.ch2.level_mod_knob = frame.ch2.level_mod_knob;
  125. d_frame.ch2.response_knob = frame.ch2.response_knob;
  126. d_frame.ch1.function_button = frame.ch1.function_button;
  127. d_frame.ch2.function_button = frame.ch2.function_button;
  128. d_frame.metering_button = frame.metering_button;
  129. for (int i = 0; i < kBlockSize; i++)
  130. {
  131. d_frame.ch1.signal_in[i] = input[i].samples[0];
  132. d_frame.ch2.signal_in[i] = input[i].samples[1];
  133. d_frame.ch1.excite_in[i] = input[i].samples[2];
  134. d_frame.ch2.excite_in[i] = input[i].samples[3];
  135. d_frame.ch1.level_adc_in[i] = input[i].samples[4];
  136. d_frame.ch2.level_adc_in[i] = input[i].samples[5];
  137. }
  138. digital_engine_.Process(d_frame);
  139. for (int i = 0; i < kBlockSize; i++)
  140. {
  141. output[i].samples[0] = d_frame.ch1.dac_out[i];
  142. output[i].samples[1] = d_frame.ch1.pwm_out[i];
  143. output[i].samples[2] = d_frame.ch2.dac_out[i];
  144. output[i].samples[3] = d_frame.ch2.pwm_out[i];
  145. }
  146. frame.ch1.led_green[0] = d_frame.ch1.led_green[0];
  147. frame.ch1.led_green[1] = d_frame.ch1.led_green[1];
  148. frame.ch1.led_green[2] = d_frame.ch1.led_green[2];
  149. frame.ch1.led_green[3] = d_frame.ch1.led_green[3];
  150. frame.ch1.led_red[0] = d_frame.ch1.led_red[0];
  151. frame.ch1.led_red[1] = d_frame.ch1.led_red[1];
  152. frame.ch1.led_red[2] = d_frame.ch1.led_red[2];
  153. frame.ch1.led_red[3] = d_frame.ch1.led_red[3];
  154. frame.ch2.led_green[0] = d_frame.ch2.led_green[0];
  155. frame.ch2.led_green[1] = d_frame.ch2.led_green[1];
  156. frame.ch2.led_green[2] = d_frame.ch2.led_green[2];
  157. frame.ch2.led_green[3] = d_frame.ch2.led_green[3];
  158. frame.ch2.led_red[0] = d_frame.ch2.led_red[0];
  159. frame.ch2.led_red[1] = d_frame.ch2.led_red[1];
  160. frame.ch2.led_red[2] = d_frame.ch2.led_red[2];
  161. frame.ch2.led_red[3] = d_frame.ch2.led_red[3];
  162. frame.lights_updated = true;
  163. });
  164. AnalogEngine::Frame a_frame;
  165. a_frame.ch1.level_mod_knob = frame.ch1.level_mod_knob;
  166. a_frame.ch1.response_knob = frame.ch1.response_knob;
  167. a_frame.ch2.level_mod_knob = frame.ch2.level_mod_knob;
  168. a_frame.ch2.response_knob = frame.ch2.response_knob;
  169. a_frame.ch1.signal_in = ch1_signal_in;
  170. a_frame.ch1.level_cv = ch1_level_cv;
  171. a_frame.ch2.signal_in = ch2_signal_in;
  172. a_frame.ch2.level_cv = ch2_level_cv;
  173. a_frame.ch1.dac_cv = d_output.samples[0];
  174. a_frame.ch1.pwm_cv = d_output.samples[1];
  175. a_frame.ch2.dac_cv = d_output.samples[2];
  176. a_frame.ch2.pwm_cv = d_output.samples[3];
  177. analog_engine_.Process(a_frame);
  178. frame.ch1.signal_out = a_frame.ch1.signal_out;
  179. frame.ch2.signal_out = a_frame.ch2.signal_out;
  180. adc_feedback_[0] = a_frame.ch1.adc_out;
  181. adc_feedback_[1] = a_frame.ch2.adc_out;
  182. }
  183. protected:
  184. static constexpr int kBlockSize = 16;
  185. static constexpr float kAdcFilterCutoff = 1.f / (2 * M_PI * 20e3f * 1e-9f);
  186. static constexpr float kAdcFilterGain = -20e3f / 100e3f;
  187. static constexpr float kAdcFilterOffset = -10.f * -20e3f / 120e3f;
  188. static constexpr float kSignalInNormalV = 5.f;
  189. static constexpr float kLevelNormalV = 8.f;
  190. dsp::TRCFilter<simd::float_4> adc_lpf_;
  191. using Rsmp = InterpolatingResampler<6, 4, kBlockSize, 256>;
  192. Rsmp resampler_;
  193. AnalogEngine analog_engine_;
  194. DigitalEngine digital_engine_;
  195. float adc_feedback_[2];
  196. };
  197. }