#ifndef __SUBSONIC_AND_AGC_H__
#define __SUBSONIC_AND_AGC_H__

#include <vstypes.h>




struct DcBlock32 {
  u_int32 mem[2];
};

void DcBlock32N(register __i0 struct DcBlock32 *mem,
		register __a1 s_int16 shiftRight,
		register __i2 s_int32 *d,
		register __a0 u_int16 n);


struct Agc32 {
  s_int16 attack;      /* In ms, e.g.  1, range 1..255 */
  s_int16 decay;       /* In ms, e.g. 40, range 1..255 */
  s_int16 targetLevel; /* Target signal level; -9 = -9 dB; range -36..0 */
  s_int16 maxGain;     /* In 1 dB steps; 12 = 12.0 dB; range   0..36 */
  s_int16 minGain;     /* In 1 dB steps;  0 =  0.0 dB; range -12..36 */
  s_int32 sampleRate;  /* Sample rate of data, range 8000..192000 */
  /* ----- internal variables start here. Don't touch! ----- */
  u_int16 phase;
  s_int16 winLen;
  double targetLevelLin;
  double maxGainLin;
  double minGainLin;
  double gainLin;
  double attackInv;
  double decayInv;
  s_int32 totPLin;
  u_int16 gainInt;
  s_int16 gainModInt;
};


/* Initialize */
void InitAgc32(register struct Agc32 *agc32);

/* Set new parameters while running */
void SetAgc32(register struct Agc32 *agc32);

/* Run Agc32 */
void Agc32(register struct Agc32 *agc, register s_int32 *d1,
	   register s_int32 *d2, register u_int16 n);

/* Calculates power of 16 MSb's of the data */
auto s_int32 Agc32CalcPow(register __i0 s_int32 *d, register __b0 s_int16 n,
			  register __b1 s_int16 shiftResultRight);

auto u_int16 Agc32Asm(register __i0 s_int32 *d1,
		      register __b0 u_int16 gainInt,
		      register __b1 s_int16 gainMod,
		     register __a1 u_int16 n);




/*
  150903:
  THE FOLLOWING ARE LEGACY DECLARATIONS; DON'T USE FOR NEW PROJECTS
  UNLESS YOU ABSOLUTELY KNOW WHAT YOU ARE DOING!!!
*/



struct SubsonicM {
  s_int16 mem0;
  s_int32 mem1;
};

struct SubsonicG {
  s_int16 b0;
  s_int16 b1;
  s_int16 a1;
};

void InitSubsonic(register __i0 struct SubsonicM *subsonicM,
		  register __a0 s_int16 channels,
		  register __i1 struct SubsonicG __mem_y *subsonicG,
		  register __reg_d u_int32 sampleRate);

auto s_int16 Subsonic(register __i0 struct SubsonicM *mem,
		      const register __i1 struct SubsonicG __mem_y *g,
		      register __a0 s_int16 d);

void SubsonicN(register __i0 struct SubsonicM *mem,
	       const register __i1 struct SubsonicG __mem_y *g,
	       register __i2 s_int16 *d,
	       register __a0 u_int16 n);

	      
struct Agc {
  s_int16 gain;   /* word  0 */
  u_int32 lpRes;  /* words 1, 2 */
  s_int32 offset; /* words 3, 4*/
};

/* agcSpeed may vary from 1 (fastest) through 7 (slowest).
   Adding one to agcSpeed doubles the attack time. Decay
   time is not affected. */
#define DEFAULT_AGC_ATTACK_DELAY 2

struct AgcConsts {
  u_int16 mr0;	// Should be MR_SAT
  u_int16 upShift; // Should be 5
  s_int16 decaySlowness1; // Should be -agcDecaySlowness
  u_int16 refLevel; // Should be 1024
  s_int16 decaySlowness2; // Should be -agcDecaySlowness-4
  u_int16 maxGain; // Default: 4096 = 4x
};



auto s_int16 AgcKeepDC(register __i0 struct Agc *agc,
		       register __i1 __mem_y const struct AgcConsts *consts,
		       register __a0 s_int16 sig);

void AgcN(register __i0 struct Agc *agc,
	  register __i1 __mem_y const struct AgcConsts *consts,
	  register __i2 s_int16 *d,
	  register __a0 u_int16 n);

void InitAgc(register struct Agc *agc, register s_int16 channels,
	     register struct AgcConsts __mem_y *agcConsts, register u_int16 maxGain,
	     register u_int32 sampleRate);	     

#define SetAgc(agcConsts, val) ((agcConsts)->maxGain = val)




#endif /*!__SUBSONIC_AND_AGC_H__*/
