26SynthesiserSound::SynthesiserSound() {}
35 return currentPlayingMidiChannel == midiChannel;
40 currentSampleRate = newRate;
50 currentlyPlayingNote = -1;
51 currentlyPlayingSound =
nullptr;
52 currentPlayingMidiChannel = 0;
60 return noteOnTime < other.noteOnTime;
64 int startSample,
int numSamples)
68 startSample, numSamples);
90 return voices [index];
103 return voices.add (newVoice);
109 voices.remove (index);
121 return sounds.add (newSound);
127 sounds.remove (index);
132 shouldStealNotes = shouldSteal;
137 jassert (numSamples > 0);
138 minimumSubBlockSize = numSamples;
139 subBlockSubdivisionIsStrict = shouldBeStrict;
145 if (sampleRate != newRate)
149 sampleRate = newRate;
151 for (
auto* voice : voices)
152 voice->setCurrentPlaybackSampleRate (newRate);
156template <
typename floatType>
163 jassert (sampleRate != 0);
167 midiIterator.setNextSamplePosition (startSample);
169 bool firstEvent =
true;
175 while (numSamples > 0)
177 if (! midiIterator.getNextEvent (m, midiEventPos))
179 if (targetChannels > 0)
185 const int samplesToNextMidiMessage = midiEventPos - startSample;
187 if (samplesToNextMidiMessage >= numSamples)
189 if (targetChannels > 0)
196 if (samplesToNextMidiMessage < ((firstEvent && ! subBlockSubdivisionIsStrict) ? 1 : minimumSubBlockSize))
204 if (targetChannels > 0)
205 renderVoices (outputAudio, startSample, samplesToNextMidiMessage);
208 startSample += samplesToNextMidiMessage;
209 numSamples -= samplesToNextMidiMessage;
212 while (midiIterator.getNextEvent (m, midiEventPos))
217template void Synthesiser::processNextBlock<float> (AudioBuffer<float>&,
const MidiBuffer&,
int,
int);
218template void Synthesiser::processNextBlock<double> (AudioBuffer<double>&,
const MidiBuffer&,
int,
int);
221 int startSample,
int numSamples)
223 processNextBlock (outputAudio, inputMidi, startSample, numSamples);
227 int startSample,
int numSamples)
229 processNextBlock (outputAudio, inputMidi, startSample, numSamples);
234 for (
auto* voice : voices)
235 voice->renderNextBlock (buffer, startSample, numSamples);
240 for (
auto* voice : voices)
241 voice->renderNextBlock (buffer, startSample, numSamples);
286 const int midiNoteNumber,
287 const float velocity)
291 for (
auto* sound : sounds)
293 if (sound->appliesToNote (midiNoteNumber) && sound->appliesToChannel (midiChannel))
297 for (
auto* voice : voices)
298 if (voice->getCurrentlyPlayingNote() == midiNoteNumber && voice->isPlayingChannel (midiChannel))
302 sound, midiChannel, midiNoteNumber, velocity);
309 const int midiChannel,
310 const int midiNoteNumber,
311 const float velocity)
313 if (voice !=
nullptr && sound !=
nullptr)
315 if (voice->currentlyPlayingSound !=
nullptr)
318 voice->currentlyPlayingNote = midiNoteNumber;
319 voice->currentPlayingMidiChannel = midiChannel;
320 voice->noteOnTime = ++lastNoteOnCounter;
321 voice->currentlyPlayingSound = sound;
326 voice->
startNote (midiNoteNumber, velocity, sound,
333 jassert (voice !=
nullptr);
335 voice->
stopNote (velocity, allowTailOff);
342 const int midiNoteNumber,
343 const float velocity,
344 const bool allowTailOff)
348 for (
auto* voice : voices)
350 if (voice->getCurrentlyPlayingNote() == midiNoteNumber
351 && voice->isPlayingChannel (midiChannel))
353 if (
auto sound = voice->getCurrentlyPlayingSound())
355 if (sound->appliesToNote (midiNoteNumber)
356 && sound->appliesToChannel (midiChannel))
358 jassert (! voice->keyIsDown || voice->isSustainPedalDown() == sustainPedalsDown [midiChannel]);
360 voice->setKeyDown (
false);
362 if (! (voice->isSustainPedalDown() || voice->isSostenutoPedalDown()))
363 stopVoice (voice, velocity, allowTailOff);
374 for (
auto* voice : voices)
375 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
376 voice->stopNote (1.0f, allowTailOff);
378 sustainPedalsDown.
clear();
385 for (
auto* voice : voices)
386 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
387 voice->pitchWheelMoved (wheelValue);
391 const int controllerNumber,
392 const int controllerValue)
394 switch (controllerNumber)
398 case 0x43:
handleSoftPedal (midiChannel, controllerValue >= 64);
break;
404 for (
auto* voice : voices)
405 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
406 voice->controllerMoved (controllerNumber, controllerValue);
413 for (
auto* voice : voices)
414 if (voice->getCurrentlyPlayingNote() == midiNoteNumber
415 && (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)))
416 voice->aftertouchChanged (aftertouchValue);
423 for (
auto* voice : voices)
424 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
425 voice->channelPressureChanged (channelPressureValue);
430 jassert (midiChannel > 0 && midiChannel <= 16);
435 sustainPedalsDown.
setBit (midiChannel);
437 for (
auto* voice : voices)
438 if (voice->isPlayingChannel (midiChannel) && voice->isKeyDown())
439 voice->setSustainPedalDown (
true);
443 for (
auto* voice : voices)
445 if (voice->isPlayingChannel (midiChannel))
447 voice->setSustainPedalDown (
false);
449 if (! (voice->isKeyDown() || voice->isSostenutoPedalDown()))
454 sustainPedalsDown.
clearBit (midiChannel);
460 jassert (midiChannel > 0 && midiChannel <= 16);
463 for (
auto* voice : voices)
465 if (voice->isPlayingChannel (midiChannel))
468 voice->setSostenutoPedalDown (
true);
469 else if (voice->isSostenutoPedalDown())
477 ignoreUnused (midiChannel);
478 jassert (midiChannel > 0 && midiChannel <= 16);
483 ignoreUnused (midiChannel, programNumber);
484 jassert (midiChannel > 0 && midiChannel <= 16);
489 int midiChannel,
int midiNoteNumber,
490 const bool stealIfNoneAvailable)
const
494 for (
auto* voice : voices)
495 if ((! voice->isVoiceActive()) && voice->canPlaySound (soundToPlay))
498 if (stealIfNoneAvailable)
505 int ,
int midiNoteNumber)
const
512 jassert (! voices.isEmpty());
522 for (
auto* voice : voices)
524 if (voice->canPlaySound (soundToPlay))
526 jassert (voice->isVoiceActive());
528 usableVoices.
add (voice);
537 std::sort (usableVoices.
begin(), usableVoices.
end(), Sorter());
539 if (! voice->isPlayingButReleased())
541 auto note = voice->getCurrentlyPlayingNote();
543 if (low ==
nullptr || note < low->getCurrentlyPlayingNote())
557 for (
auto* voice : usableVoices)
558 if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
562 for (
auto* voice : usableVoices)
567 for (
auto* voice : usableVoices)
568 if (voice != low && voice != top && ! voice->
isKeyDown())
572 for (
auto* voice : usableVoices)
573 if (voice != low && voice != top)
577 jassert (low !=
nullptr);
void ensureStorageAllocated(int minNumElements)
ElementType * begin() noexcept
ElementType * end() noexcept
void add(const ElementType &newElement)
void makeCopyOf(const AudioBuffer< OtherType > &other, bool avoidReallocating=false)
int getNumChannels() const noexcept
Type ** getArrayOfWritePointers() noexcept
void clearBit(int bitNumber) noexcept
void setBit(int bitNumber)
bool isAftertouch() const noexcept
bool isNoteOn(bool returnTrueForVelocity0=false) const noexcept
float getFloatVelocity() const noexcept
int getChannel() const noexcept
bool isProgramChange() const noexcept
bool isController() const noexcept
bool isAllSoundOff() const noexcept
int getControllerNumber() const noexcept
int getChannelPressureValue() const noexcept
bool isNoteOff(bool returnTrueForNoteOnVelocity0=true) const noexcept
bool isPitchWheel() const noexcept
int getNoteNumber() const noexcept
int getProgramChangeNumber() const noexcept
int getAfterTouchValue() const noexcept
int getControllerValue() const noexcept
bool isAllNotesOff() const noexcept
bool isChannelPressure() const noexcept
int getPitchWheelValue() const noexcept
~SynthesiserSound() override
virtual void stopNote(float velocity, bool allowTailOff)=0
void setSustainPedalDown(bool isNowDown) noexcept
virtual void channelPressureChanged(int newChannelPressureValue)
void setSostenutoPedalDown(bool isNowDown) noexcept
virtual void renderNextBlock(AudioBuffer< float > &outputBuffer, int startSample, int numSamples)=0
virtual bool isPlayingChannel(int midiChannel) const
bool isKeyDown() const noexcept
void setKeyDown(bool isNowDown) noexcept
virtual void setCurrentPlaybackSampleRate(double newRate)
virtual void aftertouchChanged(int newAftertouchValue)
int getCurrentlyPlayingNote() const noexcept
virtual void startNote(int midiNoteNumber, float velocity, SynthesiserSound *sound, int currentPitchWheelPosition)=0
bool wasStartedBefore(const SynthesiserVoice &other) const noexcept
virtual ~SynthesiserVoice()
bool isPlayingButReleased() const noexcept
SynthesiserSound::Ptr getCurrentlyPlayingSound() const noexcept
virtual bool isVoiceActive() const
virtual SynthesiserVoice * findFreeVoice(SynthesiserSound *soundToPlay, int midiChannel, int midiNoteNumber, bool stealIfNoneAvailable) const
virtual void handleProgramChange(int midiChannel, int programNumber)
void removeVoice(int index)
void startVoice(SynthesiserVoice *voice, SynthesiserSound *sound, int midiChannel, int midiNoteNumber, float velocity)
virtual void handleAftertouch(int midiChannel, int midiNoteNumber, int aftertouchValue)
void renderNextBlock(AudioBuffer< float > &outputAudio, const MidiBuffer &inputMidi, int startSample, int numSamples)
virtual void handleController(int midiChannel, int controllerNumber, int controllerValue)
virtual SynthesiserVoice * findVoiceToSteal(SynthesiserSound *soundToPlay, int midiChannel, int midiNoteNumber) const
virtual void handleSoftPedal(int midiChannel, bool isDown)
void removeSound(int index)
virtual void allNotesOff(int midiChannel, bool allowTailOff)
SynthesiserVoice * addVoice(SynthesiserVoice *newVoice)
void stopVoice(SynthesiserVoice *, float velocity, bool allowTailOff)
SynthesiserSound * addSound(const SynthesiserSound::Ptr &newSound)
virtual void renderVoices(AudioBuffer< float > &outputAudio, int startSample, int numSamples)
virtual void handleMidiEvent(const MidiMessage &)
void setNoteStealingEnabled(bool shouldStealNotes)
virtual void handlePitchWheel(int midiChannel, int wheelValue)
int lastPitchWheelValues[16]
virtual void noteOn(int midiChannel, int midiNoteNumber, float velocity)
SynthesiserVoice * getVoice(int index) const
virtual void noteOff(int midiChannel, int midiNoteNumber, float velocity, bool allowTailOff)
virtual void handleChannelPressure(int midiChannel, int channelPressureValue)
virtual void setCurrentPlaybackSampleRate(double sampleRate)
void setMinimumRenderingSubdivisionSize(int numSamples, bool shouldBeStrict=false) noexcept
virtual void handleSustainPedal(int midiChannel, bool isDown)
virtual void handleSostenutoPedal(int midiChannel, bool isDown)