OpenShot Audio Library | OpenShotAudio: juce_MPESynthesiser.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.3.2

Loading...
Searching...
No Matches
juce_MPESynthesiser.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26MPESynthesiser::MPESynthesiser()
27{
28 MPEZoneLayout zoneLayout;
29 zoneLayout.setLowerZone (15);
30 setZoneLayout (zoneLayout);
31}
32
33 MPESynthesiser::MPESynthesiser (MPEInstrument* mpeInstrument) : MPESynthesiserBase (mpeInstrument)
34{
35}
36
37MPESynthesiser::~MPESynthesiser()
38{
39}
40
41//==============================================================================
42 void MPESynthesiser::startVoice (MPESynthesiserVoice* voice, MPENote noteToStart)
43{
44 jassert (voice != nullptr);
45
46 voice->currentlyPlayingNote = noteToStart;
47 voice->noteOnTime = lastNoteOnCounter++;
48 voice->noteStarted();
49}
50
51 void MPESynthesiser::stopVoice (MPESynthesiserVoice* voice, MPENote noteToStop, bool allowTailOff)
52{
53 jassert (voice != nullptr);
54
55 voice->currentlyPlayingNote = noteToStop;
56 voice->noteStopped (allowTailOff);
57}
58
59//==============================================================================
60 void MPESynthesiser::noteAdded (MPENote newNote)
61{
62 const ScopedLock sl (voicesLock);
63
64 if (auto* voice = findFreeVoice (newNote, shouldStealVoices))
65 startVoice (voice, newNote);
66}
67
68 void MPESynthesiser::notePressureChanged (MPENote changedNote)
69{
70 const ScopedLock sl (voicesLock);
71
72 for (auto* voice : voices)
73 {
74 if (voice->isCurrentlyPlayingNote (changedNote))
75 {
76 voice->currentlyPlayingNote = changedNote;
77 voice->notePressureChanged();
78 }
79 }
80}
81
82 void MPESynthesiser::notePitchbendChanged (MPENote changedNote)
83{
84 const ScopedLock sl (voicesLock);
85
86 for (auto* voice : voices)
87 {
88 if (voice->isCurrentlyPlayingNote (changedNote))
89 {
90 voice->currentlyPlayingNote = changedNote;
91 voice->notePitchbendChanged();
92 }
93 }
94}
95
96 void MPESynthesiser::noteTimbreChanged (MPENote changedNote)
97{
98 const ScopedLock sl (voicesLock);
99
100 for (auto* voice : voices)
101 {
102 if (voice->isCurrentlyPlayingNote (changedNote))
103 {
104 voice->currentlyPlayingNote = changedNote;
105 voice->noteTimbreChanged();
106 }
107 }
108}
109
110 void MPESynthesiser::noteKeyStateChanged (MPENote changedNote)
111{
112 const ScopedLock sl (voicesLock);
113
114 for (auto* voice : voices)
115 {
116 if (voice->isCurrentlyPlayingNote (changedNote))
117 {
118 voice->currentlyPlayingNote = changedNote;
119 voice->noteKeyStateChanged();
120 }
121 }
122}
123
124 void MPESynthesiser::noteReleased (MPENote finishedNote)
125{
126 const ScopedLock sl (voicesLock);
127
128 for (auto i = voices.size(); --i >= 0;)
129 {
130 auto* voice = voices.getUnchecked (i);
131
132 if (voice->isCurrentlyPlayingNote(finishedNote))
133 stopVoice (voice, finishedNote, true);
134 }
135}
136
137 void MPESynthesiser::setCurrentPlaybackSampleRate (const double newRate)
138{
139 MPESynthesiserBase::setCurrentPlaybackSampleRate (newRate);
140
141 const ScopedLock sl (voicesLock);
142
143 turnOffAllVoices (false);
144
145 for (auto i = voices.size(); --i >= 0;)
146 voices.getUnchecked (i)->setCurrentSampleRate (newRate);
147}
148
149 void MPESynthesiser::handleMidiEvent (const MidiMessage& m)
150{
151 if (m.isController())
152 handleController (m.getChannel(), m.getControllerNumber(), m.getControllerValue());
153 else if (m.isProgramChange())
154 handleProgramChange (m.getChannel(), m.getProgramChangeNumber());
155
156 MPESynthesiserBase::handleMidiEvent (m);
157}
158
159 MPESynthesiserVoice* MPESynthesiser::findFreeVoice (MPENote noteToFindVoiceFor, bool stealIfNoneAvailable) const
160{
161 const ScopedLock sl (voicesLock);
162
163 for (auto* voice : voices)
164 {
165 if (! voice->isActive())
166 return voice;
167 }
168
169 if (stealIfNoneAvailable)
170 return findVoiceToSteal (noteToFindVoiceFor);
171
172 return nullptr;
173}
174
175 MPESynthesiserVoice* MPESynthesiser::findVoiceToSteal (MPENote noteToStealVoiceFor) const
176{
177 // This voice-stealing algorithm applies the following heuristics:
178 // - Re-use the oldest notes first
179 // - Protect the lowest & topmost notes, even if sustained, but not if they've been released.
180
181
182 // apparently you are trying to render audio without having any voices...
183 jassert (voices.size() > 0);
184
185 // These are the voices we want to protect (ie: only steal if unavoidable)
186 MPESynthesiserVoice* low = nullptr; // Lowest sounding note, might be sustained, but NOT in release phase
187 MPESynthesiserVoice* top = nullptr; // Highest sounding note, might be sustained, but NOT in release phase
188
189 // this is a list of voices we can steal, sorted by how long they've been running
190 Array<MPESynthesiserVoice*> usableVoices;
191 usableVoices.ensureStorageAllocated (voices.size());
192
193 for (auto* voice : voices)
194 {
195 jassert (voice->isActive()); // We wouldn't be here otherwise
196
197 usableVoices.add (voice);
198
199 // NB: Using a functor rather than a lambda here due to scare-stories about
200 // compilers generating code containing heap allocations..
201 struct Sorter
202 {
203 bool operator() (const MPESynthesiserVoice* a, const MPESynthesiserVoice* b) const noexcept { return a->noteOnTime < b->noteOnTime; }
204 };
205
206 std::sort (usableVoices.begin(), usableVoices.end(), Sorter());
207
208 if (! voice->isPlayingButReleased()) // Don't protect released notes
209 {
210 auto noteNumber = voice->getCurrentlyPlayingNote().initialNote;
211
212 if (low == nullptr || noteNumber < low->getCurrentlyPlayingNote().initialNote)
213 low = voice;
214
215 if (top == nullptr || noteNumber > top->getCurrentlyPlayingNote().initialNote)
216 top = voice;
217 }
218 }
219
220 // Eliminate pathological cases (ie: only 1 note playing): we always give precedence to the lowest note(s)
221 if (top == low)
222 top = nullptr;
223
224 // If we want to re-use the voice to trigger a new note,
225 // then The oldest note that's playing the same note number is ideal.
226 if (noteToStealVoiceFor.isValid())
227 for (auto* voice : usableVoices)
228 if (voice->getCurrentlyPlayingNote().initialNote == noteToStealVoiceFor.initialNote)
229 return voice;
230
231 // Oldest voice that has been released (no finger on it and not held by sustain pedal)
232 for (auto* voice : usableVoices)
233 if (voice != low && voice != top && voice->isPlayingButReleased())
234 return voice;
235
236 // Oldest voice that doesn't have a finger on it:
237 for (auto* voice : usableVoices)
238 if (voice != low && voice != top
239 && voice->getCurrentlyPlayingNote().keyState != MPENote::keyDown
240 && voice->getCurrentlyPlayingNote().keyState != MPENote::keyDownAndSustained)
241 return voice;
242
243 // Oldest voice that isn't protected
244 for (auto* voice : usableVoices)
245 if (voice != low && voice != top)
246 return voice;
247
248 // We've only got "protected" voices now: lowest note takes priority
249 jassert (low != nullptr);
250
251 // Duophonic synth: give priority to the bass note:
252 if (top != nullptr)
253 return top;
254
255 return low;
256}
257
258//==============================================================================
259 void MPESynthesiser::addVoice (MPESynthesiserVoice* const newVoice)
260{
261 const ScopedLock sl (voicesLock);
262 newVoice->setCurrentSampleRate (getSampleRate());
263 voices.add (newVoice);
264}
265
266 void MPESynthesiser::clearVoices()
267{
268 const ScopedLock sl (voicesLock);
269 voices.clear();
270}
271
272 MPESynthesiserVoice* MPESynthesiser::getVoice (const int index) const
273{
274 const ScopedLock sl (voicesLock);
275 return voices [index];
276}
277
278 void MPESynthesiser::removeVoice (const int index)
279{
280 const ScopedLock sl (voicesLock);
281 voices.remove (index);
282}
283
284 void MPESynthesiser::reduceNumVoices (const int newNumVoices)
285{
286 // we can't possibly get to a negative number of voices...
287 jassert (newNumVoices >= 0);
288
289 const ScopedLock sl (voicesLock);
290
291 while (voices.size() > newNumVoices)
292 {
293 if (auto* voice = findFreeVoice ({}, true))
294 voices.removeObject (voice);
295 else
296 voices.remove (0); // if there's no voice to steal, kill the oldest voice
297 }
298}
299
300 void MPESynthesiser::turnOffAllVoices (bool allowTailOff)
301{
302 {
303 const ScopedLock sl (voicesLock);
304
305 // first turn off all voices (it's more efficient to do this immediately
306 // rather than to go through the MPEInstrument for this).
307 for (auto* voice : voices)
308 voice->noteStopped (allowTailOff);
309 }
310
311 // finally make sure the MPE Instrument also doesn't have any notes anymore.
312 instrument->releaseAllNotes();
313}
314
315//==============================================================================
316 void MPESynthesiser::renderNextSubBlock (AudioBuffer<float>& buffer, int startSample, int numSamples)
317{
318 const ScopedLock sl (voicesLock);
319
320 for (auto* voice : voices)
321 {
322 if (voice->isActive())
323 voice->renderNextBlock (buffer, startSample, numSamples);
324 }
325}
326
327 void MPESynthesiser::renderNextSubBlock (AudioBuffer<double>& buffer, int startSample, int numSamples)
328{
329 const ScopedLock sl (voicesLock);
330
331 for (auto* voice : voices)
332 {
333 if (voice->isActive())
334 voice->renderNextBlock (buffer, startSample, numSamples);
335 }
336}
337
338} // namespace juce
juce::Array
Definition: juce_Array.h:56
juce::Array::ensureStorageAllocated
void ensureStorageAllocated(int minNumElements)
Definition: juce_Array.h:1062
juce::Array::begin
ElementType * begin() noexcept
Definition: juce_Array.h:328
juce::Array::end
ElementType * end() noexcept
Definition: juce_Array.h:344
juce::Array::add
void add(const ElementType &newElement)
Definition: juce_Array.h:418
juce::AudioBuffer
Definition: juce_AudioSampleBuffer.h:34
juce::GenericScopedLock
Definition: juce_ScopedLock.h:55
juce::MPEInstrument
Definition: juce_MPEInstrument.h:56
juce::MPESynthesiserVoice
Definition: juce_MPESynthesiserVoice.h:38
juce::MPESynthesiserVoice::setCurrentSampleRate
virtual void setCurrentSampleRate(double newRate)
Definition: juce_MPESynthesiserVoice.h:152
juce::MPESynthesiserVoice::getCurrentlyPlayingNote
MPENote getCurrentlyPlayingNote() const noexcept
Definition: juce_MPESynthesiserVoice.h:51
juce::MPESynthesiserVoice::noteStarted
virtual void noteStarted()=0
juce::MPESynthesiserVoice::noteOnTime
uint32 noteOnTime
Definition: juce_MPESynthesiserVoice.h:162
juce::MPESynthesiserVoice::noteStopped
virtual void noteStopped(bool allowTailOff)=0
juce::MPESynthesiserVoice::isPlayingButReleased
bool isPlayingButReleased() const noexcept
Definition: juce_MPESynthesiserVoice.cpp:40
juce::MPESynthesiser::removeVoice
void removeVoice(int index)
Definition: juce_MPESynthesiser.cpp:278
juce::MPESynthesiser::reduceNumVoices
void reduceNumVoices(int newNumVoices)
Definition: juce_MPESynthesiser.cpp:284
juce::MPESynthesiser::findFreeVoice
virtual MPESynthesiserVoice * findFreeVoice(MPENote noteToFindVoiceFor, bool stealIfNoneAvailable) const
Definition: juce_MPESynthesiser.cpp:159
juce::MPESynthesiser::MPESynthesiser
MPESynthesiser()
Definition: juce_MPESynthesiser.cpp:26
juce::MPESynthesiser::stopVoice
void stopVoice(MPESynthesiserVoice *voice, MPENote noteToStop, bool allowTailOff)
Definition: juce_MPESynthesiser.cpp:51
juce::MPESynthesiser::setCurrentPlaybackSampleRate
void setCurrentPlaybackSampleRate(double newRate) override
Definition: juce_MPESynthesiser.cpp:137
juce::MPESynthesiser::startVoice
void startVoice(MPESynthesiserVoice *voice, MPENote noteToStart)
Definition: juce_MPESynthesiser.cpp:42
juce::MPESynthesiser::notePressureChanged
void notePressureChanged(MPENote changedNote) override
Definition: juce_MPESynthesiser.cpp:68
juce::MPESynthesiser::noteReleased
void noteReleased(MPENote finishedNote) override
Definition: juce_MPESynthesiser.cpp:124
juce::MPESynthesiser::clearVoices
void clearVoices()
Definition: juce_MPESynthesiser.cpp:266
juce::MPESynthesiser::addVoice
void addVoice(MPESynthesiserVoice *newVoice)
Definition: juce_MPESynthesiser.cpp:259
juce::MPESynthesiser::~MPESynthesiser
~MPESynthesiser() override
Definition: juce_MPESynthesiser.cpp:37
juce::MPESynthesiser::findVoiceToSteal
virtual MPESynthesiserVoice * findVoiceToSteal(MPENote noteToStealVoiceFor=MPENote()) const
Definition: juce_MPESynthesiser.cpp:175
juce::MPESynthesiser::noteTimbreChanged
void noteTimbreChanged(MPENote changedNote) override
Definition: juce_MPESynthesiser.cpp:96
juce::MPESynthesiser::noteAdded
void noteAdded(MPENote newNote) override
Definition: juce_MPESynthesiser.cpp:60
juce::MPESynthesiser::getVoice
MPESynthesiserVoice * getVoice(int index) const
Definition: juce_MPESynthesiser.cpp:272
juce::MPESynthesiser::noteKeyStateChanged
void noteKeyStateChanged(MPENote changedNote) override
Definition: juce_MPESynthesiser.cpp:110
juce::MPESynthesiser::turnOffAllVoices
virtual void turnOffAllVoices(bool allowTailOff)
Definition: juce_MPESynthesiser.cpp:300
juce::MPESynthesiser::handleProgramChange
virtual void handleProgramChange(int, int)
Definition: juce_MPESynthesiser.h:174
juce::MPESynthesiser::renderNextSubBlock
void renderNextSubBlock(AudioBuffer< float > &outputAudio, int startSample, int numSamples) override
Definition: juce_MPESynthesiser.cpp:316
juce::MPESynthesiser::notePitchbendChanged
void notePitchbendChanged(MPENote changedNote) override
Definition: juce_MPESynthesiser.cpp:82
juce::MPESynthesiser::handleMidiEvent
void handleMidiEvent(const MidiMessage &) override
Definition: juce_MPESynthesiser.cpp:149
juce::MPESynthesiser::handleController
virtual void handleController(int, int, int)
Definition: juce_MPESynthesiser.h:163
juce::MPEZoneLayout
Definition: juce_MPEZoneLayout.h:45
juce::MPEZoneLayout::setLowerZone
void setLowerZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2) noexcept
Definition: juce_MPEZoneLayout.cpp:77
juce::MidiMessage
Definition: juce_MidiMessage.h:35
juce::MidiMessage::getChannel
int getChannel() const noexcept
Definition: juce_MidiMessage.cpp:359
juce::MidiMessage::isProgramChange
bool isProgramChange() const noexcept
Definition: juce_MidiMessage.cpp:504
juce::MidiMessage::isController
bool isController() const noexcept
Definition: juce_MidiMessage.cpp:543
juce::MidiMessage::getControllerNumber
int getControllerNumber() const noexcept
Definition: juce_MidiMessage.cpp:554
juce::MidiMessage::getProgramChangeNumber
int getProgramChangeNumber() const noexcept
Definition: juce_MidiMessage.cpp:509
juce::MidiMessage::getControllerValue
int getControllerValue() const noexcept
Definition: juce_MidiMessage.cpp:560
juce::MPENote
Definition: juce_MPENote.h:40
juce::MPENote::keyDown
@ keyDown
Definition: juce_MPENote.h:46
juce::MPENote::keyDownAndSustained
@ keyDownAndSustained
Definition: juce_MPENote.h:48
juce::MPENote::initialNote
uint8 initialNote
Definition: juce_MPENote.h:108
juce::MPENote::keyState
KeyState keyState
Definition: juce_MPENote.h:169
juce::MPENote::isValid
bool isValid() const noexcept
Definition: juce_MPENote.cpp:62
juce::MPESynthesiserBase
Definition: juce_MPESynthesiserBase.h:47
juce::MPESynthesiserBase::handleMidiEvent
virtual void handleMidiEvent(const MidiMessage &)
Definition: juce_MPESynthesiserBase.cpp:98
juce::MPESynthesiserBase::setZoneLayout
void setZoneLayout(MPEZoneLayout newLayout)
Definition: juce_MPESynthesiserBase.cpp:45
juce::MPESynthesiserBase::instrument
std::unique_ptr< MPEInstrument > instrument
Definition: juce_MPESynthesiserBase.h:198
juce::MPESynthesiserBase::setCurrentPlaybackSampleRate
virtual void setCurrentPlaybackSampleRate(double sampleRate)
Definition: juce_MPESynthesiserBase.cpp:162
juce::MPESynthesiserBase::getSampleRate
double getSampleRate() const noexcept
Definition: juce_MPESynthesiserBase.h:84