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