git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
165
deps/juce/modules/juce_audio_formats/sampler/juce_Sampler.cpp
vendored
Normal file
165
deps/juce/modules/juce_audio_formats/sampler/juce_Sampler.cpp
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
SamplerSound::SamplerSound (const String& soundName,
|
||||
AudioFormatReader& source,
|
||||
const BigInteger& notes,
|
||||
int midiNoteForNormalPitch,
|
||||
double attackTimeSecs,
|
||||
double releaseTimeSecs,
|
||||
double maxSampleLengthSeconds)
|
||||
: name (soundName),
|
||||
sourceSampleRate (source.sampleRate),
|
||||
midiNotes (notes),
|
||||
midiRootNote (midiNoteForNormalPitch)
|
||||
{
|
||||
if (sourceSampleRate > 0 && source.lengthInSamples > 0)
|
||||
{
|
||||
length = jmin ((int) source.lengthInSamples,
|
||||
(int) (maxSampleLengthSeconds * sourceSampleRate));
|
||||
|
||||
data.reset (new AudioBuffer<float> (jmin (2, (int) source.numChannels), length + 4));
|
||||
|
||||
source.read (data.get(), 0, length + 4, 0, true, true);
|
||||
|
||||
params.attack = static_cast<float> (attackTimeSecs);
|
||||
params.release = static_cast<float> (releaseTimeSecs);
|
||||
}
|
||||
}
|
||||
|
||||
SamplerSound::~SamplerSound()
|
||||
{
|
||||
}
|
||||
|
||||
bool SamplerSound::appliesToNote (int midiNoteNumber)
|
||||
{
|
||||
return midiNotes[midiNoteNumber];
|
||||
}
|
||||
|
||||
bool SamplerSound::appliesToChannel (int /*midiChannel*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SamplerVoice::SamplerVoice() {}
|
||||
SamplerVoice::~SamplerVoice() {}
|
||||
|
||||
bool SamplerVoice::canPlaySound (SynthesiserSound* sound)
|
||||
{
|
||||
return dynamic_cast<const SamplerSound*> (sound) != nullptr;
|
||||
}
|
||||
|
||||
void SamplerVoice::startNote (int midiNoteNumber, float velocity, SynthesiserSound* s, int /*currentPitchWheelPosition*/)
|
||||
{
|
||||
if (auto* sound = dynamic_cast<const SamplerSound*> (s))
|
||||
{
|
||||
pitchRatio = std::pow (2.0, (midiNoteNumber - sound->midiRootNote) / 12.0)
|
||||
* sound->sourceSampleRate / getSampleRate();
|
||||
|
||||
sourceSamplePosition = 0.0;
|
||||
lgain = velocity;
|
||||
rgain = velocity;
|
||||
|
||||
adsr.setSampleRate (sound->sourceSampleRate);
|
||||
adsr.setParameters (sound->params);
|
||||
|
||||
adsr.noteOn();
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse; // this object can only play SamplerSounds!
|
||||
}
|
||||
}
|
||||
|
||||
void SamplerVoice::stopNote (float /*velocity*/, bool allowTailOff)
|
||||
{
|
||||
if (allowTailOff)
|
||||
{
|
||||
adsr.noteOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
clearCurrentNote();
|
||||
adsr.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void SamplerVoice::pitchWheelMoved (int /*newValue*/) {}
|
||||
void SamplerVoice::controllerMoved (int /*controllerNumber*/, int /*newValue*/) {}
|
||||
|
||||
//==============================================================================
|
||||
void SamplerVoice::renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples)
|
||||
{
|
||||
if (auto* playingSound = static_cast<SamplerSound*> (getCurrentlyPlayingSound().get()))
|
||||
{
|
||||
auto& data = *playingSound->data;
|
||||
const float* const inL = data.getReadPointer (0);
|
||||
const float* const inR = data.getNumChannels() > 1 ? data.getReadPointer (1) : nullptr;
|
||||
|
||||
float* outL = outputBuffer.getWritePointer (0, startSample);
|
||||
float* outR = outputBuffer.getNumChannels() > 1 ? outputBuffer.getWritePointer (1, startSample) : nullptr;
|
||||
|
||||
while (--numSamples >= 0)
|
||||
{
|
||||
auto pos = (int) sourceSamplePosition;
|
||||
auto alpha = (float) (sourceSamplePosition - pos);
|
||||
auto invAlpha = 1.0f - alpha;
|
||||
|
||||
// just using a very simple linear interpolation here..
|
||||
float l = (inL[pos] * invAlpha + inL[pos + 1] * alpha);
|
||||
float r = (inR != nullptr) ? (inR[pos] * invAlpha + inR[pos + 1] * alpha)
|
||||
: l;
|
||||
|
||||
auto envelopeValue = adsr.getNextSample();
|
||||
|
||||
l *= lgain * envelopeValue;
|
||||
r *= rgain * envelopeValue;
|
||||
|
||||
if (outR != nullptr)
|
||||
{
|
||||
*outL++ += l;
|
||||
*outR++ += r;
|
||||
}
|
||||
else
|
||||
{
|
||||
*outL++ += (l + r) * 0.5f;
|
||||
}
|
||||
|
||||
sourceSamplePosition += pitchRatio;
|
||||
|
||||
if (sourceSamplePosition > playingSound->length)
|
||||
{
|
||||
stopNote (0.0f, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace juce
|
153
deps/juce/modules/juce_audio_formats/sampler/juce_Sampler.h
vendored
Normal file
153
deps/juce/modules/juce_audio_formats/sampler/juce_Sampler.h
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A subclass of SynthesiserSound that represents a sampled audio clip.
|
||||
|
||||
This is a pretty basic sampler, and just attempts to load the whole audio stream
|
||||
into memory.
|
||||
|
||||
To use it, create a Synthesiser, add some SamplerVoice objects to it, then
|
||||
give it some SampledSound objects to play.
|
||||
|
||||
@see SamplerVoice, Synthesiser, SynthesiserSound
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API SamplerSound : public SynthesiserSound
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a sampled sound from an audio reader.
|
||||
|
||||
This will attempt to load the audio from the source into memory and store
|
||||
it in this object.
|
||||
|
||||
@param name a name for the sample
|
||||
@param source the audio to load. This object can be safely deleted by the
|
||||
caller after this constructor returns
|
||||
@param midiNotes the set of midi keys that this sound should be played on. This
|
||||
is used by the SynthesiserSound::appliesToNote() method
|
||||
@param midiNoteForNormalPitch the midi note at which the sample should be played
|
||||
with its natural rate. All other notes will be pitched
|
||||
up or down relative to this one
|
||||
@param attackTimeSecs the attack (fade-in) time, in seconds
|
||||
@param releaseTimeSecs the decay (fade-out) time, in seconds
|
||||
@param maxSampleLengthSeconds a maximum length of audio to read from the audio
|
||||
source, in seconds
|
||||
*/
|
||||
SamplerSound (const String& name,
|
||||
AudioFormatReader& source,
|
||||
const BigInteger& midiNotes,
|
||||
int midiNoteForNormalPitch,
|
||||
double attackTimeSecs,
|
||||
double releaseTimeSecs,
|
||||
double maxSampleLengthSeconds);
|
||||
|
||||
/** Destructor. */
|
||||
~SamplerSound() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the sample's name */
|
||||
const String& getName() const noexcept { return name; }
|
||||
|
||||
/** Returns the audio sample data.
|
||||
This could return nullptr if there was a problem loading the data.
|
||||
*/
|
||||
AudioBuffer<float>* getAudioData() const noexcept { return data.get(); }
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the parameters of the ADSR envelope which will be applied to the sample. */
|
||||
void setEnvelopeParameters (ADSR::Parameters parametersToUse) { params = parametersToUse; }
|
||||
|
||||
//==============================================================================
|
||||
bool appliesToNote (int midiNoteNumber) override;
|
||||
bool appliesToChannel (int midiChannel) override;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
friend class SamplerVoice;
|
||||
|
||||
String name;
|
||||
std::unique_ptr<AudioBuffer<float>> data;
|
||||
double sourceSampleRate;
|
||||
BigInteger midiNotes;
|
||||
int length = 0, midiRootNote = 0;
|
||||
|
||||
ADSR::Parameters params;
|
||||
|
||||
JUCE_LEAK_DETECTOR (SamplerSound)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A subclass of SynthesiserVoice that can play a SamplerSound.
|
||||
|
||||
To use it, create a Synthesiser, add some SamplerVoice objects to it, then
|
||||
give it some SampledSound objects to play.
|
||||
|
||||
@see SamplerSound, Synthesiser, SynthesiserVoice
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API SamplerVoice : public SynthesiserVoice
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a SamplerVoice. */
|
||||
SamplerVoice();
|
||||
|
||||
/** Destructor. */
|
||||
~SamplerVoice() override;
|
||||
|
||||
//==============================================================================
|
||||
bool canPlaySound (SynthesiserSound*) override;
|
||||
|
||||
void startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int pitchWheel) override;
|
||||
void stopNote (float velocity, bool allowTailOff) override;
|
||||
|
||||
void pitchWheelMoved (int newValue) override;
|
||||
void controllerMoved (int controllerNumber, int newValue) override;
|
||||
|
||||
void renderNextBlock (AudioBuffer<float>&, int startSample, int numSamples) override;
|
||||
using SynthesiserVoice::renderNextBlock;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
double pitchRatio = 0;
|
||||
double sourceSamplePosition = 0;
|
||||
float lgain = 0, rgain = 0;
|
||||
|
||||
ADSR adsr;
|
||||
|
||||
JUCE_LEAK_DETECTOR (SamplerVoice)
|
||||
};
|
||||
|
||||
} // namespace juce
|
Reference in New Issue
Block a user