Add remaining files
[juce-lv2.git] / juce / source / src / audio / synthesisers / juce_Synthesiser.cpp
blobd6c703d315483bee1dd55c634ee3f27fe61975fe
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../core/juce_StandardHeader.h"
28 BEGIN_JUCE_NAMESPACE
30 #include "juce_Synthesiser.h"
33 //==============================================================================
34 SynthesiserSound::SynthesiserSound()
38 SynthesiserSound::~SynthesiserSound()
42 //==============================================================================
43 SynthesiserVoice::SynthesiserVoice()
44 : currentSampleRate (44100.0),
45 currentlyPlayingNote (-1),
46 noteOnTime (0),
47 keyIsDown (false),
48 sostenutoPedalDown (false)
52 SynthesiserVoice::~SynthesiserVoice()
56 bool SynthesiserVoice::isPlayingChannel (const int midiChannel) const
58 return currentlyPlayingSound != nullptr
59 && currentlyPlayingSound->appliesToChannel (midiChannel);
62 void SynthesiserVoice::setCurrentPlaybackSampleRate (const double newRate)
64 currentSampleRate = newRate;
67 void SynthesiserVoice::clearCurrentNote()
69 currentlyPlayingNote = -1;
70 currentlyPlayingSound = nullptr;
73 //==============================================================================
74 Synthesiser::Synthesiser()
75 : sampleRate (0),
76 lastNoteOnCounter (0),
77 shouldStealNotes (true)
79 for (int i = 0; i < numElementsInArray (lastPitchWheelValues); ++i)
80 lastPitchWheelValues[i] = 0x2000;
83 Synthesiser::~Synthesiser()
87 //==============================================================================
88 SynthesiserVoice* Synthesiser::getVoice (const int index) const
90 const ScopedLock sl (lock);
91 return voices [index];
94 void Synthesiser::clearVoices()
96 const ScopedLock sl (lock);
97 voices.clear();
100 void Synthesiser::addVoice (SynthesiserVoice* const newVoice)
102 const ScopedLock sl (lock);
103 voices.add (newVoice);
106 void Synthesiser::removeVoice (const int index)
108 const ScopedLock sl (lock);
109 voices.remove (index);
112 void Synthesiser::clearSounds()
114 const ScopedLock sl (lock);
115 sounds.clear();
118 void Synthesiser::addSound (const SynthesiserSound::Ptr& newSound)
120 const ScopedLock sl (lock);
121 sounds.add (newSound);
124 void Synthesiser::removeSound (const int index)
126 const ScopedLock sl (lock);
127 sounds.remove (index);
130 void Synthesiser::setNoteStealingEnabled (const bool shouldStealNotes_)
132 shouldStealNotes = shouldStealNotes_;
135 //==============================================================================
136 void Synthesiser::setCurrentPlaybackSampleRate (const double newRate)
138 if (sampleRate != newRate)
140 const ScopedLock sl (lock);
142 allNotesOff (0, false);
144 sampleRate = newRate;
146 for (int i = voices.size(); --i >= 0;)
147 voices.getUnchecked (i)->setCurrentPlaybackSampleRate (newRate);
151 void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer,
152 const MidiBuffer& midiData,
153 int startSample,
154 int numSamples)
156 // must set the sample rate before using this!
157 jassert (sampleRate != 0);
159 const ScopedLock sl (lock);
161 MidiBuffer::Iterator midiIterator (midiData);
162 midiIterator.setNextSamplePosition (startSample);
163 MidiMessage m (0xf4, 0.0);
165 while (numSamples > 0)
167 int midiEventPos;
168 const bool useEvent = midiIterator.getNextEvent (m, midiEventPos)
169 && midiEventPos < startSample + numSamples;
171 const int numThisTime = useEvent ? midiEventPos - startSample
172 : numSamples;
174 if (numThisTime > 0)
176 for (int i = voices.size(); --i >= 0;)
177 voices.getUnchecked (i)->renderNextBlock (outputBuffer, startSample, numThisTime);
180 if (useEvent)
181 handleMidiEvent (m);
183 startSample += numThisTime;
184 numSamples -= numThisTime;
188 void Synthesiser::handleMidiEvent (const MidiMessage& m)
190 if (m.isNoteOn())
192 noteOn (m.getChannel(),
193 m.getNoteNumber(),
194 m.getFloatVelocity());
196 else if (m.isNoteOff())
198 noteOff (m.getChannel(),
199 m.getNoteNumber(),
200 true);
202 else if (m.isAllNotesOff() || m.isAllSoundOff())
204 allNotesOff (m.getChannel(), true);
206 else if (m.isPitchWheel())
208 const int channel = m.getChannel();
209 const int wheelPos = m.getPitchWheelValue();
210 lastPitchWheelValues [channel - 1] = wheelPos;
212 handlePitchWheel (channel, wheelPos);
214 else if (m.isController())
216 handleController (m.getChannel(),
217 m.getControllerNumber(),
218 m.getControllerValue());
222 //==============================================================================
223 void Synthesiser::noteOn (const int midiChannel,
224 const int midiNoteNumber,
225 const float velocity)
227 const ScopedLock sl (lock);
229 for (int i = sounds.size(); --i >= 0;)
231 SynthesiserSound* const sound = sounds.getUnchecked(i);
233 if (sound->appliesToNote (midiNoteNumber)
234 && sound->appliesToChannel (midiChannel))
236 // If hitting a note that's still ringing, stop it first (it could be
237 // still playing because of the sustain or sostenuto pedal).
238 for (int j = voices.size(); --j >= 0;)
240 SynthesiserVoice* const voice = voices.getUnchecked (j);
242 if (voice->getCurrentlyPlayingNote() == midiNoteNumber
243 && voice->isPlayingChannel (midiChannel))
244 stopVoice (voice, true);
247 startVoice (findFreeVoice (sound, shouldStealNotes),
248 sound, midiChannel, midiNoteNumber, velocity);
253 void Synthesiser::startVoice (SynthesiserVoice* const voice,
254 SynthesiserSound* const sound,
255 const int midiChannel,
256 const int midiNoteNumber,
257 const float velocity)
259 if (voice != nullptr && sound != nullptr)
261 if (voice->currentlyPlayingSound != nullptr)
262 voice->stopNote (false);
264 voice->startNote (midiNoteNumber, velocity, sound,
265 lastPitchWheelValues [midiChannel - 1]);
267 voice->currentlyPlayingNote = midiNoteNumber;
268 voice->noteOnTime = ++lastNoteOnCounter;
269 voice->currentlyPlayingSound = sound;
270 voice->keyIsDown = true;
271 voice->sostenutoPedalDown = false;
275 void Synthesiser::stopVoice (SynthesiserVoice* voice, const bool allowTailOff)
277 jassert (voice != nullptr);
279 voice->stopNote (allowTailOff);
281 // the subclass MUST call clearCurrentNote() if it's not tailing off! RTFM for stopNote()!
282 jassert (allowTailOff || (voice->getCurrentlyPlayingNote() < 0 && voice->getCurrentlyPlayingSound() == 0));
285 void Synthesiser::noteOff (const int midiChannel,
286 const int midiNoteNumber,
287 const bool allowTailOff)
289 const ScopedLock sl (lock);
291 for (int i = voices.size(); --i >= 0;)
293 SynthesiserVoice* const voice = voices.getUnchecked (i);
295 if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
297 SynthesiserSound* const sound = voice->getCurrentlyPlayingSound();
299 if (sound != nullptr
300 && sound->appliesToNote (midiNoteNumber)
301 && sound->appliesToChannel (midiChannel))
303 voice->keyIsDown = false;
305 if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown))
306 stopVoice (voice, allowTailOff);
312 void Synthesiser::allNotesOff (const int midiChannel, const bool allowTailOff)
314 const ScopedLock sl (lock);
316 for (int i = voices.size(); --i >= 0;)
318 SynthesiserVoice* const voice = voices.getUnchecked (i);
320 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
321 voice->stopNote (allowTailOff);
324 sustainPedalsDown.clear();
327 void Synthesiser::handlePitchWheel (const int midiChannel, const int wheelValue)
329 const ScopedLock sl (lock);
331 for (int i = voices.size(); --i >= 0;)
333 SynthesiserVoice* const voice = voices.getUnchecked (i);
335 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
336 voice->pitchWheelMoved (wheelValue);
340 void Synthesiser::handleController (const int midiChannel,
341 const int controllerNumber,
342 const int controllerValue)
344 switch (controllerNumber)
346 case 0x40: handleSustainPedal (midiChannel, controllerValue >= 64); break;
347 case 0x42: handleSostenutoPedal (midiChannel, controllerValue >= 64); break;
348 case 0x43: handleSoftPedal (midiChannel, controllerValue >= 64); break;
349 default: break;
352 const ScopedLock sl (lock);
354 for (int i = voices.size(); --i >= 0;)
356 SynthesiserVoice* const voice = voices.getUnchecked (i);
358 if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
359 voice->controllerMoved (controllerNumber, controllerValue);
363 void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
365 jassert (midiChannel > 0 && midiChannel <= 16);
366 const ScopedLock sl (lock);
368 if (isDown)
370 sustainPedalsDown.setBit (midiChannel);
372 else
374 for (int i = voices.size(); --i >= 0;)
376 SynthesiserVoice* const voice = voices.getUnchecked (i);
378 if (voice->isPlayingChannel (midiChannel) && ! voice->keyIsDown)
379 stopVoice (voice, true);
382 sustainPedalsDown.clearBit (midiChannel);
386 void Synthesiser::handleSostenutoPedal (int midiChannel, bool isDown)
388 jassert (midiChannel > 0 && midiChannel <= 16);
389 const ScopedLock sl (lock);
391 for (int i = voices.size(); --i >= 0;)
393 SynthesiserVoice* const voice = voices.getUnchecked (i);
395 if (voice->isPlayingChannel (midiChannel))
397 if (isDown)
398 voice->sostenutoPedalDown = true;
399 else if (voice->sostenutoPedalDown)
400 stopVoice (voice, true);
405 void Synthesiser::handleSoftPedal (int midiChannel, bool /*isDown*/)
407 (void) midiChannel;
408 jassert (midiChannel > 0 && midiChannel <= 16);
411 //==============================================================================
412 SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay,
413 const bool stealIfNoneAvailable) const
415 const ScopedLock sl (lock);
417 for (int i = voices.size(); --i >= 0;)
418 if (voices.getUnchecked (i)->getCurrentlyPlayingNote() < 0
419 && voices.getUnchecked (i)->canPlaySound (soundToPlay))
420 return voices.getUnchecked (i);
422 if (stealIfNoneAvailable)
424 // currently this just steals the one that's been playing the longest, but could be made a bit smarter..
425 SynthesiserVoice* oldest = nullptr;
427 for (int i = voices.size(); --i >= 0;)
429 SynthesiserVoice* const voice = voices.getUnchecked (i);
431 if (voice->canPlaySound (soundToPlay)
432 && (oldest == nullptr || oldest->noteOnTime > voice->noteOnTime))
433 oldest = voice;
436 jassert (oldest != nullptr);
437 return oldest;
440 return nullptr;
444 END_JUCE_NAMESPACE