PageRenderTime 31ms CodeModel.GetById 17ms app.highlight 11ms RepoModel.GetById 1ms 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
  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
 29#include "llcommon.h"
 30
 31template <class MIXBUFFERFORMAT_T>
 32class LLWindGen
 33{
 34public:
 35	LLWindGen(const U32 sample_rate = 44100) :
 36		mTargetGain(0.f),
 37		mTargetFreq(100.f),
 38		mTargetPanGainR(0.5f),
 39		mInputSamplingRate(sample_rate),
 40		mSubSamples(2),
 41		mFilterBandWidth(50.f),
 42		mBuf0(0.0f),
 43		mBuf1(0.0f),
 44		mBuf2(0.0f),
 45		mY0(0.0f),
 46		mY1(0.0f),
 47		mCurrentGain(0.f),
 48		mCurrentFreq(100.f),
 49		mCurrentPanGainR(0.5f),
 50		mLastSample(0.f)
 51	{
 52		mSamplePeriod = (F32)mSubSamples / (F32)mInputSamplingRate;
 53		mB2 = expf(-F_TWO_PI * mFilterBandWidth * mSamplePeriod);
 54	}
 55
 56	const U32 getInputSamplingRate() { return mInputSamplingRate; }
 57	
 58	// newbuffer = the buffer passed from the previous DSP unit.
 59	// numsamples = length in samples-per-channel at this mix time.
 60	// NOTE: generates L/R interleaved stereo
 61	MIXBUFFERFORMAT_T* windGenerate(MIXBUFFERFORMAT_T *newbuffer, int numsamples)
 62	{
 63		MIXBUFFERFORMAT_T *cursamplep = newbuffer;
 64		
 65		// Filter coefficients
 66		F32 a0 = 0.0f, b1 = 0.0f;
 67		
 68		// No need to clip at normal volumes
 69		bool clip = mCurrentGain > 2.0f;
 70		
 71		bool interp_freq = false; 
 72		
 73		//if the frequency isn't changing much, we don't need to interpolate in the inner loop
 74		if (llabs(mTargetFreq - mCurrentFreq) < (mCurrentFreq * 0.112))
 75		{
 76			// calculate resonant filter coefficients
 77			mCurrentFreq = mTargetFreq;
 78			b1 = (-4.0f * mB2) / (1.0f + mB2) * cosf(F_TWO_PI * (mCurrentFreq * mSamplePeriod));
 79			a0 = (1.0f - mB2) * sqrtf(1.0f - (b1 * b1) / (4.0f * mB2));
 80		}
 81		else
 82		{
 83			interp_freq = true;
 84		}
 85		
 86		while (numsamples)
 87		{
 88			F32 next_sample;
 89			
 90			// Start with white noise
 91			// This expression is fragile, rearrange it and it will break!
 92			next_sample = (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8);
 93			
 94			// Apply a pinking filter
 95			// Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
 96			mBuf0 = mBuf0 * 0.99765f + next_sample * 0.0990460f;
 97			mBuf1 = mBuf1 * 0.96300f + next_sample * 0.2965164f;
 98			mBuf2 = mBuf2 * 0.57000f + next_sample * 1.0526913f;
 99			
100			next_sample = mBuf0 + mBuf1 + mBuf2 + next_sample * 0.1848f;
101			
102			if (interp_freq)
103			{
104				// calculate and interpolate resonant filter coefficients
105				mCurrentFreq = (0.999f * mCurrentFreq) + (0.001f * mTargetFreq);
106				b1 = (-4.0f * mB2) / (1.0f + mB2) * cosf(F_TWO_PI * (mCurrentFreq * mSamplePeriod));
107				a0 = (1.0f - mB2) * sqrtf(1.0f - (b1 * b1) / (4.0f * mB2));
108			}
109			
110			// Apply a resonant low-pass filter on the pink noise
111	        next_sample = a0 * next_sample - b1 * mY0 - mB2 * mY1;
112			mY1 = mY0;
113			mY0 = next_sample;
114			
115			mCurrentGain = (0.999f * mCurrentGain) + (0.001f * mTargetGain);
116			mCurrentPanGainR = (0.999f * mCurrentPanGainR) + (0.001f * mTargetPanGainR);
117			
118			// For a 3dB pan law use:
119			// next_sample *= mCurrentGain * ((mCurrentPanGainR*(mCurrentPanGainR-1)*1.652+1.413);
120		    next_sample *= mCurrentGain;
121			
122			// delta is used to interpolate between synthesized samples
123			F32 delta = (next_sample - mLastSample) / (F32)mSubSamples;
124			
125			// Fill the audio buffer, clipping if necessary
126			for (U8 i=mSubSamples; i && numsamples; --i, --numsamples) 
127			{
128				mLastSample = mLastSample + delta;
129				S32	sample_right = (S32)(mLastSample * mCurrentPanGainR);
130				S32	sample_left = (S32)mLastSample - sample_right;
131				
132				if (!clip)
133				{
134					*cursamplep = (MIXBUFFERFORMAT_T)sample_left;
135					++cursamplep;
136					*cursamplep = (MIXBUFFERFORMAT_T)sample_right;
137					++cursamplep;
138				}
139				else
140				{
141					*cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_left, (S32)S16_MIN, (S32)S16_MAX);
142					++cursamplep;
143					*cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_right, (S32)S16_MIN, (S32)S16_MAX);
144					++cursamplep;
145				}
146			}
147		}
148		
149		return newbuffer;
150	}
151	
152public:
153	F32 mTargetGain;
154	F32 mTargetFreq;
155	F32 mTargetPanGainR;
156	
157private:
158	U32 mInputSamplingRate;
159	U8  mSubSamples;
160	F32 mSamplePeriod;
161	F32 mFilterBandWidth;
162	F32 mB2;
163	
164	F32 mBuf0;
165	F32 mBuf1;
166	F32 mBuf2;
167	F32 mY0;
168	F32 mY1;
169	
170	F32 mCurrentGain;
171	F32 mCurrentFreq;
172	F32 mCurrentPanGainR;
173	F32 mLastSample;
174};
175
176#endif