Audio plugin host https://kx.studio/carla
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.

LFO.cpp 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. LFO.cpp - LFO implementation
  4. Copyright (C) 2002-2005 Nasca Octavian Paul
  5. Author: Nasca Octavian Paul
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. */
  11. #include "LFO.h"
  12. #include "../Params/LFOParams.h"
  13. #include "../Misc/Util.h"
  14. #include <cstdlib>
  15. #include <cstdio>
  16. #include <cmath>
  17. namespace zyncarla {
  18. LFO::LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t, WatchManager *m,
  19. const char *watch_prefix)
  20. :first_half(-1),
  21. delayTime(t, lfopars.Pdelay / 127.0f * 4.0f), //0..4 sec
  22. waveShape(lfopars.PLFOtype),
  23. deterministic(!lfopars.Pfreqrand),
  24. dt_(t.dt()),
  25. lfopars_(lfopars), basefreq_(basefreq),
  26. watchOut(m, watch_prefix, "out")
  27. {
  28. int stretch = lfopars.Pstretch;
  29. if(stretch == 0)
  30. stretch = 1;
  31. //max 2x/octave
  32. const float lfostretch = powf(basefreq / 440.0f, (stretch - 64.0f) / 63.0f);
  33. const float lfofreq =
  34. (powf(2, lfopars.Pfreq * 10.0f) - 1.0f) / 12.0f * lfostretch;
  35. phaseInc = fabs(lfofreq) * t.dt();
  36. if(!lfopars.Pcontinous) {
  37. if(lfopars.Pstartphase == 0)
  38. phase = RND;
  39. else
  40. phase = fmod((lfopars.Pstartphase - 64.0f) / 127.0f + 1.0f, 1.0f);
  41. }
  42. else {
  43. const float tmp = fmod(t.time() * phaseInc, 1.0f);
  44. phase = fmod((lfopars.Pstartphase - 64.0f) / 127.0f + 1.0f + tmp, 1.0f);
  45. }
  46. //Limit the Frequency(or else...)
  47. if(phaseInc > 0.49999999f)
  48. phaseInc = 0.499999999f;
  49. lfornd = limit(lfopars.Prandomness / 127.0f, 0.0f, 1.0f);
  50. lfofreqrnd = powf(lfopars.Pfreqrand / 127.0f, 2.0f) * 4.0f;
  51. switch(lfopars.fel) {
  52. case 1:
  53. lfointensity = lfopars.Pintensity / 127.0f;
  54. break;
  55. case 2:
  56. lfointensity = lfopars.Pintensity / 127.0f * 4.0f;
  57. break; //in octave
  58. default:
  59. lfointensity = powf(2, lfopars.Pintensity / 127.0f * 11.0f) - 1.0f; //in centi
  60. phase -= 0.25f; //chance the starting phase
  61. break;
  62. }
  63. amp1 = (1 - lfornd) + lfornd * RND;
  64. amp2 = (1 - lfornd) + lfornd * RND;
  65. incrnd = nextincrnd = 1.0f;
  66. computeNextFreqRnd();
  67. computeNextFreqRnd(); //twice because I want incrnd & nextincrnd to be random
  68. }
  69. LFO::~LFO()
  70. {}
  71. float LFO::baseOut(const char waveShape, const float phase)
  72. {
  73. switch(waveShape) {
  74. case LFO_TRIANGLE:
  75. if(phase >= 0.0f && phase < 0.25f)
  76. return 4.0f * phase;
  77. else if(phase > 0.25f && phase < 0.75f)
  78. return 2 - 4 * phase;
  79. else
  80. return 4.0f * phase - 4.0f;
  81. break;
  82. case LFO_SQUARE:
  83. if(phase < 0.5f)
  84. return -1;
  85. else
  86. return 1;
  87. break;
  88. case LFO_RAMPUP: return (phase - 0.5f) * 2.0f;
  89. case LFO_RAMPDOWN: return (0.5f - phase) * 2.0f;
  90. case LFO_EXP_DOWN1: return powf(0.05f, phase) * 2.0f - 1.0f;
  91. case LFO_EXP_DOWN2: return powf(0.001f, phase) * 2.0f - 1.0f;
  92. case LFO_RANDOM:
  93. if ((phase < 0.5) != first_half) {
  94. first_half = phase < 0.5;
  95. last_random = 2*RND-1;
  96. }
  97. return last_random;
  98. default: return cosf(phase * 2.0f * PI); //LFO_SINE
  99. }
  100. }
  101. float LFO::lfoout()
  102. {
  103. //update internals XXX TODO cleanup
  104. if ( ! lfopars_.time || lfopars_.last_update_timestamp == lfopars_.time->time())
  105. {
  106. waveShape = lfopars_.PLFOtype;
  107. int stretch = lfopars_.Pstretch;
  108. if(stretch == 0)
  109. stretch = 1;
  110. const float lfostretch = powf(basefreq_ / 440.0f, (stretch - 64.0f) / 63.0f);
  111. float lfofreq =
  112. (powf(2, lfopars_.Pfreq * 10.0f) - 1.0f) / 12.0f * lfostretch;
  113. phaseInc = fabs(lfofreq) * dt_;
  114. switch(lfopars_.fel) {
  115. case 1:
  116. lfointensity = lfopars_.Pintensity / 127.0f;
  117. break;
  118. case 2:
  119. lfointensity = lfopars_.Pintensity / 127.0f * 4.0f;
  120. break; //in octave
  121. default:
  122. lfointensity = powf(2, lfopars_.Pintensity / 127.0f * 11.0f) - 1.0f; //in centi
  123. //x -= 0.25f; //chance the starting phase
  124. break;
  125. }
  126. }
  127. float out = baseOut(waveShape, phase);
  128. if(waveShape == LFO_SINE || waveShape == LFO_TRIANGLE)
  129. out *= lfointensity * (amp1 + phase * (amp2 - amp1));
  130. else
  131. out *= lfointensity * amp2;
  132. if(delayTime.inFuture())
  133. return out;
  134. //Start oscillating
  135. if(deterministic)
  136. phase += phaseInc;
  137. else {
  138. const float tmp = (incrnd * (1.0f - phase) + nextincrnd * phase);
  139. phase += phaseInc * limit(tmp, 0.0f, 1.0f);
  140. }
  141. if(phase >= 1) {
  142. phase = fmod(phase, 1.0f);
  143. amp1 = amp2;
  144. amp2 = (1 - lfornd) + lfornd * RND;
  145. computeNextFreqRnd();
  146. }
  147. float watch_data[2] = {phase, out};
  148. watchOut(watch_data, 2);
  149. return out;
  150. }
  151. /*
  152. * LFO out (for amplitude)
  153. */
  154. float LFO::amplfoout()
  155. {
  156. return limit(1.0f - lfointensity + lfoout(), -1.0f, 1.0f);
  157. }
  158. void LFO::computeNextFreqRnd()
  159. {
  160. if(deterministic)
  161. return;
  162. incrnd = nextincrnd;
  163. nextincrnd = powf(0.5f, lfofreqrnd) + RND * (powf(2.0f, lfofreqrnd) - 1.0f);
  164. }
  165. }