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.

221 lines
5.0KB

  1. /*************************************************************************************
  2. * Original code copyright (C) 2012 Steve Folta
  3. * Converted to Juce module (C) 2016 Leo Olivers
  4. * Forked from https://github.com/stevefolta/SFZero
  5. * For license info please see the LICENSE file distributed with this source code
  6. *************************************************************************************/
  7. #include "SFZEG.h"
  8. namespace sfzero
  9. {
  10. static const float fastReleaseTime = 0.01f;
  11. EG::EG()
  12. : segment_(), sampleRate_(0), exponentialDecay_(false), level_(0), slope_(0), samplesUntilNextSegment_(0), segmentIsExponential_(false)
  13. {
  14. }
  15. void EG::setExponentialDecay(bool newExponentialDecay) { exponentialDecay_ = newExponentialDecay; }
  16. void EG::startNote(const EGParameters *newParameters, float floatVelocity, double newSampleRate,
  17. const EGParameters *velMod)
  18. {
  19. parameters_ = *newParameters;
  20. if (velMod)
  21. {
  22. parameters_.delay += floatVelocity * velMod->delay;
  23. parameters_.attack += floatVelocity * velMod->attack;
  24. parameters_.hold += floatVelocity * velMod->hold;
  25. parameters_.decay += floatVelocity * velMod->decay;
  26. parameters_.sustain += floatVelocity * velMod->sustain;
  27. if (parameters_.sustain < 0.0)
  28. {
  29. parameters_.sustain = 0.0;
  30. }
  31. else if (parameters_.sustain > 100.0)
  32. {
  33. parameters_.sustain = 100.0;
  34. }
  35. parameters_.release += floatVelocity * velMod->release;
  36. }
  37. sampleRate_ = newSampleRate;
  38. startDelay();
  39. }
  40. void EG::nextSegment()
  41. {
  42. switch (segment_)
  43. {
  44. case Delay:
  45. startAttack();
  46. break;
  47. case Attack:
  48. startHold();
  49. break;
  50. case Hold:
  51. startDecay();
  52. break;
  53. case Decay:
  54. startSustain();
  55. break;
  56. case Sustain:
  57. // Shouldn't be called.
  58. break;
  59. case Release:
  60. default:
  61. segment_ = Done;
  62. break;
  63. }
  64. }
  65. void EG::noteOff() { startRelease(); }
  66. void EG::fastRelease()
  67. {
  68. segment_ = Release;
  69. samplesUntilNextSegment_ = static_cast<int>(fastReleaseTime * sampleRate_);
  70. slope_ = -level_ / samplesUntilNextSegment_;
  71. segmentIsExponential_ = false;
  72. }
  73. void EG::startDelay()
  74. {
  75. if (parameters_.delay <= 0)
  76. {
  77. startAttack();
  78. }
  79. else
  80. {
  81. segment_ = Delay;
  82. level_ = 0.0;
  83. slope_ = 0.0;
  84. samplesUntilNextSegment_ = static_cast<int>(parameters_.delay * sampleRate_);
  85. segmentIsExponential_ = false;
  86. }
  87. }
  88. void EG::startAttack()
  89. {
  90. if (parameters_.attack <= 0)
  91. {
  92. startHold();
  93. }
  94. else
  95. {
  96. segment_ = Attack;
  97. level_ = parameters_.start / 100.0f;
  98. samplesUntilNextSegment_ = static_cast<int>(parameters_.attack * sampleRate_);
  99. slope_ = 1.0f / samplesUntilNextSegment_;
  100. segmentIsExponential_ = false;
  101. }
  102. }
  103. void EG::startHold()
  104. {
  105. if (parameters_.hold <= 0)
  106. {
  107. level_ = 1.0;
  108. startDecay();
  109. }
  110. else
  111. {
  112. segment_ = Hold;
  113. samplesUntilNextSegment_ = static_cast<int>(parameters_.hold * sampleRate_);
  114. level_ = 1.0;
  115. slope_ = 0.0;
  116. segmentIsExponential_ = false;
  117. }
  118. }
  119. void EG::startDecay()
  120. {
  121. if (parameters_.decay <= 0)
  122. {
  123. startSustain();
  124. }
  125. else
  126. {
  127. segment_ = Decay;
  128. samplesUntilNextSegment_ = static_cast<int>(parameters_.decay * sampleRate_);
  129. level_ = 1.0;
  130. if (exponentialDecay_)
  131. {
  132. // I don't truly understand this; just following what LinuxSampler does.
  133. float mysterySlope = -9.226f / samplesUntilNextSegment_;
  134. slope_ = exp(mysterySlope);
  135. segmentIsExponential_ = true;
  136. if (parameters_.sustain > 0.0)
  137. {
  138. // Again, this is following LinuxSampler's example, which is similar to
  139. // SF2-style decay, where "decay" specifies the time it would take to
  140. // get to zero, not to the sustain level. The SFZ spec is not that
  141. // specific about what "decay" means, so perhaps it's really supposed
  142. // to specify the time to reach the sustain level.
  143. samplesUntilNextSegment_ = static_cast<int>(log((parameters_.sustain / 100.0) / level_) / mysterySlope);
  144. if (samplesUntilNextSegment_ <= 0)
  145. {
  146. startSustain();
  147. }
  148. }
  149. }
  150. else
  151. {
  152. slope_ = (parameters_.sustain / 100.0f - 1.0f) / samplesUntilNextSegment_;
  153. segmentIsExponential_ = false;
  154. }
  155. }
  156. }
  157. void EG::startSustain()
  158. {
  159. if (parameters_.sustain <= 0)
  160. {
  161. startRelease();
  162. }
  163. else
  164. {
  165. segment_ = Sustain;
  166. level_ = parameters_.sustain / 100.0f;
  167. slope_ = 0.0;
  168. samplesUntilNextSegment_ = 0x7FFFFFFF;
  169. segmentIsExponential_ = false;
  170. }
  171. }
  172. void EG::startRelease()
  173. {
  174. float release = parameters_.release;
  175. if (release <= 0)
  176. {
  177. // Enforce a short release, to prevent clicks.
  178. release = fastReleaseTime;
  179. }
  180. segment_ = Release;
  181. samplesUntilNextSegment_ = static_cast<int>(release * sampleRate_);
  182. if (exponentialDecay_)
  183. {
  184. // I don't truly understand this; just following what LinuxSampler does.
  185. float mysterySlope = -9.226f / samplesUntilNextSegment_;
  186. slope_ = exp(mysterySlope);
  187. segmentIsExponential_ = true;
  188. }
  189. else
  190. {
  191. slope_ = -level_ / samplesUntilNextSegment_;
  192. segmentIsExponential_ = false;
  193. }
  194. }
  195. const float EG::BottomLevel = 0.001f;
  196. }