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.

225 lines
6.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. SamplerSound::SamplerSound (const String& soundName,
  18. AudioFormatReader& source,
  19. const BigInteger& notes,
  20. const int midiNoteForNormalPitch,
  21. const double attackTimeSecs,
  22. const double releaseTimeSecs,
  23. const double maxSampleLengthSeconds)
  24. : name (soundName),
  25. midiNotes (notes),
  26. midiRootNote (midiNoteForNormalPitch)
  27. {
  28. sourceSampleRate = source.sampleRate;
  29. if (sourceSampleRate <= 0 || source.lengthInSamples <= 0)
  30. {
  31. length = 0;
  32. attackSamples = 0;
  33. releaseSamples = 0;
  34. }
  35. else
  36. {
  37. length = jmin ((int) source.lengthInSamples,
  38. (int) (maxSampleLengthSeconds * sourceSampleRate));
  39. data = new AudioSampleBuffer (jmin (2, (int) source.numChannels), length + 4);
  40. source.read (data, 0, length + 4, 0, true, true);
  41. attackSamples = roundToInt (attackTimeSecs * sourceSampleRate);
  42. releaseSamples = roundToInt (releaseTimeSecs * sourceSampleRate);
  43. }
  44. }
  45. SamplerSound::~SamplerSound()
  46. {
  47. }
  48. bool SamplerSound::appliesToNote (int midiNoteNumber)
  49. {
  50. return midiNotes [midiNoteNumber];
  51. }
  52. bool SamplerSound::appliesToChannel (int /*midiChannel*/)
  53. {
  54. return true;
  55. }
  56. //==============================================================================
  57. SamplerVoice::SamplerVoice()
  58. : pitchRatio (0.0),
  59. sourceSamplePosition (0.0),
  60. lgain (0.0f), rgain (0.0f),
  61. attackReleaseLevel (0), attackDelta (0), releaseDelta (0),
  62. isInAttack (false), isInRelease (false)
  63. {
  64. }
  65. SamplerVoice::~SamplerVoice()
  66. {
  67. }
  68. bool SamplerVoice::canPlaySound (SynthesiserSound* sound)
  69. {
  70. return dynamic_cast<const SamplerSound*> (sound) != nullptr;
  71. }
  72. void SamplerVoice::startNote (const int midiNoteNumber,
  73. const float velocity,
  74. SynthesiserSound* s,
  75. const int /*currentPitchWheelPosition*/)
  76. {
  77. if (const SamplerSound* const sound = dynamic_cast <const SamplerSound*> (s))
  78. {
  79. pitchRatio = pow (2.0, (midiNoteNumber - sound->midiRootNote) / 12.0)
  80. * sound->sourceSampleRate / getSampleRate();
  81. sourceSamplePosition = 0.0;
  82. lgain = velocity;
  83. rgain = velocity;
  84. isInAttack = (sound->attackSamples > 0);
  85. isInRelease = false;
  86. if (isInAttack)
  87. {
  88. attackReleaseLevel = 0.0f;
  89. attackDelta = (float) (pitchRatio / sound->attackSamples);
  90. }
  91. else
  92. {
  93. attackReleaseLevel = 1.0f;
  94. attackDelta = 0.0f;
  95. }
  96. if (sound->releaseSamples > 0)
  97. releaseDelta = (float) (-pitchRatio / sound->releaseSamples);
  98. else
  99. releaseDelta = -1.0f;
  100. }
  101. else
  102. {
  103. jassertfalse; // this object can only play SamplerSounds!
  104. }
  105. }
  106. void SamplerVoice::stopNote (float /*velocity*/, bool allowTailOff)
  107. {
  108. if (allowTailOff)
  109. {
  110. isInAttack = false;
  111. isInRelease = true;
  112. }
  113. else
  114. {
  115. clearCurrentNote();
  116. }
  117. }
  118. void SamplerVoice::pitchWheelMoved (const int /*newValue*/)
  119. {
  120. }
  121. void SamplerVoice::controllerMoved (const int /*controllerNumber*/,
  122. const int /*newValue*/)
  123. {
  124. }
  125. //==============================================================================
  126. void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples)
  127. {
  128. if (const SamplerSound* const playingSound = static_cast <SamplerSound*> (getCurrentlyPlayingSound().get()))
  129. {
  130. const float* const inL = playingSound->data->getReadPointer (0);
  131. const float* const inR = playingSound->data->getNumChannels() > 1
  132. ? playingSound->data->getReadPointer (1) : nullptr;
  133. float* outL = outputBuffer.getWritePointer (0, startSample);
  134. float* outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getWritePointer (1, startSample) : nullptr;
  135. while (--numSamples >= 0)
  136. {
  137. const int pos = (int) sourceSamplePosition;
  138. const float alpha = (float) (sourceSamplePosition - pos);
  139. const float invAlpha = 1.0f - alpha;
  140. // just using a very simple linear interpolation here..
  141. float l = (inL [pos] * invAlpha + inL [pos + 1] * alpha);
  142. float r = (inR != nullptr) ? (inR [pos] * invAlpha + inR [pos + 1] * alpha)
  143. : l;
  144. l *= lgain;
  145. r *= rgain;
  146. if (isInAttack)
  147. {
  148. l *= attackReleaseLevel;
  149. r *= attackReleaseLevel;
  150. attackReleaseLevel += attackDelta;
  151. if (attackReleaseLevel >= 1.0f)
  152. {
  153. attackReleaseLevel = 1.0f;
  154. isInAttack = false;
  155. }
  156. }
  157. else if (isInRelease)
  158. {
  159. l *= attackReleaseLevel;
  160. r *= attackReleaseLevel;
  161. attackReleaseLevel += releaseDelta;
  162. if (attackReleaseLevel <= 0.0f)
  163. {
  164. stopNote (0.0f, false);
  165. break;
  166. }
  167. }
  168. if (outR != nullptr)
  169. {
  170. *outL++ += l;
  171. *outR++ += r;
  172. }
  173. else
  174. {
  175. *outL++ += (l + r) * 0.5f;
  176. }
  177. sourceSamplePosition += pitchRatio;
  178. if (sourceSamplePosition > playingSound->length)
  179. {
  180. stopNote (0.0f, false);
  181. break;
  182. }
  183. }
  184. }
  185. }