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.

130 lines
3.5KB

  1. #pragma once
  2. #include "LookupTable.h"
  3. #include "SinOscillator.h"
  4. #include "BiquadFilter.h"
  5. #include "BiquadParams.h"
  6. #include "BiquadState.h"
  7. #include "HilbertFilterDesigner.h"
  8. /**
  9. * Complete Frequency Shifter composite
  10. *
  11. * If TBase is WidgetComposite, this class is used as the implementation part of the Booty Shifter module.
  12. * If TBase is TestComposite, this class may stand alone for unit tests.
  13. */
  14. template <class TBase>
  15. class FrequencyShifter : public TBase
  16. {
  17. public:
  18. FrequencyShifter(struct Module * module) : TBase(module)
  19. {
  20. }
  21. FrequencyShifter() : TBase()
  22. {
  23. }
  24. void setSampleRate(float rate)
  25. {
  26. reciprocalSampleRate = 1 / rate;
  27. HilbertFilterDesigner<T>::design(rate, hilbertFilterParamsSin, hilbertFilterParamsCos);
  28. }
  29. // must be called after setSampleRate
  30. void init()
  31. {
  32. SinOscillator<T, true>::setFrequency(oscParams, T(.01));
  33. exponential2 = ObjectCache<T>::getExp2(); // Get a shared copy of the 2**x lookup.
  34. // This will enable exp mode to track at
  35. // 1V/ octave.
  36. }
  37. // Define all the enums here. This will let the tests and the widget access them.
  38. enum ParamIds
  39. {
  40. PITCH_PARAM, // the big pitch knob
  41. NUM_PARAMS
  42. };
  43. enum InputIds
  44. {
  45. AUDIO_INPUT,
  46. CV_INPUT,
  47. NUM_INPUTS
  48. };
  49. enum OutputIds
  50. {
  51. SIN_OUTPUT,
  52. COS_OUTPUT,
  53. NUM_OUTPUTS
  54. };
  55. enum LightIds
  56. {
  57. NUM_LIGHTS
  58. };
  59. /**
  60. * Main processing entry point. Called every sample
  61. */
  62. void step();
  63. typedef float T; // use floats for all signals
  64. T freqRange = 5; // the freq range switch
  65. private:
  66. SinOscillatorParams<T> oscParams;
  67. SinOscillatorState<T> oscState;
  68. BiquadParams<T, 3> hilbertFilterParamsSin;
  69. BiquadParams<T, 3> hilbertFilterParamsCos;
  70. BiquadState<T, 3> hilbertFilterStateSin;
  71. BiquadState<T, 3> hilbertFilterStateCos;
  72. std::shared_ptr<LookupTableParams<T>> exponential2;
  73. float reciprocalSampleRate;
  74. };
  75. template <class TBase>
  76. inline void FrequencyShifter<TBase>::step()
  77. {
  78. assert(exponential2->isValid());
  79. // Add the knob and the CV value.
  80. T freqHz;
  81. T cvTotal = TBase::params[PITCH_PARAM].value + TBase::inputs[CV_INPUT].value;
  82. if (cvTotal > 5) {
  83. cvTotal = 5;
  84. }
  85. if (cvTotal < -5) {
  86. cvTotal = -5;
  87. }
  88. if (freqRange > .2) {
  89. cvTotal *= freqRange;
  90. cvTotal *= T(1. / 5.);
  91. freqHz = cvTotal;
  92. } else {
  93. cvTotal += 7; // shift up to GE 2 (min value for out 1v/oct lookup)
  94. freqHz = LookupTable<T>::lookup(*exponential2, cvTotal);
  95. freqHz /= 2; // down to 2..2k range that we want.
  96. }
  97. SinOscillator<float, true>::setFrequency(oscParams, freqHz * reciprocalSampleRate);
  98. // Generate the quadrature sin oscillators.
  99. T x, y;
  100. SinOscillator<T, true>::runQuadrature(x, y, oscState, oscParams);
  101. // Filter the input through th quadrature filter
  102. const T input = TBase::inputs[AUDIO_INPUT].value;
  103. const T hilbertSin = BiquadFilter<T>::run(input, hilbertFilterStateSin, hilbertFilterParamsSin);
  104. const T hilbertCos = BiquadFilter<T>::run(input, hilbertFilterStateCos, hilbertFilterParamsCos);
  105. // Cross modulate the two sections.
  106. x *= hilbertSin;
  107. y *= hilbertCos;
  108. // And combine for final SSB output.
  109. TBase::outputs[SIN_OUTPUT].value = x + y;
  110. TBase::outputs[COS_OUTPUT].value = x - y;
  111. }