/*	
 *	framwsg3.c
 *
 *	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
 *	- 作成開始。
 */
#include "clip.h"

/* ※System1 typeのノイズミキシング未対応です。
 *   wsg_write_system1()でノイズパラメータの設定は行っていますので、
 *   あとはwsg_channel_process()だけの変更で対応完了できるはずです。
 */

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

void
wsg_mix(WSG* wsg, short wbuff[/*count*/], int count)
{
	DDA clock_progress;
	int cycle;
	int sample;
	WSGCHANNEL* channel = wsg->channel;

	clock_progress = wsg->clock_progress; /* 高速化のため、一時取り出し */
	while(count > 0) {
		/* 経過サイクル数を求めます。 */
		cycle = clock_progress.u;
		clock_progress.d += clock_progress.n;
		if(clock_progress.d >= 0) {
			clock_progress.d -= SPEAKER_FREQUENCY;
			cycle++;
		}

		/* 1サンプルミキシングします。 */
		sample = wsg_channel_process(wsg, &channel[0], cycle)
		       + wsg_channel_process(wsg, &channel[1], cycle)
		       + wsg_channel_process(wsg, &channel[2], cycle)
		       + wsg_channel_process(wsg, &channel[3], cycle)
		       + wsg_channel_process(wsg, &channel[4], cycle)
		       + wsg_channel_process(wsg, &channel[5], cycle)
		       + wsg_channel_process(wsg, &channel[6], cycle)
		       + wsg_channel_process(wsg, &channel[7], cycle);

		/* 最終出力が符号付き16bit(+調整分)となるよう、あらかじめボリュームをスケーリングしてあるので、
		 * ここで出力サンプルをスケーリングする必要はありません。
		 */

		/* クリッピングして格納します。 */
		if(sample < -0x7fff) sample = -0x7fff;
		if(sample >  0x7fff) sample =  0x7fff;
		*wbuff++ = sample;

		/* 残りサンプル数を減らします。 */
		count--;
	}
	wsg->clock_progress = clock_progress; /* 書き戻し。忘れずないで!! */
}

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

//int
//wsg_process(WSG* wsg, int cycle)
//{
//	return wsg_channel_process(wsg, &wsg->channel[0], cycle)	/*   符号付き 8bit */
//	     + wsg_channel_process(wsg, &wsg->channel[1], cycle)	/* + 符号付き 8bit */
//	     + wsg_channel_process(wsg, &wsg->channel[2], cycle)	/* + 符号付き 8bit */
//	     + wsg_channel_process(wsg, &wsg->channel[3], cycle)	/* + 符号付き 8bit */
//	     + wsg_channel_process(wsg, &wsg->channel[4], cycle)	/* + 符号付き 8bit */
//	     + wsg_channel_process(wsg, &wsg->channel[5], cycle)	/* + 符号付き 8bit */
//	     + wsg_channel_process(wsg, &wsg->channel[6], cycle)	/* + 符号付き 8bit */
//	     + wsg_channel_process(wsg, &wsg->channel[7], cycle);	/* + 符号付き 8bit */
//}									/* = 符号付き11bit */
//→高速化のため、wsg_mix()の中に含めました。

#ifndef PIECE

int
wsg_channel_process(WSG* wsg, WSGCHANNEL* channel, int cycle)
{
	if(!channel->volume   ) return 0;
	if(!channel->frequency) return 0;

	channel->progress += channel->frequency * cycle;

	return channel->wave[(channel->progress >> 15) & 0x1f] * channel->volume;
}

#else /*PIECE*/

asm("
	.code
	.align 1
	.global wsg_channel_process
wsg_channel_process:
	ld.w %alr, %r8			; %alr = 0
	xld.uh %r4, [%r13+0]		; %r4 = volume
	xld.w  %r5, [%r13+4]		; %r5 = frequency *anti-interlock*
	xcmp %r4, 0			; if(!volume) return 0
	xjreq wsg_channel_process_exit
	xcmp %r5, 0			; if(!frequency) return 0
	xjreq wsg_channel_process_exit
	;
	xld.w %r6, [%r13+8]		; %r6 = progress
	xld.w %r7, [%r13+12]		; %r7 = wave
	;
	mlt.w %r5, %r14			; progress += frequency * cycle
	ld.w %r5, %alr
	add %r6, %r5
	xld.w [%r13+8], %r6		; progress書き戻し
	;
	xsrl %r6, 15			; %r10 = sample
	xand %r6, %r6, 0x1f
	add %r7, %r6
	xld.b %r10, [%r7]
	mlt.h %r10, %r4			; %alr = sample * volume
	;
wsg_channel_process_exit:
	ret.d
	ld.w %r10, %alr			; *delay* (Undoc'd)
");

#endif /*PIECE*/
