Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_Synthesiser.cpp 15KB

11 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
9 years ago
11 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. SynthesiserSound::SynthesiserSound() {}
  18. SynthesiserSound::~SynthesiserSound() {}
  19. //==============================================================================
  20. SynthesiserVoice::SynthesiserVoice()
  21. : currentSampleRate (44100.0),
  22. currentlyPlayingNote (-1),
  23. currentPlayingMidiChannel (0),
  24. noteOnTime (0),
  25. keyIsDown (false),
  26. sostenutoPedalDown (false)
  27. {
  28. }
  29. SynthesiserVoice::~SynthesiserVoice()
  30. {
  31. }
  32. bool SynthesiserVoice::isPlayingChannel (const int midiChannel) const
  33. {
  34. return currentPlayingMidiChannel == midiChannel;
  35. }
  36. void SynthesiserVoice::setCurrentPlaybackSampleRate (const double newRate)
  37. {
  38. currentSampleRate = newRate;
  39. }
  40. bool SynthesiserVoice::isVoiceActive() const
  41. {
  42. return getCurrentlyPlayingNote() >= 0;
  43. }
  44. void SynthesiserVoice::clearCurrentNote()
  45. {
  46. currentlyPlayingNote = -1;
  47. currentlyPlayingSound = nullptr;
  48. currentPlayingMidiChannel = 0;
  49. }
  50. void SynthesiserVoice::aftertouchChanged (int) {}
  51. bool SynthesiserVoice::wasStartedBefore (const SynthesiserVoice& other) const noexcept
  52. {
  53. return noteOnTime < other.noteOnTime;
  54. }
  55. //==============================================================================
  56. Synthesiser::Synthesiser()
  57. : sampleRate (0),
  58. lastNoteOnCounter (0),
  59. shouldStealNotes (true)
  60. {
  61. for (int i = 0; i < numElementsInArray (lastPitchWheelValues); ++i)
  62. lastPitchWheelValues[i] = 0x2000;
  63. }
  64. Synthesiser::~Synthesiser()
  65. {
  66. }
  67. //==============================================================================
  68. SynthesiserVoice* Synthesiser::getVoice (const int index) const
  69. {
  70. const ScopedLock sl (lock);
  71. return voices [index];
  72. }
  73. void Synthesiser::clearVoices()
  74. {
  75. const ScopedLock sl (lock);
  76. voices.clear();
  77. }
  78. SynthesiserVoice* Synthesiser::addVoice (SynthesiserVoice* const newVoice)
  79. {
  80. const ScopedLock sl (lock);
  81. return voices.add (newVoice);
  82. }
  83. void Synthesiser::removeVoice (const int index)
  84. {
  85. const ScopedLock sl (lock);
  86. voices.remove (index);
  87. }
  88. void Synthesiser::clearSounds()
  89. {
  90. const ScopedLock sl (lock);
  91. sounds.clear();
  92. }
  93. SynthesiserSound* Synthesiser::addSound (const SynthesiserSound::Ptr& newSound)
  94. {
  95. const ScopedLock sl (lock);
  96. return sounds.add (newSound);
  97. }
  98. void Synthesiser::removeSound (const int index)
  99. {
  100. const ScopedLock sl (lock);
  101. sounds.remove (index);
  102. }
  103. void Synthesiser::setNoteStealingEnabled (const bool shouldSteal)
  104. {
  105. shouldStealNotes = shouldSteal;
  106. }
  107. //==============================================================================
  108. void Synthesiser::setCurrentPlaybackSampleRate (const double newRate)
  109. {
  110. if (sampleRate != newRate)
  111. {
  112. const ScopedLock sl (lock);
  113. allNotesOff (0, false);
  114. sampleRate = newRate;
  115. for (int i = voices.size(); --i >= 0;)
  116. voices.getUnchecked (i)->setCurrentPlaybackSampleRate (newRate);
  117. }
  118. }
  119. void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBuffer& midiData,
  120. int startSample, int numSamples)
  121. {
  122. // must set the sample rate before using this!
  123. jassert (sampleRate != 0);
  124. const ScopedLock sl (lock);
  125. MidiBuffer::Iterator midiIterator (midiData);
  126. midiIterator.setNextSamplePosition (startSample);
  127. MidiMessage m (0xf4, 0.0);
  128. while (numSamples > 0)
  129. {
  130. int midiEventPos;
  131. const bool useEvent = midiIterator.getNextEvent (m, midiEventPos)
  132. && midiEventPos < startSample + numSamples;
  133. const int numThisTime = useEvent ? midiEventPos - startSample
  134. : numSamples;
  135. if (numThisTime > 0)
  136. renderVoices (outputBuffer, startSample, numThisTime);
  137. if (useEvent)
  138. handleMidiEvent (m);
  139. startSample += numThisTime;
  140. numSamples -= numThisTime;
  141. }
  142. }
  143. void Synthesiser::renderVoices (AudioSampleBuffer& buffer, int startSample, int numSamples)
  144. {
  145. for (int i = voices.size(); --i >= 0;)
  146. voices.getUnchecked (i)->renderNextBlock (buffer, startSample, numSamples);
  147. }
  148. void Synthesiser::handleMidiEvent (const MidiMessage& m)
  149. {
  150. if (m.isNoteOn())
  151. {
  152. noteOn (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity());
  153. }
  154. else if (m.isNoteOff())
  155. {
  156. noteOff (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity(), true);
  157. }
  158. else if (m.isAllNotesOff() || m.isAllSoundOff())
  159. {
  160. allNotesOff (m.getChannel(), true);
  161. }
  162. else if (m.isPitchWheel())
  163. {
  164. const int channel = m.getChannel();
  165. const int wheelPos = m.getPitchWheelValue();
  166. lastPitchWheelValues [channel - 1] = wheelPos;
  167. handlePitchWheel (channel, wheelPos);
  168. }
  169. else if (m.isAftertouch())
  170. {
  171. handleAftertouch (m.getChannel(), m.getNoteNumber(), m.getAfterTouchValue());
  172. }
  173. else if (m.isController())
  174. {
  175. handleController (m.getChannel(), m.getControllerNumber(), m.getControllerValue());
  176. }
  177. }
  178. //==============================================================================
  179. void Synthesiser::noteOn (const int midiChannel,
  180. const int midiNoteNumber,
  181. const float velocity)
  182. {
  183. const ScopedLock sl (lock);
  184. for (int i = sounds.size(); --i >= 0;)
  185. {
  186. SynthesiserSound* const sound = sounds.getUnchecked(i);
  187. if (sound->appliesToNote (midiNoteNumber)
  188. && sound->appliesToChannel (midiChannel))
  189. {
  190. // If hitting a note that's still ringing, stop it first (it could be
  191. // still playing because of the sustain or sostenuto pedal).
  192. for (int j = voices.size(); --j >= 0;)
  193. {
  194. SynthesiserVoice* const voice = voices.getUnchecked (j);
  195. if (voice->getCurrentlyPlayingNote() == midiNoteNumber
  196. && voice->isPlayingChannel (midiChannel))
  197. stopVoice (voice, 1.0f, true);
  198. }
  199. startVoice (findFreeVoice (sound, midiChannel, midiNoteNumber, shouldStealNotes),
  200. sound, midiChannel, midiNoteNumber, velocity);
  201. }
  202. }
  203. }
  204. void Synthesiser::startVoice (SynthesiserVoice* const voice,
  205. SynthesiserSound* const sound,
  206. const int midiChannel,
  207. const int midiNoteNumber,
  208. const float velocity)
  209. {
  210. if (voice != nullptr && sound != nullptr)
  211. {
  212. if (voice->currentlyPlayingSound != nullptr)
  213. voice->stopNote (0.0f, false);
  214. voice->currentlyPlayingNote = midiNoteNumber;
  215. voice->currentPlayingMidiChannel = midiChannel;
  216. voice->noteOnTime = ++lastNoteOnCounter;
  217. voice->currentlyPlayingSound = sound;
  218. voice->keyIsDown = true;
  219. voice->sostenutoPedalDown = false;
  220. voice->startNote (midiNoteNumber, velocity, sound,
  221. lastPitchWheelValues [midiChannel - 1]);
  222. }
  223. }
  224. void Synthesiser::stopVoice (SynthesiserVoice* voice, float velocity, const bool allowTailOff)
  225. {
  226. jassert (voice != nullptr);
  227. voice->stopNote (velocity, allowTailOff);
  228. // the subclass MUST call clearCurrentNote() if it's not tailing off! RTFM for stopNote()!
  229. jassert (allowTailOff || (voice->getCurrentlyPlayingNote() < 0 && voice->getCurrentlyPlayingSound() == 0));
  230. }
  231. void Synthesiser::noteOff (const int midiChannel,
  232. const int midiNoteNumber,
  233. const float velocity,
  234. const bool allowTailOff)
  235. {
  236. const ScopedLock sl (lock);
  237. for (int i = voices.size(); --i >= 0;)
  238. {
  239. SynthesiserVoice* const voice = voices.getUnchecked (i);
  240. if (voice->getCurrentlyPlayingNote() == midiNoteNumber
  241. && voice->isPlayingChannel (midiChannel))
  242. {
  243. if (SynthesiserSound* const sound = voice->getCurrentlyPlayingSound())
  244. {
  245. if (sound->appliesToNote (midiNoteNumber)
  246. && sound->appliesToChannel (midiChannel))
  247. {
  248. voice->keyIsDown = false;
  249. if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown))
  250. stopVoice (voice, velocity, allowTailOff);
  251. }
  252. }
  253. }
  254. }
  255. }
  256. void Synthesiser::allNotesOff (const int midiChannel, const bool allowTailOff)
  257. {
  258. const ScopedLock sl (lock);
  259. for (int i = voices.size(); --i >= 0;)
  260. {
  261. SynthesiserVoice* const voice = voices.getUnchecked (i);
  262. if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
  263. voice->stopNote (1.0f, allowTailOff);
  264. }
  265. sustainPedalsDown.clear();
  266. }
  267. void Synthesiser::handlePitchWheel (const int midiChannel, const int wheelValue)
  268. {
  269. const ScopedLock sl (lock);
  270. for (int i = voices.size(); --i >= 0;)
  271. {
  272. SynthesiserVoice* const voice = voices.getUnchecked (i);
  273. if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
  274. voice->pitchWheelMoved (wheelValue);
  275. }
  276. }
  277. void Synthesiser::handleController (const int midiChannel,
  278. const int controllerNumber,
  279. const int controllerValue)
  280. {
  281. switch (controllerNumber)
  282. {
  283. case 0x40: handleSustainPedal (midiChannel, controllerValue >= 64); break;
  284. case 0x42: handleSostenutoPedal (midiChannel, controllerValue >= 64); break;
  285. case 0x43: handleSoftPedal (midiChannel, controllerValue >= 64); break;
  286. default: break;
  287. }
  288. const ScopedLock sl (lock);
  289. for (int i = voices.size(); --i >= 0;)
  290. {
  291. SynthesiserVoice* const voice = voices.getUnchecked (i);
  292. if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
  293. voice->controllerMoved (controllerNumber, controllerValue);
  294. }
  295. }
  296. void Synthesiser::handleAftertouch (int midiChannel, int midiNoteNumber, int aftertouchValue)
  297. {
  298. const ScopedLock sl (lock);
  299. for (int i = voices.size(); --i >= 0;)
  300. {
  301. SynthesiserVoice* const voice = voices.getUnchecked (i);
  302. if (voice->getCurrentlyPlayingNote() == midiNoteNumber
  303. && (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)))
  304. voice->aftertouchChanged (aftertouchValue);
  305. }
  306. }
  307. void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
  308. {
  309. jassert (midiChannel > 0 && midiChannel <= 16);
  310. const ScopedLock sl (lock);
  311. if (isDown)
  312. {
  313. sustainPedalsDown.setBit (midiChannel);
  314. }
  315. else
  316. {
  317. for (int i = voices.size(); --i >= 0;)
  318. {
  319. SynthesiserVoice* const voice = voices.getUnchecked (i);
  320. if (voice->isPlayingChannel (midiChannel) && ! voice->keyIsDown)
  321. stopVoice (voice, 1.0f, true);
  322. }
  323. sustainPedalsDown.clearBit (midiChannel);
  324. }
  325. }
  326. void Synthesiser::handleSostenutoPedal (int midiChannel, bool isDown)
  327. {
  328. jassert (midiChannel > 0 && midiChannel <= 16);
  329. const ScopedLock sl (lock);
  330. for (int i = voices.size(); --i >= 0;)
  331. {
  332. SynthesiserVoice* const voice = voices.getUnchecked (i);
  333. if (voice->isPlayingChannel (midiChannel))
  334. {
  335. if (isDown)
  336. voice->sostenutoPedalDown = true;
  337. else if (voice->sostenutoPedalDown)
  338. stopVoice (voice, 1.0f, true);
  339. }
  340. }
  341. }
  342. void Synthesiser::handleSoftPedal (int midiChannel, bool /*isDown*/)
  343. {
  344. (void) midiChannel;
  345. jassert (midiChannel > 0 && midiChannel <= 16);
  346. }
  347. //==============================================================================
  348. SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay,
  349. int midiChannel, int midiNoteNumber,
  350. const bool stealIfNoneAvailable) const
  351. {
  352. const ScopedLock sl (lock);
  353. for (int i = 0; i < voices.size(); ++i)
  354. {
  355. SynthesiserVoice* const voice = voices.getUnchecked (i);
  356. if ((! voice->isVoiceActive()) && voice->canPlaySound (soundToPlay))
  357. return voice;
  358. }
  359. if (stealIfNoneAvailable)
  360. return findVoiceToSteal (soundToPlay, midiChannel, midiNoteNumber);
  361. return nullptr;
  362. }
  363. struct VoiceAgeSorter
  364. {
  365. static int compareElements (SynthesiserVoice* v1, SynthesiserVoice* v2) noexcept
  366. {
  367. return v1->wasStartedBefore (*v2) ? -1 : (v2->wasStartedBefore (*v1) ? 1 : 0);
  368. }
  369. };
  370. SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
  371. int /*midiChannel*/, int midiNoteNumber) const
  372. {
  373. SynthesiserVoice* bottom = nullptr;
  374. SynthesiserVoice* top = nullptr;
  375. // this is a list of voices we can steal, sorted by how long they've been running
  376. Array<SynthesiserVoice*> usableVoices;
  377. usableVoices.ensureStorageAllocated (voices.size());
  378. for (int i = 0; i < voices.size(); ++i)
  379. {
  380. SynthesiserVoice* const voice = voices.getUnchecked (i);
  381. if (voice->canPlaySound (soundToPlay))
  382. {
  383. VoiceAgeSorter sorter;
  384. usableVoices.addSorted (sorter, voice);
  385. const int note = voice->getCurrentlyPlayingNote();
  386. if (bottom == nullptr || note < bottom->getCurrentlyPlayingNote())
  387. bottom = voice;
  388. if (top == nullptr || note > top->getCurrentlyPlayingNote())
  389. top = voice;
  390. }
  391. }
  392. const int stealableVoiceRange = usableVoices.size() - 6;
  393. // The oldest note that's playing with the target pitch playing is ideal..
  394. for (int i = 0; i < stealableVoiceRange; ++i)
  395. {
  396. SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
  397. if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
  398. return voice;
  399. }
  400. // ..otherwise, look for the oldest note that isn't the top or bottom note..
  401. for (int i = 0; i < stealableVoiceRange; ++i)
  402. {
  403. SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
  404. if (voice != bottom && voice != top)
  405. return voice;
  406. }
  407. // ..otherwise, there's only one or two voices to choose from - we'll return the oldest one..
  408. return usableVoices.getFirst();
  409. }