1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria
3 #include "emu.h"
4 #include "audio/cclimber.h"
5 
6 #include "sound/ay8910.h"
7 
8 
9 // macro to convert 4-bit unsigned samples to 16-bit signed samples
10 #define SAMPLE_CONV4(a) (0x1111*((a&0x0f))-0x8000)
11 
12 #define SND_CLOCK 3072000   /* 3.072 MHz */
13 
SAMPLES_START_CB_MEMBER(cclimber_audio_device::sh_start)14 SAMPLES_START_CB_MEMBER( cclimber_audio_device::sh_start )
15 {
16 		m_sample_buf = std::make_unique<int16_t[]>(2 * m_samples_region.bytes());
17 		save_pointer(NAME(m_sample_buf), 2 * m_samples_region.bytes());
18 }
19 
20 //**************************************************************************
21 //  DEVICE DEFINITIONS
22 //**************************************************************************
23 
24 DEFINE_DEVICE_TYPE(CCLIMBER_AUDIO, cclimber_audio_device, "cclimber_audio", "Crazy Climber Sound Board")
25 
26 
27 //-------------------------------------------------
28 //  cclimber_audio_device: Constructor
29 //-------------------------------------------------
30 
cclimber_audio_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)31 cclimber_audio_device::cclimber_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
32 	: device_t(mconfig, CCLIMBER_AUDIO, tag, owner, clock),
33 	m_sample_buf(nullptr),
34 	m_sample_num(0),
35 	m_sample_freq(0),
36 	m_sample_volume(0),
37 	m_samples(*this, "samples"),
38 	m_samples_region(*this, "samples")
39 {
40 }
41 
42 //-------------------------------------------------
43 //  device_start - device-specific startup
44 //-------------------------------------------------
45 
device_start()46 void cclimber_audio_device::device_start()
47 {
48 	save_item(NAME(m_sample_num));
49 	save_item(NAME(m_sample_freq));
50 	save_item(NAME(m_sample_volume));
51 }
52 
53 //-------------------------------------------------
54 //  device_add_mconfig - add device configuration
55 //-------------------------------------------------
56 
device_add_mconfig(machine_config & config)57 void cclimber_audio_device::device_add_mconfig(machine_config &config)
58 {
59 	ay8910_device &aysnd(AY8910(config, "aysnd", SND_CLOCK/2));
60 	aysnd.port_a_write_callback().set(FUNC(cclimber_audio_device::sample_select_w));
61 	aysnd.add_route(ALL_OUTPUTS, ":speaker", 0.5);
62 
63 	SAMPLES(config, m_samples);
64 	m_samples->set_channels(1);
65 	m_samples->set_samples_start_callback(FUNC(cclimber_audio_device::sh_start));
66 	m_samples->add_route(ALL_OUTPUTS, ":speaker", 0.5);
67 }
68 
69 
sample_select_w(uint8_t data)70 void cclimber_audio_device::sample_select_w(uint8_t data)
71 {
72 	m_sample_num = data;
73 }
74 
sample_rate_w(uint8_t data)75 void cclimber_audio_device::sample_rate_w(uint8_t data)
76 {
77 	// calculate the sampling frequency
78 	m_sample_freq = SND_CLOCK / 4 / (256 - data);
79 }
80 
sample_volume_w(uint8_t data)81 void cclimber_audio_device::sample_volume_w(uint8_t data)
82 {
83 	m_sample_volume = data & 0x1f;    // range 0-31
84 }
85 
sample_trigger(int state)86 void cclimber_audio_device::sample_trigger(int state)
87 {
88 	if (state == 0)
89 		return;
90 
91 	play_sample(32 * m_sample_num, m_sample_freq, m_sample_volume);
92 }
93 
sample_trigger_w(uint8_t data)94 void cclimber_audio_device::sample_trigger_w(uint8_t data)
95 {
96 	sample_trigger(data != 0);
97 }
98 
99 
play_sample(int start,int freq,int volume)100 void cclimber_audio_device::play_sample(int start,int freq,int volume)
101 {
102 	int romlen = m_samples_region.bytes();
103 
104 	// decode the ROM samples
105 	int len = 0;
106 	while (start + len < romlen && m_samples_region[start+len] != 0x70)
107 	{
108 		int sample;
109 
110 		sample = (m_samples_region[start + len] & 0xf0) >> 4;
111 		m_sample_buf[2*len] = SAMPLE_CONV4(sample) * volume / 31;
112 
113 		sample = m_samples_region[start + len] & 0x0f;
114 		m_sample_buf[2*len + 1] = SAMPLE_CONV4(sample) * volume / 31;
115 
116 		len++;
117 	}
118 
119 	m_samples->start_raw(0, m_sample_buf.get(), 2 * len, freq);
120 }
121