soloud_padsynth.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. SoLoud audio engine
  3. Copyright (c) 2013-2018 Jari Komppa
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. */
  19. #include "soloud.h"
  20. #include "soloud_padsynth.h"
  21. #include "soloud_fft.h"
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <math.h>
  25. class PADsynth {
  26. public:
  27. /* PADsynth:
  28. N - is the samplesize (eg: 262144)
  29. samplerate - samplerate (eg. 44100)
  30. number_harmonics - the number of harmonics that are computed */
  31. PADsynth(int aSampleCount, float aSamplerate, int aHarmonicsCount);
  32. virtual ~PADsynth();
  33. /* set the amplitude of the n'th harmonic */
  34. void setharmonic(int n,float value);
  35. /* get the amplitude of the n'th harmonic */
  36. float getharmonic(int n);
  37. /* synth() generates the wavetable
  38. f - the fundamental frequency (eg. 440 Hz)
  39. bw - bandwidth in cents of the fundamental frequency (eg. 25 cents)
  40. bwscale - how the bandwidth increase on the higher harmonics (recomanded value: 1.0)
  41. *smp - a pointer to allocated memory that can hold N samples */
  42. void synth(float aFundamental, float aBandwidth, float aBandwidthScale, float *aBuf);
  43. protected:
  44. /* relF():
  45. This method returns the N'th overtone's position relative
  46. to the fundamental frequency.
  47. By default it returns N.
  48. You may override it to make metallic sounds or other
  49. instruments where the overtones are not harmonic. */
  50. virtual float relF(int N);
  51. /* profile():
  52. This is the profile of one harmonic
  53. In this case is a Gaussian distribution (e^(-x^2))
  54. The amplitude is divided by the bandwidth to ensure that the harmonic
  55. keeps the same amplitude regardless of the bandwidth */
  56. virtual float profile(float fi, float bwi);
  57. /* RND() - a random number generator that
  58. returns values between 0 and 1
  59. */
  60. virtual float RND();
  61. private:
  62. PADsynth(const PADsynth&); // disable copy
  63. PADsynth& operator=(PADsynth const&);
  64. float *mHarmonics; //Amplitude of the harmonics
  65. float *mFreqAmp; //Amplitude spectrum
  66. float mSamplerate;
  67. int mHarmonicsCount;
  68. int mSampleCount; //Size of the sample
  69. };
  70. PADsynth::PADsynth(int aSampleCount, float aSamplerate, int aHarmonicsCount)
  71. {
  72. mSampleCount = aSampleCount;
  73. mSamplerate = aSamplerate;
  74. mHarmonicsCount = aHarmonicsCount;
  75. mHarmonics = new float[mHarmonicsCount];
  76. int i;
  77. for (i = 0; i < mHarmonicsCount; i++)
  78. mHarmonics[i] = 0.0f;
  79. mHarmonics[1] = 1.0f;//default, the first harmonic has the amplitude 1.0
  80. mFreqAmp = new float[mSampleCount / 2];
  81. };
  82. PADsynth::~PADsynth()
  83. {
  84. delete[] mHarmonics;
  85. delete[] mFreqAmp;
  86. };
  87. float PADsynth::relF(int N)
  88. {
  89. return (float)N;
  90. };
  91. void PADsynth::setharmonic(int n,float value)
  92. {
  93. if (n < 1 || n >= mHarmonicsCount) return;
  94. mHarmonics[n] = value;
  95. };
  96. float PADsynth::getharmonic(int n)
  97. {
  98. if (n < 1 || n >= mHarmonicsCount)
  99. return 0.0f;
  100. return mHarmonics[n];
  101. };
  102. float PADsynth::profile(float fi, float bwi)
  103. {
  104. float x = fi / bwi;
  105. x *= x;
  106. if (x > 14.71280603f)
  107. return 0.0f; //this avoids computing the e^(-x^2) where it's results are very close to zero
  108. return (float)exp(-x) / bwi;
  109. };
  110. void PADsynth::synth(float f, float bw, float bwscale, float *smp)
  111. {
  112. int i, nh;
  113. for (i = 0; i < mSampleCount / 2; i++)
  114. mFreqAmp[i] = 0.0f; //default, all the frequency amplitudes are zero
  115. for (nh = 1; nh < mHarmonicsCount; nh++)
  116. { //for each harmonic
  117. float bw_Hz;//bandwidth of the current harmonic measured in Hz
  118. float bwi;
  119. float fi;
  120. float rF = f * relF(nh);
  121. bw_Hz = (float)((pow(2.0f,bw / 1200.0f) - 1.0f) * f * pow(relF(nh), bwscale));
  122. bwi = (float)(bw_Hz / (2.0f * mSamplerate));
  123. fi = rF / mSamplerate;
  124. for (i = 0; i < mSampleCount / 2; i++)
  125. { //here you can optimize, by avoiding to compute the profile for the full frequency (usually it's zero or very close to zero)
  126. float hprofile = profile((i / (float)mSampleCount) - fi, bwi);
  127. mFreqAmp[i] += hprofile * mHarmonics[nh];
  128. }
  129. }
  130. //Convert the freq_amp array to complex array (real/imaginary) by making the phases random
  131. for (i = 0; i < mSampleCount / 2; i++)
  132. {
  133. float phase = RND() * 2.0f * 3.14159265358979f;
  134. smp[i * 2 + 0] = (float)(mFreqAmp[i] * cos(phase));
  135. smp[i * 2 + 1] = (float)(mFreqAmp[i] * sin(phase));
  136. };
  137. SoLoud::FFT::ifft(smp, mSampleCount);
  138. //normalize the output
  139. float max = 0.0;
  140. for (i = 0; i < mSampleCount; i++)
  141. {
  142. float amp = (float)fabs(smp[i]);
  143. if (amp > max)
  144. {
  145. max = amp;
  146. }
  147. }
  148. if (max < 0.000001f) max = 0.000001f;
  149. for (i = 0; i < mSampleCount; i++)
  150. smp[i] /= max * 0.5f;
  151. };
  152. float PADsynth::RND()
  153. {
  154. return (rand() / (RAND_MAX + 1.0f));
  155. };
  156. namespace SoLoud
  157. {
  158. result generatePadsynth(
  159. SoLoud::Wav &aTarget,
  160. unsigned int aHarmonicCount,
  161. float *aHarmonics,
  162. float aBandwidth,
  163. float aBandwidthScale,
  164. float aPrincipalFreq,
  165. float aSampleRate,
  166. int aSizePow)
  167. {
  168. if (aHarmonicCount < 1 || aHarmonics == NULL || aSizePow < 8 || aSizePow > 24)
  169. return INVALID_PARAMETER;
  170. int len = 1 << aSizePow;
  171. float *buf = new float[len];
  172. PADsynth p(len, aSampleRate, aHarmonicCount);
  173. unsigned int i;
  174. for (i = 0; i < aHarmonicCount; i++)
  175. p.setharmonic(i, aHarmonics[i]);
  176. p.synth(aPrincipalFreq, aBandwidth, aBandwidthScale, buf);
  177. aTarget.loadRawWave(buf, len, aSampleRate);
  178. aTarget.setLooping(true);
  179. return SO_NO_ERROR;
  180. }
  181. }