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.

199 lines
5.9KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. Unison.cpp - Unison effect (multivoice chorus)
  4. Copyright (C) 2002-2009 Nasca Octavian Paul
  5. Author: Nasca Octavian Paul
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of version 2 of the GNU General Public License
  8. as published by the Free Software Foundation.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License (version 2 or later) for more details.
  13. You should have received a copy of the GNU General Public License (version 2)
  14. along with this program; if not, write to the Free Software Foundation,
  15. Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. */
  17. #include <cmath>
  18. #include <cstring>
  19. #include <err.h>
  20. #include "Unison.h"
  21. Unison::Unison(int update_period_samples_, float max_delay_sec_)
  22. :unison_size(0),
  23. base_freq(1.0f),
  24. uv(NULL),
  25. update_period_samples(update_period_samples_),
  26. update_period_sample_k(0),
  27. max_delay((int)(synth->samplerate_f * max_delay_sec_) + 1),
  28. delay_k(0),
  29. first_time(false),
  30. delay_buffer(NULL),
  31. unison_amplitude_samples(0.0f),
  32. unison_bandwidth_cents(10.0f)
  33. {
  34. if(max_delay < 10)
  35. max_delay = 10;
  36. delay_buffer = new float[max_delay];
  37. memset(delay_buffer, 0, max_delay * sizeof(float));
  38. setSize(1);
  39. }
  40. Unison::~Unison() {
  41. delete [] delay_buffer;
  42. delete [] uv;
  43. }
  44. void Unison::setSize(int new_size)
  45. {
  46. if(new_size < 1)
  47. new_size = 1;
  48. unison_size = new_size;
  49. if(uv)
  50. delete [] uv;
  51. uv = new UnisonVoice[unison_size];
  52. first_time = true;
  53. updateParameters();
  54. }
  55. void Unison::setBaseFrequency(float freq)
  56. {
  57. base_freq = freq;
  58. updateParameters();
  59. }
  60. void Unison::setBandwidth(float bandwidth)
  61. {
  62. if(bandwidth < 0)
  63. bandwidth = 0.0f;
  64. if(bandwidth > 1200.0f)
  65. bandwidth = 1200.0f;
  66. /* If the bandwidth is too small, the audio may cancel itself out
  67. * (due to the sign change of the outputs)
  68. * TODO figure out the acceptable lower bound and codify it
  69. */
  70. unison_bandwidth_cents = bandwidth;
  71. updateParameters();
  72. }
  73. void Unison::updateParameters(void)
  74. {
  75. if(!uv)
  76. return;
  77. float increments_per_second = synth->samplerate_f
  78. / (float) update_period_samples;
  79. // printf("#%g, %g\n",increments_per_second,base_freq);
  80. for(int i = 0; i < unison_size; ++i) {
  81. float base = powf(UNISON_FREQ_SPAN, synth->numRandom() * 2.0f - 1.0f);
  82. uv[i].relative_amplitude = base;
  83. float period = base / base_freq;
  84. float m = 4.0f / (period * increments_per_second);
  85. if(synth->numRandom() < 0.5f)
  86. m = -m;
  87. uv[i].step = m;
  88. // printf("%g %g\n",uv[i].relative_amplitude,period);
  89. }
  90. float max_speed = powf(2.0f, unison_bandwidth_cents / 1200.0f);
  91. unison_amplitude_samples = 0.125f * (max_speed - 1.0f)
  92. * synth->samplerate_f / base_freq;
  93. //If functions exceed this limit, they should have requested a bigguer delay
  94. //and thus are buggy
  95. if(unison_amplitude_samples >= max_delay - 1) {
  96. warnx("BUG: Unison amplitude samples too big");
  97. warnx("Unision max_delay should be larger");
  98. unison_amplitude_samples = max_delay - 2;
  99. }
  100. updateUnisonData();
  101. }
  102. void Unison::process(int bufsize, float *inbuf, float *outbuf)
  103. {
  104. if(!uv)
  105. return;
  106. if(!outbuf)
  107. outbuf = inbuf;
  108. float volume = 1.0f / sqrtf(unison_size);
  109. float xpos_step = 1.0f / (float) update_period_samples;
  110. float xpos = (float) update_period_sample_k * xpos_step;
  111. for(int i = 0; i < bufsize; ++i) {
  112. if(update_period_sample_k++ >= update_period_samples) {
  113. updateUnisonData();
  114. update_period_sample_k = 0;
  115. xpos = 0.0f;
  116. }
  117. xpos += xpos_step;
  118. float in = inbuf[i], out = 0.0f;
  119. float sign = 1.0f;
  120. for(int k = 0; k < unison_size; ++k) {
  121. float vpos = uv[k].realpos1 * (1.0f - xpos) + uv[k].realpos2 * xpos; //optimize
  122. float pos = (float)(delay_k + max_delay) - vpos - 1.0f;
  123. int posi;
  124. F2I(pos, posi); //optimize!
  125. int posi_next = posi + 1;
  126. if(posi >= max_delay)
  127. posi -= max_delay;
  128. if(posi_next >= max_delay)
  129. posi_next -= max_delay;
  130. float posf = pos - floorf(pos);
  131. out += ((1.0f - posf) * delay_buffer[posi] + posf
  132. * delay_buffer[posi_next]) * sign;
  133. sign = -sign;
  134. }
  135. outbuf[i] = out * volume;
  136. // printf("%d %g\n",i,outbuf[i]);
  137. delay_buffer[delay_k] = in;
  138. delay_k = (++delay_k < max_delay) ? delay_k : 0;
  139. }
  140. }
  141. void Unison::updateUnisonData()
  142. {
  143. if(!uv)
  144. return;
  145. for(int k = 0; k < unison_size; ++k) {
  146. float pos = uv[k].position;
  147. float step = uv[k].step;
  148. pos += step;
  149. if(pos <= -1.0f) {
  150. pos = -1.0f;
  151. step = -step;
  152. }
  153. else
  154. if(pos >= 1.0f) {
  155. pos = 1.0f;
  156. step = -step;
  157. }
  158. float vibratto_val = (pos - 0.333333333f * pos * pos * pos) * 1.5f; //make the vibratto lfo smoother
  159. //Relative amplitude is utilized, so the delay may be larger than the
  160. //whole buffer, if the buffer is too small, this indicates a buggy call
  161. //to Unison()
  162. float newval = 1.0f + 0.5f
  163. * (vibratto_val + 1.0f) * unison_amplitude_samples
  164. * uv[k].relative_amplitude;
  165. if(first_time)
  166. uv[k].realpos1 = uv[k].realpos2 = newval;
  167. else {
  168. uv[k].realpos1 = uv[k].realpos2;
  169. uv[k].realpos2 = newval;
  170. }
  171. uv[k].position = pos;
  172. uv[k].step = step;
  173. }
  174. first_time = false;
  175. }