26 SynthesiserSound::SynthesiserSound() {}
35 return currentPlayingMidiChannel == midiChannel;
40 currentSampleRate = newRate;
45 return getCurrentlyPlayingNote() >= 0;
50 currentlyPlayingNote = -1;
51 currentlyPlayingSound =
nullptr;
52 currentPlayingMidiChannel = 0;
60 return noteOnTime < other.noteOnTime;
64 int startSample,
int numSamples)
68 startSample, numSamples);
71 renderNextBlock (tempBuffer, 0, numSamples);
72 subBuffer.makeCopyOf (tempBuffer,
true);
78 for (
int i = 0; i < numElementsInArray (lastPitchWheelValues); ++i)
79 lastPitchWheelValues[i] = 0x2000;
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)
148 allNotesOff (0,
false);
149 sampleRate = newRate;
151 for (
auto* voice : voices)
152 voice->setCurrentPlaybackSampleRate (newRate);
156 template <
typename floatType>
163 jassert (sampleRate != 0);
169 bool firstEvent =
true;
175 while (numSamples > 0)
179 if (targetChannels > 0)
180 renderVoices (outputAudio, startSample, numSamples);
185 const int samplesToNextMidiMessage = midiEventPos - startSample;
187 if (samplesToNextMidiMessage >= numSamples)
189 if (targetChannels > 0)
190 renderVoices (outputAudio, startSample, numSamples);
196 if (samplesToNextMidiMessage < ((firstEvent && ! subBlockSubdivisionIsStrict) ? 1 : minimumSubBlockSize))
204 if (targetChannels > 0)
205 renderVoices (outputAudio, startSample, samplesToNextMidiMessage);
208 startSample += samplesToNextMidiMessage;
209 numSamples -= samplesToNextMidiMessage;
218 template 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);
258 allNotesOff (channel,
true);
263 lastPitchWheelValues [channel - 1] = wheelPos;
264 handlePitchWheel (channel, wheelPos);
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))
299 stopVoice (voice, 1.0f,
true);
301 startVoice (findFreeVoice (sound, midiChannel, midiNoteNumber, shouldStealNotes),
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,
327 lastPitchWheelValues [midiChannel - 1]);
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)
396 case 0x40: handleSustainPedal (midiChannel, controllerValue >= 64);
break;
397 case 0x42: handleSostenutoPedal (midiChannel, controllerValue >= 64);
break;
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()))
450 stopVoice (voice, 1.0f,
true);
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())
470 stopVoice (voice, 1.0f,
true);
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)
499 return findVoiceToSteal (soundToPlay, midiChannel, midiNoteNumber);
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);
bool isAftertouch() const noexcept
virtual SynthesiserVoice * findVoiceToSteal(SynthesiserSound *soundToPlay, int midiChannel, int midiNoteNumber) const
void setNextSamplePosition(int samplePosition) noexcept
bool isPitchWheel() const noexcept
int getAfterTouchValue() const noexcept
ElementType * end() noexcept
bool wasStartedBefore(const SynthesiserVoice &other) const noexcept
bool getNextEvent(MidiMessage &result, int &samplePosition) noexcept
bool isAllNotesOff() const noexcept
void ensureStorageAllocated(int minNumElements)
void add(const ElementType &newElement)
virtual void handleSostenutoPedal(int midiChannel, bool isDown)
void removeVoice(int index)
virtual void allNotesOff(int midiChannel, bool allowTailOff)
virtual void handleController(int midiChannel, int controllerNumber, int controllerValue)
virtual bool isPlayingChannel(int midiChannel) const
void renderNextBlock(AudioBuffer< float > &outputAudio, const MidiBuffer &inputMidi, int startSample, int numSamples)
Type ** getArrayOfWritePointers() noexcept
void setSostenutoPedalDown(bool isNowDown) noexcept
virtual void handleChannelPressure(int midiChannel, int channelPressureValue)
virtual void noteOff(int midiChannel, int midiNoteNumber, float velocity, bool allowTailOff)
SynthesiserVoice * addVoice(SynthesiserVoice *newVoice)
SynthesiserSound::Ptr getCurrentlyPlayingSound() const noexcept
virtual void renderNextBlock(AudioBuffer< float > &outputBuffer, int startSample, int numSamples)=0
void stopVoice(SynthesiserVoice *, float velocity, bool allowTailOff)
bool isProgramChange() const noexcept
virtual void handleMidiEvent(const MidiMessage &)
virtual void setCurrentPlaybackSampleRate(double sampleRate)
ElementType * begin() noexcept
void setSustainPedalDown(bool isNowDown) noexcept
int getControllerNumber() const noexcept
int getChannel() const noexcept
bool isController() const noexcept
int getNumChannels() const noexcept
virtual void renderVoices(AudioBuffer< float > &outputAudio, int startSample, int numSamples)
virtual void setCurrentPlaybackSampleRate(double newRate)
virtual void startNote(int midiNoteNumber, float velocity, SynthesiserSound *sound, int currentPitchWheelPosition)=0
virtual bool isVoiceActive() const
virtual ~SynthesiserVoice()
bool isChannelPressure() const noexcept
float getFloatVelocity() const noexcept
int getProgramChangeNumber() const noexcept
int getPitchWheelValue() const noexcept
virtual void stopNote(float velocity, bool allowTailOff)=0
bool isKeyDown() const noexcept
int getChannelPressureValue() const noexcept
virtual void handleSoftPedal(int midiChannel, bool isDown)
void setMinimumRenderingSubdivisionSize(int numSamples, bool shouldBeStrict=false) noexcept
bool isNoteOff(bool returnTrueForNoteOnVelocity0=true) const noexcept
virtual void channelPressureChanged(int newChannelPressureValue)
SynthesiserSound * addSound(const SynthesiserSound::Ptr &newSound)
bool isPlayingButReleased() const noexcept
int getCurrentlyPlayingNote() const noexcept
bool isNoteOn(bool returnTrueForVelocity0=false) const noexcept
~SynthesiserSound() override
void startVoice(SynthesiserVoice *voice, SynthesiserSound *sound, int midiChannel, int midiNoteNumber, float velocity)
void makeCopyOf(const AudioBuffer< OtherType > &other, bool avoidReallocating=false)
virtual void handleProgramChange(int midiChannel, int programNumber)
virtual SynthesiserVoice * findFreeVoice(SynthesiserSound *soundToPlay, int midiChannel, int midiNoteNumber, bool stealIfNoneAvailable) const
void removeSound(int index)
int getControllerValue() const noexcept
virtual void aftertouchChanged(int newAftertouchValue)
SynthesiserVoice * getVoice(int index) const
virtual void handleSustainPedal(int midiChannel, bool isDown)
virtual void handleAftertouch(int midiChannel, int midiNoteNumber, int aftertouchValue)
int getNoteNumber() const noexcept
void setNoteStealingEnabled(bool shouldStealNotes)
virtual void noteOn(int midiChannel, int midiNoteNumber, float velocity)
virtual void handlePitchWheel(int midiChannel, int wheelValue)
void setKeyDown(bool isNowDown) noexcept
bool isAllSoundOff() const noexcept