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