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