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.

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