The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

227 lines
6.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. SamplerSound::SamplerSound (const String& name_,
  19. AudioFormatReader& source,
  20. const BigInteger& midiNotes_,
  21. const int midiNoteForNormalPitch,
  22. const double attackTimeSecs,
  23. const double releaseTimeSecs,
  24. const double maxSampleLengthSeconds)
  25. : name (name_),
  26. midiNotes (midiNotes_),
  27. midiRootNote (midiNoteForNormalPitch)
  28. {
  29. sourceSampleRate = source.sampleRate;
  30. if (sourceSampleRate <= 0 || source.lengthInSamples <= 0)
  31. {
  32. length = 0;
  33. attackSamples = 0;
  34. releaseSamples = 0;
  35. }
  36. else
  37. {
  38. length = jmin ((int) source.lengthInSamples,
  39. (int) (maxSampleLengthSeconds * sourceSampleRate));
  40. data = new AudioSampleBuffer (jmin (2, (int) source.numChannels), length + 4);
  41. source.read (data, 0, length + 4, 0, true, true);
  42. attackSamples = roundToInt (attackTimeSecs * sourceSampleRate);
  43. releaseSamples = roundToInt (releaseTimeSecs * sourceSampleRate);
  44. }
  45. }
  46. SamplerSound::~SamplerSound()
  47. {
  48. }
  49. bool SamplerSound::appliesToNote (const int midiNoteNumber)
  50. {
  51. return midiNotes [midiNoteNumber];
  52. }
  53. bool SamplerSound::appliesToChannel (const int /*midiChannel*/)
  54. {
  55. return true;
  56. }
  57. //==============================================================================
  58. SamplerVoice::SamplerVoice()
  59. : pitchRatio (0.0),
  60. sourceSamplePosition (0.0),
  61. lgain (0.0f),
  62. rgain (0.0f),
  63. isInAttack (false),
  64. isInRelease (false)
  65. {
  66. }
  67. SamplerVoice::~SamplerVoice()
  68. {
  69. }
  70. bool SamplerVoice::canPlaySound (SynthesiserSound* sound)
  71. {
  72. return dynamic_cast <const SamplerSound*> (sound) != nullptr;
  73. }
  74. void SamplerVoice::startNote (const int midiNoteNumber,
  75. const float velocity,
  76. SynthesiserSound* s,
  77. const int /*currentPitchWheelPosition*/)
  78. {
  79. const SamplerSound* const sound = dynamic_cast <const SamplerSound*> (s);
  80. jassert (sound != nullptr); // this object can only play SamplerSounds!
  81. if (sound != nullptr)
  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 = 0.0f;
  104. }
  105. }
  106. void SamplerVoice::stopNote (const 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->getSampleData (0, 0);
  131. const float* const inR = playingSound->data->getNumChannels() > 1
  132. ? playingSound->data->getSampleData (1, 0) : nullptr;
  133. float* outL = outputBuffer.getSampleData (0, startSample);
  134. float* outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getSampleData (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 (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 (false);
  181. break;
  182. }
  183. }
  184. }
  185. }