|
|
1.1 ! root 1: // Emacs style mode select -*- C++ -*- ! 2: //----------------------------------------------------------------------------- ! 3: // ! 4: // $Id:$ ! 5: // ! 6: // Copyright (C) 1993-1996 by id Software, Inc. ! 7: // ! 8: // This program is free software; you can redistribute it and/or ! 9: // modify it under the terms of the GNU General Public License ! 10: // as published by the Free Software Foundation; either version 2 ! 11: // of the License, or (at your option) any later version. ! 12: // ! 13: // This program is distributed in the hope that it will be useful, ! 14: // but WITHOUT ANY WARRANTY; without even the implied warranty of ! 15: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 16: // GNU General Public License for more details. ! 17: // ! 18: // $Log:$ ! 19: // ! 20: // DESCRIPTION: ! 21: // System interface for sound. ! 22: // ! 23: //----------------------------------------------------------------------------- ! 24: ! 25: static const char ! 26: rcsid[] = "$Id: i_unix.c,v 1.5 1997/02/03 22:45:10 b1 Exp $"; ! 27: ! 28: #include <stdio.h> ! 29: #include <stdlib.h> ! 30: #include <stdarg.h> ! 31: ! 32: #include <math.h> ! 33: ! 34: #include <sys/time.h> ! 35: #include <sys/types.h> ! 36: ! 37: #ifndef LINUX ! 38: #include <sys/filio.h> ! 39: #endif ! 40: ! 41: #include <fcntl.h> ! 42: #include <unistd.h> ! 43: #include <sys/ioctl.h> ! 44: ! 45: // Linux voxware output. ! 46: #include <linux/soundcard.h> ! 47: ! 48: // Timer stuff. Experimental. ! 49: #include <time.h> ! 50: #include <signal.h> ! 51: ! 52: #include "z_zone.h" ! 53: ! 54: #include "i_system.h" ! 55: #include "i_sound.h" ! 56: #include "m_argv.h" ! 57: #include "m_misc.h" ! 58: #include "w_wad.h" ! 59: ! 60: #include "doomdef.h" ! 61: ! 62: // UNIX hack, to be removed. ! 63: #ifdef SNDSERV ! 64: // Separate sound server process. ! 65: FILE* sndserver=0; ! 66: char* sndserver_filename = "./sndserver "; ! 67: #elif SNDINTR ! 68: ! 69: // Update all 30 millisecs, approx. 30fps synchronized. ! 70: // Linux resolution is allegedly 10 millisecs, ! 71: // scale is microseconds. ! 72: #define SOUND_INTERVAL 500 ! 73: ! 74: // Get the interrupt. Set duration in millisecs. ! 75: int I_SoundSetTimer( int duration_of_tick ); ! 76: void I_SoundDelTimer( void ); ! 77: #else ! 78: // None? ! 79: #endif ! 80: ! 81: ! 82: // A quick hack to establish a protocol between ! 83: // synchronous mix buffer updates and asynchronous ! 84: // audio writes. Probably redundant with gametic. ! 85: static int flag = 0; ! 86: ! 87: // The number of internal mixing channels, ! 88: // the samples calculated for each mixing step, ! 89: // the size of the 16bit, 2 hardware channel (stereo) ! 90: // mixing buffer, and the samplerate of the raw data. ! 91: ! 92: ! 93: // Needed for calling the actual sound output. ! 94: #define SAMPLECOUNT 512 ! 95: #define NUM_CHANNELS 8 ! 96: // It is 2 for 16bit, and 2 for two channels. ! 97: #define BUFMUL 4 ! 98: #define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL) ! 99: ! 100: #define SAMPLERATE 11025 // Hz ! 101: #define SAMPLESIZE 2 // 16bit ! 102: ! 103: // The actual lengths of all sound effects. ! 104: int lengths[NUMSFX]; ! 105: ! 106: // The actual output device. ! 107: int audio_fd; ! 108: ! 109: // The global mixing buffer. ! 110: // Basically, samples from all active internal channels ! 111: // are modifed and added, and stored in the buffer ! 112: // that is submitted to the audio device. ! 113: signed short mixbuffer[MIXBUFFERSIZE]; ! 114: ! 115: ! 116: // The channel step amount... ! 117: unsigned int channelstep[NUM_CHANNELS]; ! 118: // ... and a 0.16 bit remainder of last step. ! 119: unsigned int channelstepremainder[NUM_CHANNELS]; ! 120: ! 121: ! 122: // The channel data pointers, start and end. ! 123: unsigned char* channels[NUM_CHANNELS]; ! 124: unsigned char* channelsend[NUM_CHANNELS]; ! 125: ! 126: ! 127: // Time/gametic that the channel started playing, ! 128: // used to determine oldest, which automatically ! 129: // has lowest priority. ! 130: // In case number of active sounds exceeds ! 131: // available channels. ! 132: int channelstart[NUM_CHANNELS]; ! 133: ! 134: // The sound in channel handles, ! 135: // determined on registration, ! 136: // might be used to unregister/stop/modify, ! 137: // currently unused. ! 138: int channelhandles[NUM_CHANNELS]; ! 139: ! 140: // SFX id of the playing sound effect. ! 141: // Used to catch duplicates (like chainsaw). ! 142: int channelids[NUM_CHANNELS]; ! 143: ! 144: // Pitch to stepping lookup, unused. ! 145: int steptable[256]; ! 146: ! 147: // Volume lookups. ! 148: int vol_lookup[128*256]; ! 149: ! 150: // Hardware left and right channel volume lookup. ! 151: int* channelleftvol_lookup[NUM_CHANNELS]; ! 152: int* channelrightvol_lookup[NUM_CHANNELS]; ! 153: ! 154: ! 155: ! 156: ! 157: // ! 158: // Safe ioctl, convenience. ! 159: // ! 160: void ! 161: myioctl ! 162: ( int fd, ! 163: int command, ! 164: int* arg ) ! 165: { ! 166: int rc; ! 167: extern int errno; ! 168: ! 169: rc = ioctl(fd, command, arg); ! 170: if (rc < 0) ! 171: { ! 172: fprintf(stderr, "ioctl(dsp,%d,arg) failed\n", command); ! 173: fprintf(stderr, "errno=%d\n", errno); ! 174: exit(-1); ! 175: } ! 176: } ! 177: ! 178: ! 179: ! 180: ! 181: ! 182: // ! 183: // This function loads the sound data from the WAD lump, ! 184: // for single sound. ! 185: // ! 186: void* ! 187: getsfx ! 188: ( char* sfxname, ! 189: int* len ) ! 190: { ! 191: unsigned char* sfx; ! 192: unsigned char* paddedsfx; ! 193: int i; ! 194: int size; ! 195: int paddedsize; ! 196: char name[20]; ! 197: int sfxlump; ! 198: ! 199: ! 200: // Get the sound data from the WAD, allocate lump ! 201: // in zone memory. ! 202: sprintf(name, "ds%s", sfxname); ! 203: ! 204: // Now, there is a severe problem with the ! 205: // sound handling, in it is not (yet/anymore) ! 206: // gamemode aware. That means, sounds from ! 207: // DOOM II will be requested even with DOOM ! 208: // shareware. ! 209: // The sound list is wired into sounds.c, ! 210: // which sets the external variable. ! 211: // I do not do runtime patches to that ! 212: // variable. Instead, we will use a ! 213: // default sound for replacement. ! 214: if ( W_CheckNumForName(name) == -1 ) ! 215: sfxlump = W_GetNumForName("dspistol"); ! 216: else ! 217: sfxlump = W_GetNumForName(name); ! 218: ! 219: size = W_LumpLength( sfxlump ); ! 220: ! 221: // Debug. ! 222: // fprintf( stderr, "." ); ! 223: //fprintf( stderr, " -loading %s (lump %d, %d bytes)\n", ! 224: // sfxname, sfxlump, size ); ! 225: //fflush( stderr ); ! 226: ! 227: sfx = (unsigned char*)W_CacheLumpNum( sfxlump, PU_STATIC ); ! 228: ! 229: // Pads the sound effect out to the mixing buffer size. ! 230: // The original realloc would interfere with zone memory. ! 231: paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT; ! 232: ! 233: // Allocate from zone memory. ! 234: paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 ); ! 235: // ddt: (unsigned char *) realloc(sfx, paddedsize+8); ! 236: // This should interfere with zone memory handling, ! 237: // which does not kick in in the soundserver. ! 238: ! 239: // Now copy and pad. ! 240: memcpy( paddedsfx, sfx, size ); ! 241: for (i=size ; i<paddedsize+8 ; i++) ! 242: paddedsfx[i] = 128; ! 243: ! 244: // Remove the cached lump. ! 245: Z_Free( sfx ); ! 246: ! 247: // Preserve padded length. ! 248: *len = paddedsize; ! 249: ! 250: // Return allocated padded data. ! 251: return (void *) (paddedsfx + 8); ! 252: } ! 253: ! 254: ! 255: ! 256: ! 257: ! 258: // ! 259: // This function adds a sound to the ! 260: // list of currently active sounds, ! 261: // which is maintained as a given number ! 262: // (eight, usually) of internal channels. ! 263: // Returns a handle. ! 264: // ! 265: int ! 266: addsfx ! 267: ( int sfxid, ! 268: int volume, ! 269: int step, ! 270: int seperation ) ! 271: { ! 272: static unsigned short handlenums = 0; ! 273: ! 274: int i; ! 275: int rc = -1; ! 276: ! 277: int oldest = gametic; ! 278: int oldestnum = 0; ! 279: int slot; ! 280: ! 281: int rightvol; ! 282: int leftvol; ! 283: ! 284: // Chainsaw troubles. ! 285: // Play these sound effects only one at a time. ! 286: if ( sfxid == sfx_sawup ! 287: || sfxid == sfx_sawidl ! 288: || sfxid == sfx_sawful ! 289: || sfxid == sfx_sawhit ! 290: || sfxid == sfx_stnmov ! 291: || sfxid == sfx_pistol ) ! 292: { ! 293: // Loop all channels, check. ! 294: for (i=0 ; i<NUM_CHANNELS ; i++) ! 295: { ! 296: // Active, and using the same SFX? ! 297: if ( (channels[i]) ! 298: && (channelids[i] == sfxid) ) ! 299: { ! 300: // Reset. ! 301: channels[i] = 0; ! 302: // We are sure that iff, ! 303: // there will only be one. ! 304: break; ! 305: } ! 306: } ! 307: } ! 308: ! 309: // Loop all channels to find oldest SFX. ! 310: for (i=0; (i<NUM_CHANNELS) && (channels[i]); i++) ! 311: { ! 312: if (channelstart[i] < oldest) ! 313: { ! 314: oldestnum = i; ! 315: oldest = channelstart[i]; ! 316: } ! 317: } ! 318: ! 319: // Tales from the cryptic. ! 320: // If we found a channel, fine. ! 321: // If not, we simply overwrite the first one, 0. ! 322: // Probably only happens at startup. ! 323: if (i == NUM_CHANNELS) ! 324: slot = oldestnum; ! 325: else ! 326: slot = i; ! 327: ! 328: // Okay, in the less recent channel, ! 329: // we will handle the new SFX. ! 330: // Set pointer to raw data. ! 331: channels[slot] = (unsigned char *) S_sfx[sfxid].data; ! 332: // Set pointer to end of raw data. ! 333: channelsend[slot] = channels[slot] + lengths[sfxid]; ! 334: ! 335: // Reset current handle number, limited to 0..100. ! 336: if (!handlenums) ! 337: handlenums = 100; ! 338: ! 339: // Assign current handle number. ! 340: // Preserved so sounds could be stopped (unused). ! 341: channelhandles[slot] = rc = handlenums++; ! 342: ! 343: // Set stepping??? ! 344: // Kinda getting the impression this is never used. ! 345: channelstep[slot] = step; ! 346: // ??? ! 347: channelstepremainder[slot] = 0; ! 348: // Should be gametic, I presume. ! 349: channelstart[slot] = gametic; ! 350: ! 351: // Separation, that is, orientation/stereo. ! 352: // range is: 1 - 256 ! 353: seperation += 1; ! 354: ! 355: // Per left/right channel. ! 356: // x^2 seperation, ! 357: // adjust volume properly. ! 358: leftvol = ! 359: volume - ((volume*seperation*seperation) >> 16); ///(256*256); ! 360: seperation = seperation - 257; ! 361: rightvol = ! 362: volume - ((volume*seperation*seperation) >> 16); ! 363: ! 364: // Sanity check, clamp volume. ! 365: if (rightvol < 0 || rightvol > 127) ! 366: I_Error("rightvol out of bounds"); ! 367: ! 368: if (leftvol < 0 || leftvol > 127) ! 369: I_Error("leftvol out of bounds"); ! 370: ! 371: // Get the proper lookup table piece ! 372: // for this volume level??? ! 373: channelleftvol_lookup[slot] = &vol_lookup[leftvol*256]; ! 374: channelrightvol_lookup[slot] = &vol_lookup[rightvol*256]; ! 375: ! 376: // Preserve sound SFX id, ! 377: // e.g. for avoiding duplicates of chainsaw. ! 378: channelids[slot] = sfxid; ! 379: ! 380: // You tell me. ! 381: return rc; ! 382: } ! 383: ! 384: ! 385: ! 386: ! 387: ! 388: // ! 389: // SFX API ! 390: // Note: this was called by S_Init. ! 391: // However, whatever they did in the ! 392: // old DPMS based DOS version, this ! 393: // were simply dummies in the Linux ! 394: // version. ! 395: // See soundserver initdata(). ! 396: // ! 397: void I_SetChannels() ! 398: { ! 399: // Init internal lookups (raw data, mixing buffer, channels). ! 400: // This function sets up internal lookups used during ! 401: // the mixing process. ! 402: int i; ! 403: int j; ! 404: ! 405: int* steptablemid = steptable + 128; ! 406: ! 407: // Okay, reset internal mixing channels to zero. ! 408: /*for (i=0; i<NUM_CHANNELS; i++) ! 409: { ! 410: channels[i] = 0; ! 411: }*/ ! 412: ! 413: // This table provides step widths for pitch parameters. ! 414: // I fail to see that this is currently used. ! 415: for (i=-128 ; i<128 ; i++) ! 416: steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0); ! 417: ! 418: ! 419: // Generates volume lookup tables ! 420: // which also turn the unsigned samples ! 421: // into signed samples. ! 422: for (i=0 ; i<128 ; i++) ! 423: for (j=0 ; j<256 ; j++) ! 424: vol_lookup[i*256+j] = (i*(j-128)*256)/127; ! 425: } ! 426: ! 427: ! 428: void I_SetSfxVolume(int volume) ! 429: { ! 430: // Identical to DOS. ! 431: // Basically, this should propagate ! 432: // the menu/config file setting ! 433: // to the state variable used in ! 434: // the mixing. ! 435: snd_SfxVolume = volume; ! 436: } ! 437: ! 438: // MUSIC API - dummy. Some code from DOS version. ! 439: void I_SetMusicVolume(int volume) ! 440: { ! 441: // Internal state variable. ! 442: snd_MusicVolume = volume; ! 443: // Now set volume on output device. ! 444: // Whatever( snd_MusciVolume ); ! 445: } ! 446: ! 447: ! 448: // ! 449: // Retrieve the raw data lump index ! 450: // for a given SFX name. ! 451: // ! 452: int I_GetSfxLumpNum(sfxinfo_t* sfx) ! 453: { ! 454: char namebuf[9]; ! 455: sprintf(namebuf, "ds%s", sfx->name); ! 456: return W_GetNumForName(namebuf); ! 457: } ! 458: ! 459: // ! 460: // Starting a sound means adding it ! 461: // to the current list of active sounds ! 462: // in the internal channels. ! 463: // As the SFX info struct contains ! 464: // e.g. a pointer to the raw data, ! 465: // it is ignored. ! 466: // As our sound handling does not handle ! 467: // priority, it is ignored. ! 468: // Pitching (that is, increased speed of playback) ! 469: // is set, but currently not used by mixing. ! 470: // ! 471: int ! 472: I_StartSound ! 473: ( int id, ! 474: int vol, ! 475: int sep, ! 476: int pitch, ! 477: int priority ) ! 478: { ! 479: ! 480: // UNUSED ! 481: priority = 0; ! 482: ! 483: #ifdef SNDSERV ! 484: if (sndserver) ! 485: { ! 486: fprintf(sndserver, "p%2.2x%2.2x%2.2x%2.2x\n", id, pitch, vol, sep); ! 487: fflush(sndserver); ! 488: } ! 489: // warning: control reaches end of non-void function. ! 490: return id; ! 491: #else ! 492: // Debug. ! 493: //fprintf( stderr, "starting sound %d", id ); ! 494: ! 495: // Returns a handle (not used). ! 496: id = addsfx( id, vol, steptable[pitch], sep ); ! 497: ! 498: // fprintf( stderr, "/handle is %d\n", id ); ! 499: ! 500: return id; ! 501: #endif ! 502: } ! 503: ! 504: ! 505: ! 506: void I_StopSound (int handle) ! 507: { ! 508: // You need the handle returned by StartSound. ! 509: // Would be looping all channels, ! 510: // tracking down the handle, ! 511: // an setting the channel to zero. ! 512: ! 513: // UNUSED. ! 514: handle = 0; ! 515: } ! 516: ! 517: ! 518: int I_SoundIsPlaying(int handle) ! 519: { ! 520: // Ouch. ! 521: return gametic < handle; ! 522: } ! 523: ! 524: ! 525: ! 526: ! 527: // ! 528: // This function loops all active (internal) sound ! 529: // channels, retrieves a given number of samples ! 530: // from the raw sound data, modifies it according ! 531: // to the current (internal) channel parameters, ! 532: // mixes the per channel samples into the global ! 533: // mixbuffer, clamping it to the allowed range, ! 534: // and sets up everything for transferring the ! 535: // contents of the mixbuffer to the (two) ! 536: // hardware channels (left and right, that is). ! 537: // ! 538: // This function currently supports only 16bit. ! 539: // ! 540: void I_UpdateSound( void ) ! 541: { ! 542: #ifdef SNDINTR ! 543: // Debug. Count buffer misses with interrupt. ! 544: static int misses = 0; ! 545: #endif ! 546: ! 547: ! 548: // Mix current sound data. ! 549: // Data, from raw sound, for right and left. ! 550: register unsigned int sample; ! 551: register int dl; ! 552: register int dr; ! 553: ! 554: // Pointers in global mixbuffer, left, right, end. ! 555: signed short* leftout; ! 556: signed short* rightout; ! 557: signed short* leftend; ! 558: // Step in mixbuffer, left and right, thus two. ! 559: int step; ! 560: ! 561: // Mixing channel index. ! 562: int chan; ! 563: ! 564: // Left and right channel ! 565: // are in global mixbuffer, alternating. ! 566: leftout = mixbuffer; ! 567: rightout = mixbuffer+1; ! 568: step = 2; ! 569: ! 570: // Determine end, for left channel only ! 571: // (right channel is implicit). ! 572: leftend = mixbuffer + SAMPLECOUNT*step; ! 573: ! 574: // Mix sounds into the mixing buffer. ! 575: // Loop over step*SAMPLECOUNT, ! 576: // that is 512 values for two channels. ! 577: while (leftout != leftend) ! 578: { ! 579: // Reset left/right value. ! 580: dl = 0; ! 581: dr = 0; ! 582: ! 583: // Love thy L2 chache - made this a loop. ! 584: // Now more channels could be set at compile time ! 585: // as well. Thus loop those channels. ! 586: for ( chan = 0; chan < NUM_CHANNELS; chan++ ) ! 587: { ! 588: // Check channel, if active. ! 589: if (channels[ chan ]) ! 590: { ! 591: // Get the raw data from the channel. ! 592: sample = *channels[ chan ]; ! 593: // Add left and right part ! 594: // for this channel (sound) ! 595: // to the current data. ! 596: // Adjust volume accordingly. ! 597: dl += channelleftvol_lookup[ chan ][sample]; ! 598: dr += channelrightvol_lookup[ chan ][sample]; ! 599: // Increment index ??? ! 600: channelstepremainder[ chan ] += channelstep[ chan ]; ! 601: // MSB is next sample??? ! 602: channels[ chan ] += channelstepremainder[ chan ] >> 16; ! 603: // Limit to LSB??? ! 604: channelstepremainder[ chan ] &= 65536-1; ! 605: ! 606: // Check whether we are done. ! 607: if (channels[ chan ] >= channelsend[ chan ]) ! 608: channels[ chan ] = 0; ! 609: } ! 610: } ! 611: ! 612: // Clamp to range. Left hardware channel. ! 613: // Has been char instead of short. ! 614: // if (dl > 127) *leftout = 127; ! 615: // else if (dl < -128) *leftout = -128; ! 616: // else *leftout = dl; ! 617: ! 618: if (dl > 0x7fff) ! 619: *leftout = 0x7fff; ! 620: else if (dl < -0x8000) ! 621: *leftout = -0x8000; ! 622: else ! 623: *leftout = dl; ! 624: ! 625: // Same for right hardware channel. ! 626: if (dr > 0x7fff) ! 627: *rightout = 0x7fff; ! 628: else if (dr < -0x8000) ! 629: *rightout = -0x8000; ! 630: else ! 631: *rightout = dr; ! 632: ! 633: // Increment current pointers in mixbuffer. ! 634: leftout += step; ! 635: rightout += step; ! 636: } ! 637: ! 638: #ifdef SNDINTR ! 639: // Debug check. ! 640: if ( flag ) ! 641: { ! 642: misses += flag; ! 643: flag = 0; ! 644: } ! 645: ! 646: if ( misses > 10 ) ! 647: { ! 648: fprintf( stderr, "I_SoundUpdate: missed 10 buffer writes\n"); ! 649: misses = 0; ! 650: } ! 651: ! 652: // Increment flag for update. ! 653: flag++; ! 654: #endif ! 655: } ! 656: ! 657: ! 658: // ! 659: // This would be used to write out the mixbuffer ! 660: // during each game loop update. ! 661: // Updates sound buffer and audio device at runtime. ! 662: // It is called during Timer interrupt with SNDINTR. ! 663: // Mixing now done synchronous, and ! 664: // only output be done asynchronous? ! 665: // ! 666: void ! 667: I_SubmitSound(void) ! 668: { ! 669: // Write it to DSP device. ! 670: write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL); ! 671: } ! 672: ! 673: ! 674: ! 675: void ! 676: I_UpdateSoundParams ! 677: ( int handle, ! 678: int vol, ! 679: int sep, ! 680: int pitch) ! 681: { ! 682: // I fail too see that this is used. ! 683: // Would be using the handle to identify ! 684: // on which channel the sound might be active, ! 685: // and resetting the channel parameters. ! 686: ! 687: // UNUSED. ! 688: handle = vol = sep = pitch = 0; ! 689: } ! 690: ! 691: ! 692: ! 693: ! 694: void I_ShutdownSound(void) ! 695: { ! 696: #ifdef SNDSERV ! 697: if (sndserver) ! 698: { ! 699: // Send a "quit" command. ! 700: fprintf(sndserver, "q\n"); ! 701: fflush(sndserver); ! 702: } ! 703: #else ! 704: // Wait till all pending sounds are finished. ! 705: int done = 0; ! 706: int i; ! 707: ! 708: ! 709: // FIXME (below). ! 710: fprintf( stderr, "I_ShutdownSound: NOT finishing pending sounds\n"); ! 711: fflush( stderr ); ! 712: ! 713: while ( !done ) ! 714: { ! 715: for( i=0 ; i<8 && !channels[i] ; i++); ! 716: ! 717: // FIXME. No proper channel output. ! 718: //if (i==8) ! 719: done=1; ! 720: } ! 721: #ifdef SNDINTR ! 722: I_SoundDelTimer(); ! 723: #endif ! 724: ! 725: // Cleaning up -releasing the DSP device. ! 726: close ( audio_fd ); ! 727: #endif ! 728: ! 729: // Done. ! 730: return; ! 731: } ! 732: ! 733: ! 734: ! 735: ! 736: ! 737: ! 738: void ! 739: I_InitSound() ! 740: { ! 741: #ifdef SNDSERV ! 742: char buffer[256]; ! 743: ! 744: if (getenv("DOOMWADDIR")) ! 745: sprintf(buffer, "%s/%s", ! 746: getenv("DOOMWADDIR"), ! 747: sndserver_filename); ! 748: else ! 749: sprintf(buffer, "%s", sndserver_filename); ! 750: ! 751: // start sound process ! 752: if ( !access(buffer, X_OK) ) ! 753: { ! 754: strcat(buffer, " -quiet"); ! 755: sndserver = popen(buffer, "w"); ! 756: } ! 757: else ! 758: fprintf(stderr, "Could not start sound server [%s]\n", buffer); ! 759: #else ! 760: ! 761: int i; ! 762: ! 763: #ifdef SNDINTR ! 764: fprintf( stderr, "I_SoundSetTimer: %d microsecs\n", SOUND_INTERVAL ); ! 765: I_SoundSetTimer( SOUND_INTERVAL ); ! 766: #endif ! 767: ! 768: // Secure and configure sound device first. ! 769: fprintf( stderr, "I_InitSound: "); ! 770: ! 771: audio_fd = open("/dev/dsp", O_WRONLY); ! 772: if (audio_fd<0) ! 773: fprintf(stderr, "Could not open /dev/dsp\n"); ! 774: ! 775: ! 776: i = 11 | (2<<16); ! 777: myioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i); ! 778: myioctl(audio_fd, SNDCTL_DSP_RESET, 0); ! 779: ! 780: i=SAMPLERATE; ! 781: ! 782: myioctl(audio_fd, SNDCTL_DSP_SPEED, &i); ! 783: ! 784: i=1; ! 785: myioctl(audio_fd, SNDCTL_DSP_STEREO, &i); ! 786: ! 787: myioctl(audio_fd, SNDCTL_DSP_GETFMTS, &i); ! 788: ! 789: if (i&=AFMT_S16_LE) ! 790: myioctl(audio_fd, SNDCTL_DSP_SETFMT, &i); ! 791: else ! 792: fprintf(stderr, "Could not play signed 16 data\n"); ! 793: ! 794: fprintf(stderr, " configured audio device\n" ); ! 795: ! 796: ! 797: // Initialize external data (all sounds) at start, keep static. ! 798: fprintf( stderr, "I_InitSound: "); ! 799: ! 800: for (i=1 ; i<NUMSFX ; i++) ! 801: { ! 802: // Alias? Example is the chaingun sound linked to pistol. ! 803: if (!S_sfx[i].link) ! 804: { ! 805: // Load data from WAD file. ! 806: S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] ); ! 807: } ! 808: else ! 809: { ! 810: // Previously loaded already? ! 811: S_sfx[i].data = S_sfx[i].link->data; ! 812: lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)]; ! 813: } ! 814: } ! 815: ! 816: fprintf( stderr, " pre-cached all sound data\n"); ! 817: ! 818: // Now initialize mixbuffer with zero. ! 819: for ( i = 0; i< MIXBUFFERSIZE; i++ ) ! 820: mixbuffer[i] = 0; ! 821: ! 822: // Finished initialization. ! 823: fprintf(stderr, "I_InitSound: sound module ready\n"); ! 824: ! 825: #endif ! 826: } ! 827: ! 828: ! 829: ! 830: ! 831: // ! 832: // MUSIC API. ! 833: // Still no music done. ! 834: // Remains. Dummies. ! 835: // ! 836: void I_InitMusic(void) { } ! 837: void I_ShutdownMusic(void) { } ! 838: ! 839: static int looping=0; ! 840: static int musicdies=-1; ! 841: ! 842: void I_PlaySong(int handle, int looping) ! 843: { ! 844: // UNUSED. ! 845: handle = looping = 0; ! 846: musicdies = gametic + TICRATE*30; ! 847: } ! 848: ! 849: void I_PauseSong (int handle) ! 850: { ! 851: // UNUSED. ! 852: handle = 0; ! 853: } ! 854: ! 855: void I_ResumeSong (int handle) ! 856: { ! 857: // UNUSED. ! 858: handle = 0; ! 859: } ! 860: ! 861: void I_StopSong(int handle) ! 862: { ! 863: // UNUSED. ! 864: handle = 0; ! 865: ! 866: looping = 0; ! 867: musicdies = 0; ! 868: } ! 869: ! 870: void I_UnRegisterSong(int handle) ! 871: { ! 872: // UNUSED. ! 873: handle = 0; ! 874: } ! 875: ! 876: int I_RegisterSong(void* data) ! 877: { ! 878: // UNUSED. ! 879: data = NULL; ! 880: ! 881: return 1; ! 882: } ! 883: ! 884: // Is the song playing? ! 885: int I_QrySongPlaying(int handle) ! 886: { ! 887: // UNUSED. ! 888: handle = 0; ! 889: return looping || musicdies > gametic; ! 890: } ! 891: ! 892: ! 893: ! 894: // ! 895: // Experimental stuff. ! 896: // A Linux timer interrupt, for asynchronous ! 897: // sound output. ! 898: // I ripped this out of the Timer class in ! 899: // our Difference Engine, including a few ! 900: // SUN remains... ! 901: // ! 902: #ifdef sun ! 903: typedef sigset_t tSigSet; ! 904: #else ! 905: typedef int tSigSet; ! 906: #endif ! 907: ! 908: ! 909: // We might use SIGVTALRM and ITIMER_VIRTUAL, if the process ! 910: // time independend timer happens to get lost due to heavy load. ! 911: // SIGALRM and ITIMER_REAL doesn't really work well. ! 912: // There are issues with profiling as well. ! 913: static int /*__itimer_which*/ itimer = ITIMER_REAL; ! 914: ! 915: static int sig = SIGALRM; ! 916: ! 917: // Interrupt handler. ! 918: void I_HandleSoundTimer( int ignore ) ! 919: { ! 920: // Debug. ! 921: //fprintf( stderr, "%c", '+' ); fflush( stderr ); ! 922: ! 923: // Feed sound device if necesary. ! 924: if ( flag ) ! 925: { ! 926: // See I_SubmitSound(). ! 927: // Write it to DSP device. ! 928: write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL); ! 929: ! 930: // Reset flag counter. ! 931: flag = 0; ! 932: } ! 933: else ! 934: return; ! 935: ! 936: // UNUSED, but required. ! 937: ignore = 0; ! 938: return; ! 939: } ! 940: ! 941: // Get the interrupt. Set duration in millisecs. ! 942: int I_SoundSetTimer( int duration_of_tick ) ! 943: { ! 944: // Needed for gametick clockwork. ! 945: struct itimerval value; ! 946: struct itimerval ovalue; ! 947: struct sigaction act; ! 948: struct sigaction oact; ! 949: ! 950: int res; ! 951: ! 952: // This sets to SA_ONESHOT and SA_NOMASK, thus we can not use it. ! 953: // signal( _sig, handle_SIG_TICK ); ! 954: ! 955: // Now we have to change this attribute for repeated calls. ! 956: act.sa_handler = I_HandleSoundTimer; ! 957: #ifndef sun ! 958: //ac t.sa_mask = _sig; ! 959: #endif ! 960: act.sa_flags = SA_RESTART; ! 961: ! 962: sigaction( sig, &act, &oact ); ! 963: ! 964: value.it_interval.tv_sec = 0; ! 965: value.it_interval.tv_usec = duration_of_tick; ! 966: value.it_value.tv_sec = 0; ! 967: value.it_value.tv_usec = duration_of_tick; ! 968: ! 969: // Error is -1. ! 970: res = setitimer( itimer, &value, &ovalue ); ! 971: ! 972: // Debug. ! 973: if ( res == -1 ) ! 974: fprintf( stderr, "I_SoundSetTimer: interrupt n.a.\n"); ! 975: ! 976: return res; ! 977: } ! 978: ! 979: ! 980: // Remove the interrupt. Set duration to zero. ! 981: void I_SoundDelTimer() ! 982: { ! 983: // Debug. ! 984: if ( I_SoundSetTimer( 0 ) == -1) ! 985: fprintf( stderr, "I_SoundDelTimer: failed to remove interrupt. Doh!\n"); ! 986: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.