26SynthesiserSound::SynthesiserSound() {}
35 return currentPlayingMidiChannel == midiChannel;
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];
102 newVoice->setCurrentPlaybackSampleRate (sampleRate);
137 jassert (numSamples > 0);
138 minimumSubBlockSize = numSamples;
151 for (
auto*
voice : voices)
156template <
typename floatType>
163 jassert (sampleRate != 0);
175 while (numSamples > 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)
227 int startSample,
int numSamples)
234 for (
auto*
voice : voices)
235 voice->renderNextBlock (buffer, startSample, numSamples);
240 for (
auto*
voice : voices)
246 const int channel =
m.getChannel();
250 noteOn (channel,
m.getNoteNumber(),
m.getFloatVelocity());
252 else if (
m.isNoteOff())
254 noteOff (channel,
m.getNoteNumber(),
m.getFloatVelocity(),
true);
256 else if (
m.isAllNotesOff() ||
m.isAllSoundOff())
260 else if (
m.isPitchWheel())
262 const int wheelPos =
m.getPitchWheelValue();
266 else if (
m.isAftertouch())
270 else if (
m.isChannelPressure())
274 else if (
m.isController())
278 else if (
m.isProgramChange())
291 for (
auto*
sound : sounds)
297 for (
auto*
voice : voices)
309 const int midiChannel,
315 if (
voice->currentlyPlayingSound !=
nullptr)
316 voice->stopNote (0.0f,
false);
319 voice->currentPlayingMidiChannel = midiChannel;
320 voice->noteOnTime = ++lastNoteOnCounter;
322 voice->setKeyDown (
true);
323 voice->setSostenutoPedalDown (
false);
324 voice->setSustainPedalDown (sustainPedalsDown[midiChannel]);
333 jassert (
voice !=
nullptr);
338 jassert (
allowTailOff || (
voice->getCurrentlyPlayingNote() < 0 &&
voice->getCurrentlyPlayingSound() ==
nullptr));
348 for (
auto*
voice : voices)
351 &&
voice->isPlayingChannel (midiChannel))
353 if (
auto sound =
voice->getCurrentlyPlayingSound())
356 &&
sound->appliesToChannel (midiChannel))
358 jassert (!
voice->keyIsDown ||
voice->isSustainPedalDown() == sustainPedalsDown [midiChannel]);
360 voice->setKeyDown (
false);
362 if (! (
voice->isSustainPedalDown() ||
voice->isSostenutoPedalDown()))
374 for (
auto*
voice : voices)
378 sustainPedalsDown.
clear();
385 for (
auto*
voice : voices)
404 for (
auto*
voice : voices)
413 for (
auto*
voice : voices)
415 && (midiChannel <= 0 ||
voice->isPlayingChannel (midiChannel)))
423 for (
auto*
voice : voices)
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);
484 jassert (midiChannel > 0 && midiChannel <= 16);
494 for (
auto*
voice : voices)
522 for (
auto*
voice : voices)
526 jassert (
voice->isVoiceActive());
539 if (!
voice->isPlayingButReleased())
541 auto note =
voice->getCurrentlyPlayingNote();
546 if (
top ==
nullptr ||
note >
top->getCurrentlyPlayingNote())
577 jassert (
low !=
nullptr);
Holds a resizable array of primitive or copy-by-value objects.
bool isEmpty() const noexcept
Returns true if the array is empty, false otherwise.
void ensureStorageAllocated(int minNumElements)
Increases the array's internal storage to hold a minimum number of elements.
int size() const noexcept
Returns the current number of elements in the array.
ElementType * begin() const noexcept
Returns a pointer to the first element in the array.
void remove(int indexToRemove)
Removes an element from the array.
void add(const ElementType &newElement)
Appends a new element at the end of the array.
void clear()
Removes all elements from the array.
ElementType * end() const noexcept
Returns a pointer to the element which follows the last element in the array.
void makeCopyOf(const AudioBuffer< OtherType > &other, bool avoidReallocating=false)
Resizes this buffer to match the given one, and copies all of its content across.
void clearBit(int bitNumber) noexcept
Clears a particular bit in the number.
void clear() noexcept
Resets the value to 0.
void setBit(int bitNumber)
Sets a specified bit to 1.
Used to iterate through the events in a MidiBuffer.
Holds a sequence of time-stamped midi events.
Encapsulates a MIDI message.
Describes one of the sounds that a Synthesiser can play.
~SynthesiserSound() override
Destructor.
Represents a voice that a Synthesiser can use to play a SynthesiserSound.
SynthesiserVoice()
Creates a voice.
virtual void channelPressureChanged(int newChannelPressureValue)
Called to let the voice know that the channel pressure has changed.
virtual void renderNextBlock(AudioBuffer< float > &outputBuffer, int startSample, int numSamples)=0
Renders the next block of data for this voice.
virtual bool isPlayingChannel(int midiChannel) const
Returns true if the voice is currently playing a sound which is mapped to the given midi channel.
virtual void setCurrentPlaybackSampleRate(double newRate)
Changes the voice's reference sample rate.
virtual void aftertouchChanged(int newAftertouchValue)
Called to let the voice know that the aftertouch has changed.
int getCurrentlyPlayingNote() const noexcept
Returns the midi note that this voice is currently playing.
void clearCurrentNote()
Resets the state of this voice after a sound has finished playing.
bool wasStartedBefore(const SynthesiserVoice &other) const noexcept
Returns true if this voice started playing its current note before the other voice did.
virtual ~SynthesiserVoice()
Destructor.
virtual bool isVoiceActive() const
Returns true if this voice is currently busy playing a sound.
Synthesiser()
Creates a new synthesiser.
virtual ~Synthesiser()
Destructor.
virtual SynthesiserVoice * findFreeVoice(SynthesiserSound *soundToPlay, int midiChannel, int midiNoteNumber, bool stealIfNoneAvailable) const
Searches through the voices to find one that's not currently playing, and which can play the given so...
virtual void handleProgramChange(int midiChannel, int programNumber)
Can be overridden to handle an incoming program change message.
void removeVoice(int index)
Deletes one of the voices.
void startVoice(SynthesiserVoice *voice, SynthesiserSound *sound, int midiChannel, int midiNoteNumber, float velocity)
Starts a specified voice playing a particular sound.
virtual void handleAftertouch(int midiChannel, int midiNoteNumber, int aftertouchValue)
Sends an aftertouch message.
void renderNextBlock(AudioBuffer< float > &outputAudio, const MidiBuffer &inputMidi, int startSample, int numSamples)
Creates the next block of audio output.
virtual void handleController(int midiChannel, int controllerNumber, int controllerValue)
Sends a midi controller message to any active voices.
void clearSounds()
Deletes all sounds.
virtual SynthesiserVoice * findVoiceToSteal(SynthesiserSound *soundToPlay, int midiChannel, int midiNoteNumber) const
Chooses a voice that is most suitable for being re-used.
virtual void handleSoftPedal(int midiChannel, bool isDown)
Can be overridden to handle soft pedal events.
void removeSound(int index)
Removes and deletes one of the sounds.
virtual void allNotesOff(int midiChannel, bool allowTailOff)
Turns off all notes.
SynthesiserVoice * addVoice(SynthesiserVoice *newVoice)
Adds a new voice to the synth.
void stopVoice(SynthesiserVoice *, float velocity, bool allowTailOff)
Stops a given voice.
SynthesiserSound * addSound(const SynthesiserSound::Ptr &newSound)
Adds a new sound to the synthesiser.
virtual void renderVoices(AudioBuffer< float > &outputAudio, int startSample, int numSamples)
Renders the voices for the given range.
virtual void handleMidiEvent(const MidiMessage &)
Can be overridden to do custom handling of incoming midi events.
void setNoteStealingEnabled(bool shouldStealNotes)
If set to true, then the synth will try to take over an existing voice if it runs out and needs to pl...
virtual void handlePitchWheel(int midiChannel, int wheelValue)
Sends a pitch-wheel message to any active voices.
CriticalSection lock
This is used to control access to the rendering callback and the note trigger methods.
int lastPitchWheelValues[16]
The last pitch-wheel values for each midi channel.
virtual void noteOn(int midiChannel, int midiNoteNumber, float velocity)
Triggers a note-on event.
SynthesiserVoice * getVoice(int index) const
Returns one of the voices that have been added.
virtual void noteOff(int midiChannel, int midiNoteNumber, float velocity, bool allowTailOff)
Triggers a note-off event.
virtual void handleChannelPressure(int midiChannel, int channelPressureValue)
Sends a channel pressure message.
void clearVoices()
Deletes all voices.
virtual void setCurrentPlaybackSampleRate(double sampleRate)
Tells the synthesiser what the sample rate is for the audio it's being used to render.
void setMinimumRenderingSubdivisionSize(int numSamples, bool shouldBeStrict=false) noexcept
Sets a minimum limit on the size to which audio sub-blocks will be divided when rendering.
virtual void handleSustainPedal(int midiChannel, bool isDown)
Handles a sustain pedal event.
virtual void handleSostenutoPedal(int midiChannel, bool isDown)
Handles a sostenuto pedal event.