/*
	License: Zlib
	see https://gitlab.com/cam900/vgsound_emu/-/blob/main/LICENSE for more details

	Copyright holder(s): cam900
	Konami K053260 core
*/

#include "k053260.hpp"

void k053260_core::tick(u32 cycle)
{
	m_out[0] = m_out[1] = 0;
	if (m_ctrl.sound_en())
	{
		for (int i = 0; i < 4; i++)
		{
			m_voice[i].tick(cycle);
			m_out[0] += m_voice[i].out(0);
			m_out[1] += m_voice[i].out(1);
		}
	}
	/*
	// dac clock (YM3012 format)
	u8 dac_clock = m_dac.clock();
	if (bitfield(++dac_clock, 0, 4) == 0)
	{
		m_intf.write_int(m_dac.state());
		u8 dac_state = m_dac.state();
		if (bitfield(++dac_state, 0) == 0)
		{
			m_ym3012.tick(bitfield(dac_state, 1), m_out[bitfield(dac_state, 1) ^ 1]);
		}

		m_dac.set_state(bitfield(dac_state, 0, 2));
	}
	m_dac.set_clock(bitfield(dac_clock, 0, 4));
	*/
}

void k053260_core::voice_t::tick(u32 cycle)
{
	if (m_enable && m_busy)
	{
		// update counter
		m_counter += cycle;
		if (m_counter >= 0x1000)
		{
			if (m_bitpos < 8)
			{
				m_bitpos += 8;
				m_addr = m_reverse ? bitfield(m_addr - 1, 0, 21) : bitfield(m_addr + 1, 0, 21);
				m_remain--;
				if (m_remain < 0)  // check end flag
				{
					if (m_loop)
					{
						m_addr		= m_start;
						m_remain	= m_length;
						m_output = 0;
					}
					else
					{
						m_busy = false;
					}
				}
			}
			m_data = m_host.m_intf.read_sample(bitfield(m_addr, 0, 21));  // fetch ROM
			if (m_adpcm)
			{
				m_bitpos		-= 4;
				const u8 nibble = bitfield(m_data, m_reverse ? (~m_bitpos & 4) : (m_bitpos & 4), 4);  // get nibble from ROM
				if (nibble)
				{
					m_output += m_host.adpcm_lut(nibble);
				}
			}
			else
			{
				m_bitpos -= 8;
			}
			m_counter = (m_counter - 0x1000) + bitfield(m_pitch, 0, 12);
		}

		// calculate output
		s32 output = (m_adpcm ? m_output : sign_ext_nomax<s32>(m_data, 8)) * s32(m_volume);
		// use math for now; actually fomula unknown
		m_out[0] = (output * m_host.pan_lut(m_pan, 0)) >> 7;
		m_out[1] = (output * m_host.pan_lut(m_pan, 1)) >> 7;
	}
	else
	{
		m_out[0] = m_out[1] = 0;
	}
}

u8 k053260_core::read(u8 address)
{
	address &= 0x3f;  // 6 bit for CPU read

	switch (address)
	{
		case 0x0:
		case 0x1:  // Answer from host
			return m_host2snd[address & 1];
			break;
		case 0x29:	// Voice playing status
			return (m_voice[0].busy() ? 0x1 : 0x0) | (m_voice[1].busy() ? 0x2 : 0x0) |
				   (m_voice[2].busy() ? 0x4 : 0x0) | (m_voice[3].busy() ? 0x8 : 0x0);
		case 0x2e:	// ROM readback
			{
				if (!m_ctrl.rom_read())
				{
					return 0xff;
				}

				const u32 rom_addr = m_voice[0].start() + m_voice[0].length();
				m_voice[0].length_inc();
				return m_intf.read_sample(rom_addr);
			}
	}
	return 0xff;
}

void k053260_core::write(u8 address, u8 data)
{
	address &= 0x3f;  // 6 bit for CPU write

	switch (address)
	{
		case 0x2:
		case 0x3:  // Reply to host
			m_snd2host[address & 1] = data;
			break;
		case 0x08:
		case 0x09:
		case 0x0a:
		case 0x0b:
		case 0x0c:
		case 0x0d:
		case 0x0e:
		case 0x0f:	// voice 0
		case 0x10:
		case 0x11:
		case 0x12:
		case 0x13:
		case 0x14:
		case 0x15:
		case 0x16:
		case 0x17:	// voice 1
		case 0x18:
		case 0x19:
		case 0x1a:
		case 0x1b:
		case 0x1c:
		case 0x1d:
		case 0x1e:
		case 0x1f:	// voice 2
		case 0x20:
		case 0x21:
		case 0x22:
		case 0x23:
		case 0x24:
		case 0x25:
		case 0x26:
		case 0x27:	// voice 3
			m_voice[bitfield(address - 0x8, 3, 2)].write(bitfield(address, 0, 3), data);
			break;
		case 0x28:	// keyon/off toggle
			for (int i = 0; i < 4; i++)
			{
				m_voice[i].set_reverse(bitfield(data, 4 + i));
				if (bitfield(data, i) && (!m_voice[i].enable()))
				{  // rising edge (keyon)
					m_voice[i].keyon();
				}
				else if ((!bitfield(data, i)) && m_voice[i].enable())
				{  // falling edge (keyoff)
					m_voice[i].keyoff();
				}
			}
			break;
		case 0x2a:	// loop/adpcm flag
			for (int i = 0; i < 4; i++)
			{
				m_voice[i].set_loop(bitfield(data, i));
				m_voice[i].set_adpcm(bitfield(data, i + 4));
			}
			break;
		case 0x2c:
			m_voice[0].set_pan(bitfield(data, 0, 3));
			m_voice[1].set_pan(bitfield(data, 3, 3));
			break;
		case 0x2d:
			m_voice[2].set_pan(bitfield(data, 0, 3));
			m_voice[3].set_pan(bitfield(data, 3, 3));
			break;
		case 0x2f: m_ctrl.write(data); break;
		default: break;
	}

	m_reg[address] = data;
}

// write registers on each voices
void k053260_core::voice_t::write(u8 address, u8 data)
{
	switch (address)
	{
		case 0:	 // pitch LSB
			m_pitch = (m_pitch & ~0x00ff) | data;
			break;
		case 1:	 // pitch MSB
			m_pitch = (m_pitch & ~0x0f00) | (u16(bitfield(data, 0, 4)) << 8);
			break;
		case 2:	 // source length LSB
			m_length = (m_length & ~0x000ff) | data;
			break;
		case 3:	 // source length MSB
			m_length = (m_length & ~0x0ff00) | (u16(data) << 8);
			break;
		case 4:	 // start address bit 0-7
			m_start = (m_start & ~0x0000ff) | data;
			break;
		case 5:	 // start address bit 8-15
			m_start = (m_start & ~0x00ff00) | (u32(data) << 8);
			break;
		case 6:	 // start address bit 16-20
			m_start = (m_start & ~0x1f0000) | (u32(bitfield(data, 0, 5)) << 16);
			break;
		case 7:	 // volume
			m_volume = bitfield(data, 0, 7);
			break;
	}
}

// key on trigger
void k053260_core::voice_t::keyon()
{
	m_enable = m_busy = 1;
	m_counter		  = bitfield(m_pitch, 0, 12);
	m_addr			  = m_start;
	m_remain		  = m_length;
	m_bitpos		  = 4;
	m_data			  = 0;
	m_output		  = 0;
	std::fill_n(m_out, 2, 0);
}

// key off trigger
void k053260_core::voice_t::keyoff() { m_enable = m_busy = 0; }

// reset chip
void k053260_core::reset()
{
	for (auto &elem : m_voice)
	{
		elem.reset();
	}

	//m_intf.write_int(0);

	std::fill_n(m_host2snd, 2, 0);
	std::fill_n(m_snd2host, 2, 0);
	m_ctrl.reset();
	//m_dac.reset();

	std::fill_n(m_reg, 64, 0);
	std::fill_n(m_out, 2, 0);
}

// reset voice
void k053260_core::voice_t::reset()
{
	m_enable  = 0;
	m_busy	  = 0;
	m_loop	  = 0;
	m_adpcm	  = 0;
	m_pitch	  = 0;
	m_reverse = 0;
	m_start	  = 0;
	m_length  = 0;
	m_volume  = 0;
	m_pan	  = 4;
	m_counter = 0;
	m_addr	  = 0;
	m_remain  = 0;
	m_bitpos  = 4;
	m_data	  = 0;
	m_output  = 0;
	m_out[0] = m_out[1] = 0;
}
