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.

215 lines
6.2KB

  1. /*
  2. * DISTRHO Kars Plugin, based on karplong by Chris Cannam.
  3. * Copyright (C) 2015 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. START_NAMESPACE_DISTRHO
  18. // -----------------------------------------------------------------------
  19. DistrhoPluginKars::DistrhoPluginKars()
  20. : Plugin(paramCount, 0, 0), // 0 programs, 0 states
  21. fSustain(false),
  22. fSampleRate(getSampleRate()),
  23. fBlockStart(0)
  24. {
  25. for (int i=kMaxNotes; --i >= 0;)
  26. {
  27. fNotes[i].index = i;
  28. fNotes[i].setSampleRate(fSampleRate);
  29. }
  30. }
  31. // -----------------------------------------------------------------------
  32. // Init
  33. void DistrhoPluginKars::initParameter(uint32_t index, Parameter& parameter)
  34. {
  35. if (index != 0)
  36. return;
  37. parameter.hints = kParameterIsAutomable|kParameterIsBoolean;
  38. parameter.name = "Sustain";
  39. parameter.symbol = "sustain";
  40. parameter.ranges.def = 0.0f;
  41. parameter.ranges.min = 0.0f;
  42. parameter.ranges.max = 1.0f;
  43. }
  44. // -----------------------------------------------------------------------
  45. // Internal data
  46. float DistrhoPluginKars::getParameterValue(uint32_t index) const
  47. {
  48. if (index != 0)
  49. return 0.0f;
  50. return fSustain ? 1.0f : 0.0f;
  51. }
  52. void DistrhoPluginKars::setParameterValue(uint32_t index, float value)
  53. {
  54. if (index != 0)
  55. return;
  56. fSustain = value > 0.5f;
  57. }
  58. // -----------------------------------------------------------------------
  59. // Process
  60. void DistrhoPluginKars::activate()
  61. {
  62. fBlockStart = 0;
  63. for (int i=kMaxNotes; --i >= 0;)
  64. {
  65. fNotes[i].on = kNoteNull;
  66. fNotes[i].off = kNoteNull;
  67. fNotes[i].velocity = 0;
  68. }
  69. }
  70. void DistrhoPluginKars::run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount)
  71. {
  72. uint8_t note, velo;
  73. float* out = outputs[0];
  74. for (uint32_t count, pos=0, curEventIndex=0; pos<frames;)
  75. {
  76. for (;curEventIndex < midiEventCount && pos >= midiEvents[curEventIndex].frame; ++curEventIndex)
  77. {
  78. if (midiEvents[curEventIndex].size > MidiEvent::kDataSize)
  79. continue;
  80. const uint8_t* data = midiEvents[curEventIndex].data;
  81. const uint8_t status = data[0] & 0xF0;
  82. switch (status)
  83. {
  84. case 0x90:
  85. note = data[1];
  86. velo = data[2];
  87. DISTRHO_SAFE_ASSERT_BREAK(note < 128); // kMaxNotes
  88. if (velo > 0)
  89. {
  90. fNotes[note].on = fBlockStart + midiEvents[curEventIndex].frame;
  91. fNotes[note].off = kNoteNull;
  92. fNotes[note].velocity = velo;
  93. break;
  94. }
  95. // fall through
  96. case 0x80:
  97. note = data[1];
  98. DISTRHO_SAFE_ASSERT_BREAK(note < 128); // kMaxNotes
  99. fNotes[note].off = fBlockStart + midiEvents[curEventIndex].frame;
  100. break;
  101. }
  102. }
  103. if (curEventIndex < midiEventCount && midiEvents[curEventIndex].frame < frames)
  104. count = midiEvents[curEventIndex].frame - pos;
  105. else
  106. count = frames - pos;
  107. std::memset(out+pos, 0, sizeof(float)*count);
  108. //for (uint32_t i=0; i<count; ++i)
  109. // out[pos + i] = 0.0f;
  110. for (int i=kMaxNotes; --i >= 0;)
  111. {
  112. if (fNotes[i].on != kNoteNull)
  113. addSamples(out, i, pos, count);
  114. }
  115. pos += count;
  116. }
  117. fBlockStart += frames;
  118. }
  119. void DistrhoPluginKars::addSamples(float* out, int voice, uint32_t offset, uint32_t count)
  120. {
  121. const uint32_t start = fBlockStart + offset;
  122. Note& note(fNotes[voice]);
  123. if (start < note.on)
  124. return;
  125. if (start == note.on)
  126. {
  127. for (int i=note.sizei; --i >= 0;)
  128. note.wavetable[i] = (float(rand()) / float(RAND_MAX)) * 2.0f - 1.0f;
  129. }
  130. const float vgain = float(note.velocity) / 127.0f;
  131. bool decay;
  132. float gain, sample;
  133. uint32_t index, size;
  134. for (uint32_t i=0, s=start-note.on; i<count; ++i, ++s)
  135. {
  136. gain = vgain;
  137. if ((! fSustain) && note.off != kNoteNull && note.off < i+start)
  138. {
  139. // reuse index and size to save some performance.
  140. // actual values are release and dist
  141. index = 1 + uint32_t(0.01 * fSampleRate); // release, not index
  142. size = i + start - note.off; // dist, not size
  143. if (size > index)
  144. {
  145. note.on = kNoteNull;
  146. break;
  147. }
  148. gain = gain * float(index - size) / float(index);
  149. }
  150. size = uint32_t(note.sizei);
  151. decay = s > size;
  152. index = s % size;
  153. sample = note.wavetable[index];
  154. if (decay)
  155. {
  156. if (index == 0)
  157. sample += note.wavetable[size-1];
  158. else
  159. sample += note.wavetable[index-1];
  160. note.wavetable[index] = sample/2;
  161. }
  162. out[offset+i] += gain * sample;
  163. }
  164. }
  165. // -----------------------------------------------------------------------
  166. Plugin* createPlugin()
  167. {
  168. return new DistrhoPluginKars();
  169. }
  170. // -----------------------------------------------------------------------
  171. END_NAMESPACE_DISTRHO