- Library code update
- project update (added Eigen) git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@94 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
@@ -163,10 +163,7 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
|
||||
: numSamples;
|
||||
|
||||
if (numThisTime > 0)
|
||||
{
|
||||
for (int i = voices.size(); --i >= 0;)
|
||||
voices.getUnchecked (i)->renderNextBlock (outputBuffer, startSample, numThisTime);
|
||||
}
|
||||
renderVoices (outputBuffer, startSample, numThisTime);
|
||||
|
||||
if (useEvent)
|
||||
handleMidiEvent (m);
|
||||
@@ -176,6 +173,12 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
|
||||
}
|
||||
}
|
||||
|
||||
void Synthesiser::renderVoices (AudioSampleBuffer& buffer, int startSample, int numSamples)
|
||||
{
|
||||
for (int i = voices.size(); --i >= 0;)
|
||||
voices.getUnchecked (i)->renderNextBlock (buffer, startSample, numSamples);
|
||||
}
|
||||
|
||||
void Synthesiser::handleMidiEvent (const MidiMessage& m)
|
||||
{
|
||||
if (m.isNoteOn())
|
||||
@@ -184,7 +187,7 @@ void Synthesiser::handleMidiEvent (const MidiMessage& m)
|
||||
}
|
||||
else if (m.isNoteOff())
|
||||
{
|
||||
noteOff (m.getChannel(), m.getNoteNumber(), true);
|
||||
noteOff (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity(), true);
|
||||
}
|
||||
else if (m.isAllNotesOff() || m.isAllSoundOff())
|
||||
{
|
||||
@@ -230,10 +233,10 @@ void Synthesiser::noteOn (const int midiChannel,
|
||||
|
||||
if (voice->getCurrentlyPlayingNote() == midiNoteNumber
|
||||
&& voice->isPlayingChannel (midiChannel))
|
||||
stopVoice (voice, true);
|
||||
stopVoice (voice, 1.0f, true);
|
||||
}
|
||||
|
||||
startVoice (findFreeVoice (sound, shouldStealNotes),
|
||||
startVoice (findFreeVoice (sound, midiChannel, midiNoteNumber, shouldStealNotes),
|
||||
sound, midiChannel, midiNoteNumber, velocity);
|
||||
}
|
||||
}
|
||||
@@ -248,7 +251,7 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice,
|
||||
if (voice != nullptr && sound != nullptr)
|
||||
{
|
||||
if (voice->currentlyPlayingSound != nullptr)
|
||||
voice->stopNote (false);
|
||||
voice->stopNote (0.0f, false);
|
||||
|
||||
voice->startNote (midiNoteNumber, velocity, sound,
|
||||
lastPitchWheelValues [midiChannel - 1]);
|
||||
@@ -261,11 +264,11 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice,
|
||||
}
|
||||
}
|
||||
|
||||
void Synthesiser::stopVoice (SynthesiserVoice* voice, const bool allowTailOff)
|
||||
void Synthesiser::stopVoice (SynthesiserVoice* voice, float velocity, const bool allowTailOff)
|
||||
{
|
||||
jassert (voice != nullptr);
|
||||
|
||||
voice->stopNote (allowTailOff);
|
||||
voice->stopNote (velocity, allowTailOff);
|
||||
|
||||
// the subclass MUST call clearCurrentNote() if it's not tailing off! RTFM for stopNote()!
|
||||
jassert (allowTailOff || (voice->getCurrentlyPlayingNote() < 0 && voice->getCurrentlyPlayingSound() == 0));
|
||||
@@ -273,6 +276,7 @@ void Synthesiser::stopVoice (SynthesiserVoice* voice, const bool allowTailOff)
|
||||
|
||||
void Synthesiser::noteOff (const int midiChannel,
|
||||
const int midiNoteNumber,
|
||||
const float velocity,
|
||||
const bool allowTailOff)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
@@ -291,7 +295,7 @@ void Synthesiser::noteOff (const int midiChannel,
|
||||
voice->keyIsDown = false;
|
||||
|
||||
if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown))
|
||||
stopVoice (voice, allowTailOff);
|
||||
stopVoice (voice, velocity, allowTailOff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,7 +311,7 @@ void Synthesiser::allNotesOff (const int midiChannel, const bool allowTailOff)
|
||||
SynthesiserVoice* const voice = voices.getUnchecked (i);
|
||||
|
||||
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
|
||||
voice->stopNote (allowTailOff);
|
||||
voice->stopNote (1.0f, allowTailOff);
|
||||
}
|
||||
|
||||
sustainPedalsDown.clear();
|
||||
@@ -379,7 +383,7 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
|
||||
SynthesiserVoice* const voice = voices.getUnchecked (i);
|
||||
|
||||
if (voice->isPlayingChannel (midiChannel) && ! voice->keyIsDown)
|
||||
stopVoice (voice, true);
|
||||
stopVoice (voice, 1.0f, true);
|
||||
}
|
||||
|
||||
sustainPedalsDown.clearBit (midiChannel);
|
||||
@@ -400,7 +404,7 @@ void Synthesiser::handleSostenutoPedal (int midiChannel, bool isDown)
|
||||
if (isDown)
|
||||
voice->sostenutoPedalDown = true;
|
||||
else if (voice->sostenutoPedalDown)
|
||||
stopVoice (voice, true);
|
||||
stopVoice (voice, 1.0f, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -412,7 +416,9 @@ void Synthesiser::handleSoftPedal (int midiChannel, bool /*isDown*/)
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, const bool stealIfNoneAvailable) const
|
||||
SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay,
|
||||
int midiChannel, int midiNoteNumber,
|
||||
const bool stealIfNoneAvailable) const
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
@@ -425,25 +431,68 @@ SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, con
|
||||
}
|
||||
|
||||
if (stealIfNoneAvailable)
|
||||
return findVoiceToSteal (soundToPlay);
|
||||
return findVoiceToSteal (soundToPlay, midiChannel, midiNoteNumber);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay) const
|
||||
struct VoiceAgeSorter
|
||||
{
|
||||
// currently this just steals the one that's been playing the longest, but could be made a bit smarter..
|
||||
SynthesiserVoice* oldest = nullptr;
|
||||
static int compareElements (SynthesiserVoice* v1, SynthesiserVoice* v2) noexcept
|
||||
{
|
||||
return v1->wasStartedBefore (*v2) ? 1 : (v2->wasStartedBefore (*v1) ? -1 : 0);
|
||||
}
|
||||
};
|
||||
|
||||
SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
|
||||
int /*midiChannel*/, int midiNoteNumber) const
|
||||
{
|
||||
SynthesiserVoice* bottom = nullptr;
|
||||
SynthesiserVoice* top = nullptr;
|
||||
|
||||
// this is a list of voices we can steal, sorted by how long they've been running
|
||||
Array<SynthesiserVoice*> usableVoices;
|
||||
usableVoices.ensureStorageAllocated (voices.size());
|
||||
|
||||
for (int i = 0; i < voices.size(); ++i)
|
||||
{
|
||||
SynthesiserVoice* const voice = voices.getUnchecked (i);
|
||||
|
||||
if (voice->canPlaySound (soundToPlay)
|
||||
&& (oldest == nullptr || voice->wasStartedBefore (*oldest)))
|
||||
oldest = voice;
|
||||
if (voice->canPlaySound (soundToPlay))
|
||||
{
|
||||
VoiceAgeSorter sorter;
|
||||
usableVoices.addSorted (sorter, voice);
|
||||
|
||||
const int note = voice->getCurrentlyPlayingNote();
|
||||
|
||||
if (bottom == nullptr || note < bottom->getCurrentlyPlayingNote())
|
||||
bottom = voice;
|
||||
|
||||
if (top == nullptr || note > top->getCurrentlyPlayingNote())
|
||||
top = voice;
|
||||
}
|
||||
}
|
||||
|
||||
jassert (oldest != nullptr);
|
||||
return oldest;
|
||||
jassert (bottom != nullptr && top != nullptr);
|
||||
|
||||
// The oldest note that's playing with the target pitch playing is ideal..
|
||||
for (int i = 0; i < usableVoices.size(); ++i)
|
||||
{
|
||||
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
|
||||
|
||||
if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
|
||||
return voice;
|
||||
}
|
||||
|
||||
// ..otherwise, look for the oldest note that isn't the top or bottom note..
|
||||
for (int i = 0; i < usableVoices.size(); ++i)
|
||||
{
|
||||
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
|
||||
|
||||
if (voice != bottom && voice != top)
|
||||
return voice;
|
||||
}
|
||||
|
||||
// ..otherwise, there's only one or two voices to choose from - we'll return the top one..
|
||||
return top;
|
||||
}
|
||||
|
||||
@@ -55,14 +55,14 @@ public:
|
||||
The Synthesiser will use this information when deciding which sounds to trigger
|
||||
for a given note.
|
||||
*/
|
||||
virtual bool appliesToNote (const int midiNoteNumber) = 0;
|
||||
virtual bool appliesToNote (int midiNoteNumber) = 0;
|
||||
|
||||
/** Returns true if the sound should be triggered by midi events on a given channel.
|
||||
|
||||
The Synthesiser will use this information when deciding which sounds to trigger
|
||||
for a given note.
|
||||
*/
|
||||
virtual bool appliesToChannel (const int midiChannel) = 0;
|
||||
virtual bool appliesToChannel (int midiChannel) = 0;
|
||||
|
||||
/** The class is reference-counted, so this is a handy pointer class for it. */
|
||||
typedef ReferenceCountedObjectPtr<SynthesiserSound> Ptr;
|
||||
@@ -127,6 +127,8 @@ public:
|
||||
|
||||
This will be called during the rendering callback, so must be fast and thread-safe.
|
||||
|
||||
The velocity indicates how quickly the note was released - 0 is slowly, 1 is quickly.
|
||||
|
||||
If allowTailOff is false or the voice doesn't want to tail-off, then it must stop all
|
||||
sound immediately, and must call clearCurrentNote() to reset the state of this voice
|
||||
and allow the synth to reassign it another sound.
|
||||
@@ -136,7 +138,7 @@ public:
|
||||
finishes playing (during the rendering callback), it must make sure that it calls
|
||||
clearCurrentNote().
|
||||
*/
|
||||
virtual void stopNote (bool allowTailOff) = 0;
|
||||
virtual void stopNote (float velocity, bool allowTailOff) = 0;
|
||||
|
||||
/** Called to let the voice know that the pitch wheel has been moved.
|
||||
This will be called during the rendering callback, so must be fast and thread-safe.
|
||||
@@ -173,13 +175,6 @@ public:
|
||||
int startSample,
|
||||
int numSamples) = 0;
|
||||
|
||||
/** Returns true if the voice is currently playing a sound which is mapped to the given
|
||||
midi channel.
|
||||
|
||||
If it's not currently playing, this will return false.
|
||||
*/
|
||||
bool isPlayingChannel (int midiChannel) const;
|
||||
|
||||
/** Changes the voice's reference sample rate.
|
||||
|
||||
The rate is set so that subclasses know the output rate and can set their pitch
|
||||
@@ -188,7 +183,19 @@ public:
|
||||
This method is called by the synth, and subclasses can access the current rate with
|
||||
the currentSampleRate member.
|
||||
*/
|
||||
void setCurrentPlaybackSampleRate (double newRate);
|
||||
virtual void setCurrentPlaybackSampleRate (double newRate);
|
||||
|
||||
/** Returns the current target sample rate at which rendering is being done.
|
||||
Subclasses may need to know this so that they can pitch things correctly.
|
||||
*/
|
||||
double getSampleRate() const noexcept { return currentSampleRate; }
|
||||
|
||||
/** Returns true if the voice is currently playing a sound which is mapped to the given
|
||||
midi channel.
|
||||
|
||||
If it's not currently playing, this will return false.
|
||||
*/
|
||||
bool isPlayingChannel (int midiChannel) const;
|
||||
|
||||
/** Returns true if the key that triggered this voice is still held down.
|
||||
Note that the voice may still be playing after the key was released (e.g because the
|
||||
@@ -203,13 +210,6 @@ public:
|
||||
bool wasStartedBefore (const SynthesiserVoice& other) const noexcept;
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Returns the current target sample rate at which rendering is being done.
|
||||
|
||||
This is available for subclasses so they can pitch things correctly.
|
||||
*/
|
||||
double getSampleRate() const { return currentSampleRate; }
|
||||
|
||||
/** Resets the state of this voice after a sound has finished playing.
|
||||
|
||||
The subclass must call this when it finishes playing a note and becomes available
|
||||
@@ -235,6 +235,11 @@ private:
|
||||
SynthesiserSound::Ptr currentlyPlayingSound;
|
||||
bool keyIsDown, sostenutoPedalDown;
|
||||
|
||||
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
||||
// Note the new parameters for this method.
|
||||
virtual int stopNote (bool) { return 0; }
|
||||
#endif
|
||||
|
||||
JUCE_LEAK_DETECTOR (SynthesiserVoice)
|
||||
};
|
||||
|
||||
@@ -268,8 +273,7 @@ class JUCE_API Synthesiser
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a new synthesiser.
|
||||
|
||||
You'll need to add some sounds and voices before it'll make any sound..
|
||||
You'll need to add some sounds and voices before it'll make any sound.
|
||||
*/
|
||||
Synthesiser();
|
||||
|
||||
@@ -365,6 +369,7 @@ public:
|
||||
*/
|
||||
virtual void noteOff (int midiChannel,
|
||||
int midiNoteNumber,
|
||||
float velocity,
|
||||
bool allowTailOff);
|
||||
|
||||
/** Turns off all notes.
|
||||
@@ -444,7 +449,7 @@ public:
|
||||
This value is propagated to the voices so that they can use it to render the correct
|
||||
pitches.
|
||||
*/
|
||||
void setCurrentPlaybackSampleRate (double sampleRate);
|
||||
virtual void setCurrentPlaybackSampleRate (double sampleRate);
|
||||
|
||||
/** Creates the next block of audio output.
|
||||
|
||||
@@ -463,6 +468,11 @@ public:
|
||||
int startSample,
|
||||
int numSamples);
|
||||
|
||||
/** Returns the current target sample rate at which rendering is being done.
|
||||
Subclasses may need to know this so that they can pitch things correctly.
|
||||
*/
|
||||
double getSampleRate() const noexcept { return sampleRate; }
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** This is used to control access to the rendering callback and the note trigger methods. */
|
||||
@@ -474,21 +484,34 @@ protected:
|
||||
/** The last pitch-wheel values for each midi channel. */
|
||||
int lastPitchWheelValues [16];
|
||||
|
||||
/** Searches through the voices to find one that's not currently playing, and which
|
||||
can play the given sound.
|
||||
/** Renders the voices for the given range.
|
||||
By default this just calls renderNextBlock() on each voice, but you may need
|
||||
to override it to handle custom cases.
|
||||
*/
|
||||
virtual void renderVoices (AudioSampleBuffer& outputAudio,
|
||||
int startSample, int numSamples);
|
||||
|
||||
/** Searches through the voices to find one that's not currently playing, and
|
||||
which can play the given sound.
|
||||
|
||||
Returns nullptr if all voices are busy and stealing isn't enabled.
|
||||
|
||||
This can be overridden to implement custom voice-stealing algorithms.
|
||||
To implement a custom note-stealing algorithm, you can either override this
|
||||
method, or (preferably) override findVoiceToSteal().
|
||||
*/
|
||||
virtual SynthesiserVoice* findFreeVoice (SynthesiserSound* soundToPlay,
|
||||
const bool stealIfNoneAvailable) const;
|
||||
int midiChannel,
|
||||
int midiNoteNumber,
|
||||
bool stealIfNoneAvailable) const;
|
||||
|
||||
/** Chooses a voice that is most suitable for being re-used.
|
||||
The default method returns the one that has been playing for the longest, but
|
||||
you may want to override this and do something more cunning instead.
|
||||
The default method will attempt to find the oldest voice that isn't the
|
||||
bottom or top note being played. If that's not suitable for your synth,
|
||||
you can override this method and do something more cunning instead.
|
||||
*/
|
||||
virtual SynthesiserVoice* findVoiceToSteal (SynthesiserSound* soundToPlay) const;
|
||||
virtual SynthesiserVoice* findVoiceToSteal (SynthesiserSound* soundToPlay,
|
||||
int midiChannel,
|
||||
int midiNoteNumber) const;
|
||||
|
||||
/** Starts a specified voice playing a particular sound.
|
||||
|
||||
@@ -511,11 +534,14 @@ private:
|
||||
bool shouldStealNotes;
|
||||
BigInteger sustainPedalsDown;
|
||||
|
||||
void stopVoice (SynthesiserVoice*, bool allowTailOff);
|
||||
void stopVoice (SynthesiserVoice*, float velocity, bool allowTailOff);
|
||||
|
||||
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
||||
// Note the new parameters for this method.
|
||||
// Note the new parameters for these methods.
|
||||
virtual int findFreeVoice (const bool) const { return 0; }
|
||||
virtual int noteOff (int, int, int) { return 0; }
|
||||
virtual int findFreeVoice (SynthesiserSound*, const bool) { return 0; }
|
||||
virtual int findVoiceToSteal (SynthesiserSound*) const { return 0; }
|
||||
#endif
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Synthesiser)
|
||||
|
||||
Reference in New Issue
Block a user