/*	
 *	clipsid.h
 *
 *	P/ECE SID(MOS6581) Emulator
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2003 Naoyuki Sawa
 *
 *	* Sat Dec 27 06:00:00 JST 2003 Naoyuki Sawa
 *	- 作成開始。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 */
#ifndef __CLIP_SID_H__
#define __CLIP_SID_H__

#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus

/****************************************************************************
 *
 ****************************************************************************/

#define SIDBUFLEN 320 /* = 16000/50 … 1[tick](=1/50[sec])当たりのサンプル数 */

typedef struct _SID SID;

/***** Tone Oscilator *****/
typedef struct _SIDTO {
	int freq;		/* Frequency */
	int progress;		/* 進行カウンタ */
} SIDTO;

int sidto_process(SIDTO* to, int step);

/***** Waveform Generator *****/
typedef struct _SIDWG {
	int pw;			/* Pulse Width */
	int wf;			/* Waveform */
} SIDWG;

/* SIDWG.wf */
#define SIDWG_TRIANGLE		(1 << 0)
#define SIDWG_SAWTOOTH		(1 << 1)
#define SIDWG_PULSE		(1 << 2)
#define SIDWG_NOISE		(1 << 3)

int sidwg_process(SIDWG* wg, int value);

/***** Envelope Generator *****/
typedef struct _SIDEG {
	int atk;		/* Attack rate */
	int dcy;		/* Decay rate */
	int stn;		/* Sustain amplitude */
	int rls;		/* Release rate */
	//
	int cycle;		/* ATTACK/DECAY/SUSTAIN/RELEASE */
	int progress;		/* 進行カウンタ */
} SIDEG;

/* SIDEG.cycle */
#define SIDEG_ATTACK		4
#define SIDEG_DECAY		3
#define SIDEG_SUSTAIN		2
#define SIDEG_RELEASE		1

int sideg_process(SIDEG* eg, int step);

/***** Voice *****/
typedef struct _SIDVOICE {
	SIDTO to;		/* Tone Oscilator */
	SIDWG wg;		/* Waveform Generator */
	SIDEG eg;		/* Envelope Generator */
} SIDVOICE;

int sid_voice_process(SIDVOICE* voice, int step);

/***** SID Chip *****/
/*typedef*/ struct _SID {
	unsigned char reg[32];	/* レジスタ */
	SIDVOICE voice[3];	/* ボイスx3 */
	int vol;		/* ボリューム */
	//
	DDA clock;		/* クロック進行用DDA */
} /*SID*/;

/****************************************************************************
 *
 ****************************************************************************/

extern const char sid_noise_table[256];		/* ノイズジェネレータテーブル */
extern const int sid_attack_table[16];		/* ATTACK RATE テーブル */
extern const int sid_decay_release_table[16];	/* DECAY/RELEASE RATE テーブル */

/****************************************************************************
 *	アプリケーション用関数
 ****************************************************************************/

/* SIDコアをリセットします。
 * [in]
 *	sid		SID構造体。
 *	clock		入力クロック。
 * [note]
 *	* アプリケーションプログラムは、少なくとも最初に一度、この関数を呼び出してください。
 *	  その後は、SIDリセットを行う場合に、必要に応じて呼び出してください。
 */
void sid_reset(SID* sid, int clock);

/* レジスタ値を読み込みます。
 * [in]
 *	sid		SID構造体。
 *	regno		レジスタ番号。(25〜28)
 */
unsigned char sid_read(SID* sid, int regno);

/* レジスタ値を書き込みます。
 * [in]
 *	sid		SID構造体。
 *	regno		レジスタ番号。(0〜24)
 *	data		レジスタ値。
 */
void sid_write(SID* sid, int regno, unsigned char data);

/* 1サンプル分のミキシングを行います。
 * [in]
 *	sid		SID構造体。
 *	pstep		経過したクロック数を格納する変数へのポインタ。
 *			NULLは不可です。
 * [out]
 *	戻り値		出力サンプル値。(符号付き17.5bit＝符号付き16bit×3VOICE加算)
 *			符号付き16bitへのスケーリング・クリッピングは行っていません。
 *			必要に応じて、呼び出し元でクリッピングを行ってください。
 * [note]
 *	* 出力サンプル値をクリッピングしていない理由は、拡張SIDの出力サンプル値との加算がまだだからです。
 *	  呼び出し元で、拡張SIDの出力サンプル値との加算後に、スケーリング・クリッピングを行ってください。
 */
int sid_mix1(SID* sid, int* pstep);

/* 1/50秒分のミキシングを行います。
 * [in]
 *	sid		SID構造体。
 *	wbuff		出力サンプルバッファ。
 * [note]
 *	* PSIDドライバはサンプル毎にCPUとSIDを処理するために、sid_mix1()を使います。
 *	  PSIDドライバはsid_mix()を使いません。
 *	* アプリケーションからSIDを利用する際に、1/50秒単位の同期で充分な場合には、
 *	  sid_mix1()よりもsid_mix()を使った方が処理が軽くなります。
 */
void sid_mix(SID* sid, short wbuff[/*SIDBUFLEN*/]);

#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus

#endif /*__CLIP_SID_H__*/
