Collection of DPF-based plugins for packaging
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.

256 lines
7.2KB

  1. /*
  2. * DISTRHO Kars Plugin, based on karplong by Chris Cannam.
  3. * Copyright (C) 2015-2022 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "DistrhoPluginKars.hpp"
  17. #include "DistrhoPluginUtils.hpp"
  18. START_NAMESPACE_DISTRHO
  19. // -----------------------------------------------------------------------
  20. DistrhoPluginKars::DistrhoPluginKars()
  21. : Plugin(paramCount, 0, 0), // 0 programs, 0 states
  22. fSustain(false),
  23. fRelease(0.01),
  24. fVolume(75.0f),
  25. fSampleRate(getSampleRate()),
  26. fBlockStart(0)
  27. {
  28. for (int i=kMaxNotes; --i >= 0;)
  29. {
  30. fNotes[i].voice = i;
  31. fNotes[i].setSampleRate(fSampleRate);
  32. }
  33. }
  34. // -----------------------------------------------------------------------
  35. // Init
  36. void DistrhoPluginKars::initAudioPort(bool input, uint32_t index, AudioPort& port)
  37. {
  38. port.groupId = kPortGroupMono;
  39. Plugin::initAudioPort(input, index, port);
  40. }
  41. void DistrhoPluginKars::initParameter(uint32_t index, Parameter& parameter)
  42. {
  43. switch (index)
  44. {
  45. case paramSustain:
  46. parameter.hints = kParameterIsAutomatable|kParameterIsBoolean;
  47. parameter.name = "Sustain";
  48. parameter.symbol = "sustain";
  49. parameter.ranges.def = 0.0f;
  50. parameter.ranges.min = 0.0f;
  51. parameter.ranges.max = 1.0f;
  52. break;
  53. case paramRelease:
  54. parameter.hints = kParameterIsAutomatable;
  55. parameter.name = "Release";
  56. parameter.symbol = "release";
  57. parameter.unit = "s";
  58. parameter.ranges.def = 0.01f;
  59. parameter.ranges.min = 0.0f;
  60. parameter.ranges.max = 5.0f;
  61. break;
  62. case paramVolume:
  63. parameter.hints = kParameterIsAutomatable;
  64. parameter.name = "Volume";
  65. parameter.symbol = "volume";
  66. parameter.unit = "%";
  67. parameter.ranges.def = 75.0f;
  68. parameter.ranges.min = 0.0f;
  69. parameter.ranges.max = 100.0f;
  70. break;
  71. }
  72. }
  73. // -----------------------------------------------------------------------
  74. // Internal data
  75. float DistrhoPluginKars::getParameterValue(uint32_t index) const
  76. {
  77. switch (index)
  78. {
  79. case paramSustain: return fSustain ? 1.0f : 0.0f;
  80. case paramRelease: return fRelease;
  81. case paramVolume: return fVolume;
  82. }
  83. return 0.0f;
  84. }
  85. void DistrhoPluginKars::setParameterValue(uint32_t index, float value)
  86. {
  87. switch (index)
  88. {
  89. case paramSustain:
  90. fSustain = value > 0.5f;
  91. break;
  92. case paramRelease:
  93. fRelease = value;
  94. break;
  95. case paramVolume:
  96. fVolume = value;
  97. break;
  98. }
  99. }
  100. // -----------------------------------------------------------------------
  101. // Process
  102. void DistrhoPluginKars::activate()
  103. {
  104. fBlockStart = 0;
  105. for (int i=kMaxNotes; --i >= 0;)
  106. {
  107. fNotes[i].on = kNoteNull;
  108. fNotes[i].off = kNoteNull;
  109. fNotes[i].velocity = 0;
  110. }
  111. }
  112. void DistrhoPluginKars::run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount)
  113. {
  114. uint8_t note, velo;
  115. std::memset(outputs[0], 0, sizeof(float)*frames);
  116. for (AudioMidiSyncHelper amsh(outputs, frames, midiEvents, midiEventCount); amsh.nextEvent();)
  117. {
  118. for (uint32_t i=0; i<amsh.midiEventCount; ++i)
  119. {
  120. if (amsh.midiEvents[i].size > MidiEvent::kDataSize)
  121. continue;
  122. const uint8_t* data = amsh.midiEvents[i].data;
  123. const uint8_t status = data[0] & 0xF0;
  124. switch (status)
  125. {
  126. case 0x90:
  127. note = data[1];
  128. velo = data[2];
  129. DISTRHO_SAFE_ASSERT_BREAK(note < 128); // kMaxNotes
  130. if (velo > 0)
  131. {
  132. fNotes[note].on = fBlockStart;
  133. fNotes[note].off = kNoteNull;
  134. fNotes[note].velocity = velo;
  135. break;
  136. }
  137. // fall through
  138. case 0x80:
  139. note = data[1];
  140. DISTRHO_SAFE_ASSERT_BREAK(note < 128); // kMaxNotes
  141. fNotes[note].off = fBlockStart;
  142. break;
  143. }
  144. }
  145. float* const out = amsh.outputs[0];
  146. for (int i=kMaxNotes; --i >= 0;)
  147. {
  148. if (fNotes[i].on != kNoteNull)
  149. addSamples(out, i, amsh.frames);
  150. }
  151. fBlockStart += amsh.frames;
  152. }
  153. }
  154. void DistrhoPluginKars::sampleRateChanged(double newSampleRate)
  155. {
  156. fSampleRate = getSampleRate();
  157. for (int i=kMaxNotes; --i >= 0;)
  158. fNotes[i].setSampleRate(newSampleRate);
  159. }
  160. void DistrhoPluginKars::addSamples(float* out, int voice, uint32_t frames)
  161. {
  162. const uint32_t start = fBlockStart;
  163. Note& note(fNotes[voice]);
  164. if (start < note.on)
  165. return;
  166. if (start == note.on)
  167. {
  168. for (int i=note.sizei; --i >= 0;)
  169. note.wavetable[i] = (float(rand()) / float(RAND_MAX)) * 2.0f - 1.0f;
  170. }
  171. const float vgain = float(note.velocity) / 127.0f;
  172. bool decay;
  173. float gain, sample;
  174. uint32_t index, size;
  175. for (uint32_t i=0, s=start-note.on; i<frames; ++i, ++s)
  176. {
  177. gain = vgain;
  178. if ((! fSustain) && note.off != kNoteNull && note.off < i+start)
  179. {
  180. // reuse index and size to save some performance.
  181. // actual values are release and dist
  182. index = 1 + uint32_t(fRelease * fSampleRate); // release, not index
  183. size = i + start - note.off; // dist, not size
  184. if (size > index)
  185. {
  186. note.on = kNoteNull;
  187. break;
  188. }
  189. gain = gain * float(index - size) / float(index);
  190. }
  191. size = uint32_t(note.sizei);
  192. decay = s > size;
  193. index = s % size;
  194. sample = note.wavetable[index];
  195. if (decay)
  196. {
  197. if (index == 0)
  198. sample += note.wavetable[size-1];
  199. else
  200. sample += note.wavetable[index-1];
  201. note.wavetable[index] = sample/2;
  202. }
  203. out[i] += gain * sample * (fVolume / 100.0f);
  204. }
  205. }
  206. // -----------------------------------------------------------------------
  207. Plugin* createPlugin()
  208. {
  209. return new DistrhoPluginKars();
  210. }
  211. // -----------------------------------------------------------------------
  212. END_NAMESPACE_DISTRHO