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.

322 lines
11KB

  1. // Copyright 2014 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. // See http://creativecommons.org/licenses/MIT/ for more information.
  24. //
  25. // -----------------------------------------------------------------------------
  26. //
  27. // "Ominous" is a dark 2x2-op FM synth (based on Braids' FM and FBFM modes).
  28. #include "elements/dsp/ominous_voice.h"
  29. #include <algorithm>
  30. #include <cstdio>
  31. namespace elements {
  32. using namespace std;
  33. using namespace stmlib;
  34. // scipy.signal.remez(101, [0, 0.3 / 8, 0.495 / 8, 0.5], [1, 0]);
  35. const float kDownsamplingFilter[] = {
  36. -0.001859272945f, 0.001184937535f, 0.001212413444f, 0.001369688661f,
  37. 0.001555406705f, 0.001685761819f, 0.001692922383f, 0.001526182555f,
  38. 0.001157229282f, 0.000582212588f, -0.000172916131f, -0.001054896973f,
  39. -0.001981709311f, -0.002852566234f, -0.003555372122f, -0.003977161477f,
  40. -0.004020648315f, -0.003616652394f, -0.002735861951f, -0.001399720214f,
  41. 0.000314317050f, 0.002272758644f, 0.004295073578f, 0.006166173855f,
  42. 0.007654982354f, 0.008534833653f, 0.008614353501f, 0.007761247708f,
  43. 0.005919024408f, 0.003133736224f, -0.000445934810f, -0.004563290490f,
  44. -0.008867277113f, -0.012932060625f, -0.016287075604f, -0.018456326393f,
  45. -0.018994127671f, -0.017542469537f, -0.013838153737f, -0.007789574712f,
  46. 0.000541523640f, 0.010920252821f, 0.022936167260f, 0.036030557729f,
  47. 0.049530599001f, 0.062696232995f, 0.074769247024f, 0.085030908865f,
  48. 0.092854033134f, 0.097753623479f, 0.099422113893f, 0.097753623479f,
  49. 0.092854033134f, 0.085030908865f, 0.074769247024f, 0.062696232995f,
  50. 0.049530599001f, 0.036030557729f, 0.022936167260f, 0.010920252821f,
  51. 0.000541523640f, -0.007789574712f, -0.013838153737f, -0.017542469537f,
  52. -0.018994127671f, -0.018456326393f, -0.016287075604f, -0.012932060625f,
  53. -0.008867277113f, -0.004563290490f, -0.000445934810f, 0.003133736224f,
  54. 0.005919024408f, 0.007761247708f, 0.008614353501f, 0.008534833653f,
  55. 0.007654982354f, 0.006166173855f, 0.004295073578f, 0.002272758644f,
  56. 0.000314317050f, -0.001399720214f, -0.002735861951f, -0.003616652394f,
  57. -0.004020648315f, -0.003977161477f, -0.003555372122f, -0.002852566234f,
  58. -0.001981709311f, -0.001054896973f, -0.000172916131f, 0.000582212588f,
  59. 0.001157229282f, 0.001526182555f, 0.001692922383f, 0.001685761819f,
  60. 0.001555406705f, 0.001369688661f, 0.001212413444f, 0.001184937535f,
  61. -0.001859272945f,
  62. };
  63. void Spatializer::Init(float fixed_position) {
  64. angle_ = 0.0f;
  65. fixed_position_ = fixed_position;
  66. left_ = 0.0f;
  67. right_ = 0.0f;
  68. distance_ = 0.0f;
  69. behind_filter_.Init();
  70. behind_filter_.set_f_q<FREQUENCY_EXACT>(0.05f, 1.0f);
  71. }
  72. void Spatializer::Process(
  73. float* source,
  74. float* center,
  75. float* sides,
  76. size_t size) {
  77. behind_filter_.Process<FILTER_MODE_LOW_PASS>(source, behind_, size, 1);
  78. float angle = angle_;
  79. float x = distance_ * stmlib::InterpolateWrap(
  80. lut_sine, angle, 4096.0f);
  81. float y = distance_ * stmlib::InterpolateWrap(
  82. lut_sine, angle + 0.25f, 4096.0f);
  83. float backfront = (1.0f + y) * 0.5f * distance_;
  84. x += fixed_position_ * (1.0f - distance_);
  85. float target_left = stmlib::InterpolateWrap(
  86. lut_sine, (1.0f + x) * 0.125f, 4096.0f);
  87. float target_right = stmlib::InterpolateWrap(
  88. lut_sine, (3.0f + x) * 0.125f, 4096.0f);
  89. // Prevent zipper noise during rendering.
  90. float step = 1.0f / static_cast<float>(size);
  91. float left_increment = (target_left - left_) * step;
  92. float right_increment = (target_right - right_) * step;
  93. for (size_t i = 0; i < size; ++i) {
  94. left_ += left_increment;
  95. right_ += right_increment;
  96. float y = source[i] + backfront * (behind_[i] - source[i]);
  97. float l = left_ * y;
  98. float r = right_ * y;
  99. center[i] += (l + r) * 0.5f;
  100. sides[i] += (l - r) * 0.5f / 0.7f;
  101. }
  102. }
  103. void FmOscillator::Process(
  104. float frequency,
  105. float ratio,
  106. float feedback_amount,
  107. float target_fm_amount,
  108. const float* external_fm,
  109. float* destination,
  110. size_t size) {
  111. ratio = Interpolate(lut_fm_frequency_quantizer, ratio, 128.0f);
  112. uint32_t inc_carrier = midi_to_increment(frequency);
  113. uint32_t inc_mod = midi_to_increment(frequency + ratio);
  114. uint32_t phase_carrier = phase_carrier_;
  115. uint32_t phase_mod = phase_mod_;
  116. // Linear interpolation on FM amount parameter.
  117. float step = 1.0f / static_cast<float>(size);
  118. float fm_amount = fm_amount_;
  119. float fm_amount_increment = (target_fm_amount - fm_amount) * step;
  120. float previous_sample = previous_sample_;
  121. // To prevent aliasing, reduce FM amount when frequency or feedback are
  122. // too high.
  123. float brightness = frequency + ratio * 0.75f - 60.0f + \
  124. feedback_amount * 24.0f;
  125. float amount_attenuation = brightness <= 0.0f
  126. ? 1.0f
  127. : 1.0f - brightness * brightness * 0.0015f;
  128. if (amount_attenuation < 0.0f) {
  129. amount_attenuation = 0.0f;
  130. }
  131. for (size_t i = 0; i < size; ++i) {
  132. fm_amount += fm_amount_increment;
  133. phase_carrier += inc_carrier;
  134. phase_mod += inc_mod;
  135. float mod = SineFm(phase_mod, feedback_amount * previous_sample);
  136. destination[i] = previous_sample = SineFm(
  137. phase_carrier,
  138. amount_attenuation * (mod * fm_amount + external_fm[i]));
  139. }
  140. phase_carrier_ = phase_carrier;
  141. phase_mod_ = phase_mod;
  142. fm_amount_ = fm_amount;
  143. previous_sample_ = previous_sample;
  144. }
  145. void OminousVoice::Init() {
  146. envelope_.Init();
  147. envelope_.set_adsr(0.5f, 0.5f, 0.5f, 0.5f);
  148. previous_gate_ = false;
  149. level_state_ = 0.0f;
  150. for (size_t i = 0; i < kNumOscillators; ++i) {
  151. external_fm_state_[i] = 0.0f;
  152. oscillator_[i].Init();
  153. // Downsampling is done mostly by the FIR, but since the stopband
  154. // attenuation peaks at -48dB, we can get a few extra dB of attenution with
  155. // the IIR for the highest frequencies.
  156. fir_downsampler_[i].Init(kDownsamplingFilter);
  157. iir_downsampler_[i].Init();
  158. iir_downsampler_[i].set_f_q<FREQUENCY_EXACT>(
  159. 1.0f / kOversamplingUp * 0.8f,
  160. 0.5f);
  161. osc_level_[i] = 0.0f;
  162. filter_[i].Init();
  163. spatializer_[i].Init(i == 0 ? - 0.7f : 0.7f);
  164. }
  165. }
  166. void OminousVoice::ConfigureEnvelope(const Patch& patch) {
  167. if (patch.exciter_envelope_shape < 0.4f) {
  168. float a = 0.0f;
  169. float dr = (patch.exciter_envelope_shape * 0.625f + 0.2f) * 1.8f;
  170. envelope_.set_adsr(a, dr, 0.0f, dr);
  171. } else if (patch.exciter_envelope_shape < 0.6f) {
  172. float s = (patch.exciter_envelope_shape - 0.4f) * 5.0f;
  173. envelope_.set_adsr(0.0f, 0.80f, s, 0.80f);
  174. } else {
  175. float a = 0.0f;
  176. float dr = ((1.0f - patch.exciter_envelope_shape) * 0.75f + 0.15f) * 1.8f;
  177. envelope_.set_adsr(a, dr, 1.0f, dr);
  178. }
  179. }
  180. void OminousVoice::Process(
  181. const Patch& patch,
  182. float frequency,
  183. float strength,
  184. const bool gate_in,
  185. const float* blow_in,
  186. const float* strike_in,
  187. float* raw,
  188. float* center,
  189. float* sides,
  190. size_t size) {
  191. uint8_t flags = GetGateFlags(gate_in);
  192. // Compute the envelope.
  193. ConfigureEnvelope(patch);
  194. float level = envelope_.Process(flags);
  195. level += strength >= 0.5f ? 2.0f * strength - 1.0f : 0.0f;
  196. float level_increment = (level - level_state_) / size;
  197. damping_ += 0.1f * (patch.resonator_damping - damping_);
  198. float filter_env_amount = damping_ <= 0.9f ? 1.1f * damping_ : 0.99f;
  199. float vca_env_amount = 1.0f + \
  200. damping_ * damping_ * damping_ * damping_ * 0.5f;
  201. // Comfigure the filter.
  202. float cutoff_midi = 12.0f;
  203. cutoff_midi += patch.resonator_brightness * 140.0f;
  204. cutoff_midi += filter_env_amount * level * 120.0f;
  205. cutoff_midi += 0.5f * (frequency - 64.0f);
  206. float cutoff = midi_to_frequency(cutoff_midi);
  207. float q_bump = patch.resonator_geometry - 0.6f;
  208. float q = 1.72f - q_bump * q_bump * 2.0f;
  209. float cutoff_2 = cutoff * (1.0f + patch.resonator_modulation_offset);
  210. filter_[0].set_f_q<FREQUENCY_FAST>(cutoff, q);
  211. filter_[1].set_f_q<FREQUENCY_FAST>(cutoff_2, q * 1.25f);
  212. // Process each oscillator.
  213. fill(&center[0], &center[size], 0.0f);
  214. fill(&sides[0], &sides[size], 0.0f);
  215. fill(&raw[0], &raw[size], 0.0f);
  216. const float rotation_speed[2] = { 1.0f, 1.123456f };
  217. feedback_ += 0.01f * (patch.exciter_bow_timbre - feedback_);
  218. frequency += kOversamplingDownMidi;
  219. for (size_t i = 0; i < 2; ++i) {
  220. Upsample<kOversamplingUp>(
  221. &external_fm_state_[i],
  222. i == 0 ? blow_in : strike_in,
  223. external_fm_oversampled_, size);
  224. float detune, ratio, amount, level;
  225. if (i == 0) {
  226. detune = 0.0f;
  227. ratio = patch.exciter_blow_meta;
  228. amount = patch.exciter_blow_timbre;
  229. level = patch.exciter_blow_level;
  230. } else {
  231. detune = Interpolate(
  232. lut_detune_quantizer, patch.exciter_bow_level, 64.0f);
  233. ratio = patch.exciter_strike_meta;
  234. amount = patch.exciter_strike_timbre;
  235. level = patch.exciter_strike_level;
  236. }
  237. oscillator_[i].Process(
  238. frequency + detune,
  239. ratio,
  240. feedback_ * (0.25f + 0.15f * patch.exciter_signature),
  241. (2.0f - patch.exciter_signature * feedback_) * amount,
  242. external_fm_oversampled_,
  243. osc_oversampled_,
  244. size * kOversamplingUp);
  245. iir_downsampler_[i].Process<FILTER_MODE_LOW_PASS>(
  246. osc_oversampled_,
  247. osc_oversampled_,
  248. size * kOversamplingUp,
  249. 1);
  250. fir_downsampler_[i].Process(osc_oversampled_, osc_, size * kOversamplingUp);
  251. // Copy to raw buffer.
  252. float level_state = osc_level_[i];
  253. for (size_t j = 0; j < size; ++j) {
  254. level_state += 0.01f * (level - level_state);
  255. osc_[j] *= level_state;
  256. raw[j] += osc_[j];
  257. }
  258. osc_level_[i] = level_state;
  259. // Apply filter.
  260. filter_[i].ProcessMultimode(osc_, osc_, size, patch.resonator_geometry);
  261. // Apply VCA.
  262. float l = level_state_;
  263. for (size_t j = 0; j < size; ++j) {
  264. float gain = l * vca_env_amount;
  265. if (gain >= 1.0f) gain = 1.0f;
  266. osc_[j] *= gain;
  267. l += level_increment;
  268. }
  269. // Spatialize.
  270. float f = patch.resonator_position * patch.resonator_position * 0.001f;
  271. float distance = patch.resonator_position;
  272. spatializer_[i].Rotate(f * rotation_speed[i]);
  273. spatializer_[i].set_distance(distance * (2.0f - distance));
  274. spatializer_[i].Process(osc_, center, sides, size);
  275. }
  276. level_state_ = level;
  277. }
  278. } // namespace elements