PageRenderTime 28ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llaudio/llwindgen.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 176 lines | 109 code | 25 blank | 42 comment | 6 complexity | 8616f37d09dbd2c4050c869b85065cee MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file windgen.h
  3. * @brief Templated wind noise generation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #ifndef WINDGEN_H
  27. #define WINDGEN_H
  28. #include "llcommon.h"
  29. template <class MIXBUFFERFORMAT_T>
  30. class LLWindGen
  31. {
  32. public:
  33. LLWindGen(const U32 sample_rate = 44100) :
  34. mTargetGain(0.f),
  35. mTargetFreq(100.f),
  36. mTargetPanGainR(0.5f),
  37. mInputSamplingRate(sample_rate),
  38. mSubSamples(2),
  39. mFilterBandWidth(50.f),
  40. mBuf0(0.0f),
  41. mBuf1(0.0f),
  42. mBuf2(0.0f),
  43. mY0(0.0f),
  44. mY1(0.0f),
  45. mCurrentGain(0.f),
  46. mCurrentFreq(100.f),
  47. mCurrentPanGainR(0.5f),
  48. mLastSample(0.f)
  49. {
  50. mSamplePeriod = (F32)mSubSamples / (F32)mInputSamplingRate;
  51. mB2 = expf(-F_TWO_PI * mFilterBandWidth * mSamplePeriod);
  52. }
  53. const U32 getInputSamplingRate() { return mInputSamplingRate; }
  54. // newbuffer = the buffer passed from the previous DSP unit.
  55. // numsamples = length in samples-per-channel at this mix time.
  56. // NOTE: generates L/R interleaved stereo
  57. MIXBUFFERFORMAT_T* windGenerate(MIXBUFFERFORMAT_T *newbuffer, int numsamples)
  58. {
  59. MIXBUFFERFORMAT_T *cursamplep = newbuffer;
  60. // Filter coefficients
  61. F32 a0 = 0.0f, b1 = 0.0f;
  62. // No need to clip at normal volumes
  63. bool clip = mCurrentGain > 2.0f;
  64. bool interp_freq = false;
  65. //if the frequency isn't changing much, we don't need to interpolate in the inner loop
  66. if (llabs(mTargetFreq - mCurrentFreq) < (mCurrentFreq * 0.112))
  67. {
  68. // calculate resonant filter coefficients
  69. mCurrentFreq = mTargetFreq;
  70. b1 = (-4.0f * mB2) / (1.0f + mB2) * cosf(F_TWO_PI * (mCurrentFreq * mSamplePeriod));
  71. a0 = (1.0f - mB2) * sqrtf(1.0f - (b1 * b1) / (4.0f * mB2));
  72. }
  73. else
  74. {
  75. interp_freq = true;
  76. }
  77. while (numsamples)
  78. {
  79. F32 next_sample;
  80. // Start with white noise
  81. // This expression is fragile, rearrange it and it will break!
  82. next_sample = (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8);
  83. // Apply a pinking filter
  84. // Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
  85. mBuf0 = mBuf0 * 0.99765f + next_sample * 0.0990460f;
  86. mBuf1 = mBuf1 * 0.96300f + next_sample * 0.2965164f;
  87. mBuf2 = mBuf2 * 0.57000f + next_sample * 1.0526913f;
  88. next_sample = mBuf0 + mBuf1 + mBuf2 + next_sample * 0.1848f;
  89. if (interp_freq)
  90. {
  91. // calculate and interpolate resonant filter coefficients
  92. mCurrentFreq = (0.999f * mCurrentFreq) + (0.001f * mTargetFreq);
  93. b1 = (-4.0f * mB2) / (1.0f + mB2) * cosf(F_TWO_PI * (mCurrentFreq * mSamplePeriod));
  94. a0 = (1.0f - mB2) * sqrtf(1.0f - (b1 * b1) / (4.0f * mB2));
  95. }
  96. // Apply a resonant low-pass filter on the pink noise
  97. next_sample = a0 * next_sample - b1 * mY0 - mB2 * mY1;
  98. mY1 = mY0;
  99. mY0 = next_sample;
  100. mCurrentGain = (0.999f * mCurrentGain) + (0.001f * mTargetGain);
  101. mCurrentPanGainR = (0.999f * mCurrentPanGainR) + (0.001f * mTargetPanGainR);
  102. // For a 3dB pan law use:
  103. // next_sample *= mCurrentGain * ((mCurrentPanGainR*(mCurrentPanGainR-1)*1.652+1.413);
  104. next_sample *= mCurrentGain;
  105. // delta is used to interpolate between synthesized samples
  106. F32 delta = (next_sample - mLastSample) / (F32)mSubSamples;
  107. // Fill the audio buffer, clipping if necessary
  108. for (U8 i=mSubSamples; i && numsamples; --i, --numsamples)
  109. {
  110. mLastSample = mLastSample + delta;
  111. S32 sample_right = (S32)(mLastSample * mCurrentPanGainR);
  112. S32 sample_left = (S32)mLastSample - sample_right;
  113. if (!clip)
  114. {
  115. *cursamplep = (MIXBUFFERFORMAT_T)sample_left;
  116. ++cursamplep;
  117. *cursamplep = (MIXBUFFERFORMAT_T)sample_right;
  118. ++cursamplep;
  119. }
  120. else
  121. {
  122. *cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_left, (S32)S16_MIN, (S32)S16_MAX);
  123. ++cursamplep;
  124. *cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_right, (S32)S16_MIN, (S32)S16_MAX);
  125. ++cursamplep;
  126. }
  127. }
  128. }
  129. return newbuffer;
  130. }
  131. public:
  132. F32 mTargetGain;
  133. F32 mTargetFreq;
  134. F32 mTargetPanGainR;
  135. private:
  136. U32 mInputSamplingRate;
  137. U8 mSubSamples;
  138. F32 mSamplePeriod;
  139. F32 mFilterBandWidth;
  140. F32 mB2;
  141. F32 mBuf0;
  142. F32 mBuf1;
  143. F32 mBuf2;
  144. F32 mY0;
  145. F32 mY1;
  146. F32 mCurrentGain;
  147. F32 mCurrentFreq;
  148. F32 mCurrentPanGainR;
  149. F32 mLastSample;
  150. };
  151. #endif