// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria, hap
/***************************************************************************

Crazy Climber sound hardware

It has an AY-3-8910.
And 8KB ROM for voice samples, done with TTL chips.

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

#include "emu.h"
#include "cclimber_a.h"

#include "sound/ay8910.h"


//**************************************************************************
//  DEVICE DEFINITIONS
//**************************************************************************

DEFINE_DEVICE_TYPE(CCLIMBER_AUDIO, cclimber_audio_device, "cclimber_audio", "Crazy Climber Sound Board")


//-------------------------------------------------
//  cclimber_audio_device: Constructor
//-------------------------------------------------

cclimber_audio_device::cclimber_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
	device_t(mconfig, CCLIMBER_AUDIO, tag, owner, clock),
	m_dac(*this, "dac"),
	m_volume(*this, "volume"),
	m_rom(*this, "samples"),
	m_sample_clockdiv(2)
{ }


//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void cclimber_audio_device::device_start()
{
	assert(m_rom.bytes() == 0x2000);

	m_address = 0;
	m_start_address = 0;
	m_loop_address = 0;
	m_sample_rate = 0;
	m_sample_trigger = 0;

	m_sample_timer = timer_alloc(FUNC(cclimber_audio_device::sample_tick), this);
	m_sample_timer->adjust(attotime::zero);

	// register for savestates
	save_item(NAME(m_address));
	save_item(NAME(m_start_address));
	save_item(NAME(m_loop_address));
	save_item(NAME(m_sample_rate));
	save_item(NAME(m_sample_trigger));
}


//-------------------------------------------------
//  device_add_mconfig - add device configuration
//-------------------------------------------------

void cclimber_audio_device::device_add_mconfig(machine_config &config)
{
	ay8910_device &aysnd(AY8910(config, "aysnd", DERIVED_CLOCK(1, 1)));
	aysnd.port_a_write_callback().set(FUNC(cclimber_audio_device::start_address_w));
	aysnd.port_b_write_callback().set(FUNC(cclimber_audio_device::loop_address_w));
	aysnd.add_route(ALL_OUTPUTS, ":speaker", 0.5);

	DAC_4BIT_R2R(config, m_dac).add_route(ALL_OUTPUTS, "volume", 0.5);

	FILTER_VOLUME(config, m_volume).add_route(ALL_OUTPUTS, ":speaker", 1.0);
}


//-------------------------------------------------
//  handlers
//-------------------------------------------------

void cclimber_audio_device::sample_rate_w(u8 data)
{
	m_sample_rate = data;
}

void cclimber_audio_device::sample_volume_w(u8 data)
{
	m_volume->set_gain(double(data & 0x1f) / 31.0); // range 0-31
}

void cclimber_audio_device::sample_trigger(int state)
{
	// start playing on rising edge
	if (state && !m_sample_trigger)
		m_address = m_start_address * 64;

	m_sample_trigger = state;
}

void cclimber_audio_device::sample_trigger_w(u8 data)
{
	sample_trigger(data != 0);
}

TIMER_CALLBACK_MEMBER(cclimber_audio_device::sample_tick)
{
	u8 data = m_rom[m_address >> 1 & 0x1fff];

	m_dac->write((m_address & 1) ? (data & 0xf) : (data >> 4));

	if (m_sample_trigger)
		m_address++;

	// sample end marker, continue from loop point
	if (data == 0x70)
		m_address = m_loop_address * 64;

	m_sample_timer->adjust(attotime::from_ticks(256 - m_sample_rate, clock() / m_sample_clockdiv));
}
