1 /***************************************************************************
2 
3 	Wiping sound driver (quick hack of the Namco sound driver)
4 
5 	used by wiping.c and clshroad.c
6 
7 ***************************************************************************/
8 
9 #include "driver.h"
10 
11 
12 /* 8 voices max */
13 #define MAX_VOICES 8
14 
15 
16 static const int samplerate = 48000;
17 static const int defgain = 48;
18 
19 
20 /* this structure defines the parameters for a channel */
21 typedef struct
22 {
23 	int frequency;
24 	int counter;
25 	int volume;
26 	const unsigned char *wave;
27 	int oneshot;
28 	int oneshotplaying;
29 } sound_channel;
30 
31 
32 /* globals available to everyone */
33 unsigned char *wiping_soundregs;
34 
35 /* data about the sound system */
36 static sound_channel channel_list[MAX_VOICES];
37 static sound_channel *last_channel;
38 
39 /* global sound parameters */
40 static const unsigned char *sound_prom,*sound_rom;
41 static int num_voices;
42 static int sound_enable;
43 static int stream;
44 
45 /* mixer tables and internal buffers */
46 static INT16 *mixer_table;
47 static INT16 *mixer_lookup;
48 static short *mixer_buffer;
49 static short *mixer_buffer_2;
50 
51 
52 
53 /* build a table to divide by the number of voices; gain is specified as gain*16 */
make_mixer_table(int voices,int gain)54 static int make_mixer_table(int voices, int gain)
55 {
56 	int count = voices * 128;
57 	int i;
58 
59 	/* allocate memory */
60 	mixer_table = auto_malloc(256 * voices * sizeof(INT16));
61 	if (!mixer_table)
62 		return 1;
63 
64 	/* find the middle of the table */
65 	mixer_lookup = mixer_table + (128 * voices);
66 
67 	/* fill in the table - 16 bit case */
68 	for (i = 0; i < count; i++)
69 	{
70 		int val = i * gain * 16 / voices;
71 		if (val > 32767) val = 32767;
72 		mixer_lookup[ i] = val;
73 		mixer_lookup[-i] = -val;
74 	}
75 
76 	return 0;
77 }
78 
79 
80 /* generate sound to the mix buffer in mono */
wiping_update_mono(int ch,INT16 * buffer,int length)81 static void wiping_update_mono(int ch, INT16 *buffer, int length)
82 {
83 	sound_channel *voice;
84 	short *mix;
85 	int i;
86 
87 	/* if no sound, we're done */
88 	if (sound_enable == 0)
89 	{
90 		memset(buffer, 0, length * 2);
91 		return;
92 	}
93 
94 	/* zap the contents of the mixer buffer */
95 	memset(mixer_buffer, 0, length * sizeof(short));
96 
97 	/* loop over each voice and add its contribution */
98 	for (voice = channel_list; voice < last_channel; voice++)
99 	{
100 		int f = 16*voice->frequency;
101 		int v = voice->volume;
102 
103 		/* only update if we have non-zero volume and frequency */
104 		if (v && f)
105 		{
106 			const unsigned char *w = voice->wave;
107 			int c = voice->counter;
108 
109 			mix = mixer_buffer;
110 
111 			/* add our contribution */
112 			for (i = 0; i < length; i++)
113 			{
114 				int offs;
115 
116 				c += f;
117 
118 				if (voice->oneshot)
119 				{
120 					if (voice->oneshotplaying)
121 					{
122 						offs = (c >> 15);
123 						if (w[offs>>1] == 0xff)
124 						{
125 							voice->oneshotplaying = 0;
126 						}
127 
128 						if (voice->oneshotplaying)
129 						{
130 							/* use full byte, first the high 4 bits, then the low 4 bits */
131 							if (offs & 1)
132 								*mix++ += ((w[offs>>1] & 0x0f) - 8) * v;
133 							else
134 								*mix++ += (((w[offs>>1]>>4) & 0x0f) - 8) * v;
135 						}
136 					}
137 				}
138 				else
139 				{
140 					offs = (c >> 15) & 0x1f;
141 
142 					/* use full byte, first the high 4 bits, then the low 4 bits */
143 					if (offs & 1)
144 						*mix++ += ((w[offs>>1] & 0x0f) - 8) * v;
145 					else
146 						*mix++ += (((w[offs>>1]>>4) & 0x0f) - 8) * v;
147 				}
148 			}
149 
150 			/* update the counter for this voice */
151 			voice->counter = c;
152 		}
153 	}
154 
155 	/* mix it down */
156 	mix = mixer_buffer;
157 	for (i = 0; i < length; i++)
158 		*buffer++ = mixer_lookup[*mix++];
159 }
160 
161 
162 
wiping_sh_start(const struct MachineSound * msound)163 int wiping_sh_start(const struct MachineSound *msound)
164 {
165 	const char *mono_name = "Wiping";
166 	sound_channel *voice;
167 
168 	/* get stream channels */
169 	stream = stream_init(mono_name,100/*intf->volume*/, samplerate, 0, wiping_update_mono);
170 
171 	/* allocate a pair of buffers to mix into - 1 second's worth should be more than enough */
172 	if ((mixer_buffer = auto_malloc(2 * sizeof(short) * samplerate)) == 0)
173 		return 1;
174 	mixer_buffer_2 = mixer_buffer + samplerate;
175 
176 	/* build the mixer table */
177 	if (make_mixer_table(8, defgain))
178 		return 1;
179 
180 	/* extract globals from the interface */
181 	num_voices = 8;
182 	last_channel = channel_list + num_voices;
183 
184 	sound_rom = memory_region(REGION_SOUND1);
185 	sound_prom = memory_region(REGION_SOUND2);
186 
187 	/* start with sound enabled, many games don't have a sound enable register */
188 	sound_enable = 1;
189 
190 	/* reset all the voices */
191 	for (voice = channel_list; voice < last_channel; voice++)
192 	{
193 		voice->frequency = 0;
194 		voice->volume = 0;
195 		voice->wave = &sound_prom[0];
196 		voice->counter = 0;
197 	}
198 
199 	return 0;
200 }
201 
202 
wiping_sh_stop(void)203 void wiping_sh_stop(void)
204 {
205 }
206 
207 
208 /********************************************************************************/
209 
WRITE_HANDLER(wiping_sound_w)210 WRITE_HANDLER( wiping_sound_w )
211 {
212 	sound_channel *voice;
213 	int base;
214 
215 	/* update the streams */
216 	stream_update(stream, 0);
217 
218 	/* set the register */
219 	wiping_soundregs[offset] = data;
220 
221 	/* recompute all the voice parameters */
222 	if (offset <= 0x3f)
223 	{
224 		for (base = 0, voice = channel_list; voice < last_channel; voice++, base += 8)
225 		{
226 			voice->frequency = wiping_soundregs[0x02 + base] & 0x0f;
227 			voice->frequency = voice->frequency * 16 + ((wiping_soundregs[0x01 + base]) & 0x0f);
228 			voice->frequency = voice->frequency * 16 + ((wiping_soundregs[0x00 + base]) & 0x0f);
229 
230 			voice->volume = wiping_soundregs[0x07 + base] & 0x0f;
231 			if (wiping_soundregs[0x5 + base] & 0x0f)
232 			{
233 				voice->wave = &sound_rom[128 * (16 * (wiping_soundregs[0x5 + base] & 0x0f)
234 						+ (wiping_soundregs[0x2005 + base] & 0x0f))];
235 				voice->oneshot = 1;
236 			}
237 			else
238 			{
239 				voice->wave = &sound_rom[16 * (wiping_soundregs[0x3 + base] & 0x0f)];
240 				voice->oneshot = 0;
241 				voice->oneshotplaying = 0;
242 			}
243 		}
244 	}
245 	else if (offset >= 0x2000)
246 	{
247 		voice = &channel_list[(offset & 0x3f)/8];
248 		if (voice->oneshot)
249 		{
250 			voice->counter = 0;
251 			voice->oneshotplaying = 1;
252 		}
253 	}
254 }
255