C++程序  |  487行  |  14.97 KB

/*----------------------------------------------------------------------------
 *
 * File: 
 * eas_reverbdata.h
 *
 * Contents and purpose:
 * Contains the prototypes for the Reverb effect.
 *
 *
 * Copyright Sonic Network Inc. 2006

 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *----------------------------------------------------------------------------
 * Revision Control:
 *   $Revision: 499 $
 *   $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $
 *----------------------------------------------------------------------------
*/

#ifndef _EAS_REVERBDATA_H
#define _EAS_REVERBDATA_H

#include "eas_types.h"
#include "eas_audioconst.h"

/*------------------------------------
 * defines
 *------------------------------------
*/

/*
CIRCULAR() calculates the array index using modulo arithmetic.
The "trick" is that modulo arithmetic is simplified by masking
the effective address where the mask is (2^n)-1. This only works
if the buffer size is a power of two.
*/
#define CIRCULAR(base,offset,size) (EAS_U32)(				\
			(												\
				((EAS_I32)(base)) + ((EAS_I32)(offset))		\
			)												\
			& size											\
											)

/* reverb parameters are updated every 2^(REVERB_UPDATE_PERIOD_IN_BITS) samples */
#if	defined (_SAMPLE_RATE_8000)

#define	REVERB_UPDATE_PERIOD_IN_BITS		5
#define	REVERB_BUFFER_SIZE_IN_SAMPLES		2048

#elif defined (_SAMPLE_RATE_16000)

#define	REVERB_UPDATE_PERIOD_IN_BITS		6
#define	REVERB_BUFFER_SIZE_IN_SAMPLES		4096

#elif defined (_SAMPLE_RATE_22050)

#define	REVERB_UPDATE_PERIOD_IN_BITS		7
#define	REVERB_BUFFER_SIZE_IN_SAMPLES		4096

#elif defined (_SAMPLE_RATE_32000)

#define	REVERB_UPDATE_PERIOD_IN_BITS		7
#define	REVERB_BUFFER_SIZE_IN_SAMPLES		8192

#elif defined (_SAMPLE_RATE_44100)

#define	REVERB_UPDATE_PERIOD_IN_BITS		8
#define	REVERB_BUFFER_SIZE_IN_SAMPLES		8192

#elif defined (_SAMPLE_RATE_48000)

#define	REVERB_UPDATE_PERIOD_IN_BITS		8
#define	REVERB_BUFFER_SIZE_IN_SAMPLES		8192

#endif

// Define a mask for circular addressing, so that array index
// can wraparound and stay in array boundary of 0, 1, ..., (buffer size -1)
// The buffer size MUST be a power of two
#define	REVERB_BUFFER_MASK					(REVERB_BUFFER_SIZE_IN_SAMPLES -1)

#define REVERB_MAX_ROOM_TYPE			4	// any room numbers larger than this are invalid
#define REVERB_MAX_NUM_REFLECTIONS		5	// max num reflections per channel

/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SAMPLES */
#define REVERB_UPDATE_PERIOD_IN_SAMPLES	(EAS_I32)(0x1L << REVERB_UPDATE_PERIOD_IN_BITS)

/*
calculate the update counter by bitwise ANDING with this value to 
generate a 2^n modulo value
*/
#define REVERB_MODULO_UPDATE_PERIOD_IN_SAMPLES	(EAS_I32)(REVERB_UPDATE_PERIOD_IN_SAMPLES -1)

/* synth parameters are updated every SYNTH_UPDATE_PERIOD_IN_SECONDS seconds */
#define REVERB_UPDATE_PERIOD_IN_SECONDS		(REVERB_UPDATE_PERIOD_IN_SAMPLES / _OUTPUT_SAMPLE_RATE)

// xfade parameters
#define	REVERB_XFADE_PERIOD_IN_SECONDS		(100.0 / 1000.0)		// xfade once every this many seconds

#define	REVERB_XFADE_PERIOD_IN_SAMPLES		(REVERB_XFADE_PERIOD_IN_SECONDS * _OUTPUT_SAMPLE_RATE)

#define	REVERB_XFADE_PHASE_INCREMENT	(EAS_I16)(65536 / ((EAS_I16)REVERB_XFADE_PERIOD_IN_SAMPLES/(EAS_I16)REVERB_UPDATE_PERIOD_IN_SAMPLES))

/**********/
/* the entire synth uses various flags in a bit field */

/* if flag is set, synth reset has been requested */
#define	REVERB_FLAG_RESET_IS_REQUESTED			0x01	/* bit 0 */
#define	MASK_REVERB_RESET_IS_REQUESTED			0x01
#define	MASK_REVERB_RESET_IS_NOT_REQUESTED		(EAS_U32)(~MASK_REVERB_RESET_IS_REQUESTED)

/*
by default, we always want to update ALL channel parameters
when we reset the synth (e.g., during GM ON)
*/
#define	DEFAULT_REVERB_FLAGS					0x0

/* coefficients for generating sin, cos */
#define	REVERB_PAN_G2	4294940151			/* -0.82842712474619 = 2 - 4/sqrt(2) */
/*
EAS_I32 nPanG1 = +1.0 for sin
EAS_I32 nPanG1 = -1.0 for cos
*/
#define REVERB_PAN_G0	23170				/* 0.707106781186547 = 1/sqrt(2) */

/*************************************************************/
// define the input injection points
#define	GUARD				5						// safety guard of this many samples

#define	MAX_AP_TIME			(double) (20.0/1000.0)	// delay time in milliseconds
#define	MAX_DELAY_TIME		(double) (65.0/1000.0)	// delay time in milliseconds

#define	MAX_AP_SAMPLES		(int)(((double) MAX_AP_TIME)	* ((double) _OUTPUT_SAMPLE_RATE))
#define	MAX_DELAY_SAMPLES	(int)(((double) MAX_DELAY_TIME) * ((double) _OUTPUT_SAMPLE_RATE))

#define	AP0_IN				0
#define	AP1_IN				(AP0_IN		+ MAX_AP_SAMPLES	+ GUARD)
#define	DELAY0_IN			(AP1_IN		+ MAX_AP_SAMPLES	+ GUARD)
#define	DELAY1_IN			(DELAY0_IN	+ MAX_DELAY_SAMPLES	+ GUARD)

// Define the max offsets for the end points of each section
// i.e., we don't expect a given section's taps to go beyond
// the following limits
#define	AP0_OUT				(AP0_IN		+ MAX_AP_SAMPLES	-1)
#define	AP1_OUT				(AP1_IN		+ MAX_AP_SAMPLES	-1)
#define	DELAY0_OUT			(DELAY0_IN	+ MAX_DELAY_SAMPLES	-1)
#define	DELAY1_OUT			(DELAY1_IN	+ MAX_DELAY_SAMPLES	-1)

#define	REVERB_DEFAULT_ROOM_NUMBER		1		// default preset number 
#define	DEFAULT_AP0_LENGTH				(int)(((double) (17.0/1000.0))	* ((double) _OUTPUT_SAMPLE_RATE))
#define	DEFAULT_AP0_GAIN				19400
#define	DEFAULT_AP1_LENGTH				(int)(((double) (16.5/1000.0))	* ((double) _OUTPUT_SAMPLE_RATE))
#define	DEFAULT_AP1_GAIN				-19400

#define	REVERB_DEFAULT_WET				32767
#define	REVERB_DEFAULT_DRY				0

#define EAS_REVERB_WET_MAX				32767
#define EAS_REVERB_WET_MIN				0
#define EAS_REVERB_DRY_MAX				32767
#define EAS_REVERB_DRY_MIN				0

/* parameters for each allpass */
typedef struct
{
	EAS_U16				m_zApOut;		// delay offset for ap out

	EAS_I16				m_nApGain;		// gain for ap

	EAS_U16				m_zApIn;		// delay offset for ap in

} S_ALLPASS_OBJECT;


/* parameters for each allpass */
typedef struct
{
	EAS_PCM				m_zLpf;						// actual state variable, not a length

	EAS_I16				m_nLpfFwd;					// lpf forward gain

	EAS_I16				m_nLpfFbk;					// lpf feedback gain

	EAS_U16				m_zDelay[REVERB_MAX_NUM_REFLECTIONS];	// delay offset for ap out

	EAS_I16				m_nGain[REVERB_MAX_NUM_REFLECTIONS];	// gain for ap

} S_EARLY_REFLECTION_OBJECT;

//demo
typedef struct
{
	EAS_I16				m_nLpfFbk;
	EAS_I16				m_nLpfFwd;

	EAS_I16				m_nEarly;
	EAS_I16				m_nWet;
	EAS_I16				m_nDry;

	EAS_I16				m_nEarlyL_LpfFbk;
	EAS_I16				m_nEarlyL_LpfFwd;

	EAS_I16				m_nEarlyL_Delay0; //8
	EAS_I16				m_nEarlyL_Gain0;
	EAS_I16				m_nEarlyL_Delay1;
	EAS_I16				m_nEarlyL_Gain1;
	EAS_I16				m_nEarlyL_Delay2;
	EAS_I16				m_nEarlyL_Gain2;
	EAS_I16				m_nEarlyL_Delay3;
	EAS_I16				m_nEarlyL_Gain3;
	EAS_I16				m_nEarlyL_Delay4;
	EAS_I16				m_nEarlyL_Gain4;

	EAS_I16				m_nEarlyR_Delay0; //18
	EAS_I16				m_nEarlyR_Gain0;
	EAS_I16				m_nEarlyR_Delay1;
	EAS_I16				m_nEarlyR_Gain1;
	EAS_I16				m_nEarlyR_Delay2;
	EAS_I16				m_nEarlyR_Gain2;
	EAS_I16				m_nEarlyR_Delay3;
	EAS_I16				m_nEarlyR_Gain3;
	EAS_I16				m_nEarlyR_Delay4;
	EAS_I16				m_nEarlyR_Gain4;

	EAS_U16				m_nMaxExcursion; //28
	EAS_I16				m_nXfadeInterval;

	EAS_I16				m_nAp0_ApGain; //30
	EAS_I16				m_nAp0_ApOut;
	EAS_I16				m_nAp1_ApGain;
	EAS_I16				m_nAp1_ApOut;

	EAS_I16				m_rfu4;
	EAS_I16				m_rfu5;
	EAS_I16				m_rfu6;
	EAS_I16				m_rfu7;
	EAS_I16				m_rfu8;
	EAS_I16				m_rfu9;
	EAS_I16				m_rfu10; //43

} S_REVERB_PRESET;

typedef struct
{
	S_REVERB_PRESET		m_sPreset[REVERB_MAX_ROOM_TYPE];	//array of presets

} S_REVERB_PRESET_BANK;

/* parameters for each reverb */
typedef struct
{
	/* controls entire reverb playback volume */
	/* to conserve memory, use the MSB and ignore the LSB */
	EAS_U8				m_nMasterVolume;

	/* update counter keeps track of when synth params need updating */
	/* only needs to be as large as REVERB_UPDATE_PERIOD_IN_SAMPLES */
	EAS_I16				m_nUpdateCounter;	
	
	EAS_U16				m_nMinSamplesToAdd;			/* ComputeReverb() generates this many samples */

	EAS_U8				m_nFlags;					/* misc flags/bit fields */
	
	EAS_PCM				*m_pOutputBuffer;
	EAS_PCM				*m_pInputBuffer;

	EAS_U16				m_nNumSamplesInOutputBuffer;
	EAS_U16				m_nNumSamplesInInputBuffer;

	EAS_U16				m_nNumInputSamplesRead;		// if m_nNumInputSamplesRead >= NumSamplesInInputBuffer 
													// then get a new input buffer
	EAS_PCM				*m_pNextInputSample;

	EAS_U16				m_nBaseIndex;									// base index for circular buffer

	// reverb delay line offsets, allpass parameters, etc:

	EAS_PCM				m_nRevOutFbkR;				// combine feedback reverb right out with dry left in

	S_ALLPASS_OBJECT	m_sAp0;						// allpass 0 (left channel)

	EAS_U16				m_zD0In;					// delay offset for delay line D0 in

	EAS_PCM				m_nRevOutFbkL;				// combine feedback reverb left out with dry right in

	S_ALLPASS_OBJECT	m_sAp1;						// allpass 1 (right channel)

	EAS_U16				m_zD1In;					// delay offset for delay line D1 in

	// delay output taps, notice criss cross order
	EAS_U16				m_zD0Self;					// self feeds forward d0 --> d0

	EAS_U16				m_zD1Cross;					// cross feeds across d1 --> d0

	EAS_PCM				m_zLpf0;					// actual state variable, not a length

	EAS_U16				m_zD1Self;					// self feeds forward d1 --> d1

	EAS_U16				m_zD0Cross;					// cross feeds across d0 --> d1

	EAS_PCM				m_zLpf1;					// actual state variable, not a length

	EAS_I16				m_nSin;						// gain for self taps

	EAS_I16				m_nCos;						// gain for cross taps

	EAS_I16				m_nSinIncrement;			// increment for gain

	EAS_I16				m_nCosIncrement;			// increment for gain

	EAS_I16				m_nLpfFwd;					// lpf forward gain (includes scaling for mixer)

	EAS_I16				m_nLpfFbk;					// lpf feedback gain

	EAS_U16				m_nXfadeInterval;			// update/xfade after this many samples

	EAS_U16				m_nXfadeCounter;			// keep track of when to xfade

	EAS_I16				m_nPhase;					// -1 <= m_nPhase < 1
													// but during sin,cos calculations
													// use m_nPhase/2

	EAS_I16				m_nPhaseIncrement;			// add this to m_nPhase each frame

	EAS_I16				m_nNoise;					// random noise sample

	EAS_U16				m_nMaxExcursion;			// the taps can excurse +/- this amount

	EAS_BOOL			m_bUseNoise;				// if EAS_TRUE, use noise as input signal

	EAS_BOOL			m_bBypass;					// if EAS_TRUE, then bypass reverb and copy input to output

	EAS_I16				m_nCurrentRoom;				// preset number for current room

	EAS_I16				m_nNextRoom;				// preset number for next room

	EAS_I16				m_nWet;						// gain for wet (processed) signal

	EAS_I16				m_nDry;						// gain for dry (unprocessed) signal

	EAS_I16				m_nEarly;					// gain for early (widen) signal
	
	S_EARLY_REFLECTION_OBJECT	m_sEarlyL;			// left channel early reflections
	S_EARLY_REFLECTION_OBJECT	m_sEarlyR;			// right channel early reflections

	EAS_PCM				m_nDelayLine[REVERB_BUFFER_SIZE_IN_SAMPLES];	// one large delay line for all reverb elements

	S_REVERB_PRESET		pPreset;

	S_REVERB_PRESET_BANK	m_sPreset;

	//EAS_I8			preset;

} S_REVERB_OBJECT;


/*------------------------------------
 * prototypes
 *------------------------------------
*/

/*----------------------------------------------------------------------------
 * ReverbUpdateXfade
 *----------------------------------------------------------------------------
 * Purpose: 
 * Update the xfade parameters as required
 *
 * Inputs: 
 * nNumSamplesToAdd - number of samples to write to buffer
 *
 * Outputs:
 * 
 * 
 * Side Effects:
 * - xfade parameters will be changed
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT ReverbUpdateXfade(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd);

/*----------------------------------------------------------------------------
 * ReverbCalculateNoise
 *----------------------------------------------------------------------------
 * Purpose: 
 * Calculate a noise sample and limit its value
 *
 * Inputs: 
 * nMaxExcursion - noise value is limited to this value
 * pnNoise - return new noise sample in this (not limited)
 *
 * Outputs:
 * new limited noise value
 * 
 * Side Effects:
 * - *pnNoise noise value is updated
 *
 *----------------------------------------------------------------------------
*/
static EAS_U16 ReverbCalculateNoise(EAS_U16 nMaxExcursion, EAS_I16 *pnNoise);

/*----------------------------------------------------------------------------
 * ReverbCalculateSinCos
 *----------------------------------------------------------------------------
 * Purpose: 
 * Calculate a new sin and cosine value based on the given phase
 *
 * Inputs: 
 * nPhase	- phase angle
 * pnSin	- input old value, output new value
 * pnCos	- input old value, output new value
 *
 * Outputs:
 * 
 * Side Effects:
 * - *pnSin, *pnCos are updated
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT ReverbCalculateSinCos(EAS_I16 nPhase, EAS_I16 *pnSin, EAS_I16 *pnCos);

/*----------------------------------------------------------------------------
 * Reverb
 *----------------------------------------------------------------------------
 * Purpose: 
 * apply reverb to the given signal
 *
 * Inputs: 
 * nNu
 * pnSin	- input old value, output new value
 * pnCos	- input old value, output new value
 *
 * Outputs:
 * number of samples actually reverberated
 * 
 * Side Effects:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT Reverb(S_REVERB_OBJECT* pReverbData, EAS_INT nNumSamplesToAdd, EAS_PCM *pOutputBuffer, EAS_PCM *pInputBuffer);

/*----------------------------------------------------------------------------
 * ReverbReadInPresets()
 *----------------------------------------------------------------------------
 * Purpose: sets global reverb preset bank to defaults
 * 
 * Inputs: 
 *			
 * Outputs:
 *
 *----------------------------------------------------------------------------
*/
static EAS_RESULT ReverbReadInPresets(S_REVERB_OBJECT* pReverbData);


/*----------------------------------------------------------------------------
 * ReverbUpdateRoom
 *----------------------------------------------------------------------------
 * Purpose: 
 * Update the room's preset parameters as required
 *
 * Inputs: 
 *
 * Outputs:
 * 
 * 
 * Side Effects:
 * - reverb paramters (fbk, fwd, etc) will be changed
 * - m_nCurrentRoom := m_nNextRoom
 *----------------------------------------------------------------------------
*/
static EAS_RESULT ReverbUpdateRoom(S_REVERB_OBJECT* pReverbData);

#endif /* #ifndef _EAS_REVERBDATA_H */