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