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