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.

200 lines
5.0KB

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