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.

Unison.cpp 5.9KB

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