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