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/a8/a2/r16/a2/r16/a8/c2/r16/", 59 "b8/a8/b4/b4/a4./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 ÿ