OpenShot Library | OpenShotAudio  0.2.2
juce_Sampler.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
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 5 End-User License
11  Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12  27th April 2017).
13 
14  End User License Agreement: www.juce.com/juce-5-licence
15  Privacy Policy: www.juce.com/juce-5-privacy-policy
16 
17  Or: You may also use this code under the terms of the GPL v3 (see
18  www.gnu.org/licenses).
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 
31  AudioFormatReader& source,
32  const BigInteger& notes,
33  int midiNoteForNormalPitch,
34  double attackTimeSecs,
35  double releaseTimeSecs,
36  double maxSampleLengthSeconds)
37  : name (soundName),
38  sourceSampleRate (source.sampleRate),
39  midiNotes (notes),
40  midiRootNote (midiNoteForNormalPitch)
41 {
42  if (sourceSampleRate > 0 && source.lengthInSamples > 0)
43  {
44  length = jmin ((int) source.lengthInSamples,
45  (int) (maxSampleLengthSeconds * sourceSampleRate));
46 
47  data.reset (new AudioBuffer<float> (jmin (2, (int) source.numChannels), length + 4));
48 
49  source.read (data.get(), 0, length + 4, 0, true, true);
50 
51  params.attack = static_cast<float> (attackTimeSecs);
52  params.release = static_cast<float> (releaseTimeSecs);
53  }
54 }
55 
57 {
58 }
59 
60 bool SamplerSound::appliesToNote (int midiNoteNumber)
61 {
62  return midiNotes[midiNoteNumber];
63 }
64 
65 bool SamplerSound::appliesToChannel (int /*midiChannel*/)
66 {
67  return true;
68 }
69 
70 //==============================================================================
73 
75 {
76  return dynamic_cast<const SamplerSound*> (sound) != nullptr;
77 }
78 
79 void SamplerVoice::startNote (int midiNoteNumber, float velocity, SynthesiserSound* s, int /*currentPitchWheelPosition*/)
80 {
81  if (auto* sound = dynamic_cast<const SamplerSound*> (s))
82  {
83  pitchRatio = std::pow (2.0, (midiNoteNumber - sound->midiRootNote) / 12.0)
84  * sound->sourceSampleRate / getSampleRate();
85 
86  sourceSamplePosition = 0.0;
87  lgain = velocity;
88  rgain = velocity;
89 
90  adsr.setSampleRate (sound->sourceSampleRate);
91  adsr.setParameters (sound->params);
92 
93  adsr.noteOn();
94  }
95  else
96  {
97  jassertfalse; // this object can only play SamplerSounds!
98  }
99 }
100 
101 void SamplerVoice::stopNote (float /*velocity*/, bool allowTailOff)
102 {
103  if (allowTailOff)
104  {
105  adsr.noteOff();
106  }
107  else
108  {
110  adsr.reset();
111  }
112 }
113 
114 void SamplerVoice::pitchWheelMoved (int /*newValue*/) {}
115 void SamplerVoice::controllerMoved (int /*controllerNumber*/, int /*newValue*/) {}
116 
117 //==============================================================================
118 void SamplerVoice::renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples)
119 {
120  if (auto* playingSound = static_cast<SamplerSound*> (getCurrentlyPlayingSound().get()))
121  {
122  auto& data = *playingSound->data;
123  const float* const inL = data.getReadPointer (0);
124  const float* const inR = data.getNumChannels() > 1 ? data.getReadPointer (1) : nullptr;
125 
126  float* outL = outputBuffer.getWritePointer (0, startSample);
127  float* outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getWritePointer (1, startSample) : nullptr;
128 
129  while (--numSamples >= 0)
130  {
131  auto pos = (int) sourceSamplePosition;
132  auto alpha = (float) (sourceSamplePosition - pos);
133  auto invAlpha = 1.0f - alpha;
134 
135  // just using a very simple linear interpolation here..
136  float l = (inL[pos] * invAlpha + inL[pos + 1] * alpha);
137  float r = (inR != nullptr) ? (inR[pos] * invAlpha + inR[pos + 1] * alpha)
138  : l;
139 
140  auto envelopeValue = adsr.getNextSample();
141 
142  l *= lgain * envelopeValue;
143  r *= rgain * envelopeValue;
144 
145  if (outR != nullptr)
146  {
147  *outL++ += l;
148  *outR++ += r;
149  }
150  else
151  {
152  *outL++ += (l + r) * 0.5f;
153  }
154 
155  sourceSamplePosition += pitchRatio;
156 
157  if (sourceSamplePosition > playingSound->length)
158  {
159  stopNote (0.0f, false);
160  break;
161  }
162  }
163  }
164 }
165 
166 } // namespace juce
void setSampleRate(double sampleRate)
Sets the sample rate that will be used for the envelope.
Definition: juce_ADSR.h:103
void setParameters(const Parameters &newParameters)
Sets the parameters that will be used by an ADSR object.
Definition: juce_ADSR.h:78
void noteOff()
Starts the release phase of the envelope.
Definition: juce_ADSR.h:136
float attack
Attack time in seconds.
Definition: juce_ADSR.h:59
float getNextSample()
Returns the next sample value for an ADSR object.
Definition: juce_ADSR.h:157
void noteOn()
Starts the attack phase of the envelope.
Definition: juce_ADSR.h:118
void reset()
Resets the envelope to an idle state.
Definition: juce_ADSR.h:111
float release
Release time in seconds.
Definition: juce_ADSR.h:68
Type * getWritePointer(int channelNumber) noexcept
Returns a writeable pointer to one of the buffer's channels.
int getNumChannels() const noexcept
Returns the number of channels of audio data that this buffer contains.
Reads samples from an audio file stream.
bool read(float *const *destChannels, int numDestChannels, int64 startSampleInSource, int numSamplesToRead)
Reads samples from the stream.
int64 lengthInSamples
The total number of samples in the audio stream.
unsigned int numChannels
The total number of channels in the audio stream.
An arbitrarily large integer class.
A subclass of SynthesiserSound that represents a sampled audio clip.
Definition: juce_Sampler.h:49
bool appliesToChannel(int midiChannel) override
Returns true if the sound should be triggered by midi events on a given channel.
SamplerSound(const String &name, AudioFormatReader &source, const BigInteger &midiNotes, int midiNoteForNormalPitch, double attackTimeSecs, double releaseTimeSecs, double maxSampleLengthSeconds)
Creates a sampled sound from an audio reader.
bool appliesToNote(int midiNoteNumber) override
Returns true if this sound should be played when a given midi note is pressed.
~SamplerSound() override
Destructor.
~SamplerVoice() override
Destructor.
void startNote(int midiNoteNumber, float velocity, SynthesiserSound *, int pitchWheel) override
Called to start a new note.
void controllerMoved(int controllerNumber, int newValue) override
Called to let the voice know that a midi controller has been moved.
bool canPlaySound(SynthesiserSound *) override
Must return true if this voice object is capable of playing the given sound.
virtual void renderNextBlock(AudioBuffer< float > &outputBuffer, int startSample, int numSamples)=0
Renders the next block of data for this voice.
void pitchWheelMoved(int newValue) override
Called to let the voice know that the pitch wheel has been moved.
SamplerVoice()
Creates a SamplerVoice.
void stopNote(float velocity, bool allowTailOff) override
Called to stop a note.
The JUCE String class!
Definition: juce_String.h:43
Describes one of the sounds that a Synthesiser can play.
double getSampleRate() const noexcept
Returns the current target sample rate at which rendering is being done.
void clearCurrentNote()
Resets the state of this voice after a sound has finished playing.
SynthesiserSound::Ptr getCurrentlyPlayingSound() const noexcept
Returns the sound that this voice is currently playing.