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.

444 lines
13KB

  1. /**
  2. * This is a modified version of the VCV Fundamental VCO.
  3. * See LICENSE-dist.txt for full license info.
  4. * This code has been modified extensively by Squinky Labs. Mainly modifications were:
  5. * re-code hot-spots to lower CPU usage.
  6. * Fix compiler warnings.
  7. * Make it compile in Visual Studio
  8. */
  9. #pragma once
  10. #if defined(_MSC_VER)
  11. #pragma warning (push)
  12. #pragma warning (disable: 4305 4244 4267)
  13. #define __attribute__(x)
  14. #endif
  15. #include "SqMath.h"
  16. #include "dsp/filter.hpp"
  17. #include "BiquadFilter.h"
  18. #include "BiquadParams.h"
  19. #include "BiquadState.h"
  20. #include "ButterworthFilterDesigner.h"
  21. #include "ObjectCache.h"
  22. #include "IIRDecimator.h"
  23. extern float sqsawTable[2048];
  24. extern float sqtriTable[2048];
  25. // When this is defined, will use Squinky Labs anti-aliasing decimators,
  26. // rather than rack::Decimator<>
  27. #define _USEIIR
  28. template <int OVERSAMPLE, int QUALITY>
  29. struct VoltageControlledOscillator
  30. {
  31. float sampleTime = 0;
  32. bool analog = false;
  33. bool soft = false;
  34. float lastSyncValue = 0.0f;
  35. float phase = 0.0f;
  36. float freq;
  37. float pw = 0.5f;
  38. float pitch;
  39. bool syncEnabled = false;
  40. bool syncDirection = false;
  41. /**
  42. * flags to help decide not to do redundant work
  43. */
  44. bool sinEnabled = false;
  45. bool sqEnabled = false;
  46. bool sawEnabled = false;
  47. bool triEnabled = false;
  48. #ifdef _USEIIR
  49. IIRDecimator sinDecimator;
  50. IIRDecimator triDecimator;
  51. IIRDecimator sawDecimator;
  52. IIRDecimator sqrDecimator;
  53. #else
  54. rack::Decimator<OVERSAMPLE, QUALITY> sinDecimator;
  55. rack::Decimator<OVERSAMPLE, QUALITY> triDecimator;
  56. rack::Decimator<OVERSAMPLE, QUALITY> sawDecimator;
  57. rack::Decimator<OVERSAMPLE, QUALITY> sqrDecimator;
  58. #endif
  59. sq::RCFilter sqrFilter;
  60. // For analog detuning effect
  61. float pitchSlew = 0.0f;
  62. int pitchSlewIndex = 0;
  63. float sinBuffer[OVERSAMPLE] = {};
  64. float triBuffer[OVERSAMPLE] = {};
  65. float sawBuffer[OVERSAMPLE] = {};
  66. float sqrBuffer[OVERSAMPLE] = {};
  67. // Use interpolating lookups for these transcendentals
  68. std::shared_ptr<LookupTableParams<float>> sinLookup;
  69. std::function<float(float)> expLookup;
  70. void init()
  71. {
  72. sinLookup = ObjectCache<float>::getSinLookup();
  73. expLookup = ObjectCache<float>::getExp2Ex();
  74. // Set anti-alias 3-db down point an octave below nyquist: .25
  75. //float cutoff = .25f / float(OVERSAMPLE);
  76. sinDecimator.setup(16);
  77. sinDecimator.setup(16);
  78. sawDecimator.setup(16);
  79. sqrDecimator.setup(16);
  80. triDecimator.setup(16);
  81. }
  82. // Use the standard c++ library for random generation
  83. std::default_random_engine generator{99};
  84. std::normal_distribution<double> distribution{0, 1.0};
  85. float noise()
  86. {
  87. return (float) distribution(generator);
  88. }
  89. void setPitch(float pitchKnob, float pitchCv)
  90. {
  91. // Compute frequency
  92. pitch = pitchKnob;
  93. if (analog) {
  94. // Apply pitch slew
  95. const float pitchSlewAmount = 3.0f;
  96. pitch += pitchSlew * pitchSlewAmount;
  97. } else {
  98. // Quantize coarse knob if digital mode
  99. pitch = roundf(pitch);
  100. }
  101. pitch += pitchCv;
  102. // Note C4
  103. // freq = 261.626f * powf(2.0f, pitch / 12.0f);
  104. const float q = float(log2(261.626)); // move up to pitch range up
  105. pitch = (pitch / 12.0f) + q;
  106. freq = expLookup(pitch);
  107. }
  108. void setPulseWidth(float pulseWidth)
  109. {
  110. const float pwMin = 0.01f;
  111. pw = sq::clamp(pulseWidth, pwMin, 1.0f - pwMin);
  112. }
  113. void process(float deltaTime, float syncValue)
  114. {
  115. assert(sinLookup);
  116. assert(sampleTime > 0);
  117. if (analog) {
  118. // Adjust pitch slew
  119. if (++pitchSlewIndex > 64) {
  120. const float pitchSlewTau = 100.0f; // Time constant for leaky integrator in seconds
  121. pitchSlew += (noise() - pitchSlew / pitchSlewTau) *sampleTime;
  122. pitchSlewIndex = 0;
  123. }
  124. }
  125. // Advance phase
  126. float deltaPhaseOver = sq::clamp(freq * deltaTime, 1e-6, 0.5f) * (1.0f / OVERSAMPLE);
  127. // Detect sync
  128. int syncIndex = -1; // Index in the oversample loop where sync occurs [0, OVERSAMPLE)
  129. float syncCrossing = 0.0f; // Offset that sync occurs [0.0f, 1.0f)
  130. if (syncEnabled) {
  131. syncValue -= 0.01f;
  132. if (syncValue > 0.0f && lastSyncValue <= 0.0f) {
  133. float deltaSync = syncValue - lastSyncValue;
  134. syncCrossing = 1.0f - syncValue / deltaSync;
  135. syncCrossing *= OVERSAMPLE;
  136. syncIndex = (int) syncCrossing;
  137. syncCrossing -= syncIndex;
  138. }
  139. lastSyncValue = syncValue;
  140. }
  141. if (syncDirection)
  142. deltaPhaseOver *= -1.0f;
  143. if (sqEnabled) {
  144. sqrFilter.setCutoff(40.0f * deltaTime);
  145. }
  146. for (int i = 0; i < OVERSAMPLE; i++) {
  147. if (syncIndex == i) {
  148. if (soft) {
  149. syncDirection = !syncDirection;
  150. deltaPhaseOver *= -1.0f;
  151. } else {
  152. // phase = syncCrossing * deltaPhase / OVERSAMPLE;
  153. phase = 0.0f;
  154. }
  155. }
  156. if (sinEnabled) {
  157. if (analog) {
  158. // Quadratic approximation of sine, slightly richer harmonics
  159. if (phase < 0.5f)
  160. sinBuffer[i] = 1.f - 16.f * powf(phase - 0.25f, 2);
  161. else
  162. sinBuffer[i] = -1.f + 16.f * powf(phase - 0.75f, 2);
  163. sinBuffer[i] *= 1.08f;
  164. } else {
  165. // sinBuffer[i] = sinf(2.f*M_PI * phase);
  166. sinBuffer[i] = LookupTable<float>::lookup(*sinLookup, phase, true);
  167. }
  168. }
  169. if (triEnabled) {
  170. if (analog) {
  171. triBuffer[i] = 1.25f * sq::interpolateLinear(sqtriTable, phase * 2047.f);
  172. } else {
  173. if (phase < 0.25f)
  174. triBuffer[i] = 4.f * phase;
  175. else if (phase < 0.75f)
  176. triBuffer[i] = 2.f - 4.f * phase;
  177. else
  178. triBuffer[i] = -4.f + 4.f * phase;
  179. }
  180. }
  181. if (sawEnabled) {
  182. if (analog) {
  183. sawBuffer[i] = 1.66f * sq::interpolateLinear(sqsawTable, phase * 2047.f);
  184. } else {
  185. if (phase < 0.5f)
  186. sawBuffer[i] = 2.f * phase;
  187. else
  188. sawBuffer[i] = -2.f + 2.f * phase;
  189. }
  190. }
  191. if (sqEnabled) {
  192. sqrBuffer[i] = (phase < pw) ? 1.f : -1.f;
  193. if (analog) {
  194. // Simply filter here
  195. sqrFilter.process(sqrBuffer[i]);
  196. sqrBuffer[i] = 0.71f * sqrFilter.highpass();
  197. }
  198. }
  199. // don't divide by oversample every time.
  200. // don't do that expensive mod
  201. phase += deltaPhaseOver;
  202. while (phase > 1.0f) {
  203. phase -= 1.0f;
  204. }
  205. while (phase < 0) {
  206. phase += 1.0f;
  207. }
  208. }
  209. }
  210. float sin()
  211. {
  212. return sinDecimator.process(sinBuffer);
  213. }
  214. float tri()
  215. {
  216. return triDecimator.process(triBuffer);
  217. }
  218. float saw()
  219. {
  220. return sawDecimator.process(sawBuffer);
  221. }
  222. float sqr()
  223. {
  224. return sqrDecimator.process(sqrBuffer);
  225. }
  226. #if 0
  227. float light()
  228. {
  229. return sinf(2 * M_PI * phase);
  230. }
  231. #endif
  232. };
  233. #if 0 // let's remove from regular builds
  234. template <int OVERSAMPLE, int QUALITY>
  235. struct VoltageControlledOscillatorOrig
  236. {
  237. float sampleTime = 0;
  238. bool analog = false;
  239. bool soft = false;
  240. float lastSyncValue = 0.0f;
  241. float phase = 0.0f;
  242. float freq;
  243. float pw = 0.5f;
  244. float pitch;
  245. bool syncEnabled = false;
  246. bool syncDirection = false;
  247. rack::Decimator<OVERSAMPLE, QUALITY> sinDecimator;
  248. rack::Decimator<OVERSAMPLE, QUALITY> triDecimator;
  249. rack::Decimator<OVERSAMPLE, QUALITY> sawDecimator;
  250. rack::Decimator<OVERSAMPLE, QUALITY> sqrDecimator;
  251. RCFilter sqrFilter;
  252. // For analog detuning effect
  253. float pitchSlew = 0.0f;
  254. int pitchSlewIndex = 0;
  255. float sinBuffer[OVERSAMPLE] = {};
  256. float triBuffer[OVERSAMPLE] = {};
  257. float sawBuffer[OVERSAMPLE] = {};
  258. float sqrBuffer[OVERSAMPLE] = {};
  259. std::default_random_engine generator{99};
  260. std::normal_distribution<double> distribution{-1.0, 1.0};
  261. float noise()
  262. {
  263. return (float) distribution(generator);
  264. }
  265. void setPitch(float pitchKnob, float pitchCv)
  266. {
  267. // Compute frequency
  268. pitch = pitchKnob;
  269. if (analog) {
  270. // Apply pitch slew
  271. const float pitchSlewAmount = 3.0f;
  272. pitch += pitchSlew * pitchSlewAmount;
  273. } else {
  274. // Quantize coarse knob if digital mode
  275. pitch = roundf(pitch);
  276. }
  277. pitch += pitchCv;
  278. // Note C4
  279. freq = 261.626f * powf(2.0f, pitch / 12.0f);
  280. }
  281. void setPulseWidth(float pulseWidth)
  282. {
  283. const float pwMin = 0.01f;
  284. pw = clamp(pulseWidth, pwMin, 1.0f - pwMin);
  285. }
  286. void init()
  287. {
  288. }
  289. void process(float deltaTime, float syncValue)
  290. {
  291. assert(sampleTime > 0);
  292. if (analog) {
  293. // Adjust pitch slew
  294. if (++pitchSlewIndex > 32) {
  295. const float pitchSlewTau = 100.0f; // Time constant for leaky integrator in seconds
  296. // pitchSlew += (randomNormal() - pitchSlew / pitchSlewTau) * sampleTime;
  297. pitchSlew += (noise() - pitchSlew / pitchSlewTau) *sampleTime;
  298. pitchSlewIndex = 0;
  299. }
  300. }
  301. // Advance phase
  302. float deltaPhase = clamp(freq * deltaTime, 1e-6, 0.5f);
  303. // Detect sync
  304. int syncIndex = -1; // Index in the oversample loop where sync occurs [0, OVERSAMPLE)
  305. float syncCrossing = 0.0f; // Offset that sync occurs [0.0f, 1.0f)
  306. if (syncEnabled) {
  307. syncValue -= 0.01f;
  308. if (syncValue > 0.0f && lastSyncValue <= 0.0f) {
  309. float deltaSync = syncValue - lastSyncValue;
  310. syncCrossing = 1.0f - syncValue / deltaSync;
  311. syncCrossing *= OVERSAMPLE;
  312. syncIndex = (int) syncCrossing;
  313. syncCrossing -= syncIndex;
  314. }
  315. lastSyncValue = syncValue;
  316. }
  317. if (syncDirection)
  318. deltaPhase *= -1.0f;
  319. sqrFilter.setCutoff(40.0f * deltaTime);
  320. for (int i = 0; i < OVERSAMPLE; i++) {
  321. if (syncIndex == i) {
  322. if (soft) {
  323. syncDirection = !syncDirection;
  324. deltaPhase *= -1.0f;
  325. } else {
  326. // phase = syncCrossing * deltaPhase / OVERSAMPLE;
  327. phase = 0.0f;
  328. }
  329. }
  330. if (analog) {
  331. // Quadratic approximation of sine, slightly richer harmonics
  332. if (phase < 0.5f)
  333. sinBuffer[i] = 1.f - 16.f * powf(phase - 0.25f, 2);
  334. else
  335. sinBuffer[i] = -1.f + 16.f * powf(phase - 0.75f, 2);
  336. sinBuffer[i] *= 1.08f;
  337. } else {
  338. sinBuffer[i] = sinf(2.f*M_PI * phase);
  339. }
  340. if (analog) {
  341. triBuffer[i] = 1.25f * interpolateLinear(sqtriTable, phase * 2047.f);
  342. } else {
  343. if (phase < 0.25f)
  344. triBuffer[i] = 4.f * phase;
  345. else if (phase < 0.75f)
  346. triBuffer[i] = 2.f - 4.f * phase;
  347. else
  348. triBuffer[i] = -4.f + 4.f * phase;
  349. }
  350. if (analog) {
  351. sawBuffer[i] = 1.66f * interpolateLinear(sqsawTable, phase * 2047.f);
  352. } else {
  353. if (phase < 0.5f)
  354. sawBuffer[i] = 2.f * phase;
  355. else
  356. sawBuffer[i] = -2.f + 2.f * phase;
  357. }
  358. sqrBuffer[i] = (phase < pw) ? 1.f : -1.f;
  359. if (analog) {
  360. // Simply filter here
  361. sqrFilter.process(sqrBuffer[i]);
  362. sqrBuffer[i] = 0.71f * sqrFilter.highpass();
  363. }
  364. // Advance phase
  365. phase += deltaPhase / OVERSAMPLE;
  366. phase = eucmod(phase, 1.0f);
  367. }
  368. }
  369. float sin()
  370. {
  371. return sinDecimator.process(sinBuffer);
  372. }
  373. float tri()
  374. {
  375. return triDecimator.process(triBuffer);
  376. }
  377. float saw()
  378. {
  379. return sawDecimator.process(sawBuffer);
  380. }
  381. float sqr()
  382. {
  383. return sqrDecimator.process(sqrBuffer);
  384. }
  385. float light()
  386. {
  387. return sinf(2 * M_PI * phase);
  388. }
  389. };
  390. #endif
  391. #if defined(_MSC_VER)
  392. #pragma warning(pop)
  393. #endif