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 13KB

11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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. {
  132. for (int i = voices.size(); --i >= 0;)
  133. voices.getUnchecked (i)->renderNextBlock (outputBuffer, startSample, numThisTime);
  134. }
  135. if (useEvent)
  136. handleMidiEvent (m);
  137. startSample += numThisTime;
  138. numSamples -= numThisTime;
  139. }
  140. }
  141. void Synthesiser::handleMidiEvent (const MidiMessage& m)
  142. {
  143. if (m.isNoteOn())
  144. {
  145. noteOn (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity());
  146. }
  147. else if (m.isNoteOff())
  148. {
  149. noteOff (m.getChannel(), m.getNoteNumber(), true);
  150. }
  151. else if (m.isAllNotesOff() || m.isAllSoundOff())
  152. {
  153. allNotesOff (m.getChannel(), true);
  154. }
  155. else if (m.isPitchWheel())
  156. {
  157. const int channel = m.getChannel();
  158. const int wheelPos = m.getPitchWheelValue();
  159. lastPitchWheelValues [channel - 1] = wheelPos;
  160. handlePitchWheel (channel, wheelPos);
  161. }
  162. else if (m.isAftertouch())
  163. {
  164. handleAftertouch (m.getChannel(), m.getNoteNumber(), m.getAfterTouchValue());
  165. }
  166. else if (m.isController())
  167. {
  168. handleController (m.getChannel(), m.getControllerNumber(), m.getControllerValue());
  169. }
  170. }
  171. //==============================================================================
  172. void Synthesiser::noteOn (const int midiChannel,
  173. const int midiNoteNumber,
  174. const float velocity)
  175. {
  176. const ScopedLock sl (lock);
  177. for (int i = sounds.size(); --i >= 0;)
  178. {
  179. SynthesiserSound* const sound = sounds.getUnchecked(i);
  180. if (sound->appliesToNote (midiNoteNumber)
  181. && sound->appliesToChannel (midiChannel))
  182. {
  183. // If hitting a note that's still ringing, stop it first (it could be
  184. // still playing because of the sustain or sostenuto pedal).
  185. for (int j = voices.size(); --j >= 0;)
  186. {
  187. SynthesiserVoice* const voice = voices.getUnchecked (j);
  188. if (voice->getCurrentlyPlayingNote() == midiNoteNumber
  189. && voice->isPlayingChannel (midiChannel))
  190. stopVoice (voice, true);
  191. }
  192. startVoice (findFreeVoice (sound, shouldStealNotes),
  193. sound, midiChannel, midiNoteNumber, velocity);
  194. }
  195. }
  196. }
  197. void Synthesiser::startVoice (SynthesiserVoice* const voice,
  198. SynthesiserSound* const sound,
  199. const int midiChannel,
  200. const int midiNoteNumber,
  201. const float velocity)
  202. {
  203. if (voice != nullptr && sound != nullptr)
  204. {
  205. if (voice->currentlyPlayingSound != nullptr)
  206. voice->stopNote (false);
  207. voice->startNote (midiNoteNumber, velocity, sound,
  208. lastPitchWheelValues [midiChannel - 1]);
  209. voice->currentlyPlayingNote = midiNoteNumber;
  210. voice->noteOnTime = ++lastNoteOnCounter;
  211. voice->currentlyPlayingSound = sound;
  212. voice->keyIsDown = true;
  213. voice->sostenutoPedalDown = false;
  214. }
  215. }
  216. void Synthesiser::stopVoice (SynthesiserVoice* voice, const bool allowTailOff)
  217. {
  218. jassert (voice != nullptr);
  219. voice->stopNote (allowTailOff);
  220. // the subclass MUST call clearCurrentNote() if it's not tailing off! RTFM for stopNote()!
  221. jassert (allowTailOff || (voice->getCurrentlyPlayingNote() < 0 && voice->getCurrentlyPlayingSound() == 0));
  222. }
  223. void Synthesiser::noteOff (const int midiChannel,
  224. const int midiNoteNumber,
  225. const bool allowTailOff)
  226. {
  227. const ScopedLock sl (lock);
  228. for (int i = voices.size(); --i >= 0;)
  229. {
  230. SynthesiserVoice* const voice = voices.getUnchecked (i);
  231. if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
  232. {
  233. if (SynthesiserSound* const sound = voice->getCurrentlyPlayingSound())
  234. {
  235. if (sound->appliesToNote (midiNoteNumber)
  236. && sound->appliesToChannel (midiChannel))
  237. {
  238. voice->keyIsDown = false;
  239. if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown))
  240. stopVoice (voice, allowTailOff);
  241. }
  242. }
  243. }
  244. }
  245. }
  246. void Synthesiser::allNotesOff (const int midiChannel, const bool allowTailOff)
  247. {
  248. const ScopedLock sl (lock);
  249. for (int i = voices.size(); --i >= 0;)
  250. {
  251. SynthesiserVoice* const voice = voices.getUnchecked (i);
  252. if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
  253. voice->stopNote (allowTailOff);
  254. }
  255. sustainPedalsDown.clear();
  256. }
  257. void Synthesiser::handlePitchWheel (const int midiChannel, const int wheelValue)
  258. {
  259. const ScopedLock sl (lock);
  260. for (int i = voices.size(); --i >= 0;)
  261. {
  262. SynthesiserVoice* const voice = voices.getUnchecked (i);
  263. if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
  264. voice->pitchWheelMoved (wheelValue);
  265. }
  266. }
  267. void Synthesiser::handleController (const int midiChannel,
  268. const int controllerNumber,
  269. const int controllerValue)
  270. {
  271. switch (controllerNumber)
  272. {
  273. case 0x40: handleSustainPedal (midiChannel, controllerValue >= 64); break;
  274. case 0x42: handleSostenutoPedal (midiChannel, controllerValue >= 64); break;
  275. case 0x43: handleSoftPedal (midiChannel, controllerValue >= 64); break;
  276. default: break;
  277. }
  278. const ScopedLock sl (lock);
  279. for (int i = voices.size(); --i >= 0;)
  280. {
  281. SynthesiserVoice* const voice = voices.getUnchecked (i);
  282. if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
  283. voice->controllerMoved (controllerNumber, controllerValue);
  284. }
  285. }
  286. void Synthesiser::handleAftertouch (int midiChannel, int midiNoteNumber, int aftertouchValue)
  287. {
  288. const ScopedLock sl (lock);
  289. for (int i = voices.size(); --i >= 0;)
  290. {
  291. SynthesiserVoice* const voice = voices.getUnchecked (i);
  292. if (voice->getCurrentlyPlayingNote() == midiNoteNumber
  293. && (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)))
  294. voice->aftertouchChanged (aftertouchValue);
  295. }
  296. }
  297. void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
  298. {
  299. jassert (midiChannel > 0 && midiChannel <= 16);
  300. const ScopedLock sl (lock);
  301. if (isDown)
  302. {
  303. sustainPedalsDown.setBit (midiChannel);
  304. }
  305. else
  306. {
  307. for (int i = voices.size(); --i >= 0;)
  308. {
  309. SynthesiserVoice* const voice = voices.getUnchecked (i);
  310. if (voice->isPlayingChannel (midiChannel) && ! voice->keyIsDown)
  311. stopVoice (voice, true);
  312. }
  313. sustainPedalsDown.clearBit (midiChannel);
  314. }
  315. }
  316. void Synthesiser::handleSostenutoPedal (int midiChannel, bool isDown)
  317. {
  318. jassert (midiChannel > 0 && midiChannel <= 16);
  319. const ScopedLock sl (lock);
  320. for (int i = voices.size(); --i >= 0;)
  321. {
  322. SynthesiserVoice* const voice = voices.getUnchecked (i);
  323. if (voice->isPlayingChannel (midiChannel))
  324. {
  325. if (isDown)
  326. voice->sostenutoPedalDown = true;
  327. else if (voice->sostenutoPedalDown)
  328. stopVoice (voice, true);
  329. }
  330. }
  331. }
  332. void Synthesiser::handleSoftPedal (int midiChannel, bool /*isDown*/)
  333. {
  334. (void) midiChannel;
  335. jassert (midiChannel > 0 && midiChannel <= 16);
  336. }
  337. //==============================================================================
  338. SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, const bool stealIfNoneAvailable) const
  339. {
  340. const ScopedLock sl (lock);
  341. for (int i = 0; i < voices.size(); ++i)
  342. {
  343. SynthesiserVoice* const voice = voices.getUnchecked (i);
  344. if (voice->getCurrentlyPlayingNote() < 0 && voice->canPlaySound (soundToPlay))
  345. return voice;
  346. }
  347. if (stealIfNoneAvailable)
  348. return findVoiceToSteal (soundToPlay);
  349. return nullptr;
  350. }
  351. SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay) const
  352. {
  353. // currently this just steals the one that's been playing the longest, but could be made a bit smarter..
  354. SynthesiserVoice* oldest = nullptr;
  355. for (int i = 0; i < voices.size(); ++i)
  356. {
  357. SynthesiserVoice* const voice = voices.getUnchecked (i);
  358. if (voice->canPlaySound (soundToPlay)
  359. && (oldest == nullptr || voice->wasStartedBefore (*oldest)))
  360. oldest = voice;
  361. }
  362. jassert (oldest != nullptr);
  363. return oldest;
  364. }