1 /*
2 	swsound  -	SW sound generation
3 
4 	Copyright (C) 1984-2003 David L. Clark.
5 	This program is free software; you can redistribute it and/or modify it under
6 	the terms of the GNU General Public License as published by the Free Software
7 	Foundation; either version 2 of the License, or (at your option) any later
8 	version. This program is distributed in the hope that it will be useful,
9 	but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 	or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 	more details. You should have received a copy of the GNU General Public
12 	License along with this program; if not, write to the Free Software Foundation,
13 	Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
14 
15 			Author: Dave Clark
16 
17 	Modification History:
18 			84-04-11	Development
19 			87-03-10	Microsoft compiler.
20 			2003-01-27	GNU General Public License
21 */
22 #include	"sw.h"
23 
24 
25 
26 #define 	TIMER	0x40
27 #define 	PORTB	0x61
28 #define 	SNDSIZE 100
29 
30 
31 extern	int	soundflg;		/*  Sound flag			    */
32 extern	int	dispdbg;		/*  Debug value to be displayed   */
33 
34 
35 static	int	 soundtype = 32767;	 /*  Current sound type and	     */
36 static	int	 soundparm = 32767;	 /*	and priority parameter	     */
37 static	OBJECTS  *soundobj =  NULL;	 /*  Object making sound	     */
38 static	unsigned lastfreq  = 0; 	 /*  Last frequency used	     */
39 static	OBJECTS  *lastobj   = NULL;	 /*  Previous object making sound    */
40 static	int	 ( *toneadj ) () = NULL; /*  Tone adjustment on clock tick   */
41 
42 static	TONETAB  tonetab[SNDSIZE];	 /*  Continuous tone table	     */
43 static	TONETAB  *frsttone, *freetone;	 /*  Tone list and free list	     */
44 static	unsigned soundticks;		 /*  Ticks since last sound selection*/
45 
46 static	int	 numexpls;		 /*  Number of explosions currently  */
47 					 /*  active			     */
48 static	int	 explplace;		 /*  Place in explosion tune;	     */
49 static	int	 explline;		 /* Line in explosion tune	     */
50 static	unsigned expltone;		 /*  Current explosion tone	     */
51 static	int	 explticks;		 /*  Ticks until note change	     */
52 static	int	 exploctv;		 /*  Octave			     */
53 static	char	 *expltune[7] = {
54        "b4/d8/d2/r16/c8/b8/a8/b4./c4./c+4./d4./",
55        "e4/g8/g2/r16/>a8/<g8/e8/d2./",
56        "b4/d8/d2/r16/c8/b8/a8/b4./c4./c+4./d4./",
57        "e4/>a8/a2/r16/<g8/f+8/e8/d2./",
58        "d8/g2/r16/g8/g+2/r16/g+8/>a2/r16/a8/c2/r16/",
59        "b8/a8/<g8/>b4/<g8/>b4/<g8/>a4./<g1/",
60        ""
61 };
62 
63 static	BOOL	 titleflg;		 /* Playing title tune		     */
64 static	int	 titlplace;		 /*  Place in title tune;	     */
65 static	int	 titlline;		 /* Line in title tune		     */
66 static	unsigned titltone;		 /*  Current title tone 	     */
67 static	int	 titlticks;		 /*  Ticks until note change	     */
68 static	int	 titloctv;		 /*  Octave			     */
69 
70 
71 
72 static	char	 **tune;		  /* Tune player statics	      */
73 static	int	 line;
74 static	int	 place;
75 static	unsigned tunefreq;
76 static	int	 tunedura;
77 static	int	 octavefactor;
78 
79 
80 
81 
82 initsndt()
83 {
84 register TONETAB *tt;
85 register int	 i;
86 
87 	for ( i = 0, tt = tonetab; i < ( SNDSIZE - 1 ); ++i, ++tt )
88 		tt->tt_next = tt + 1;
89 	tt->tt_next = NULL;
90 	frsttone = NULL;
91 	freetone = tonetab;
92 }
93 
94 
95 
96 sound( type, parm, ob )
97 int	type, parm;
98 OBJECTS *ob;
99 {
100 
101 	if ( type < soundtype ) {
102 		soundtype = type;
103 		soundparm = parm;
104 		soundobj = ob;
105 	} else
106 		if ( ( type == soundtype ) && ( parm < soundparm ) ) {
107 			soundparm = parm;
108 			soundobj = ob;
109 		}
110 }
111 
112 
113 
114 
115 swsound()
116 {
117 unsigned	  rand();
118 int		  adjcont(),  adjshot();
119 register TONETAB  *tt;
120 
121 	intsoff();
122 	tt = frsttone;
123 	while ( tt ) {
124 		tt->tt_tone += ( tt->tt_chng * soundticks );
125 		tt = tt->tt_next;
126 	}
127 
128 	soundticks = 0;
129 	titleflg = FALSE;
130 
131 	switch ( soundtype ) {
132 
133 		case 0:
134 		case 32767:
135 		default:
136 			soundoff();
137 			lastobj = NULL;
138 			toneadj = NULL;
139 			break;
140 
141 		case S_PLANE:
142 			if ( soundparm == 0 )
143 				tone( 0xF000 );
144 			else
145 				tone( 0xD000 + soundparm * 0x1000 );
146 			lastobj = NULL;
147 			toneadj = NULL;
148 			break;
149 
150 		case S_BOMB:
151 			if ( soundobj == lastobj )
152 				break;
153 			toneadj = adjcont;
154 			lastobj = soundobj;
155 			adjcont();
156 			break;
157 
158 		case S_FALLING:
159 			if ( soundobj == lastobj )
160 				break;
161 			toneadj = adjcont;
162 			lastobj = soundobj;
163 			adjcont();
164 			break;
165 
166 		case S_HIT:
167 			tone( rand( 2 ) ? 0x9000 : 0xF000 );
168 			lastobj = NULL;
169 			toneadj = NULL;
170 			break;
171 
172 		case S_EXPLOSION:
173 			tone( expltone );
174 			toneadj = NULL;
175 			lastobj = NULL;
176 			break;
177 
178 		case S_SHOT:
179 			tone( 0x1000 );
180 			toneadj = adjshot;
181 			lastobj = NULL;
182 			break;
183 
184 		case S_TITLE:
185 			titlline = 0;
186 			titlplace = 0;
187 			titlnote();
188 			toneadj = NULL;
189 			lastobj = NULL;
190 			titleflg = TRUE;
191 			break;
192 
193 	}
194 
195 	intson();
196 	soundtype = soundparm = 32767;
197 }
198 
199 
200 
201 
202 
203 soundadj()
204 {
205 
206 	++soundticks;
207 
208 	if ( lastfreq && toneadj )
209 		( *toneadj )();
210 
211 	if ( numexpls )
212 		adjexpl();
213 
214 	if ( titleflg )
215 		adjtitl();
216 }
217 
218 
219 
220 
221 static	adjcont()
222 {
223 register TONETAB *tt;
224 
225 	if ( tt = lastobj->ob_sound )
226 		tone( tt->tt_tone + tt->tt_chng * soundticks );
227 }
228 
229 
230 
231 
232 static	adjshot()
233 {
234 static	unsigned savefreq;
235 
236 	if ( lastfreq == 0xF000 )
237 		tone( savefreq );
238 	else {
239 		savefreq = lastfreq;
240 		tone( 0xF000 );
241 	}
242 }
243 
244 
245 
246 
247 static adjexpl()
248 {
249 	if ( --explticks >= 0 )
250 		return;
251 
252 	explnote();
253 }
254 
255 
256 
257 
258 static explnote()
259 {
260 	line = explline;
261 	place = explplace;
262 	tune = expltune;
263 	octavefactor = exploctv;
264 	playnote();
265 	explline = line;
266 	explplace = place;
267 	expltone = tunefreq;
268 	intsoff();
269 	explticks += tunedura;
270 	intson();
271 	exploctv = octavefactor;
272 }
273 
274 
275 
276 
277 static adjtitl()
278 {
279 	if ( --titlticks >= 0 )
280 		return;
281 	titlnote();
282 }
283 
284 
285 
286 
287 static titlnote()
288 {
289 
290 	line = titlline;
291 	place = titlplace;
292 	tune = expltune;
293 	octavefactor = titloctv;
294 	playnote();
295 	titlline = line;
296 	titlplace = place;
297 	titltone = tunefreq;
298 	intsoff();
299 	titlticks += tunedura;
300 	intson();
301 	titloctv = octavefactor;
302 	soundoff();
303 	tone( titltone );
304 }
305 
306 
307 
308 
309 
310 initsound( obp, type )
311 OBJECTS *obp;
312 int	type;
313 {
314 register OBJECTS *ob;
315 register TONETAB *tt;
316 TONETAB 	 *allocton();
317 
318 	if ( ( ob = obp )->ob_sound )
319 		return;
320 
321 	if ( ob->ob_type == EXPLOSION ) {
322 		intsoff();
323 		if ( ++numexpls == 1 ) {
324 			explline = 0;
325 			explplace = 0;
326 			explnote();
327 		}
328 		ob->ob_sound = (struct tt *) 1;
329 		intson();
330 		return;
331 	}
332 
333 	if ( tt = allocton() ) {
334 		intsoff();
335 		switch ( type ) {
336 			case S_BOMB:
337 				tt->tt_tone = 0x0300;
338 				tt->tt_chng = 8;
339 				break;
340 			case S_FALLING:
341 				tt->tt_tone = 0x1200;
342 				tt->tt_chng = -8;
343 				break;
344 			default:
345 				break;
346 		}
347 		ob->ob_sound = tt;
348 		intson();
349 		return;
350 	}
351 }
352 
353 
354 
355 
356 static	TONETAB *allocton()
357 {
358 register TONETAB *tt;
359 
360 	if ( !freetone )
361 		return( 0 );
362 
363 	tt = freetone;
364 	freetone = tt->tt_next;
365 
366 	tt->tt_next = frsttone;
367 	tt->tt_prev = NULL;
368 
369 	if ( frsttone )
370 		frsttone->tt_prev = tt;
371 
372 	return( frsttone = tt );
373 }
374 
375 
376 
377 static	deallton( ttp )
378 TONETAB *ttp;
379 {
380 register TONETAB *ttb, *tt;
381 
382 
383 	if ( ttb = ( tt = ttp )->tt_prev )
384 		ttb->tt_next = tt->tt_next;
385 	else
386 		frsttone = tt->tt_next;
387 
388 	if ( ttb = tt->tt_next )
389 		ttb->tt_prev = tt->tt_prev;
390 
391 	tt->tt_next = freetone;
392 	freetone = tt;
393 }
394 
395 
396 
397 
398 
399 
400 
401 
402 stopsound( ob )
403 OBJECTS *ob;
404 {
405 TONETAB *tt;
406 
407 	if ( !( tt = ob->ob_sound ) )
408 		return;
409 
410 	intsoff();
411 	if ( ob->ob_type == EXPLOSION )
412 		--numexpls;
413 	else
414 		deallton( tt );
415 	ob->ob_sound = NULL;
416 	intson();
417 }
418 
419 
420 
421 
422 
423 
424 static	tone( freq )
425 unsigned freq;
426 {
427 
428 	if ( !soundflg )
429 		return;
430 
431 	if ( lastfreq == freq )
432 		return;
433 
434 #ifdef IBMPC
435 	if ( !lastfreq )
436 		outportb( TIMER + 3, 0xB6 );
437 	outportb( TIMER + 2, freq & 0x00FF );
438 	outportb( TIMER + 2, freq >> 8 );
439 	if ( !lastfreq )
440 		outportb( PORTB, 0x03 | inportb( PORTB ) );
441 #endif
442 
443 	lastfreq = freq;
444 	dispdbg = freq;
445 }
446 
447 
448 
449 
450 soundoff()
451 {
452 	if ( lastfreq ) {
453 #ifdef IBMPC
454 		outportb( PORTB, 0xFC & inportb( PORTB ) );
455 #endif
456 		lastfreq = 0;
457 		dispdbg = 0;
458 	}
459 }
460 
461 
462 
463 
464 
465 static	int	  seed[50] = {
466 	0x90B9, 0xBCFB, 0x6564, 0x3313, 0x3190, 0xA980, 0xBCF0, 0x6F97,
467 	0x37F4, 0x064B, 0x9FD8, 0x595B, 0x1EEE, 0x820C, 0x4201, 0x651E,
468 	0x848E, 0x15D5, 0x1DE7, 0x1585, 0xA850, 0x213B, 0x3953, 0x1EB0,
469 	0x97A7, 0x35DD, 0xAF2F, 0x1629, 0xBE9B, 0x243F, 0x847D, 0x313A,
470 	0x3295, 0xBC11, 0x6E6D, 0x3398, 0xAD43, 0x51CE, 0x8F95, 0x507E,
471 	0x499E, 0x3BC1, 0x5243, 0x2017, 0x9510, 0x9865, 0x65F6, 0x6B56,
472 	0x36B9, 0x5026
473 };
474 
475 
476 
477 static	unsigned  rand( modulo )
478 unsigned  modulo;
479 {
480 static	  i = 0;
481 
482 	if ( i >= 50 )
483 		i = 0;
484 	return( seed[i++] % modulo );
485 }
486 
487 
488 
489 
490 
491 
492 
493 #define NOTEEND     '/'
494 #define UPOCTAVE    '>'
495 #define DOWNOCTAVE  '<'
496 #define SHARP	    '+'
497 #define FLAT	    '-'
498 #define DOT	    '.'
499 #define REST	    'R'
500 
501 
502 
503 
504 
505 playnote()
506   {
507 
508     static int noteindex[] = { 0,2,3,5,7,8,10 };
509     static int notefreq[]  = {440,466,494,523,554,587,622,659,698,740,784,831};
510 
511     static int durplace, test, freq, duration;
512     static int index;
513     static int indexadj;
514 
515     static  char    durstring[5];
516     static  char    charatplace, noteletter;
517 
518     static  int   noteoctavefactor;
519     static  int   dottednote;
520 
521     BOOL	  firstplace = TRUE;
522 
523     indexadj = 0;
524     durplace = 0;
525     dottednote = 2;
526     noteoctavefactor = 256;
527 
528     FOREVER {
529 	if ( ( !line ) && ( !place ) )
530 		octavefactor = 256;
531 
532 	if ( !( charatplace = toupper( tune[line][place++] ) ) ) {
533 		if ( !( charatplace = tune[++line][place = 0] ) ) {
534 			line = 0;
535 		}
536 
537 		if ( firstplace )
538 			continue;
539 		break;
540 	}
541 	firstplace = FALSE;
542 	if ( charatplace == NOTEEND )
543 		break;
544 
545 	if ( test = isalpha( charatplace )) {
546 	    index = *(noteindex + (charatplace - 'A'));
547 	    noteletter = charatplace;
548 	} else
549 	    switch( charatplace ) {
550 		case UPOCTAVE : octavefactor <<= 1; break;
551 		case DOWNOCTAVE : octavefactor >>= 1; break;
552 		case SHARP    : indexadj++; break;
553 		case FLAT     : indexadj--; break;
554 		case DOT      : dottednote = 3; break;
555 		default       :
556 			if ( test = isdigit(charatplace))
557 			    *(durstring + durplace++) = charatplace;
558 			break;
559 	    }
560 
561     }
562 
563     *(durstring + durplace) = '\0';
564     duration = atoi( durstring );
565     if (duration <= 0) duration = 4;
566     duration = (1440 * dottednote / (60*duration)) >> 1;
567 
568     if (noteletter == REST)
569 	freq = 32000;
570     else {
571 	index += indexadj;
572 	while (index < 0) {
573 	    index += 12;
574 	    noteoctavefactor >>= 1 ;
575 	}
576 	while ( index >= 12 ) {
577 	    index -= 12;
578 	    noteoctavefactor <<= 1 ;
579 	}
580 	freq = soundmul( *(notefreq+index), octavefactor, noteoctavefactor );
581     }
582     tunefreq = sounddiv( 1331000L, freq );
583     tunedura = duration;
584   }
585 