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.

204 lines
6.1KB

  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 "../Misc/Allocator.h"
  20. #include "Unison.h"
  21. #ifndef errx
  22. #include <err.h>
  23. #endif
  24. Unison::Unison(Allocator *alloc_, int update_period_samples_, float max_delay_sec_, float srate_f)
  25. :unison_size(0),
  26. base_freq(1.0f),
  27. uv(NULL),
  28. update_period_samples(update_period_samples_),
  29. update_period_sample_k(0),
  30. max_delay((int)(srate_f * max_delay_sec_) + 1),
  31. delay_k(0),
  32. first_time(false),
  33. delay_buffer(NULL),
  34. unison_amplitude_samples(0.0f),
  35. unison_bandwidth_cents(10.0f),
  36. samplerate_f(srate_f),
  37. alloc(*alloc_)
  38. {
  39. if(max_delay < 10)
  40. max_delay = 10;
  41. delay_buffer = alloc.valloc<float>(max_delay);
  42. memset(delay_buffer, 0, max_delay * sizeof(float));
  43. setSize(1);
  44. }
  45. Unison::~Unison() {
  46. alloc.devalloc(delay_buffer);
  47. alloc.devalloc(uv);
  48. }
  49. void Unison::setSize(int new_size)
  50. {
  51. if(new_size < 1)
  52. new_size = 1;
  53. unison_size = new_size;
  54. alloc.devalloc(uv);
  55. uv = alloc.valloc<UnisonVoice>(unison_size);
  56. first_time = true;
  57. updateParameters();
  58. }
  59. void Unison::setBaseFrequency(float freq)
  60. {
  61. base_freq = freq;
  62. updateParameters();
  63. }
  64. void Unison::setBandwidth(float bandwidth)
  65. {
  66. if(bandwidth < 0)
  67. bandwidth = 0.0f;
  68. if(bandwidth > 1200.0f)
  69. bandwidth = 1200.0f;
  70. /* If the bandwidth is too small, the audio may cancel itself out
  71. * (due to the sign change of the outputs)
  72. * TODO figure out the acceptable lower bound and codify it
  73. */
  74. unison_bandwidth_cents = bandwidth;
  75. updateParameters();
  76. }
  77. void Unison::updateParameters(void)
  78. {
  79. if(!uv)
  80. return;
  81. float increments_per_second = samplerate_f
  82. / (float) update_period_samples;
  83. // printf("#%g, %g\n",increments_per_second,base_freq);
  84. for(int i = 0; i < unison_size; ++i) {
  85. float base = powf(UNISON_FREQ_SPAN, SYNTH_T::numRandom() * 2.0f - 1.0f);
  86. uv[i].relative_amplitude = base;
  87. float period = base / base_freq;
  88. float m = 4.0f / (period * increments_per_second);
  89. if(SYNTH_T::numRandom() < 0.5f)
  90. m = -m;
  91. uv[i].step = m;
  92. // printf("%g %g\n",uv[i].relative_amplitude,period);
  93. }
  94. float max_speed = powf(2.0f, unison_bandwidth_cents / 1200.0f);
  95. unison_amplitude_samples = 0.125f * (max_speed - 1.0f)
  96. * samplerate_f / base_freq;
  97. //If functions exceed this limit, they should have requested a bigguer delay
  98. //and thus are buggy
  99. if(unison_amplitude_samples >= max_delay - 1) {
  100. warnx("BUG: Unison amplitude samples too big");
  101. warnx("Unision max_delay should be larger");
  102. unison_amplitude_samples = max_delay - 2;
  103. }
  104. updateUnisonData();
  105. }
  106. void Unison::process(int bufsize, float *inbuf, float *outbuf)
  107. {
  108. if(!uv)
  109. return;
  110. if(!outbuf)
  111. outbuf = inbuf;
  112. float volume = 1.0f / sqrtf(unison_size);
  113. float xpos_step = 1.0f / (float) update_period_samples;
  114. float xpos = (float) update_period_sample_k * xpos_step;
  115. for(int i = 0; i < bufsize; ++i) {
  116. if(update_period_sample_k++ >= update_period_samples) {
  117. updateUnisonData();
  118. update_period_sample_k = 0;
  119. xpos = 0.0f;
  120. }
  121. xpos += xpos_step;
  122. float in = inbuf[i], out = 0.0f;
  123. float sign = 1.0f;
  124. for(int k = 0; k < unison_size; ++k) {
  125. float vpos = uv[k].realpos1 * (1.0f - xpos) + uv[k].realpos2 * xpos; //optimize
  126. float pos = (float)(delay_k + max_delay) - vpos - 1.0f;
  127. int posi;
  128. F2I(pos, posi); //optimize!
  129. int posi_next = posi + 1;
  130. if(posi >= max_delay)
  131. posi -= max_delay;
  132. if(posi_next >= max_delay)
  133. posi_next -= max_delay;
  134. float posf = pos - floorf(pos);
  135. out += ((1.0f - posf) * delay_buffer[posi] + posf
  136. * delay_buffer[posi_next]) * sign;
  137. sign = -sign;
  138. }
  139. outbuf[i] = out * volume;
  140. // printf("%d %g\n",i,outbuf[i]);
  141. delay_buffer[delay_k] = in;
  142. delay_k = (++delay_k < max_delay) ? delay_k : 0;
  143. }
  144. }
  145. void Unison::updateUnisonData()
  146. {
  147. if(!uv)
  148. return;
  149. for(int k = 0; k < unison_size; ++k) {
  150. float pos = uv[k].position;
  151. float step = uv[k].step;
  152. pos += step;
  153. if(pos <= -1.0f) {
  154. pos = -1.0f;
  155. step = -step;
  156. }
  157. else
  158. if(pos >= 1.0f) {
  159. pos = 1.0f;
  160. step = -step;
  161. }
  162. float vibratto_val = (pos - 0.333333333f * pos * pos * pos) * 1.5f; //make the vibratto lfo smoother
  163. //Relative amplitude is utilized, so the delay may be larger than the
  164. //whole buffer, if the buffer is too small, this indicates a buggy call
  165. //to Unison()
  166. float newval = 1.0f + 0.5f
  167. * (vibratto_val + 1.0f) * unison_amplitude_samples
  168. * uv[k].relative_amplitude;
  169. if(first_time)
  170. uv[k].realpos1 = uv[k].realpos2 = newval;
  171. else {
  172. uv[k].realpos1 = uv[k].realpos2;
  173. uv[k].realpos2 = newval;
  174. }
  175. uv[k].position = pos;
  176. uv[k].step = step;
  177. }
  178. first_time = false;
  179. }