1 /*
2  * Berzerk/Frenzy Soundhardware Driver
3  * Copyright Alex Judd 1997/98
4  * V1.1 for Mame 0.31 13March98
5  *
6  * these were the original values but I have adjusted them to take account of the
7  * default sample rate of 22050. I guess the original samples were at 24000.
8  * case 0 : samplefrequency = 19500;
9  * case 1 : samplefrequency = 20800;
10  * case 2 : samplefrequency = 22320;
11  * case 3 : samplefrequency = 24000;
12  * case 4 : samplefrequency = 26000;
13  * case 5 : samplefrequency = 28400;
14  * case 6 : samplefrequency = 31250;
15  * case 7 : samplefrequency = 34700;
16  *
17  */
18 
19 #include "driver.h"
20 #include "includes/berzerk.h"
21 
22 
23 static const char *sample_names[] =
24 {
25 	"*berzerk", /* universal samples directory */
26 	"",
27 	"01.wav", /* "kill"*/
28 	"02.wav", /* "attack"*/
29 	"03.wav", /* "charge"*/
30 	"04.wav", /* "got"*/
31 	"05.wav", /* "to"*/
32 	"06.wav", /* "get"*/
33 	"",
34 	"08.wav", /* "alert"*/
35 	"09.wav", /* "detected"*/
36 	"10.wav", /* "the"*/
37 	"11.wav", /* "in"*/
38 	"12.wav", /* "it"*/
39 	"",
40 	"",
41 	"15.wav", /* "humanoid"*/
42 	"16.wav", /* "coins"*/
43 	"17.wav", /* "pocket"*/
44 	"18.wav", /* "intruder"*/
45 	"",
46 	"20.wav", /* "escape"*/
47 	"21.wav", /* "destroy"*/
48 	"22.wav", /* "must"*/
49 	"23.wav", /* "not"*/
50 	"24.wav", /* "chicken"*/
51 	"25.wav", /* "fight"*/
52 	"26.wav", /* "like"*/
53 	"27.wav", /* "a"*/
54 	"28.wav", /* "robot"*/
55 	"",
56 	"30.wav", /* player fire*/
57 	"31.wav", /* baddie fire*/
58 	"32.wav", /* kill baddie*/
59 	"33.wav", /* kill human (real)*/
60 	"34.wav", /* kill human (cheat)*/
61 	0	/* end of array */
62 };
63 
64 
65 #define VOICE_PITCH_MODULATION	/* remove this to disable voice pitch modulation */
66 
67 /* Note: We have the ability to replace the real death sound (33) and the
68  * real voices with sample (34) as no good death sample could be obtained.
69  */
70 /*#define FAKE_DEATH_SOUND*/
71 
72 
73 /* volume and channel controls */
74 #define VOICE_VOLUME 100
75 #define SOUND_VOLUME 80
76 #define SOUND_CHANNEL 1    /* channel for sound effects */
77 #define VOICE_CHANNEL 5    /* special channel for voice sounds only */
78 #define DEATH_CHANNEL 6    /* special channel for fake death sound only */
79 
80 /* berzerk sound */
81 static int lastfreq = 0;
82 static int lastnoise = 0;
83 static int lastvoice = 0;
84 
85 /* sound controls */
86 static int berzerknoisemulate = 0;
87 static int voicevolume = 100;
88 static long samplefrequency = 22320;
89 static int voice_playing;
90 static int deathsound = 0;          /* trigger for playing collision sound */
91 static int nextdata5 = -1;
92 
berzerk_sh_start(const struct MachineSound * msound)93 static int berzerk_sh_start(const struct MachineSound *msound)
94 {
95 	int i;
96 
97 
98 	berzerknoisemulate = 1;
99 
100 	if (Machine->samples)
101 	{
102 		for (i = 0;i < 5;i++)
103 		{
104 			if (Machine->samples->sample[i])
105 				berzerknoisemulate = 0;
106 		}
107 	}
108 	return 0;
109 }
110 
WRITE_HANDLER(berzerk_sound_control_a_w)111 WRITE_HANDLER( berzerk_sound_control_a_w )
112 {
113 	int noise = 0;
114 	int voice = 0;
115 	int voicefrequency = 0;
116 
117 /* Throw out all the non-need sound info. (for the moment) */
118 
119 	if (offset < 3) return;
120 
121 /* Decode message for voice samples */
122 
123 	if (offset==4)
124 	{
125 		if ((data & 0x40) == 0)
126 		{
127 			voice = data;
128 			voice_playing = 0;
129 		}
130 		else
131 		{
132 			/* We should use the volume and frequency on the voice samples */
133 			voicevolume = ((data & 0x38) >> 3);
134 			if (voicevolume > 0) voicevolume=255;
135 
136 			voicefrequency = (data & 0x07);
137 #ifdef VOICE_PITCH_MODULATION
138 			switch(voicefrequency)
139 			{
140 			case 0 : samplefrequency = 17640; break;
141 			case 1 : samplefrequency = 19404; break;
142 			case 2 : samplefrequency = 20947; break;
143 			case 3 : samplefrequency = 22050; break;
144 			case 4 : samplefrequency = 26019; break;
145 			case 5 : samplefrequency = 27783; break;
146 			case 6 : samplefrequency = 31250; break;
147 			case 7 : samplefrequency = 34700; break;
148 			default: samplefrequency = 22050; break;
149 			}
150 #endif
151 			return;
152 		}
153 	}
154 
155 /* Check for player fire sample reset */
156 
157 	if ((offset==3) || (offset==5))
158 	{
159 		if (lastnoise==70)
160 		{
161 			if ((offset==3) && (data==172))
162 			{
163 				nextdata5 = 25;
164 				return;
165 			}
166 
167 			if (offset==5)
168 			{
169 				if (data==nextdata5)
170 				{
171 #ifdef FAKE_DEATH_SOUND
172 					deathsound = 1; /* trigger death sound */
173 #else
174 					deathsound = 2; /* trigger death sound */
175 #endif
176 					lastnoise = 64; /* reset death sound */
177 				}
178 
179 				nextdata5 = -1;
180 			}
181 
182 			return;
183 		}
184 
185 		if (lastnoise==69)
186 		{
187 			if ((offset==3) && (data==50))
188 			{
189 				nextdata5 = 50;
190 				return;
191 			}
192 
193 			if (offset==5)
194 			{
195 				if (data==nextdata5)
196 				{
197 					lastnoise = 64; /* reset laser sound */
198 				}
199 
200 				nextdata5 = -1;
201 			}
202 		}
203 
204 		return;
205 	}
206 
207 /* Check to see what game sound should be playing */
208 
209 	if ((data > 60) && (data < 72) && (offset==6))
210 		noise = data;
211 	else
212 		noise = lastnoise;
213 
214 /* One day I'll do this... */
215 
216 	if (berzerknoisemulate)
217 	{
218 		return;
219 		if (voicefrequency != 1750*(4-noise))
220 		{
221 			voicefrequency = 1750*(4-noise);
222 			voicevolume = 85*noise;
223 		}
224 
225 		if (noise)
226 		{
227 			sample_set_freq(2,voicefrequency);
228 			sample_set_volume(2,voicevolume);
229 		}
230 		else
231 		{
232 			sample_set_volume(2,0);
233 			voicevolume = 0;
234 		}
235 	}
236 	else
237 	{
238 		if ((offset==6) && (lastnoise != noise))  /* Game sound effects */
239 		{
240 			switch (noise)
241 			{
242 			case 69 : /* shot sample */
243 				sample_start(1,30,0);
244 				break;
245 			case 70 : /* baddie laser */
246         log_cb(RETRO_LOG_DEBUG, LOGPRE "Trying death sound");
247 				switch(deathsound)
248 				{
249 				case 1 :
250 					sample_start(2,33,0);
251 					deathsound=0;
252 					break;
253 				case 2 :
254 					sample_start(DEATH_CHANNEL,34,0);
255 					deathsound=3;
256 					break;
257 				case 0 :
258 					sample_start(2,31,0);
259 					break;
260 				}
261 				break;
262 			case 71 : /* kill baddie */
263 				sample_start(3,32,0);
264 				break;
265 			default :
266 				break;
267 			}
268 		}
269 		lastnoise = noise;           /* make sure we only play the sound once */
270 
271 		if (offset==4)               /* Game voice sounds */
272 		{
273 			if (deathsound<2)	       /* no voices for real death sound */
274 			{
275 				if (lastvoice==24 && voice==27)
276 				{
277 					lastvoice=voice;    /* catch for the 'chicken ayye' problem */
278 					return;
279 				}
280 				sample_start(VOICE_CHANNEL,voice,0);
281 #ifdef VOICE_PITCH_MODULATION
282 				sample_set_freq(VOICE_CHANNEL,samplefrequency);
283 #endif
284 				lastvoice=voice;
285 			}
286 		}
287 	} /* End of berzerknoisemulate */
288 }
289 
WRITE_HANDLER(berzerk_sound_control_b_w)290 WRITE_HANDLER( berzerk_sound_control_b_w )
291 {
292 	log_cb(RETRO_LOG_DEBUG, LOGPRE "B Data value %d and offset %d at %d\n", data, offset, lastfreq);
293 }
294 
berzerk_sh_update(void)295 static void berzerk_sh_update(void)
296 {
297 	voice_playing = !sample_playing(VOICE_CHANNEL);
298 	if (deathsound==3 && sample_playing(DEATH_CHANNEL) == 0 && lastnoise != 70)
299 		deathsound=0;               /* reset death sound */
300 }
301 
302 
READ_HANDLER(berzerk_voiceboard_r)303 READ_HANDLER( berzerk_voiceboard_r )
304 {
305    if (!voice_playing)
306       return 0x00;
307    else
308       return 0x40;
309 }
310 
311 
312 struct Samplesinterface berzerk_samples_interface =
313 {
314 	8,	/* 8 channels */
315 	25,	/* volume */
316 	sample_names
317 };
318 
319 struct CustomSound_interface berzerk_custom_interface =
320 {
321 	berzerk_sh_start,
322 	0,
323 	berzerk_sh_update
324 };
325