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.

173 lines
4.2KB

  1. /*************************************************************************************
  2. * Original code copyright (C) 2012 Steve Folta
  3. * Converted to Juce module (C) 2016 Leo Olivers
  4. * Forked from https://github.com/stevefolta/SFZero
  5. * For license info please see the LICENSE file distributed with this source code
  6. *************************************************************************************/
  7. #include "SFZSynth.h"
  8. #include "SFZSound.h"
  9. #include "SFZVoice.h"
  10. namespace sfzero
  11. {
  12. Synth::Synth() : Synthesiser() {}
  13. void Synth::noteOn(int midiChannel, int midiNoteNumber, float velocity)
  14. {
  15. int i;
  16. int midiVelocity = static_cast<int>(velocity * 127);
  17. // First, stop any currently-playing sounds in the group.
  18. //*** Currently, this only pays attention to the first matching region.
  19. int group = 0;
  20. Sound *sound = dynamic_cast<Sound *>(getSound(0));
  21. if (sound)
  22. {
  23. Region *region = sound->getRegionFor(midiNoteNumber, midiVelocity);
  24. if (region)
  25. {
  26. group = region->group;
  27. }
  28. }
  29. if (group != 0)
  30. {
  31. for (i = voices.size(); --i >= 0;)
  32. {
  33. Voice *voice = dynamic_cast<Voice *>(voices.getUnchecked(i));
  34. if (voice == nullptr)
  35. {
  36. continue;
  37. }
  38. if (voice->getGroup() == group)
  39. {
  40. voice->stopNoteForGroup();
  41. }
  42. }
  43. }
  44. // Are any notes playing? (Needed for first/legato trigger handling.)
  45. // Also stop any voices still playing this note.
  46. bool anyNotesPlaying = false;
  47. for (i = voices.size(); --i >= 0;)
  48. {
  49. Voice *voice = dynamic_cast<Voice *>(voices.getUnchecked(i));
  50. if (voice == nullptr)
  51. {
  52. continue;
  53. }
  54. if (voice->isPlayingChannel(midiChannel))
  55. {
  56. if (voice->isPlayingNoteDown())
  57. {
  58. if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
  59. {
  60. if (!voice->isPlayingOneShot())
  61. {
  62. voice->stopNoteQuick();
  63. }
  64. }
  65. else
  66. {
  67. anyNotesPlaying = true;
  68. }
  69. }
  70. }
  71. }
  72. // Play *all* matching regions.
  73. Region::Trigger trigger = (anyNotesPlaying ? Region::legato : Region::first);
  74. if (sound)
  75. {
  76. int numRegions = sound->getNumRegions();
  77. for (i = 0; i < numRegions; ++i)
  78. {
  79. Region *region = sound->regionAt(i);
  80. if (region->matches(midiNoteNumber, midiVelocity, trigger))
  81. {
  82. Voice *voice =
  83. dynamic_cast<Voice *>(findFreeVoice(sound, midiNoteNumber, midiChannel, isNoteStealingEnabled()));
  84. if (voice)
  85. {
  86. voice->setRegion(region);
  87. startVoice(voice, sound, midiChannel, midiNoteNumber, velocity);
  88. }
  89. }
  90. }
  91. }
  92. noteVelocities_[midiNoteNumber] = midiVelocity;
  93. }
  94. void Synth::noteOff(int midiChannel, int midiNoteNumber, float velocity, bool allowTailOff)
  95. {
  96. Synthesiser::noteOff(midiChannel, midiNoteNumber, velocity, allowTailOff);
  97. // Start release region.
  98. Sound *sound = dynamic_cast<Sound *>(getSound(0));
  99. if (sound)
  100. {
  101. Region *region = sound->getRegionFor(midiNoteNumber, noteVelocities_[midiNoteNumber], Region::release);
  102. if (region)
  103. {
  104. Voice *voice = dynamic_cast<Voice *>(findFreeVoice(sound, midiNoteNumber, midiChannel, false));
  105. if (voice)
  106. {
  107. // Synthesiser is too locked-down (ivars are private rt protected), so
  108. // we have to use a "setRegion()" mechanism.
  109. voice->setRegion(region);
  110. startVoice(voice, sound, midiChannel, midiNoteNumber, noteVelocities_[midiNoteNumber] / 127.0f);
  111. }
  112. }
  113. }
  114. }
  115. int Synth::numVoicesUsed()
  116. {
  117. int numUsed = 0;
  118. for (int i = voices.size(); --i >= 0;)
  119. {
  120. if (voices.getUnchecked(i)->getCurrentlyPlayingNote() >= 0)
  121. {
  122. numUsed += 1;
  123. }
  124. }
  125. return numUsed;
  126. }
  127. water::String Synth::voiceInfoString()
  128. {
  129. enum
  130. {
  131. maxShownVoices = 20,
  132. };
  133. water::StringArray lines;
  134. int numUsed = 0, numShown = 0;
  135. for (int i = voices.size(); --i >= 0;)
  136. {
  137. Voice *voice = dynamic_cast<Voice *>(voices.getUnchecked(i));
  138. if (voice->getCurrentlyPlayingNote() < 0)
  139. {
  140. continue;
  141. }
  142. numUsed += 1;
  143. if (numShown >= maxShownVoices)
  144. {
  145. continue;
  146. }
  147. lines.add(voice->infoString());
  148. }
  149. lines.insert(0, "voices used: " + water::String(numUsed));
  150. return lines.joinIntoString("\n");
  151. }
  152. }