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.

493 lines
13KB

  1. /**
  2. * This file contains a modified version of EvenVCO.cpp, from the
  3. * Befaco repo. See LICENSE-dist.txt for full license info.
  4. *
  5. * This code has been modified extensively by Squinky Labs. Mainly modifications were:
  6. * re-code hot-spots to lower CPU usage.
  7. * Fix compiler warnings.
  8. * Make it compile in Visual Studio
  9. */
  10. // Need to make this compile in MS tools for unit tests
  11. #if defined(_MSC_VER)
  12. #define __attribute__(x)
  13. #pragma warning (push)
  14. #pragma warning ( disable: 4244 4267 )
  15. #endif
  16. #include "SqMath.h"
  17. #include "SqBlep.h"
  18. #include "AudioMath.h"
  19. #include "ObjectCache.h"
  20. using namespace rack;
  21. template <class TBase>
  22. struct EvenVCO : TBase
  23. {
  24. EvenVCO(struct Module * module);
  25. EvenVCO();
  26. enum ParamIds
  27. {
  28. OCTAVE_PARAM,
  29. TUNE_PARAM,
  30. PWM_PARAM,
  31. NUM_PARAMS
  32. };
  33. enum InputIds
  34. {
  35. PITCH1_INPUT,
  36. PITCH2_INPUT,
  37. FM_INPUT,
  38. PWM_INPUT,
  39. NUM_INPUTS
  40. };
  41. enum OutputIds
  42. {
  43. TRI_OUTPUT,
  44. SINE_OUTPUT,
  45. EVEN_OUTPUT,
  46. SAW_OUTPUT,
  47. SQUARE_OUTPUT,
  48. NUM_OUTPUTS
  49. };
  50. enum LightIds
  51. {
  52. NUM_LIGHTS
  53. };
  54. float phase = 0.0;
  55. float tri = 0.0;
  56. /**
  57. * References to shared lookup tables.
  58. * Destructor will free them automatically.
  59. */
  60. std::shared_ptr<LookupTableParams<float>> sinLookup;
  61. std::function<float(float)> expLookup;
  62. /** Whether we are past the pulse width already */
  63. bool halfPhase = false;
  64. SqBlep triSquareMinBLEP;
  65. SqBlep triMinBLEP;
  66. SqBlep sineMinBLEP;
  67. SqBlep doubleSawMinBLEP;
  68. SqBlep sawMinBLEP;
  69. SqBlep squareMinBLEP;
  70. void step() override;
  71. void step_even(float deltaPhase);
  72. void step_saw(float deltaPhase);
  73. void step_sq(float deltaPhase);
  74. void step_sin(float deltaPhase);
  75. void step_tri(float deltaPhase);
  76. void step_all(float deltaPhase);
  77. void step_old();
  78. void initialize();
  79. void zeroOutputsExcept(int except);
  80. int dispatcher = 0;
  81. int loopCounter = 0;
  82. /**
  83. * To avoid scanning outputs for changes every sample, we
  84. * save the state here.
  85. */
  86. bool doSaw = false;
  87. bool doEven = false;
  88. bool doTri = false;
  89. bool doSq = false;
  90. bool doSin = false;
  91. /**
  92. * Variables added purely to enable unit testing
  93. */
  94. float _freq = 0;
  95. float _testFreq = 0;
  96. };
  97. template <class TBase>
  98. inline EvenVCO<TBase>::EvenVCO() : TBase()
  99. {
  100. initialize();
  101. }
  102. template <class TBase>
  103. inline EvenVCO<TBase>::EvenVCO(struct Module * module) : TBase(module)
  104. {
  105. initialize();
  106. }
  107. #ifdef __V1
  108. using namespace rack::dsp;
  109. #else
  110. using namespace rack;
  111. #endif
  112. template <class TBase>
  113. inline void EvenVCO<TBase>::initialize()
  114. {
  115. #if 0
  116. triSquareMinBLEP.minblep = minblep_16_32;
  117. triSquareMinBLEP.oversample = 32;
  118. triMinBLEP.minblep = minblep_16_32;
  119. triMinBLEP.oversample = 32;
  120. sineMinBLEP.minblep = minblep_16_32;
  121. sineMinBLEP.oversample = 32;
  122. doubleSawMinBLEP.minblep = minblep_16_32;
  123. doubleSawMinBLEP.oversample = 32;
  124. sawMinBLEP.minblep = minblep_16_32;
  125. sawMinBLEP.oversample = 32;
  126. squareMinBLEP.minblep = minblep_16_32;
  127. squareMinBLEP.oversample = 32;
  128. #endif
  129. sinLookup = ObjectCache<float>::getSinLookup();
  130. expLookup = ObjectCache<float>::getExp2Ex();
  131. }
  132. template <class TBase>
  133. void EvenVCO<TBase>::zeroOutputsExcept(int except)
  134. {
  135. for (int i = 0; i < NUM_OUTPUTS; ++i) {
  136. if (i != except) {
  137. // if we do even, we do sin at same time
  138. if ((i == SINE_OUTPUT) && (except == EVEN_OUTPUT)) {
  139. } else {
  140. TBase::outputs[i].value = 0;
  141. }
  142. }
  143. }
  144. }
  145. template <class TBase>
  146. inline void EvenVCO<TBase>::step_even(float deltaPhase)
  147. {
  148. float oldPhase = phase;
  149. phase += deltaPhase;
  150. if (oldPhase < 0.5 && phase >= 0.5) {
  151. float crossing = -(phase - 0.5) / deltaPhase;
  152. doubleSawMinBLEP.jump(crossing, -2.0);
  153. }
  154. // Reset phase if at end of cycle
  155. if (phase >= 1.0) {
  156. phase -= 1.0;
  157. float crossing = -phase / deltaPhase;
  158. doubleSawMinBLEP.jump(crossing, -2.0);
  159. }
  160. //sine = -cosf(2*AudioMath::Pi * phase);
  161. // want cosine, but only have sine lookup
  162. float adjPhase = phase + .25f;
  163. if (adjPhase >= 1) {
  164. adjPhase -= 1;
  165. }
  166. const float sine = -LookupTable<float>::lookup(*sinLookup, adjPhase, true);
  167. float doubleSaw = (phase < 0.5) ? (-1.0 + 4.0*phase) : (-1.0 + 4.0*(phase - 0.5));
  168. doubleSaw += doubleSawMinBLEP.shift();
  169. const float even = 0.55 * (doubleSaw + 1.27 * sine);
  170. TBase::outputs[SINE_OUTPUT].value = 5.0*sine;
  171. TBase::outputs[EVEN_OUTPUT].value = 5.0*even;
  172. }
  173. template <class TBase>
  174. inline void EvenVCO<TBase>::step_saw(float deltaPhase)
  175. {
  176. phase += deltaPhase;
  177. // Reset phase if at end of cycle
  178. if (phase >= 1.0) {
  179. phase -= 1.0;
  180. float crossing = -phase / deltaPhase;
  181. static float cMin = 100;
  182. static float cMax = -100;
  183. cMin = std::min(crossing, cMin);
  184. cMax = std::max(crossing, cMax);
  185. // printf("sawJump ph=%.2f, delta=%.2f cross=%.2f (%.2f, %.2f)\n", phase, deltaPhase, crossing, cMin, cMax);
  186. sawMinBLEP.jump(crossing, -2.0);
  187. }
  188. float saw = -1.0 + 2.0*phase;
  189. saw += sawMinBLEP.shift();
  190. TBase::outputs[SAW_OUTPUT].value = 5.0*saw;
  191. }
  192. template <class TBase>
  193. inline void EvenVCO<TBase>::step_sin(float deltaPhase)
  194. {
  195. phase += deltaPhase;
  196. // Reset phase if at end of cycle
  197. if (phase >= 1.0) {
  198. phase -= 1.0;
  199. }
  200. // want cosine, but only have sine lookup
  201. float adjPhase = phase + .25f;
  202. if (adjPhase >= 1) {
  203. adjPhase -= 1;
  204. }
  205. const float sine = -LookupTable<float>::lookup(*sinLookup, adjPhase, true);
  206. TBase::outputs[SINE_OUTPUT].value = 5.0*sine;
  207. }
  208. template <class TBase>
  209. inline void EvenVCO<TBase>::step_tri(float deltaPhase)
  210. {
  211. float oldPhase = phase;
  212. phase += deltaPhase;
  213. if (oldPhase < 0.5 && phase >= 0.5) {
  214. const float crossing = -(phase - 0.5) / deltaPhase;
  215. triSquareMinBLEP.jump(crossing, 2.0);
  216. }
  217. // Reset phase if at end of cycle
  218. if (phase >= 1.0) {
  219. phase -= 1.0;
  220. float crossing = -phase / deltaPhase;
  221. triSquareMinBLEP.jump(crossing, -2.0);
  222. halfPhase = false;
  223. }
  224. // Outputs
  225. float triSquare = (phase < 0.5) ? -1.0 : 1.0;
  226. triSquare += triSquareMinBLEP.shift();
  227. // Integrate square for triangle
  228. tri += 4.0 * triSquare * _freq * TBase::engineGetSampleTime();
  229. tri *= (1.0 - 40.0 * TBase::engineGetSampleTime());
  230. // Set output
  231. TBase::outputs[TRI_OUTPUT].value = 5.0*tri;
  232. }
  233. template <class TBase>
  234. inline void EvenVCO<TBase>::step_sq(float deltaPhase)
  235. {
  236. phase += deltaPhase;
  237. // Pulse width
  238. float pw;
  239. if (doSq) {
  240. pw = TBase::params[PWM_PARAM].value + TBase::inputs[PWM_INPUT].value / 5.0;
  241. const float minPw = 0.05f;
  242. pw = sq::rescale(sq::clamp(pw, -1.0f, 1.0f), -1.0f, 1.0f, minPw, 1.0f - minPw);
  243. if (!halfPhase && phase >= pw) {
  244. float crossing = -(phase - pw) / deltaPhase;
  245. squareMinBLEP.jump(crossing, 2.0);
  246. halfPhase = true;
  247. }
  248. }
  249. // Reset phase if at end of cycle
  250. if (phase >= 1.0) {
  251. phase -= 1.0;
  252. float crossing = -phase / deltaPhase;
  253. squareMinBLEP.jump(crossing, -2.0);
  254. halfPhase = false;
  255. }
  256. float square = (phase < pw) ? -1.0 : 1.0;
  257. square += squareMinBLEP.shift();
  258. TBase::outputs[SQUARE_OUTPUT].value = 5.0*square;
  259. }
  260. template <class TBase>
  261. inline void EvenVCO<TBase>::step()
  262. {
  263. // We don't need to look for connected outputs every cycle.
  264. // do it less often, and store results.
  265. if (--loopCounter < 0) {
  266. loopCounter = 16;
  267. doSaw = TBase::outputs[SAW_OUTPUT].active;
  268. doEven = TBase::outputs[EVEN_OUTPUT].active;
  269. doTri = TBase::outputs[TRI_OUTPUT].active;
  270. doSq = TBase::outputs[SQUARE_OUTPUT].active;
  271. doSin = TBase::outputs[SINE_OUTPUT].active;
  272. if (doSaw && !doEven && !doTri && !doSq && !doSin) {
  273. dispatcher = SAW_OUTPUT;
  274. zeroOutputsExcept(SAW_OUTPUT);
  275. } else if (!doSaw && doEven && !doTri && !doSq) {
  276. dispatcher = EVEN_OUTPUT;
  277. zeroOutputsExcept(EVEN_OUTPUT);
  278. } else if (!doSaw && !doEven && !doTri && !doSq && doSin) {
  279. dispatcher = SINE_OUTPUT;
  280. zeroOutputsExcept(SINE_OUTPUT);
  281. } else if (!doSaw && !doEven && doTri && !doSq && !doSin) {
  282. dispatcher = TRI_OUTPUT;
  283. zeroOutputsExcept(TRI_OUTPUT);
  284. } else if (!doSaw && !doEven && !doTri && doSq && !doSin) {
  285. dispatcher = SQUARE_OUTPUT;
  286. zeroOutputsExcept(SQUARE_OUTPUT);
  287. } else {
  288. dispatcher = NUM_OUTPUTS;
  289. }
  290. }
  291. // Compute frequency, pitch is 1V/oct
  292. float pitch = 1.0 + roundf(TBase::params[OCTAVE_PARAM].value) + TBase::params[TUNE_PARAM].value / 12.0;
  293. pitch += TBase::inputs[PITCH1_INPUT].value + TBase::inputs[PITCH2_INPUT].value;
  294. pitch += TBase::inputs[FM_INPUT].value / 4.0;
  295. #if 1 // Use lookup table for pitch lookup
  296. const float q = float(log2(261.626)); // move up to pitch range of EvenVCO
  297. pitch += q;
  298. _freq = expLookup(pitch);
  299. #else
  300. _freq = 261.626 * powf(2.0, pitch);
  301. _freq = clamp(_freq, 0.0f, 20000.0f);
  302. #endif
  303. // Advance phase
  304. float f = (_testFreq) ? _testFreq : _freq;
  305. float deltaPhase = sq::clamp(f * TBase::engineGetSampleTime(), 1e-6f, 0.5f);
  306. // call the dedicated dispatch routines for the special case waveforms.
  307. switch (dispatcher) {
  308. case SAW_OUTPUT:
  309. step_saw(deltaPhase);
  310. break;
  311. case EVEN_OUTPUT:
  312. step_even(deltaPhase);
  313. break;
  314. case SINE_OUTPUT:
  315. step_sin(deltaPhase);
  316. break;
  317. case TRI_OUTPUT:
  318. step_tri(deltaPhase);
  319. break;
  320. case SQUARE_OUTPUT:
  321. step_sq(deltaPhase);
  322. break;
  323. case NUM_OUTPUTS:
  324. step_all(deltaPhase);
  325. break;
  326. default:
  327. assert(false);
  328. }
  329. }
  330. /**
  331. * Less optimized version that can do all waveform combinations
  332. */
  333. template <class TBase>
  334. inline void EvenVCO<TBase>::step_all(float deltaPhase)
  335. {
  336. float oldPhase = phase;
  337. phase += deltaPhase;
  338. if (oldPhase < 0.5 && phase >= 0.5) {
  339. const float crossing = -(phase - 0.5) / deltaPhase;
  340. if (doTri) {
  341. triSquareMinBLEP.jump(crossing, 2.0);
  342. }
  343. if (doEven) {
  344. doubleSawMinBLEP.jump(crossing, -2.0);
  345. }
  346. }
  347. // Pulse width
  348. float pw;
  349. if (doSq) {
  350. pw = TBase::params[PWM_PARAM].value + TBase::inputs[PWM_INPUT].value / 5.0;
  351. const float minPw = 0.05f;
  352. pw = sq::rescale(sq::clamp(pw, -1.0f, 1.0f), -1.0f, 1.0f, minPw, 1.0f - minPw);
  353. if (!halfPhase && phase >= pw) {
  354. const float crossing = -(phase - pw) / deltaPhase;
  355. squareMinBLEP.jump(crossing, 2.0);
  356. halfPhase = true;
  357. }
  358. }
  359. // Reset phase if at end of cycle
  360. if (phase >= 1.0) {
  361. phase -= 1.0;
  362. float crossing = -phase / deltaPhase;
  363. if (doTri) {
  364. triSquareMinBLEP.jump(crossing, -2.0);
  365. }
  366. if (doEven) {
  367. doubleSawMinBLEP.jump(crossing, -2.0);
  368. }
  369. if (doSq) {
  370. squareMinBLEP.jump(crossing, -2.0);
  371. }
  372. if (doSaw) {
  373. sawMinBLEP.jump(crossing, -2.0);
  374. }
  375. halfPhase = false;
  376. }
  377. // Outputs
  378. if (doTri) {
  379. float triSquare = (phase < 0.5) ? -1.0 : 1.0;
  380. triSquare += triSquareMinBLEP.shift();
  381. // Integrate square for triangle
  382. tri += 4.0 * triSquare * _freq * TBase::engineGetSampleTime();
  383. tri *= (1.0 - 40.0 * TBase::engineGetSampleTime());
  384. }
  385. float sine = 0;
  386. float even = 0;
  387. float saw = 0;
  388. float square = 0;
  389. if (doSin || doEven) {
  390. //sine = -cosf(2*AudioMath::Pi * phase);
  391. // want cosine, but only have sine lookup
  392. float adjPhase = phase + .25f;
  393. if (adjPhase >= 1) {
  394. adjPhase -= 1;
  395. }
  396. sine = -LookupTable<float>::lookup(*sinLookup, adjPhase, true);
  397. }
  398. if (doEven) {
  399. float doubleSaw = (phase < 0.5) ? (-1.0 + 4.0*phase) : (-1.0 + 4.0*(phase - 0.5));
  400. doubleSaw += doubleSawMinBLEP.shift();
  401. even = 0.55 * (doubleSaw + 1.27 * sine);
  402. }
  403. if (doSaw) {
  404. saw = -1.0 + 2.0*phase;
  405. saw += sawMinBLEP.shift();
  406. }
  407. if (doSq) {
  408. square = (phase < pw) ? -1.0 : 1.0;
  409. square += squareMinBLEP.shift();
  410. } else {
  411. TBase::outputs[SQUARE_OUTPUT].value = 0;
  412. }
  413. // Set outputs
  414. // get rid of redundant stuff here
  415. TBase::outputs[TRI_OUTPUT].value = doTri ? 5.0*tri : 0;
  416. TBase::outputs[SINE_OUTPUT].value = 5.0*sine;
  417. TBase::outputs[EVEN_OUTPUT].value = 5.0*even;
  418. TBase::outputs[SAW_OUTPUT].value = 5.0*saw;
  419. TBase::outputs[SQUARE_OUTPUT].value = 5.0*square;
  420. }
  421. #if defined(_MSC_VER)
  422. #pragma warning (pop)
  423. #endif