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