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.

197 lines
5.7KB

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