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.

232 lines
6.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. SamplerSound::SamplerSound (const String& soundName,
  22. AudioFormatReader& source,
  23. const BigInteger& notes,
  24. const int midiNoteForNormalPitch,
  25. const double attackTimeSecs,
  26. const double releaseTimeSecs,
  27. const double maxSampleLengthSeconds)
  28. : name (soundName),
  29. midiNotes (notes),
  30. midiRootNote (midiNoteForNormalPitch)
  31. {
  32. sourceSampleRate = source.sampleRate;
  33. if (sourceSampleRate <= 0 || source.lengthInSamples <= 0)
  34. {
  35. length = 0;
  36. attackSamples = 0;
  37. releaseSamples = 0;
  38. }
  39. else
  40. {
  41. length = jmin ((int) source.lengthInSamples,
  42. (int) (maxSampleLengthSeconds * sourceSampleRate));
  43. data = new AudioSampleBuffer (jmin (2, (int) source.numChannels), length + 4);
  44. source.read (data, 0, length + 4, 0, true, true);
  45. attackSamples = roundToInt (attackTimeSecs * sourceSampleRate);
  46. releaseSamples = roundToInt (releaseTimeSecs * sourceSampleRate);
  47. }
  48. }
  49. SamplerSound::~SamplerSound()
  50. {
  51. }
  52. bool SamplerSound::appliesToNote (int midiNoteNumber)
  53. {
  54. return midiNotes [midiNoteNumber];
  55. }
  56. bool SamplerSound::appliesToChannel (int /*midiChannel*/)
  57. {
  58. return true;
  59. }
  60. //==============================================================================
  61. SamplerVoice::SamplerVoice()
  62. : pitchRatio (0.0),
  63. sourceSamplePosition (0.0),
  64. lgain (0.0f), rgain (0.0f),
  65. attackReleaseLevel (0), attackDelta (0), releaseDelta (0),
  66. isInAttack (false), isInRelease (false)
  67. {
  68. }
  69. SamplerVoice::~SamplerVoice()
  70. {
  71. }
  72. bool SamplerVoice::canPlaySound (SynthesiserSound* sound)
  73. {
  74. return dynamic_cast<const SamplerSound*> (sound) != nullptr;
  75. }
  76. void SamplerVoice::startNote (const int midiNoteNumber,
  77. const float velocity,
  78. SynthesiserSound* s,
  79. const int /*currentPitchWheelPosition*/)
  80. {
  81. if (const SamplerSound* const sound = dynamic_cast<const SamplerSound*> (s))
  82. {
  83. pitchRatio = pow (2.0, (midiNoteNumber - sound->midiRootNote) / 12.0)
  84. * sound->sourceSampleRate / getSampleRate();
  85. sourceSamplePosition = 0.0;
  86. lgain = velocity;
  87. rgain = velocity;
  88. isInAttack = (sound->attackSamples > 0);
  89. isInRelease = false;
  90. if (isInAttack)
  91. {
  92. attackReleaseLevel = 0.0f;
  93. attackDelta = (float) (pitchRatio / sound->attackSamples);
  94. }
  95. else
  96. {
  97. attackReleaseLevel = 1.0f;
  98. attackDelta = 0.0f;
  99. }
  100. if (sound->releaseSamples > 0)
  101. releaseDelta = (float) (-pitchRatio / sound->releaseSamples);
  102. else
  103. releaseDelta = -1.0f;
  104. }
  105. else
  106. {
  107. jassertfalse; // this object can only play SamplerSounds!
  108. }
  109. }
  110. void SamplerVoice::stopNote (float /*velocity*/, bool allowTailOff)
  111. {
  112. if (allowTailOff)
  113. {
  114. isInAttack = false;
  115. isInRelease = true;
  116. }
  117. else
  118. {
  119. clearCurrentNote();
  120. }
  121. }
  122. void SamplerVoice::pitchWheelMoved (const int /*newValue*/)
  123. {
  124. }
  125. void SamplerVoice::controllerMoved (const int /*controllerNumber*/,
  126. const int /*newValue*/)
  127. {
  128. }
  129. //==============================================================================
  130. void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples)
  131. {
  132. if (const SamplerSound* const playingSound = static_cast<SamplerSound*> (getCurrentlyPlayingSound().get()))
  133. {
  134. const float* const inL = playingSound->data->getReadPointer (0);
  135. const float* const inR = playingSound->data->getNumChannels() > 1
  136. ? playingSound->data->getReadPointer (1) : nullptr;
  137. float* outL = outputBuffer.getWritePointer (0, startSample);
  138. float* outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getWritePointer (1, startSample) : nullptr;
  139. while (--numSamples >= 0)
  140. {
  141. const int pos = (int) sourceSamplePosition;
  142. const float alpha = (float) (sourceSamplePosition - pos);
  143. const float invAlpha = 1.0f - alpha;
  144. // just using a very simple linear interpolation here..
  145. float l = (inL [pos] * invAlpha + inL [pos + 1] * alpha);
  146. float r = (inR != nullptr) ? (inR [pos] * invAlpha + inR [pos + 1] * alpha)
  147. : l;
  148. l *= lgain;
  149. r *= rgain;
  150. if (isInAttack)
  151. {
  152. l *= attackReleaseLevel;
  153. r *= attackReleaseLevel;
  154. attackReleaseLevel += attackDelta;
  155. if (attackReleaseLevel >= 1.0f)
  156. {
  157. attackReleaseLevel = 1.0f;
  158. isInAttack = false;
  159. }
  160. }
  161. else if (isInRelease)
  162. {
  163. l *= attackReleaseLevel;
  164. r *= attackReleaseLevel;
  165. attackReleaseLevel += releaseDelta;
  166. if (attackReleaseLevel <= 0.0f)
  167. {
  168. stopNote (0.0f, false);
  169. break;
  170. }
  171. }
  172. if (outR != nullptr)
  173. {
  174. *outL++ += l;
  175. *outR++ += r;
  176. }
  177. else
  178. {
  179. *outL++ += (l + r) * 0.5f;
  180. }
  181. sourceSamplePosition += pitchRatio;
  182. if (sourceSamplePosition > playingSound->length)
  183. {
  184. stopNote (0.0f, false);
  185. break;
  186. }
  187. }
  188. }
  189. }
  190. } // namespace juce