/*	
 *	clipdms.h
 *
 *	P/ECE DMG-Sound Emulator
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2004 Naoyuki Sawa
 *
 *	* Thu Jan 15 20:09:00 JST 2004 Naoyuki Sawa
 *	- 作成開始。
 */
#ifndef __CLIP_DMS_H__
#define __CLIP_DMS_H__

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

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

/*
 *	トーンチャネル (Ch#1-2)
 */
typedef struct _DMGSOUNDTONE {
	/* Sound Length */
	int sound_length;		/* サウンド出力時間 (0:停止/>0:残りサイクル数/<0:INFINITE) */
	/* Sweep (Ch#1のみ) */
	int sweep_time;			/* スイープ更新周期 */
	int sweep_up_down;		/* スイープ方向 (0:増加/1:減少) */
	int sweep_shift;		/* スイープ変化量 */
	int sweep_progress;		/* スイープ進行カウンタ */
	/* Envelope */
	int envelope;			/* エンベロープ現在値 */
	int envelope_time;		/* エンベロープ更新周期 */
	int envelope_up_down;		/* エンベロープ方向 (0:減少/1:増加) */
	int envelope_progress;		/* エンベロープ進行カウンタ */
	/* Wave Pattern */
	int wave_pattern;		/* 波形パターン現在値 (0〜7) */
	int wave_pattern_duty;		/* 波形パターンデューティー比 (1/2/4/6) */
	/* Frequency */
	int frequency;			/* 周波数設定値 */
	int frequency_progress;		/* 周波数進行カウンタ */
} DMGSOUNDTONE;

/*
 *	PCMチャネル (Ch#3)
 */
typedef struct _DMGSOUNDPCM {
	/* Sound ON/OFF */
	int sound_on_off;		/* サウンド出力 (0:OFF/1:ON) */
	/* Sound Length */
	int sound_length;		/* サウンド出力時間 (0:停止/>0:残りサイクル数/<0:INFINITE) */
	/* Output Level */
	int output_level;		/* サウンド出力レベル (0〜3) */
	/* Wave Pattern */
	int wave_pattern;		/* 波形パターン現在値 (0〜31) */
	char wave_pattern_ram[32];	/* 波形メモリ(-15〜+15) */
	/* Frequency */
	int frequency;			/* 周波数設定値 */
	int frequency_progress;		/* 周波数進行カウンタ */
} DMGSOUNDPCM;

/*
 *	ノイズチャネル (Ch#4)
 */
typedef struct _DMGSOUNDNOISE {
	/* Sound Length */
	int sound_length;		/* サウンド出力時間 (0:停止/>0:残りサイクル数/<0:INFINITE) */
	/* Envelope */
	int envelope;			/* エンベロープ現在値 */
	int envelope_time;		/* エンベロープ更新周期 */
	int envelope_up_down;		/* エンベロープ方向 (0:減少/1:増加) */
	int envelope_progress;		/* エンベロープ進行カウンタ */
	/* LFSR */
	int lfsr;			/* Linear Feedback Shift Register */
	int lfsr_bits;			/* LFSRビット数 (0:15bit/1:7bit) */
	/* Frequency */
	int frequency;			/* 周波数設定値 */
	int frequency_progress;		/* 周波数進行カウンタ */
} DMGSOUNDNOISE;

/*
 *	DMG-Soundコア
 */
typedef struct _DMGSOUND {
	DDA progress;			/* クロック進行DDA */
	//
	unsigned char* reg;		/* レジスタメモリ(外部) */
	//
	int all_sound_on_off;		/* 1:ON/0:OFF */
					/* OFFの場合、単に音声出力OFFではなく、回路が停止します。 */
	int sound_output;		/* bit0: Ch#1 Left  1:ON/0:OFF */
					/* bit1: Ch#2 Left  1:ON/0:OFF */
					/* bit2: Ch#3 Left  1:ON/0:OFF */
					/* bit3: Ch#4 Left  1:ON/0:OFF */
					/* bit4: Ch#1 Right 1:ON/0:OFF */
					/* bit5: Ch#2 Right 1:ON/0:OFF */
					/* bit6: Ch#3 Right 1:ON/0:OFF */
					/* bit7: Ch#4 Right 1:ON/0:OFF */
	int volume[2];			/* マスタボリューム [0:Left/1:Right] */
	//
	DMGSOUNDTONE  ch1;		/* Ch#1: トーン(スイープ有) */
	DMGSOUNDTONE  ch2;		/* Ch#2: トーン(スイープ無) */
	DMGSOUNDPCM   ch3;		/* Ch#3: PCM */
	DMGSOUNDNOISE ch4;		/* Ch#4: ノイズ */
} DMGSOUND;

int dmgsound_process(DMGSOUND* ds, int cycle);				/* 符号付き11bit */
int dmgsound_tone_process(DMGSOUND* ds, DMGSOUNDTONE* ch, int cycle);	/* 符号付き5bit{-15〜15} */
int dmgsound_pcm_process(DMGSOUND* ds, DMGSOUNDPCM* ch, int cycle);	/* 符号付き5bit{-15〜15} */
int dmgsound_noise_process(DMGSOUND* ds, DMGSOUNDNOISE* ch, int cycle);	/* 符号付き5bit{-15〜15} */

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

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

/* DMG-Soundコアをリセットします。
 * [in]
 *	ds		DMGSOUND構造体。
 *	reg		レジスタメモリ(外部)
 *			* 少なくとも0x40バイトのレジスタメモリが必要です。
 *			  GBSプレイヤーでは、DMG-CPUの論理アドレス0xff00-0xff3fを共有してください。
 *			* dmgsound_reset()呼び出し後、外部からメモリ内容を書き換えてはいけません。
 *			  必ずdmgsound_write()を経由してください。
 *			* レジスタ値を読み出す場合は、レジスタメモリの値を直接読み出してください。
 *			  ※ただし2004/01/18現在、読み出し可能レジスタ値の更新は未実装です。
 *			  ↓2005/02/25変更
 *			  dmgsound_read()関数を追加しました。
 *			  今後は、レジスタの読み出しは、dmgsound_read()関数を呼び出してください。
 *			  もう、メインメモリを共有する必要は無いかも知れません。
 *			  再実装の機会があれば、メインメモリの共有を取りやめたいと思います。
 *	clock		入力クロック。
 * [note]
 *	* アプリケーションプログラムは、少なくとも最初に一度、この関数を呼び出してください。
 *	  その後は、DMG-Soundリセットを行う場合に、必要に応じて呼び出してください。
 */
void dmgsound_reset(DMGSOUND* ds, unsigned char* reg, int clock);

/* DMG-Soundのレジスタに書き込みます。
 * [in]
 *	ds		DMGSOUND構造体。
 *	addr		レジスタアドレス。
 *			CPU論理アドレスの下位バイトで指定してください。
 *				NR10: 0xff10 => 0x10
 *				NR11: 0xff11 => 0x11
 *				NR12: 0xff12 => 0x12
 *				NR13: 0xff13 => 0x13
 *				NR14: 0xff14 => 0x14
 *				NR21: 0xff16 => 0x16
 *				NR22: 0xff17 => 0x17
 *				NR23: 0xff18 => 0x18
 *				NR24: 0xff19 => 0x19
 *				NR30: 0xff1a => 0x1a
 *				NR31: 0xff1b => 0x1b
 *				NR32: 0xff1c => 0x1c
 *				NR33: 0xff1d => 0x1d
 *				NR34: 0xff1e => 0x1e
 *				NR41: 0xff20 => 0x20
 *				NR42: 0xff21 => 0x21
 *				NR43: 0xff22 => 0x22
 *				NR44: 0xff23 => 0x23
 *				NR50: 0xff24 => 0x24
 *				NR51: 0xff25 => 0x25
 *				NR52: 0xff26 => 0x26
 *				AUD3W: 0xff30-0xff3f => 0x30-0x3f
 *	data		書き込むデータ。
 * [note]
 *	* 不正なレジスタアドレスが指定された場合は、何もせずに帰ります。
 */
void dmgsound_write(DMGSOUND* ds, unsigned char addr, unsigned char data);

/* DMG-Soundのレジスタを読み出します。(2005/02/25追加)
 * [in]
 *	ds		DMGSOUND構造体。
 *	addr		レジスタアドレス。
 *			CPU論理アドレスの下位バイトで指定してください。
 *			詳しくは、dmgsound_write()の説明を参照してください。
 * [out]
 *	戻り値		読み出したデータ。
 */
unsigned char dmgsound_read(DMGSOUND* ds, unsigned char addr);

/* 出力サンプリングレート=SPEAKER_OUTPUT[Hz]で、指定されたサンプル数のミキシングを行います。
 * [in]
 *	ds		DMGSOUND構造体。
 *	wbuff		出力サンプルバッファ。
 *	count		出力サンプル数。
 */
void dmgsound_mix(DMGSOUND* ds, short wbuff[/*count*/], int count);

#endif /*__CLIP_DMS_H__*/
