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 6.1KB

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