SHOW:
|
|
- or go back to the newest paste.
| 1 | **UPDATE: I dug around in the Surge source code and found the relevant bits here, I hope this helps** | |
| 2 | ||
| 3 | ``` | |
| 4 | class ControllerModulationSource : public ModulationSource | |
| 5 | {
| |
| 6 | public: | |
| 7 | // Smoothing and Shaping Behaviors | |
| 8 | enum SmoothingMode | |
| 9 | {
| |
| 10 | LEGACY = -1, // This is (1) the exponential backoff and (2) not streamed. | |
| 11 | SLOW_EXP, // Legacy with a sigma clamp | |
| 12 | FAST_EXP, // Faster Legacy with a sigma clamp | |
| 13 | FAST_LINE, // Linearly move | |
| 14 | DIRECT // Apply the value directly | |
| 15 | } smoothingMode = LEGACY; | |
| 16 | ||
| 17 | ControllerModulationSource() | |
| 18 | {
| |
| 19 | target = 0.f; | |
| 20 | output = 0.f; | |
| 21 | bipolar = false; | |
| 22 | changed = true; | |
| 23 | smoothingMode = LEGACY; | |
| 24 | } | |
| 25 | ControllerModulationSource(SmoothingMode mode) : ControllerModulationSource() | |
| 26 | {
| |
| 27 | smoothingMode = mode; | |
| 28 | } | |
| 29 | ||
| 30 | virtual ~ControllerModulationSource() {}
| |
| 31 | void set_target(float f) | |
| 32 | {
| |
| 33 | target = f; | |
| 34 | startingpoint = output; | |
| 35 | changed = true; | |
| 36 | } | |
| 37 | ||
| 38 | void init(float f) | |
| 39 | {
| |
| 40 | target = f; | |
| 41 | output = f; | |
| 42 | startingpoint = f; | |
| 43 | changed = true; | |
| 44 | } | |
| 45 | ||
| 46 | void set_target01(float f, bool updatechanged = true) | |
| 47 | {
| |
| 48 | if (bipolar) | |
| 49 | target = 2.f * f - 1.f; | |
| 50 | else | |
| 51 | target = f; | |
| 52 | startingpoint = output; | |
| 53 | if (updatechanged) | |
| 54 | changed = true; | |
| 55 | } | |
| 56 | ||
| 57 | virtual float get_output01(int i) override | |
| 58 | {
| |
| 59 | if (bipolar) | |
| 60 | return 0.5f + 0.5f * output; | |
| 61 | return output; | |
| 62 | } | |
| 63 | ||
| 64 | virtual float get_target01() | |
| 65 | {
| |
| 66 | if (bipolar) | |
| 67 | return 0.5f + 0.5f * target; | |
| 68 | return target; | |
| 69 | } | |
| 70 | ||
| 71 | virtual bool has_changed(bool reset) | |
| 72 | {
| |
| 73 | if (changed) | |
| 74 | {
| |
| 75 | if (reset) | |
| 76 | changed = false; | |
| 77 | return true; | |
| 78 | } | |
| 79 | return false; | |
| 80 | } | |
| 81 | ||
| 82 | virtual void reset() override | |
| 83 | {
| |
| 84 | target = 0.f; | |
| 85 | output = 0.f; | |
| 86 | bipolar = false; | |
| 87 | } | |
| 88 | inline void processSmoothing(SmoothingMode mode, float sigma) | |
| 89 | {
| |
| 90 | if (mode == LEGACY || mode == SLOW_EXP || mode == FAST_EXP) | |
| 91 | {
| |
| 92 | float b = fabs(target - output); | |
| 93 | - | if (b < sigma && mode != LEGACY) |
| 93 | + | if (b < sigma && mode != LEGACY) |
| 94 | {
| |
| 95 | output = target; | |
| 96 | } | |
| 97 | else | |
| 98 | {
| |
| 99 | float a = (mode == FAST_EXP ? 0.99f : 0.9f) * 44100 * samplerate_inv * b; | |
| 100 | output = (1 - a) * output + a * target; | |
| 101 | } | |
| 102 | return; | |
| 103 | }; | |
| 104 | if (mode == FAST_LINE) | |
| 105 | {
| |
| 106 | /* | |
| 107 | * Apply a constant change until we get there. | |
| 108 | * Rate is set so we cover the entire range (0,1) | |
| 109 | * in 50 blocks at 44k | |
| 110 | */ | |
| 111 | float sampf = samplerate / 44100; | |
| 112 | float da = (target - startingpoint) / (50 * sampf); | |
| 113 | float b = target - output; | |
| 114 | if (fabs(b) < fabs(da)) | |
| 115 | {
| |
| 116 | output = target; | |
| 117 | } | |
| 118 | else | |
| 119 | {
| |
| 120 | output += da; | |
| 121 | } | |
| 122 | } | |
| 123 | if (mode == DIRECT) | |
| 124 | {
| |
| 125 | output = target; | |
| 126 | } | |
| 127 | } | |
| 128 | virtual void process_block() override | |
| 129 | {
| |
| 130 | processSmoothing(smoothingMode, smoothingMode == FAST_EXP ? 0.005f : 0.0025f); | |
| 131 | } | |
| 132 | ||
| 133 | virtual bool process_block_until_close(float sigma) | |
| 134 | {
| |
| 135 | if (smoothingMode == LEGACY) | |
| 136 | processSmoothing(SLOW_EXP, sigma); | |
| 137 | else | |
| 138 | processSmoothing(smoothingMode, sigma); | |
| 139 | ||
| 140 | return (output != target); // continue | |
| 141 | } | |
| 142 | ||
| 143 | virtual bool is_bipolar() override { return bipolar; }
| |
| 144 | virtual void set_bipolar(bool b) override { bipolar = b; }
| |
| 145 | ||
| 146 | float target, startingpoint; | |
| 147 | int id; // can be used to assign the controller to a parameter id | |
| 148 | bool bipolar; | |
| 149 | bool changed; | |
| 150 | }; | |
| 151 | ``` | |
| 152 | ||
| 153 | **And then, elsewhere in the code, the smoothing is applied to these midi signals:** | |
| 154 | ||
| 155 | ``` | |
| 156 | scene.modsources[ms_modwheel] = new ControllerModulationSource(storage.smoothingMode); | |
| 157 | scene.modsources[ms_breath] = new ControllerModulationSource(storage.smoothingMode); | |
| 158 | scene.modsources[ms_expression] = new ControllerModulationSource(storage.smoothingMode); | |
| 159 | scene.modsources[ms_sustain] = new ControllerModulationSource(storage.smoothingMode); | |
| 160 | scene.modsources[ms_aftertouch] = new ControllerModulationSource(storage.smoothingMode); | |
| 161 | scene.modsources[ms_pitchbend] = new ControllerModulationSource(storage.smoothingMode); | |
| 162 | scene.modsources[ms_lowest_key] = new ControllerModulationSource(storage.smoothingMode); | |
| 163 | scene.modsources[ms_highest_key] = new ControllerModulationSource(storage.smoothingMode); | |
| 164 | scene.modsources[ms_latest_key] = new ControllerModulationSource(storage.smoothingMode); | |
| 165 | ``` |