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.

300 lines
6.8KB

  1. /*
  2. * Segment Synthesizer Design
  3. * Implemented by Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz .
  4. *
  5. * Copyright (C) 2014 Andre Sklenar <andre.sklenar@gmail.com>, www.juicelab.cz
  6. */
  7. #ifndef SYNTH_HXX_INCLUDED
  8. #define SYNTH_HXX_INCLUDED
  9. #include <cmath>
  10. #include <cstdlib>
  11. class CSynth
  12. {
  13. public:
  14. CSynth()
  15. {
  16. for (int i=0; i<6; i++) {
  17. waves[i] = 3.0f;
  18. }
  19. for (int i=0; i<6; i++) {
  20. FMs[i] = 0.5f*64;
  21. }
  22. for (int i=0; i<6; i++) {
  23. pans[i] = 1.0f;
  24. }
  25. for (int i=0; i<6; i++) {
  26. amps[i] = 0.5f;
  27. }
  28. waveBlend = 0;
  29. freq = 0;
  30. phaseAccum = 0;
  31. playing = false;
  32. cycleSize = 0;
  33. sampleRate = 0;
  34. notePlaying = 0;
  35. env = 0;
  36. envPhase = 0;
  37. aCoeff=dCoeff=rCoeff=0;
  38. stereo = 0;
  39. tFreq=0;
  40. gl = 0;
  41. glideDistance = 0;
  42. attack=decay=sustain=release=0.0f;
  43. mAmp = 0.5;
  44. freqOffset = 0;
  45. }
  46. float getSinePhase(float x) {
  47. return -(std::sin(x));
  48. }
  49. float getSawPhase(float x) {
  50. return (-(2/M_PI *std::atan(1/std::tan(x/2))));
  51. }
  52. float getRevSawPhase(float x) {
  53. return ((2/M_PI *std::atan(1/std::tan(x/2))));
  54. }
  55. float getSquarePhase(float x) {
  56. return (std::round((std::sin(x)+1)/2)-0.5)*2;
  57. }
  58. //saw, sqr, sin, revSaw
  59. float getBlendedPhase(float x, float wave, float polarity)
  60. {
  61. //wave = 2;
  62. if (wave>=1 && wave<2) {
  63. /* saw vs sqr */
  64. waveBlend = wave-1;
  65. return (getSawPhase(x)*(1-waveBlend) + getSquarePhase(x)*waveBlend)*polarity;
  66. } else if (wave>=2 && wave<3) {
  67. /* sqr vs sin */
  68. waveBlend = wave-2;
  69. return (getSquarePhase(x)*(1-waveBlend) + getSinePhase(x)*waveBlend)*polarity;
  70. } else if (wave>=3 && wave<=4) {
  71. /* sin vs revSaw */
  72. waveBlend = wave-3;
  73. return (getSinePhase(x)*(1-waveBlend) + getRevSawPhase(x)*waveBlend)*polarity;
  74. } else {
  75. return 0.0f;
  76. }
  77. }
  78. void setWave(int i, float nWave) {
  79. waves[i] = nWave;
  80. }
  81. void setFM(int i, float nFM) {
  82. FMs[i] = nFM*64;
  83. }
  84. void setPan(int i, float nPan) {
  85. pans[i] = (nPan+1)/2;
  86. }
  87. void setAmp(int i, float nAmp) {
  88. amps[i] = nAmp;
  89. }
  90. void setMAmp(float nMAmp) {
  91. mAmp = nMAmp;
  92. }
  93. void setStereo(float nStereo) {
  94. stereo = nStereo;
  95. if (playing) {
  96. freq = 440.0 * pow(2.0, (notePlaying - 69)/12);
  97. freq += freq*(stereo/12);
  98. }
  99. }
  100. void setTune(float nTune) {
  101. freqOffset = nTune;
  102. if (playing) {
  103. freq = 440.0 * pow(2.0, (notePlaying - 69)/12);
  104. freq +=freq*freqOffset;
  105. freq += freq*(stereo/12);
  106. tFreq = freq;
  107. //gl = 1;
  108. //freq += freq*freqOffset;
  109. glideDistance = 0;
  110. cycleSize = sampleRate/(freq/4);
  111. //glide init
  112. //gCoeff = 1.0f - expf(-1/glide);
  113. }
  114. }
  115. void setAttack(float nAttack) {
  116. attack = nAttack*sampleRate*4;
  117. }
  118. void setDecay(float nDecay) {
  119. decay = nDecay*sampleRate;
  120. }
  121. void setSustain(float nSustain) {
  122. sustain = nSustain*4;
  123. }
  124. void setRelease(float nRelease) {
  125. release = nRelease*sampleRate;
  126. }
  127. void setGlide(float nGlide) {
  128. glide = nGlide*sampleRate;
  129. }
  130. float getWave(int i) {
  131. return waves[i];
  132. }
  133. float getFM(int i) {
  134. return FMs[i];
  135. }
  136. float getPan(int i) {
  137. return (pans[i]*2)-1;
  138. }
  139. float getAmp(int i) {
  140. return amps[i];
  141. }
  142. void stop(int note) {
  143. if (note==notePlaying) {
  144. envPhase = 2; //release
  145. }
  146. }
  147. void play(float note) {
  148. if (!playing || (playing && notePlaying==note)) {
  149. notePlaying = note;
  150. freq = 440.0 * pow(2.0, (notePlaying - 69)/12);
  151. freq += freq*(freqOffset);
  152. freq += freq*(stereo/12);
  153. cycleSize = sampleRate/(freq/4);
  154. tFreq = freq;
  155. playing = true;
  156. phaseAccum = 0;
  157. env = 0.0f;
  158. envPhase = 0;
  159. //env init
  160. aCoeff = 1.0f - expf(-1/attack);
  161. dCoeff = 1.0f - expf(-1/decay);
  162. rCoeff = 1.0f - expf(-1/release);
  163. } else {
  164. std::cout << "not playing" << std::endl;
  165. //glide towards the target freq
  166. notePlaying = note;
  167. tFreq = 440.0 * pow(2.0, (notePlaying - 69)/12);
  168. tFreq += tFreq*(freqOffset);
  169. tFreq += tFreq*(stereo/12);
  170. glideDistance = tFreq-freq;
  171. gl = 0;
  172. if (envPhase == 2) {
  173. envPhase = 0;
  174. }
  175. //glide init
  176. gCoeff = 1.0f - expf(-1/glide);
  177. }
  178. }
  179. float run() {
  180. float out = 0;
  181. if (playing) {
  182. if (freq!=tFreq) {
  183. //gliding yo
  184. gl+=gCoeff * ((1.0/1.0) - gl);
  185. freq=(tFreq-glideDistance)+glideDistance*gl;
  186. cycleSize = sampleRate/(freq/4);
  187. }
  188. out = getSinePhase((phaseAccum/cycleSize)*(2*M_PI))*amps[0]*0.5;
  189. out += getSinePhase((phaseAccum/cycleSize)*2*(2*M_PI))*amps[0]*0.5;
  190. out += getBlendedPhase((phaseAccum/cycleSize)*(getBlendedPhase(phaseAccum/(cycleSize/8), waves[0], 1)*FMs[0])*(2*M_PI), waves[0], 1)*pans[0]*amps[0]*0.5;
  191. if (phaseAccum<cycleSize*0.5) {
  192. out += getBlendedPhase((phaseAccum/cycleSize)*(getBlendedPhase(phaseAccum/(cycleSize*2), waves[1], -1)*FMs[1])*(2*M_PI), waves[1], -1)*pans[1]*amps[1]*0.5*2;
  193. out += getBlendedPhase((phaseAccum/cycleSize)*(getBlendedPhase(phaseAccum/(cycleSize*2), waves[2], -1)*FMs[2])*(2*M_PI), waves[2], -1)*pans[2]*amps[2]*0.5*2;
  194. } else if (phaseAccum<cycleSize*0.75) {
  195. out += getBlendedPhase((phaseAccum/cycleSize)*(getBlendedPhase(phaseAccum/(cycleSize*8), waves[3], 1)*FMs[3])*4*(2*M_PI), waves[3], 1)*pans[3]*amps[3]*0.5*2;
  196. out += getBlendedPhase((phaseAccum/cycleSize)*(getBlendedPhase(phaseAccum/(cycleSize*8), waves[4], 1)*FMs[4])*8*(2*M_PI), waves[4], 1)*pans[4]*amps[4]*0.5*2;
  197. } else {// if (phaseAccum<cycleSize*0.875) {
  198. out += getBlendedPhase((phaseAccum/cycleSize)*(getBlendedPhase(phaseAccum/(cycleSize*8), waves[5], -1)*FMs[5])*16*(2*M_PI), waves[5], -1)*pans[5]*amps[5]*0.5*2;
  199. }
  200. phaseAccum++;
  201. if (phaseAccum>cycleSize) {
  202. phaseAccum = 0;
  203. }
  204. //calculate amplitude envelope
  205. if (envPhase==0) {
  206. //attack phase
  207. env+=aCoeff * ((1.0/0.63) - env);
  208. if (env>1.0) envPhase++;
  209. } else if (envPhase==1) {
  210. //decay and sustain phase
  211. env+=dCoeff * (sustain - env);
  212. } else {
  213. //release phase
  214. env += rCoeff * (1.0-(1.0/0.63) - env);
  215. if (env<0.0) { playing = false; env = 0.0; }
  216. }
  217. //apply amplitude envelope
  218. out*=env;
  219. //apply master volume
  220. out*=mAmp*0.5;
  221. //apply hard clipping
  222. if (out>1) out=1;
  223. if (out<-1) out=-1;
  224. }
  225. return out;
  226. }
  227. void setSampleRate(float sr) {
  228. sampleRate = sr;
  229. attack = sampleRate/2;
  230. decay = sampleRate/2;
  231. release = sampleRate/2;
  232. }
  233. private:
  234. /* vcf filter */
  235. float waves[6];
  236. float FMs[6];
  237. float pans[6];
  238. float amps[6];
  239. float waveBlend;
  240. float freq;
  241. float freqOffset;
  242. float tFreq; //target frequency for gliding
  243. float glideDistance; //freq distance
  244. float stereo;
  245. float mAmp;
  246. float phaseAccum;
  247. float cycleSize;
  248. float sampleRate;
  249. float notePlaying;
  250. float glide, gl;
  251. bool playing;
  252. float attack, decay, sustain, release;
  253. float env;
  254. float envPhase; //0, 1(d+s), 2
  255. float aCoeff, dCoeff, rCoeff, gCoeff;
  256. };
  257. #endif // SYNTH_HXX_INCLUDED