1 // license:BSD-3-Clause
2 // copyright-holders:Allard van der Bas
3 /***************************************************************************
4 
5     Wiping sound driver (quick hack of the Namco sound driver)
6 
7     used by wiping.cpp and clshroad.cpp
8 
9 ***************************************************************************/
10 
11 #include "emu.h"
12 #include "audio/wiping.h"
13 
14 DEFINE_DEVICE_TYPE(WIPING_CUSTOM, wiping_sound_device, "wiping_sound", "Wiping Custom Sound")
15 
wiping_sound_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)16 wiping_sound_device::wiping_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
17 	: device_t(mconfig, WIPING_CUSTOM, tag, owner, clock),
18 	device_sound_interface(mconfig, *this),
19 	m_last_channel(nullptr),
20 	m_sound_prom(nullptr),
21 	m_sound_rom(nullptr),
22 	m_num_voices(0),
23 	m_sound_enable(0),
24 	m_stream(nullptr)
25 {
26 	memset(m_channel_list, 0, sizeof(wp_sound_channel)*MAX_VOICES);
27 	memset(m_soundregs, 0, sizeof(uint8_t)*0x4000);
28 }
29 
30 
31 //-------------------------------------------------
32 //  device_start - device-specific startup
33 //-------------------------------------------------
34 
device_start()35 void wiping_sound_device::device_start()
36 {
37 	wp_sound_channel *voice;
38 
39 	/* get stream channels */
40 	m_stream = stream_alloc(0, 1, clock()/2);
41 
42 	/* allocate a buffer to mix into - 1 second's worth should be more than enough */
43 	m_mixer_buffer.resize(clock()/2);
44 
45 	/* extract globals from the interface */
46 	m_num_voices = 8;
47 	m_last_channel = m_channel_list + m_num_voices;
48 
49 	m_sound_rom = machine().root_device().memregion("samples")->base();
50 	m_sound_prom = machine().root_device().memregion("soundproms")->base();
51 
52 	/* start with sound enabled, many games don't have a sound enable register */
53 	m_sound_enable = 1;
54 
55 	/* reset all the voices */
56 	for (voice = m_channel_list; voice < m_last_channel; voice++)
57 	{
58 		voice->frequency = 0;
59 		voice->volume = 0;
60 		voice->wave = &m_sound_prom[0];
61 		voice->counter = 0;
62 	}
63 
64 	save_item(NAME(m_soundregs));
65 
66 	for (int i = 0; i < MAX_VOICES; i++)
67 	{
68 		save_item(NAME(m_channel_list[i].frequency), i);
69 		save_item(NAME(m_channel_list[i].counter), i);
70 		save_item(NAME(m_channel_list[i].volume), i);
71 		save_item(NAME(m_channel_list[i].oneshot), i);
72 		save_item(NAME(m_channel_list[i].oneshotplaying), i);
73 	}
74 }
75 
76 /********************************************************************************/
77 
sound_w(offs_t offset,uint8_t data)78 void wiping_sound_device::sound_w(offs_t offset, uint8_t data)
79 {
80 	wp_sound_channel *voice;
81 	int base;
82 
83 	/* update the streams */
84 	m_stream->update();
85 
86 	/* set the register */
87 	m_soundregs[offset] = data;
88 
89 	/* recompute all the voice parameters */
90 	if (offset <= 0x3f)
91 	{
92 		for (base = 0, voice = m_channel_list; voice < m_last_channel; voice++, base += 8)
93 		{
94 			voice->frequency = m_soundregs[0x02 + base] & 0x0f;
95 			voice->frequency = voice->frequency * 16 + ((m_soundregs[0x01 + base]) & 0x0f);
96 			voice->frequency = voice->frequency * 16 + ((m_soundregs[0x00 + base]) & 0x0f);
97 
98 			voice->volume = m_soundregs[0x07 + base] & 0x0f;
99 			if (m_soundregs[0x5 + base] & 0x0f)
100 			{
101 				voice->wave = &m_sound_rom[128 * (16 * (m_soundregs[0x5 + base] & 0x0f)
102 						+ (m_soundregs[0x2005 + base] & 0x0f))];
103 				voice->oneshot = 1;
104 			}
105 			else
106 			{
107 				voice->wave = &m_sound_rom[16 * (m_soundregs[0x3 + base] & 0x0f)];
108 				voice->oneshot = 0;
109 				voice->oneshotplaying = 0;
110 			}
111 		}
112 	}
113 	else if (offset >= 0x2000)
114 	{
115 		voice = &m_channel_list[(offset & 0x3f)/8];
116 		if (voice->oneshot)
117 		{
118 			voice->counter = 0;
119 			voice->oneshotplaying = 1;
120 		}
121 	}
122 }
123 
124 //-------------------------------------------------
125 //  sound_stream_update - handle a stream update
126 //-------------------------------------------------
127 
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)128 void wiping_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
129 {
130 	auto &buffer = outputs[0];
131 	wp_sound_channel *voice;
132 	short *mix;
133 	int i;
134 
135 	/* if no sound, we're done */
136 	if (m_sound_enable == 0)
137 	{
138 		buffer.fill(0);
139 		return;
140 	}
141 
142 	/* zap the contents of the mixer buffer */
143 	std::fill_n(&m_mixer_buffer[0], buffer.samples(), 0);
144 
145 	/* loop over each voice and add its contribution */
146 	for (voice = m_channel_list; voice < m_last_channel; voice++)
147 	{
148 		int f = 16*voice->frequency;
149 		int v = voice->volume;
150 
151 		/* only update if we have non-zero volume and frequency */
152 		if (v && f)
153 		{
154 			const uint8_t *w = voice->wave;
155 			int c = voice->counter;
156 
157 			mix = &m_mixer_buffer[0];
158 
159 			/* add our contribution */
160 			for (i = 0; i < buffer.samples(); i++)
161 			{
162 				int offs;
163 
164 				c += f;
165 
166 				if (voice->oneshot)
167 				{
168 					if (voice->oneshotplaying)
169 					{
170 						offs = (c >> 15);
171 						if (w[offs>>1] == 0xff)
172 						{
173 							voice->oneshotplaying = 0;
174 						}
175 
176 						else
177 						{
178 							/* use full byte, first the high 4 bits, then the low 4 bits */
179 							if (offs & 1)
180 								*mix++ += ((w[offs>>1] & 0x0f) - 8) * v;
181 							else
182 								*mix++ += (((w[offs>>1]>>4) & 0x0f) - 8) * v;
183 						}
184 					}
185 				}
186 				else
187 				{
188 					offs = (c >> 15) & 0x1f;
189 
190 					/* use full byte, first the high 4 bits, then the low 4 bits */
191 					if (offs & 1)
192 						*mix++ += ((w[offs>>1] & 0x0f) - 8) * v;
193 					else
194 						*mix++ += (((w[offs>>1]>>4) & 0x0f) - 8) * v;
195 				}
196 			}
197 
198 			/* update the counter for this voice */
199 			voice->counter = c;
200 		}
201 	}
202 
203 	/* mix it down */
204 	mix = &m_mixer_buffer[0];
205 	for (i = 0; i < buffer.samples(); i++)
206 		buffer.put_int(i, *mix++, 128 * MAX_VOICES);
207 }
208