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.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. #define errx(...) {}
  17. #define warnx(...) {}
  18. #ifndef errx
  19. #include <err.h>
  20. #endif
  21. Unison::Unison(Allocator *alloc_, 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. alloc(*alloc_)
  35. {
  36. if(max_delay < 10)
  37. max_delay = 10;
  38. delay_buffer = alloc.valloc<float>(max_delay);
  39. memset(delay_buffer, 0, max_delay * sizeof(float));
  40. setSize(1);
  41. }
  42. Unison::~Unison() {
  43. alloc.devalloc(delay_buffer);
  44. alloc.devalloc(uv);
  45. }
  46. void Unison::setSize(int new_size)
  47. {
  48. if(new_size < 1)
  49. new_size = 1;
  50. unison_size = new_size;
  51. alloc.devalloc(uv);
  52. uv = alloc.valloc<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. }