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.

499 lines
15KB

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