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

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

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

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

/* [以下、MAME 0.67 NAMCO sound driver (src/sound/namco.c) より]
 *
 * =======================
 * Xevious type (C15 chip)
 * =======================
 *
 *	0x05:	?????www	w = Ch0 Wavetable Select (前半8音色のみ使用)
 *	0x0a:	?????www	w = Ch1 Wavetable Select (前半8音色のみ使用)
 *	0x0f:	?????www	w = Ch2 Wavetable Select (前半8音色のみ使用)
 *
 *	0x10:	????ffff	f = Ch0 Frequency[ 3: 0]
 *	0x11:	????ffff	f = Ch0 Frequency[ 7: 4]
 *	0x12:	????ffff	f = Ch0 Frequency[11: 8]
 *	0x13:	????ffff	f = Ch0 Frequency[15:12]
 *	0x14:	????ffff	f = Ch0 Frequency[19:16]
 *	0x15:	????vvvv	v = Ch0 Volume
 *
 *				    Ch1 Frequency[ 3: 0]は0固定
 *	0x16:	????ffff	f = Ch1 Frequency[ 7: 4]
 *	0x17:	????ffff	f = Ch1 Frequency[11: 8]
 *	0x18:	????ffff	f = Ch1 Frequency[15:12]
 *	0x19:	????ffff	f = Ch1 Frequency[19:16]
 *	0x1a:	????vvvv	v = Ch1 Volume
 *
 *				    Ch2 Frequency[ 3: 0]は0固定
 *	0x1b:	????ffff	f = Ch2 Frequency[ 7: 4]
 *	0x1c:	????ffff	f = Ch2 Frequency[11: 8]
 *	0x1d:	????ffff	f = Ch2 Frequency[15:12]
 *	0x1e:	????ffff	f = Ch2 Frequency[19:16]
 *	0x1f:	????vvvv	v = Ch2 Volume
 *
 *	波形テーブルはROMです。
 *	1サンプル1バイト、下位4bitのみ使用(0〜15)、8音色分、全256バイトです。
 *
 * =====================
 * Mappy type (C30 chip)
 * =====================
 *
 *	0x03:	????vvvv	v = Ch0 Volume
 *	0x04:	ffffffff	f = Ch0 Frequency[ 7: 0]
 *	0x05:	ffffffff	f = Ch0 Frequency[15: 8]
 *	0x06:	?wwwffff	f = Ch0 Frequency[19:16]
 *				w = Ch0 Wavetable Select (前半8音色のみ使用)
 *
 *	0x0b:	????vvvv	v = Ch1 Volume
 *	0x0c:	ffffffff	f = Ch1 Frequency[ 7: 0]
 *	0x0d:	ffffffff	f = Ch1 Frequency[15: 8]
 *	0x0e:	?wwwffff	f = Ch1 Frequency[19:16]
 *				w = Ch1 Wavetable Select (前半8音色のみ使用)
 *
 *	0x13:	????vvvv	v = Ch2 Volume
 *	0x14:	ffffffff	f = Ch2 Frequency[ 7: 0]
 *	0x15:	ffffffff	f = Ch2 Frequency[15: 8]
 *	0x16:	?wwwffff	f = Ch2 Frequency[19:16]
 *				w = Ch2 Wavetable Select (前半8音色のみ使用)
 *
 *	0x1b:	????vvvv	v = Ch3 Volume
 *	0x1c:	ffffffff	f = Ch3 Frequency[ 7: 0]
 *	0x1d:	ffffffff	f = Ch3 Frequency[15: 8]
 *	0x1e:	?wwwffff	f = Ch3 Frequency[19:16]
 *				w = Ch3 Wavetable Select (前半8音色のみ使用)
 *
 *	0x23:	????vvvv	v = Ch4 Volume
 *	0x24:	ffffffff	f = Ch4 Frequency[ 7: 0]
 *	0x25:	ffffffff	f = Ch4 Frequency[15: 8]
 *	0x26:	?wwwffff	f = Ch4 Frequency[19:16]
 *				w = Ch4 Wavetable Select (前半8音色のみ使用)
 *
 *	0x2b:	????vvvv	v = Ch5 Volume
 *	0x2c:	ffffffff	f = Ch5 Frequency[ 7: 0]
 *	0x2d:	ffffffff	f = Ch5 Frequency[15: 8]
 *	0x2e:	?wwwffff	f = Ch5 Frequency[19:16]
 *				w = Ch5 Wavetable Select (前半8音色のみ使用)
 *
 *	0x33:	????vvvv	v = Ch6 Volume
 *	0x34:	ffffffff	f = Ch6 Frequency[ 7: 0]
 *	0x35:	ffffffff	f = Ch6 Frequency[15: 8]
 *	0x36:	?wwwffff	f = Ch6 Frequency[19:16]
 *				w = Ch6 Wavetable Select (前半8音色のみ使用)
 *
 *	0x3b:	????vvvv	v = Ch7 Volume
 *	0x3c:	ffffffff	f = Ch7 Frequency[ 7: 0]
 *	0x3d:	ffffffff	f = Ch7 Frequency[15: 8]
 *	0x3e:	?wwwffff	f = Ch7 Frequency[19:16]
 *				w = Ch7 Wavetable Select (前半8音色のみ使用)
 *
 *	波形テーブルはROMです。
 *	1サンプル1バイト、下位4bitのみ使用(0〜15)、8音色分、全256バイトです。
 *
 * =========================
 * System1 type (C30 chip?)
 * =========================
 *
 *	0x000:	aaaabbbb	a = Waveform 0 Sample 0
 *				b = Waveform 0 Sample 1
 *	0x001:	ccccdddd	c = Waveform 0 Sample 2
 *				d = Waveform 0 Sample 3
 *	...
 *	0x00f:	yyyyzzzz	y = Waveform 0 Sample30
 *				z = Waveform 0 Sample31
 *
 *	0x010:	aaaabbbb	a = Waveform 1 Sample 0
 *				b = Waveform 1 Sample 1
 *	...
 *	0x0ff:	yyyyzzzz	y = Waveform15 Sample30
 *				z = Waveform15 Sample31
 *
 *	0x100:	????vvvv	v = Ch0 Volume Left
 *	0x101	wwwwffff	w = Ch0 Wavetable Select (全16音色を使用)
 *				f = Ch0 Frequency[19:16]
 *	0x102:	ffffffff	f = Ch0 Frequency[15: 8]
 *	0x103:	ffffffff	f = Ch0 Frequency[ 7: 0]
 *	0x104:	n???vvvv	v = Ch0 Right Volume
 *				n = Ch1 Noise Switch (次のチャネル用です)
 *
 *	0x108:	????vvvv	v = Ch1 Volume Left
 *	0x109	wwwwffff	w = Ch1 Wavetable Select (全16音色を使用)
 *				f = Ch1 Frequency[19:16]
 *	0x10a:	ffffffff	f = Ch1 Frequency[15: 8]
 *	0x10b:	ffffffff	f = Ch1 Frequency[ 7: 0]
 *	0x10c:	n???vvvv	v = Ch1 Right Volume
 *				n = Ch2 Noise Switch (次のチャネル用です)
 *
 *	0x110:	????vvvv	v = Ch2 Volume Left
 *	0x111	wwwwffff	w = Ch2 Wavetable Select (全16音色を使用)
 *				f = Ch2 Frequency[19:16]
 *	0x112:	ffffffff	f = Ch2 Frequency[15: 8]
 *	0x113:	ffffffff	f = Ch2 Frequency[ 7: 0]
 *	0x114:	n???vvvv	v = Ch2 Right Volume
 *				n = Ch3 Noise Switch (次のチャネル用です)
 *
 *	0x118:	????vvvv	v = Ch3 Volume Left
 *	0x119	wwwwffff	w = Ch3 Wavetable Select (全16音色を使用)
 *				f = Ch3 Frequency[19:16]
 *	0x11a:	ffffffff	f = Ch3 Frequency[15: 8]
 *	0x11b:	ffffffff	f = Ch3 Frequency[ 7: 0]
 *	0x11c:	n???vvvv	v = Ch3 Right Volume
 *				n = Ch4 Noise Switch (次のチャネル用です)
 *
 *	0x120:	????vvvv	v = Ch4 Volume Left
 *	0x121	wwwwffff	w = Ch4 Wavetable Select (全16音色を使用)
 *				f = Ch4 Frequency[19:16]
 *	0x122:	ffffffff	f = Ch4 Frequency[15: 8]
 *	0x123:	ffffffff	f = Ch4 Frequency[ 7: 0]
 *	0x124:	n???vvvv	v = Ch4 Right Volume
 *				n = Ch5 Noise Switch (次のチャネル用です)
 *
 *	0x128:	????vvvv	v = Ch5 Volume Left
 *	0x129	wwwwffff	w = Ch5 Wavetable Select (全16音色を使用)
 *				f = Ch5 Frequency[19:16]
 *	0x12a:	ffffffff	f = Ch5 Frequency[15: 8]
 *	0x12b:	ffffffff	f = Ch5 Frequency[ 7: 0]
 *	0x12c:	n???vvvv	v = Ch5 Right Volume
 *				n = Ch6 Noise Switch (次のチャネル用です)
 *
 *	0x130:	????vvvv	v = Ch6 Volume Left
 *	0x131	wwwwffff	w = Ch6 Wavetable Select (全16音色を使用)
 *				f = Ch6 Frequency[19:16]
 *	0x132:	ffffffff	f = Ch6 Frequency[15: 8]
 *	0x133:	ffffffff	f = Ch6 Frequency[ 7: 0]
 *	0x134:	n???vvvv	v = Ch6 Right Volume
 *				n = Ch7 Noise Switch (次のチャネル用です)
 *
 *	0x138:	????vvvv	v = Ch7 Volume Left
 *	0x139	wwwwffff	w = Ch7 Wavetable Select (全16音色を使用)
 *				f = Ch7 Frequency[19:16]
 *	0x13a:	ffffffff	f = Ch7 Frequency[15: 8]
 *	0x13b:	ffffffff	f = Ch7 Frequency[ 7: 0]
 *	0x13c:	n???vvvv	v = Ch7 Right Volume
 *				n = Ch0 Noise Switch (最初のチャネル用です)
 *
 *	波形テーブルはRAMです。
 *	2サンプル1バイト、上位4bit→下位4bitの順、16音色分、全256バイトです。
 */
#define WSG_NUM_REGS	0x140	/* 最大レジスタ数 */

/* * ボリュームを考慮しなければ、出力サンプルのビット数は
 *	符号付き4bit × 8チャネル ＝ 符号付き7bit
 *   です。
 *   ボリュームを考慮すると、
 *	符号付き7bit × 符号無し4bit ＝ 符号付き11bit
 *   です。
 *   最終出力は符号付き16bitなので、必要なスケーリングは
 *	16bit − 11bit ＋ (調整分) ＝ 5 ＋ (調整分)
 *   となります。
 *   実際には全チャネルが同時に鳴ることは少なく、2bit(=4倍)ぐらい多めにスケーリングしておくのがいいようです。
 *   ミキシング時に1サンプルづつスケーリングするよりも、あらかじめボリュームをスケーリングしておく方が効率的です。
 *   従って、ボリューム設定時に左7bitシフトしてから格納します。
 *   ボリューム格納用変数には、符号付き4bit ＋ 7bit ＝ 11bit以上必要です。
 *   すなわち、ボリューム格納用変数はshortとしてください。
 * * 別の方法として、波形データをスケーリングしておく方法もありますが、今回は採用しませんでした。
 *   波形データは符号付き4bitですから、7bitシフトすると11bit必要となります。
 *   現在は波形データを1サンプル1バイトで確保していますが、これをshortに変更しなければいけなくなってしまいます。
 *   ボリュームならばチャネル数分の増加で済みますが、波形データだと数百バイト分の増加になってしまいます。
 *   また、波形データが2バイト単位になると、ミキシング処理にもオフセット計算の手間が増えてしまいます。
 *   よって今回は、波形データではなく、ボリュームをスケーリングする方法を採用することにしました。
 */
#define WSG_VOLUME_SHIFT	(16 - 11 + 2)
				//         +-調整可

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

typedef struct _WSG WSG;

/*
 *	WSGチャネル
 */
typedef struct _WSGCHANNEL {
	unsigned short volume;		/* + 0,2: ボリューム (0〜15)<<WSG_VOLUME_SHIFT */
	unsigned short noise;		/* + 1,2: 0:トーン / 0以外:ノイズLFSR */
	int frequency;			/* + 4,4: 周波数           (17.15bit固定小数) */
	int progress;			/* + 8,4: 波形進行カウンタ (17.15bit固定小数) */
	char* wave/*[0x20]*/;		/* +12,4: 波形データの先頭アドレス */
} WSGCHANNEL;				/* =16 */

/*
 *	WSGコア
 */
/*typedef*/ struct _WSG {
	unsigned char reg[WSG_NUM_REGS];/* レジスタ値 */
	char wavetable[16][0x20];	/* 波形テーブル (サンプル値:-8〜+7) */
					/* 波形テーブルROM使用時(Xevious,Mappy type)は、前半8音色のみ使用します。 */
					/* 波形テーブルRAM使用時(System1 type)は、全16音色を使用します。 */
	//
	WSGCHANNEL channel[8];		/* チャネル */
	//
	DDA clock_progress;		/* クロック進行DDA */
} /*WSG*/;

/****************************************************************************
 *	内部関数
 ****************************************************************************/

//int wsg_process(WSG* wsg, int cycle);→高速化のため、wsg_mix()の中に含めました。
int wsg_channel_process(WSG* wsg, WSGCHANNEL* channel, int cycle);

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

/* WSGコアをリセットします。
 * [in]
 *	wsg		WSG構造体。
 *	clock		サンプリングクロック。
 *	wavetable	波形テーブルROMイメージへのポインタ。
 *			波形テーブルROMがない場合は、NULLを指定してください。
 * [note]
 *	* アプリケーションプログラムは、少なくとも最初に一度、この関数を呼び出してください。
 *	  その後は、WSGリセットを行う場合に、必要に応じて呼び出してください。
 *	* 波形テーブルROMイメージの形式は、次の通りです。
 *	  ・1サンプル1バイト、下位4bitのみ使用。サンプル値は0〜15。
 *	  ・1波形32サンプル。8波形分のテーブル。(WSG.wavetable[16][0x20]の前半8音色のみ使用します)
 *	  ・従って、波形テーブル全体のサイズは32×8=256バイトです。
 *	* wsg_reset()の中で波形テーブルのコピーを作成します。
 *	  wsg_reset()が処理を返したら、呼び出し側は波形テーブルを破棄して構いません。
 */
void wsg_reset(WSG* wsg, int clock, const void* wavetable/*[8][0x20]*/);

/* レジスタ値を書き込みます。
 * [in]
 *	wsg		WSG構造体。
 *	addr		レジスタアドレス。
 *	data		レジスタ値。
 */
void wsg_write_xevious(WSG* wsg, int addr, unsigned char data);	/* Xevious type */
void wsg_write_mappy(WSG* wsg, int addr, unsigned char data);	/* Mappy type */
void wsg_write_system1(WSG* wsg, int addr, unsigned char data);	/* System1 type */

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

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

#endif /*__CLIP_WSG_H__*/
