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.

219 lines
5.6KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. Envelope.cpp - Envelope 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 <cmath>
  12. #include "Envelope.h"
  13. #include "../Params/EnvelopeParams.h"
  14. namespace zyncarla {
  15. Envelope::Envelope(EnvelopeParams &pars, float basefreq, float bufferdt,
  16. WatchManager *m, const char *watch_prefix)
  17. :watchOut(m, watch_prefix, "out")
  18. {
  19. envpoints = pars.Penvpoints;
  20. if(envpoints > MAX_ENVELOPE_POINTS)
  21. envpoints = MAX_ENVELOPE_POINTS;
  22. envsustain = (pars.Penvsustain == 0) ? -1 : pars.Penvsustain;
  23. forcedrelease = pars.Pforcedrelease;
  24. envstretch = powf(440.0f / basefreq, pars.Penvstretch / 64.0f);
  25. linearenvelope = pars.Plinearenvelope;
  26. if(!pars.Pfreemode)
  27. pars.converttofree();
  28. int mode = pars.Envmode;
  29. //for amplitude envelopes
  30. if((mode == 1) && !linearenvelope)
  31. mode = 2; //change to log envelope
  32. if((mode == 2) && linearenvelope)
  33. mode = 1; //change to linear
  34. for(int i = 0; i < MAX_ENVELOPE_POINTS; ++i) {
  35. const float tmp = pars.getdt(i) / 1000.0f * envstretch;
  36. if(tmp > bufferdt)
  37. envdt[i] = bufferdt / tmp;
  38. else
  39. envdt[i] = 2.0f; //any value larger than 1
  40. switch(mode) {
  41. case 2:
  42. envval[i] = (1.0f - pars.Penvval[i] / 127.0f) * -40;
  43. break;
  44. case 3:
  45. envval[i] =
  46. (powf(2, 6.0f
  47. * fabs(pars.Penvval[i]
  48. - 64.0f) / 64.0f) - 1.0f) * 100.0f;
  49. if(pars.Penvval[i] < 64)
  50. envval[i] = -envval[i];
  51. break;
  52. case 4:
  53. envval[i] = (pars.Penvval[i] - 64.0f) / 64.0f * 6.0f; //6 octaves (filtru)
  54. break;
  55. case 5:
  56. envval[i] = (pars.Penvval[i] - 64.0f) / 64.0f * 10;
  57. break;
  58. default:
  59. envval[i] = pars.Penvval[i] / 127.0f;
  60. }
  61. }
  62. envdt[0] = 1.0f;
  63. currentpoint = 1; //the envelope starts from 1
  64. keyreleased = false;
  65. t = 0.0f;
  66. envfinish = false;
  67. inct = envdt[1];
  68. envoutval = 0.0f;
  69. }
  70. Envelope::~Envelope()
  71. {}
  72. /*
  73. * Release the key (note envelope)
  74. */
  75. void Envelope::releasekey()
  76. {
  77. if(keyreleased)
  78. return;
  79. keyreleased = true;
  80. if(forcedrelease)
  81. t = 0.0f;
  82. }
  83. void Envelope::forceFinish(void)
  84. {
  85. envfinish = true;
  86. }
  87. /*
  88. * Envelope Output
  89. */
  90. float Envelope::envout(bool doWatch)
  91. {
  92. float out;
  93. if(envfinish) { //if the envelope is finished
  94. envoutval = envval[envpoints - 1];
  95. if(doWatch) {
  96. float pos[2] = {(float)envpoints - 1, envoutval};
  97. watchOut(pos, 2);
  98. }
  99. return envoutval;
  100. }
  101. if((currentpoint == envsustain + 1) && !keyreleased) { //if it is sustaining now
  102. envoutval = envval[envsustain];
  103. if(doWatch) {
  104. float pos[2] = {(float)envsustain, envoutval};
  105. watchOut(pos, 2);
  106. }
  107. return envoutval;
  108. }
  109. if(keyreleased && forcedrelease) { //do the forced release
  110. int tmp = (envsustain < 0) ? (envpoints - 1) : (envsustain + 1); //if there is no sustain point, use the last point for release
  111. if(envdt[tmp] < 0.00000001f)
  112. out = envval[tmp];
  113. else
  114. out = envoutval + (envval[tmp] - envoutval) * t;
  115. t += envdt[tmp] * envstretch;
  116. if(t >= 1.0f) {
  117. currentpoint = envsustain + 2;
  118. forcedrelease = 0;
  119. t = 0.0f;
  120. inct = envdt[currentpoint];
  121. if((currentpoint >= envpoints) || (envsustain < 0))
  122. envfinish = true;
  123. }
  124. if(doWatch) {
  125. float pos[2] = {(float)tmp + t, envoutval};
  126. watchOut(pos, 2);
  127. }
  128. return out;
  129. }
  130. if(inct >= 1.0f)
  131. out = envval[currentpoint];
  132. else
  133. out = envval[currentpoint - 1]
  134. + (envval[currentpoint] - envval[currentpoint - 1]) * t;
  135. t += inct;
  136. if(t >= 1.0f) {
  137. if(currentpoint >= envpoints - 1)
  138. envfinish = true;
  139. else
  140. currentpoint++;
  141. t = 0.0f;
  142. inct = envdt[currentpoint];
  143. }
  144. envoutval = out;
  145. if(doWatch) {
  146. float pos[2] = {(float)currentpoint + t, envoutval};
  147. watchOut(pos, 2);
  148. }
  149. return out;
  150. }
  151. /*
  152. * Envelope Output (dB)
  153. */
  154. float Envelope::envout_dB()
  155. {
  156. float out;
  157. if(linearenvelope)
  158. return envout(true);
  159. if((currentpoint == 1) && (!keyreleased || !forcedrelease)) { //first point is always lineary interpolated
  160. float v1 = EnvelopeParams::env_dB2rap(envval[0]);
  161. float v2 = EnvelopeParams::env_dB2rap(envval[1]);
  162. out = v1 + (v2 - v1) * t;
  163. t += inct;
  164. if(t >= 1.0f) {
  165. t = 0.0f;
  166. inct = envdt[2];
  167. currentpoint++;
  168. out = v2;
  169. }
  170. if(out > 0.001f)
  171. envoutval = EnvelopeParams::env_rap2dB(out);
  172. else
  173. envoutval = MIN_ENVELOPE_DB;
  174. } else
  175. out = EnvelopeParams::env_dB2rap(envout(false));
  176. float pos[2] = {(float)currentpoint + t, out};
  177. watchOut(pos, 2);
  178. return out;
  179. }
  180. bool Envelope::finished() const
  181. {
  182. return envfinish;
  183. }
  184. }