OpenShot Library | OpenShotAudio  0.2.1
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  {
109  clearCurrentNote();
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
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.
~SamplerSound() override
Destructor.
float attack
Attack time in seconds.
Definition: juce_ADSR.h:59
float release
Release time in seconds.
Definition: juce_ADSR.h:68
bool canPlaySound(SynthesiserSound *) override
Must return true if this voice object is capable of playing the given sound.
int64 lengthInSamples
The total number of samples in the audio stream.
The JUCE String class!
Definition: juce_String.h:42
void pitchWheelMoved(int newValue) override
Called to let the voice know that the pitch wheel has been moved.
Describes one of the sounds that a Synthesiser can play.
An arbitrarily large integer class.
void stopNote(float velocity, bool allowTailOff) override
Called to stop a note.
int getNumChannels() const noexcept
Returns the number of channels of audio data that this buffer contains.
~SamplerVoice() override
Destructor.
void controllerMoved(int controllerNumber, int newValue) override
Called to let the voice know that a midi controller has been moved.
void startNote(int midiNoteNumber, float velocity, SynthesiserSound *, int pitchWheel) override
Called to start a new note.
bool appliesToChannel(int midiChannel) override
Returns true if the sound should be triggered by midi events on a given channel.
bool appliesToNote(int midiNoteNumber) override
Returns true if this sound should be played when a given midi note is pressed.
bool read(float *const *destChannels, int numDestChannels, int64 startSampleInSource, int numSamplesToRead)
Reads samples from the stream.
Type * getWritePointer(int channelNumber) noexcept
Returns a writeable pointer to one of the buffer&#39;s channels.
Reads samples from an audio file stream.
A subclass of SynthesiserSound that represents a sampled audio clip.
Definition: juce_Sampler.h:48
SamplerVoice()
Creates a SamplerVoice.
void renderNextBlock(AudioBuffer< float > &, int startSample, int numSamples) override
Renders the next block of data for this voice.
unsigned int numChannels
The total number of channels in the audio stream.