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.

166 lines
5.1KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  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 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. SamplerSound::SamplerSound (const String& soundName,
  21. AudioFormatReader& source,
  22. const BigInteger& notes,
  23. int midiNoteForNormalPitch,
  24. double attackTimeSecs,
  25. double releaseTimeSecs,
  26. double maxSampleLengthSeconds)
  27. : name (soundName),
  28. sourceSampleRate (source.sampleRate),
  29. midiNotes (notes),
  30. midiRootNote (midiNoteForNormalPitch)
  31. {
  32. if (sourceSampleRate > 0 && source.lengthInSamples > 0)
  33. {
  34. length = jmin ((int) source.lengthInSamples,
  35. (int) (maxSampleLengthSeconds * sourceSampleRate));
  36. data.reset (new AudioBuffer<float> (jmin (2, (int) source.numChannels), length + 4));
  37. source.read (data.get(), 0, length + 4, 0, true, true);
  38. params.attack = static_cast<float> (attackTimeSecs);
  39. params.release = static_cast<float> (releaseTimeSecs);
  40. }
  41. }
  42. SamplerSound::~SamplerSound()
  43. {
  44. }
  45. bool SamplerSound::appliesToNote (int midiNoteNumber)
  46. {
  47. return midiNotes[midiNoteNumber];
  48. }
  49. bool SamplerSound::appliesToChannel (int /*midiChannel*/)
  50. {
  51. return true;
  52. }
  53. //==============================================================================
  54. SamplerVoice::SamplerVoice() {}
  55. SamplerVoice::~SamplerVoice() {}
  56. bool SamplerVoice::canPlaySound (SynthesiserSound* sound)
  57. {
  58. return dynamic_cast<const SamplerSound*> (sound) != nullptr;
  59. }
  60. void SamplerVoice::startNote (int midiNoteNumber, float velocity, SynthesiserSound* s, int /*currentPitchWheelPosition*/)
  61. {
  62. if (auto* sound = dynamic_cast<const SamplerSound*> (s))
  63. {
  64. pitchRatio = std::pow (2.0, (midiNoteNumber - sound->midiRootNote) / 12.0)
  65. * sound->sourceSampleRate / getSampleRate();
  66. sourceSamplePosition = 0.0;
  67. lgain = velocity;
  68. rgain = velocity;
  69. adsr.setSampleRate (sound->sourceSampleRate);
  70. adsr.setParameters (sound->params);
  71. adsr.noteOn();
  72. }
  73. else
  74. {
  75. jassertfalse; // this object can only play SamplerSounds!
  76. }
  77. }
  78. void SamplerVoice::stopNote (float /*velocity*/, bool allowTailOff)
  79. {
  80. if (allowTailOff)
  81. {
  82. adsr.noteOff();
  83. }
  84. else
  85. {
  86. clearCurrentNote();
  87. adsr.reset();
  88. }
  89. }
  90. void SamplerVoice::pitchWheelMoved (int /*newValue*/) {}
  91. void SamplerVoice::controllerMoved (int /*controllerNumber*/, int /*newValue*/) {}
  92. //==============================================================================
  93. void SamplerVoice::renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples)
  94. {
  95. if (auto* playingSound = static_cast<SamplerSound*> (getCurrentlyPlayingSound().get()))
  96. {
  97. auto& data = *playingSound->data;
  98. const float* const inL = data.getReadPointer (0);
  99. const float* const inR = data.getNumChannels() > 1 ? data.getReadPointer (1) : nullptr;
  100. float* outL = outputBuffer.getWritePointer (0, startSample);
  101. float* outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getWritePointer (1, startSample) : nullptr;
  102. while (--numSamples >= 0)
  103. {
  104. auto pos = (int) sourceSamplePosition;
  105. auto alpha = (float) (sourceSamplePosition - pos);
  106. auto invAlpha = 1.0f - alpha;
  107. // just using a very simple linear interpolation here..
  108. float l = (inL[pos] * invAlpha + inL[pos + 1] * alpha);
  109. float r = (inR != nullptr) ? (inR[pos] * invAlpha + inR[pos + 1] * alpha)
  110. : l;
  111. auto envelopeValue = adsr.getNextSample();
  112. l *= lgain * envelopeValue;
  113. r *= rgain * envelopeValue;
  114. if (outR != nullptr)
  115. {
  116. *outL++ += l;
  117. *outR++ += r;
  118. }
  119. else
  120. {
  121. *outL++ += (l + r) * 0.5f;
  122. }
  123. sourceSamplePosition += pitchRatio;
  124. if (sourceSamplePosition > playingSound->length)
  125. {
  126. stopNote (0.0f, false);
  127. break;
  128. }
  129. }
  130. }
  131. }
  132. } // namespace juce