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.

223 lines
5.7KB

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