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.

SynthNote.cpp 5.6KB

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