OpenShot Library | libopenshot-audio 0.2.0
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
27namespace 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
60bool SamplerSound::appliesToNote (int midiNoteNumber)
61{
62 return midiNotes[midiNoteNumber];
63}
64
65bool SamplerSound::appliesToChannel (int /*midiChannel*/)
66{
67 return true;
68}
69
70//==============================================================================
73
75{
76 return dynamic_cast<const SamplerSound*> (sound) != nullptr;
77}
78
79void 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
101void SamplerVoice::stopNote (float /*velocity*/, bool allowTailOff)
102{
103 if (allowTailOff)
104 {
105 adsr.noteOff();
106 }
107 else
108 {
110 adsr.reset();
111 }
112}
113
114void SamplerVoice::pitchWheelMoved (int /*newValue*/) {}
115void SamplerVoice::controllerMoved (int /*controllerNumber*/, int /*newValue*/) {}
116
117//==============================================================================
118void 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:97
void setParameters(const Parameters &newParameters)
Sets the parameters that will be used by an ADSR object.
Definition juce_ADSR.h:72
void noteOff()
Starts the release phase of the envelope.
Definition juce_ADSR.h:120
float getNextSample()
Returns the next sample value for an ADSR object.
Definition juce_ADSR.h:143
void noteOn()
Starts the attack phase of the envelope.
Definition juce_ADSR.h:112
void reset()
Resets the envelope to an idle state.
Definition juce_ADSR.h:105
A multi-channel buffer containing floating point audio samples.
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.
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.
void renderNextBlock(AudioBuffer< float > &, int startSample, int numSamples) override
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.
float attack
Attack time in seconds.
Definition juce_ADSR.h:53
float release
Release time in seconds.
Definition juce_ADSR.h:62