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.

161 lines
5.6KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. SynthNote.cpp - Abstract Synthesizer Note Instance
  4. Copyright (C) 2016 Mark McCurry
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. */
  10. #include "SynthNote.h"
  11. #include "../globals.h"
  12. #include <cstring>
  13. #include <new>
  14. #include <iostream>
  15. SynthNote::SynthNote(SynthParams &pars)
  16. :memory(pars.memory),
  17. legato(pars.synth, pars.frequency, pars.velocity, pars.portamento,
  18. pars.note, pars.quiet), ctl(pars.ctl), synth(pars.synth), time(pars.time)
  19. {}
  20. SynthNote::Legato::Legato(const SYNTH_T &synth_, float freq, float vel, int port,
  21. int note, bool quiet)
  22. :synth(synth_)
  23. {
  24. // Initialise some legato-specific vars
  25. msg = LM_Norm;
  26. fade.length = (int)(synth.samplerate_f * 0.005f); // 0.005f seems ok.
  27. if(fade.length < 1)
  28. fade.length = 1; // (if something's fishy)
  29. fade.step = (1.0f / fade.length);
  30. decounter = -10;
  31. param.freq = freq;
  32. param.vel = vel;
  33. param.portamento = port;
  34. param.midinote = note;
  35. lastfreq = 0.0f;
  36. silent = quiet;
  37. }
  38. int SynthNote::Legato::update(LegatoParams pars)
  39. {
  40. if(pars.externcall)
  41. msg = LM_Norm;
  42. if(msg != LM_CatchUp) {
  43. lastfreq = param.freq;
  44. param.freq = pars.frequency;
  45. param.vel = pars.velocity;
  46. param.portamento = pars.portamento;
  47. param.midinote = pars.midinote;
  48. if(msg == LM_Norm) {
  49. if(silent) {
  50. fade.m = 0.0f;
  51. msg = LM_FadeIn;
  52. }
  53. else {
  54. fade.m = 1.0f;
  55. msg = LM_FadeOut;
  56. return 1;
  57. }
  58. }
  59. if(msg == LM_ToNorm)
  60. msg = LM_Norm;
  61. }
  62. return 0;
  63. }
  64. void SynthNote::Legato::apply(SynthNote &note, float *outl, float *outr)
  65. {
  66. if(silent) // Silencer
  67. if(msg != LM_FadeIn) {
  68. memset(outl, 0, synth.bufferbytes);
  69. memset(outr, 0, synth.bufferbytes);
  70. }
  71. try {
  72. switch (msg) {
  73. case LM_CatchUp: // Continue the catch-up...
  74. if (decounter == -10)
  75. decounter = fade.length;
  76. //Yea, could be done without the loop...
  77. for (int i = 0; i < synth.buffersize; ++i) {
  78. decounter--;
  79. if (decounter < 1) {
  80. // Catching-up done, we can finally set
  81. // the note to the actual parameters.
  82. decounter = -10;
  83. msg = LM_ToNorm;
  84. LegatoParams pars{param.freq, param.vel, param.portamento,
  85. param.midinote, false};
  86. note.legatonote(pars);
  87. break;
  88. }
  89. }
  90. break;
  91. case LM_FadeIn: // Fade-in
  92. if (decounter == -10)
  93. decounter = fade.length;
  94. silent = false;
  95. for (int i = 0; i < synth.buffersize; ++i) {
  96. decounter--;
  97. if (decounter < 1) {
  98. decounter = -10;
  99. msg = LM_Norm;
  100. break;
  101. }
  102. fade.m += fade.step;
  103. outl[i] *= fade.m;
  104. outr[i] *= fade.m;
  105. }
  106. break;
  107. case LM_FadeOut: // Fade-out, then set the catch-up
  108. if (decounter == -10)
  109. decounter = fade.length;
  110. for (int i = 0; i < synth.buffersize; ++i) {
  111. decounter--;
  112. if (decounter < 1) {
  113. for (int j = i; j < synth.buffersize; ++j) {
  114. outl[j] = 0.0f;
  115. outr[j] = 0.0f;
  116. }
  117. decounter = -10;
  118. silent = true;
  119. // Fading-out done, now set the catch-up :
  120. decounter = fade.length;
  121. msg = LM_CatchUp;
  122. //This freq should make this now silent note to catch-up/resync
  123. //with the heard note for the same length it stayed at the
  124. //previous freq during the fadeout.
  125. float catchupfreq = param.freq * (param.freq / lastfreq);
  126. LegatoParams pars{catchupfreq, param.vel, param.portamento,
  127. param.midinote, false};
  128. note.legatonote(pars);
  129. break;
  130. }
  131. fade.m -= fade.step;
  132. outl[i] *= fade.m;
  133. outr[i] *= fade.m;
  134. }
  135. break;
  136. default:
  137. break;
  138. }
  139. } catch (std::bad_alloc &ba) {
  140. std::cerr << "failed to apply legato: " << ba.what() << std::endl;
  141. }
  142. }
  143. void SynthNote::setVelocity(float velocity_) {
  144. legato.setSilent(true); //Let legato.update(...) returns 0.
  145. LegatoParams pars{legato.getFreq(), velocity_,
  146. legato.getPortamento(), legato.getMidinote(), true};
  147. try {
  148. legatonote(pars);
  149. } catch (std::bad_alloc &ba) {
  150. std::cerr << "failed to set velocity to legato note: " << ba.what() << std::endl;
  151. }
  152. legato.setDecounter(0); //avoid chopping sound due fade-in
  153. }