/*
 *  SID.h - 6581 emulation
 *
 *  SIDPlayer (C) 1996 Christian Bauer
 */

#ifndef _SID_H
#define _SID_H

#include <MediaKit.h>
#include "Types.h"

#include "panprop.h"
#include "volprop.h"


// Define this if you want an emulation of a 8580
// (affects combined waveforms)
#undef EMUL_MOS8580


// Structure for one voice
struct DRVoice {
	int wave;		// Selected waveform
	int eg_state;	// Current state of EG
	DRVoice *mod_by;	// Voice that modulates this one
	DRVoice *mod_to;	// Voice that is modulated by this one

	ULONG count;	// Counter for waveform generator, 8.16 fixed
	ULONG add;		// Added to counter in every frame

	UWORD freq;		// SID frequency value
	UWORD pw;		// SID pulse-width value

	ULONG a_add;	// EG parameters
	ULONG d_sub;
	ULONG s_level;
	ULONG r_sub;
	ULONG eg_level;	// Current EG level, 8.16 fixed

	ULONG noise;	// Last noise generator output value

	bool gate;		// EG gate bit
	bool ring;		// Ring modulation bit
	bool test;		// Test bit
	bool filter;	// Flag: Voice filtered

					// The following bit is set for the modulating
					// voice, not for the modulated one (as the SID bits)
	bool sync;		// Sync modulation bit
};

class MOS6510;

// Class for 6581 emulation
class MOS6581 {
public:
	MOS6581(float *glbvol);
	~MOS6581();

	void Reset(void);
	void SetReplayFreq(ULONG freq);
	UBYTE ReadRegister(UWORD adr);
	void WriteRegister(UWORD adr, UBYTE byte);
	void EnableFilters(bool enable);
	void PauseSound(void);
	void ResumeSound(void);
	bool IsPaused(void);

	MOS6510 *TheCPU;	// Pointer to CPU
	UBYTE *TheRAM;		// Pointer to 64K RAM
	UWORD PlayAdr;		// Start address of play routine

	panprop *panprop[4];	// Panning sliders
	volprop *volprop[4];	// Volume sliders

	static bool stream_func(void *arg, char *buf, long count);

private:
	void calc_buffer(WORD *buf, long count);
	void calc_filter(void);

	bool ready;						// Flag: Subscriber has subscribed
	bool in_stream;					// Flag: Subscriber has entered stream
	UBYTE volume;					// Master volume
	bool v3_mute;					// Voice 3 muted

	static const ULONG EGTable[16]; 	// Increment/decrement values for all A/D/R settings
	static UWORD TriTable[0x1000*2];	// Tables for certain waveforms
	static const UWORD TriSawTable[0x100];
	static const UWORD TriRectTable[0x100];
	static const UWORD SawRectTable[0x100];
	static const UWORD TriSawRectTable[0x100];
	static const UBYTE EGDRShift[256]; // For exponential approximation of D/R
	static const WORD SampleTab[3][16]; // Table for samples at volumes 0..2

	ULONG replay_freq;				// Frequency at which the replay routine is called in Hz
	ULONG replay_count;				// Counter for timing replay routine

	DRVoice voice[3];				// Data for 3 voices

	bool f_enabled;					// Flag: Filters enabled
	UBYTE f_type;					// Filter type
	UBYTE f_freq;					// SID filter frequency (upper 8 bits)
	UBYTE f_res;					// Filter resonance (0..15)
	float f_ampl;					// IIR filter input attenuation
	float d1, d2, g1, g2;			// IIR filter coefficients
	float xn1[4], xn2[4], yn1[4], yn2[4];	// IIR filter previous input/output signal

	int v4_state;					// State of voice 4 (Galway noise/samples)
	ULONG v4_count;					// Counter for voice 4
	ULONG v4_add;					// Added to counter in every frame

	UWORD gn_adr;					// C64 address of tone list
	UWORD gn_tone_length;			// Length of each tone in samples
	ULONG gn_volume_add;			// Added to SID volume reg. for every sample
	int	gn_tone_counter;			// Number of tones in list
	UWORD gn_base_cycles;			// Cycles for before sample
	UWORD gn_loop_cycles;			// Cycles between samples

	ULONG sm_adr;					// C64 nybble address of sample
	ULONG sm_end_adr;				// C64 nybble address of end of sample
	ULONG sm_rep_adr;				// C64 nybble address of sample repeat point
	UWORD sm_volume;				// Sample volume (0..2, 0=loudest)
	UBYTE sm_rep_count;				// Sample repeat counter (0xff=continous)
	bool sm_big_endian;				// Flag: Sample is big-endian

	UBYTE regs[0x80];				// Copy of SID registers
	UBYTE last_sid_byte;			// Last value written to SID
	
	float *globalvolume;
};

#endif
