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);
70 tempBuffer.makeCopyOf (subBuffer,
true);
89 const ScopedLock sl (
lock);
90 return voices [index];
95 const ScopedLock sl (
lock);
104 const ScopedLock sl (
lock);
106 voice = voices.add (newVoice);
110 const ScopedLock sl (stealLock);
111 usableVoicesToStealArray.ensureStorageAllocated (voices.size() + 1);
119 const ScopedLock sl (
lock);
120 voices.remove (index);
125 const ScopedLock sl (
lock);
131 const ScopedLock sl (
lock);
132 return sounds.add (newSound);
137 const ScopedLock sl (
lock);
138 sounds.remove (index);
143 shouldStealNotes = shouldSteal;
148 jassert (numSamples > 0);
149 minimumSubBlockSize = numSamples;
150 subBlockSubdivisionIsStrict = shouldBeStrict;
156 if (! approximatelyEqual (sampleRate, newRate))
158 const ScopedLock sl (
lock);
160 sampleRate = newRate;
162 for (
auto* voice : voices)
163 voice->setCurrentPlaybackSampleRate (newRate);
167template <
typename floatType>
174 jassert (! exactlyEqual (sampleRate, 0.0));
179 bool firstEvent =
true;
181 const ScopedLock sl (
lock);
183 for (; numSamples > 0; ++midiIterator)
185 if (midiIterator == midiData.
cend())
187 if (targetChannels > 0)
193 const auto metadata = *midiIterator;
194 const int samplesToNextMidiMessage = metadata.samplePosition - startSample;
196 if (samplesToNextMidiMessage >= numSamples)
198 if (targetChannels > 0)
205 if (samplesToNextMidiMessage < ((firstEvent && ! subBlockSubdivisionIsStrict) ? 1 : minimumSubBlockSize))
213 if (targetChannels > 0)
214 renderVoices (outputAudio, startSample, samplesToNextMidiMessage);
217 startSample += samplesToNextMidiMessage;
218 numSamples -= samplesToNextMidiMessage;
221 std::for_each (midiIterator,
223 [&] (
const MidiMessageMetadata& meta) { handleMidiEvent (meta.getMessage()); });
231 int startSample,
int numSamples)
233 processNextBlock (outputAudio, inputMidi, startSample, numSamples);
237 int startSample,
int numSamples)
239 processNextBlock (outputAudio, inputMidi, startSample, numSamples);
244 for (
auto* voice : voices)
245 voice->renderNextBlock (buffer, startSample, numSamples);
250 for (
auto* voice : voices)
251 voice->renderNextBlock (buffer, startSample, numSamples);
296 const int midiNoteNumber,
297 const float velocity)
299 const ScopedLock sl (
lock);
301 for (
auto* sound : sounds)
303 if (sound->appliesToNote (midiNoteNumber) && sound->appliesToChannel (midiChannel))
307 for (
auto* voice : voices)
308 if (voice->getCurrentlyPlayingNote() == midiNoteNumber && voice->isPlayingChannel (midiChannel))
312 sound, midiChannel, midiNoteNumber, velocity);
319 const int midiChannel,
320 const int midiNoteNumber,
321 const float velocity)
323 if (voice !=
nullptr && sound !=
nullptr)
325 if (voice->currentlyPlayingSound !=
nullptr)
328 voice->currentlyPlayingNote = midiNoteNumber;
329 voice->currentPlayingMidiChannel = midiChannel;
330 voice->noteOnTime = ++lastNoteOnCounter;
331 voice->currentlyPlayingSound = sound;
336 voice->
startNote (midiNoteNumber, velocity, sound,
343 jassert (voice !=
nullptr);
345 voice->
stopNote (velocity, allowTailOff);
352 const int midiNoteNumber,
353 const float velocity,
354 const bool allowTailOff)
356 const ScopedLock sl (
lock);
358 for (
auto* voice : voices)
360 if (voice->getCurrentlyPlayingNote() == midiNoteNumber
361 && voice->isPlayingChannel (midiChannel))
363 if (
auto sound = voice->getCurrentlyPlayingSound())
365 if (sound->appliesToNote (midiNoteNumber)
366 && sound->appliesToChannel (midiChannel))
368 jassert (! voice->keyIsDown || voice->isSustainPedalDown() == sustainPedalsDown [midiChannel]);
370 voice->setKeyDown (
false);
372 if (! (voice->isSustainPedalDown() || voice->isSostenutoPedalDown()))
373 stopVoice (voice, velocity, allowTailOff);
382 const ScopedLock sl (
lock);
384 for (
auto* voice : voices)
385 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
386 voice->stopNote (1.0f, allowTailOff);
388 sustainPedalsDown.clear();
393 const ScopedLock sl (
lock);
395 for (
auto* voice : voices)
396 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
397 voice->pitchWheelMoved (wheelValue);
401 const int controllerNumber,
402 const int controllerValue)
404 switch (controllerNumber)
408 case 0x43:
handleSoftPedal (midiChannel, controllerValue >= 64);
break;
412 const ScopedLock sl (
lock);
414 for (
auto* voice : voices)
415 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
416 voice->controllerMoved (controllerNumber, controllerValue);
421 const ScopedLock sl (
lock);
423 for (
auto* voice : voices)
424 if (voice->getCurrentlyPlayingNote() == midiNoteNumber
425 && (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)))
426 voice->aftertouchChanged (aftertouchValue);
431 const ScopedLock sl (
lock);
433 for (
auto* voice : voices)
434 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
435 voice->channelPressureChanged (channelPressureValue);
440 jassert (midiChannel > 0 && midiChannel <= 16);
441 const ScopedLock sl (
lock);
445 sustainPedalsDown.setBit (midiChannel);
447 for (
auto* voice : voices)
448 if (voice->isPlayingChannel (midiChannel) && voice->isKeyDown())
449 voice->setSustainPedalDown (
true);
453 for (
auto* voice : voices)
455 if (voice->isPlayingChannel (midiChannel))
457 voice->setSustainPedalDown (
false);
459 if (! (voice->isKeyDown() || voice->isSostenutoPedalDown()))
464 sustainPedalsDown.clearBit (midiChannel);
470 jassert (midiChannel > 0 && midiChannel <= 16);
471 const ScopedLock sl (
lock);
473 for (
auto* voice : voices)
475 if (voice->isPlayingChannel (midiChannel))
478 voice->setSostenutoPedalDown (
true);
479 else if (voice->isSostenutoPedalDown())
487 jassert (midiChannel > 0 && midiChannel <= 16);
491 [[maybe_unused]]
int programNumber)
493 jassert (midiChannel > 0 && midiChannel <= 16);
498 int midiChannel,
int midiNoteNumber,
499 const bool stealIfNoneAvailable)
const
501 const ScopedLock sl (
lock);
503 for (
auto* voice : voices)
504 if ((! voice->isVoiceActive()) && voice->canPlaySound (soundToPlay))
507 if (stealIfNoneAvailable)
514 int ,
int midiNoteNumber)
const
521 jassert (! voices.isEmpty());
530 const ScopedLock sl (stealLock);
533 usableVoicesToStealArray.clear();
535 for (
auto* voice : voices)
537 if (voice->canPlaySound (soundToPlay))
539 jassert (voice->isVoiceActive());
541 usableVoicesToStealArray.add (voice);
550 std::sort (usableVoicesToStealArray.begin(), usableVoicesToStealArray.end(), Sorter());
552 if (! voice->isPlayingButReleased())
554 auto note = voice->getCurrentlyPlayingNote();
556 if (low ==
nullptr || note < low->getCurrentlyPlayingNote())
570 for (
auto* voice : usableVoicesToStealArray)
571 if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
575 for (
auto* voice : usableVoicesToStealArray)
580 for (
auto* voice : usableVoicesToStealArray)
581 if (voice != low && voice != top && ! voice->
isKeyDown())
585 for (
auto* voice : usableVoicesToStealArray)
586 if (voice != low && voice != top)
590 jassert (low !=
nullptr);
void makeCopyOf(const AudioBuffer< OtherType > &other, bool avoidReallocating=false)
int getNumChannels() const noexcept
Type *const * getArrayOfWritePointers() noexcept
MidiBufferIterator findNextSamplePosition(int samplePosition) const noexcept
MidiBufferIterator cend() const noexcept
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
ReferenceCountedObjectPtr< SynthesiserSound > Ptr
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)