/*	
 *	clipsv.c
 *
 *	P/ECE SUPERVISION Video/Sound Emulator
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2005 Naoyuki Sawa
 *
 *	* Thu Apr 14 05:55:00 JST 2005 Naoyuki Sawa
 *	- 作成開始。
 */
#include "clip.h"

/****************************************************************************
 *	Video
 ****************************************************************************/

SVVIDEO svvideo;

void
svvideo_reset(unsigned char ram[/*0x0000..0x0x5fdf*/])
{
	SVVIDEO* video = &svvideo;

	/* まずクリアします。 */
	memset(video, 0, sizeof(SVVIDEO));

	/* RAM/レジスタへのポインタを格納します。 */
	video->ram = ram;
}

void
svvideo_write(int addr, int data)
{
	SVVIDEO* video = &svvideo;
	unsigned char* ram = video->ram;

	ram[addr] = data;

	/* 現在のところ、レジスタ書き込みによって起動する動作はありません。 */
	//switch(addr) {
	//case 0x2000:	/* x size (※未対応) */
	//case 0x2001:	/* y size (※未対応) */
	//case 0x2002:	/* horicontal offset in pixel */
	//case 0x2003:	/* vertical   offset in pixel */
	//}
}

/****************************************************************************
 *	Sound
 ****************************************************************************/

SVSOUND svsound;

void
svsound_reset(unsigned char ram[/*0x0000..0x5fff*/],
        const unsigned char rom[/*0x0000..0x7fff or 0xffff*/])
{
	SVSOUND* sound = &svsound;

	/* まずクリアします。 */
	memset(sound, 0, sizeof(SVSOUND));

	/* RAM/レジスタと、ROMイメージへのポインタを格納します。 */
	sound->ram = ram;
	sound->rom = rom;

	/* LFSRを初期化します。 */
	sound->noise.lfsr = 1;
}
void
svsound_write(int addr, int data)
{
	SVSOUND* sound = &svsound;
	unsigned char* ram = sound->ram;
	//
	SVSOUNDTONE* tone;
	SVSOUNDNOISE* noise;

	ram[addr] = data;

	switch(addr) {
	/*========== Tone ==========*/
	case 0x2010:
	case 0x2014:
		tone = &sound->tone[(addr >> 2) & 1];
		tone->period = data | (ram[addr + 1] & 7) << 8;
		if(tone->period >= 7) {
			tone->period *= 32;
		} else {
			tone->period = 0; /* Off */
		}
		return;
	case 0x2011:
	case 0x2015:
		tone = &sound->tone[(addr >> 2) & 1];
		tone->period = ram[addr - 1] | (data & 7) << 8;
		if(tone->period >= 7) {
			tone->period *= 32;
		} else {
			tone->period = 0; /* Off */
		}
		return;
	case 0x2012:
	case 0x2016:
		tone = &sound->tone[(addr >> 2) & 1];
		tone->volume = data & 15;
		return;
	//case 0x2013: (※不明)
	//case 0x2017: (※不明)
	// 仕様では、発声時間を4/255秒単位で指定するレジスタ、となっているのですが、
	// 発声時間を管理すると、Crystball等のゲームで音が鳴らなくなってしまいます。
	// 既存のエミュレータでも、発声時間は管理していないようです。
	/*========== Noise ==========*/
	case 0x2028:
		noise = &sound->noise;
		noise->volume = data & 15;
		noise->period = data >> 4;
		return;
	//case 0x2029: (※不明)
	// 仕様では、発声時間を4/255秒単位で指定するレジスタ、となっているのですが、
	// 発声時間を管理すると、Crystball等のゲームで音が鳴らなくなってしまいます。
	// 既存のエミュレータでも、発声時間は管理していないようです。
	case 0x202a:
		noise = &sound->noise;
		noise->on = (data >> 4) & 1;
		return;
	///*========== DMA ==========*/
	//case 0x2018: (※未対応)
	//case 0x2019: (※未対応)
	//case 0x201a: (※未対応)
	//case 0x201b: (※未対応)
	//case 0x201c: (※未対応)
	}
}

void
svsound_mix(short wbuff[/*SVSOUNDBUFLEN*/])
{
	SVSOUND* sound = &svsound;

	memset(wbuff, 0, sizeof(short) * SVSOUNDBUFLEN);

	svsound_tone_mix(&sound->tone[0], wbuff);
	svsound_tone_mix(&sound->tone[1], wbuff);
	svsound_noise_mix(&sound->noise, wbuff);

	svsound_volume_shift(wbuff);
}

