- int audio_fd; /* file descriptor of /dev/audio or -1 if not open */
- int audio_format;
- int sample_rate;
- int fragment_size;
- unsigned char *audio_buffer; /* actual buffer pumped to /dev/audio */
- short *mix_buffer;
-
- char sound_play[SAMPLE_MAX]; /* if set, we should be playing these sounds */
- long sound_pos[SAMPLE_MAX]; /* position in the sound */
- int mix_play[MIXER_MAX]; /* which sounds we have chosen to mix (calculated each time) */
- int mix_count;
-
- int i;
-
-loop:
- audio_fd = -1;
- audio_format = AUDIO_ULAW; /* defaults for non-OSS /dev/audio */
- sample_rate = 8000;
- fragment_size = 256;
- audio_buffer = 0;
- mix_buffer = 0;
- mix_count = 0;
-
- memset(sound_play, 0, sizeof(sound_play)); /* not playing any sounds */
-
- for(;;) {
- for(;;) {
-
-/* pick sounds to play, if any */
- if(sound_play[SAMPLE_exit] || sound_play[SAMPLE_die]) sound_play[SAMPLE_boom] = 0; /* no explosions if player goes home */
- mix_count = 0;
- for(i = 0; i < SAMPLE_MAX; i++) {
- if(sound_play[sound_priority[i]]) {
- mix_play[mix_count++] = sound_priority[i];
- if(mix_count == MIXER_MAX) break; /* cant mix too many sounds at once */
- }
- }
-
-/* check for incoming messages */
- if(mix_count || audio_fd != -1) { /* dont block if we are playing sounds */
- fd_set rfds;
- struct timeval tv;
- FD_ZERO(&rfds);
- FD_SET(sound_pipe[0], &rfds);
- tv.tv_sec = 0;
- tv.tv_usec = 0; /* (900000 * fragment_size / sample_rate) */
- i = select(sound_pipe[0] + 1, &rfds, 0, 0, &tv); /* dont block */
- if(i == -1) {
- fprintf(stderr, "%s: %s: %s\n", progname, "select failed", strerror(errno));
- goto fail;
- }
- if(i == 0) break; /* no messages */
- }
-
-/* get a message and start a sound */
- i = read(sound_pipe[0], &play, sizeof(play));
- if(i == -1) {
- fprintf(stderr, "%s: %s: %s\n", progname, "read failed", strerror(errno));
- goto fail;
- }
- if(i == 0) {
- fprintf(stderr, "%s: %s: %s\n", progname, "read sound", "Broken pipe");
- goto fail;
- }
- if(i != sizeof(play)) {
- fprintf(stderr, "%s: %s\n", progname, "bad message length");
- goto fail;
- }
- for(i = 0; i < SAMPLE_MAX; i++) {
- if(play[i]) {
- sound_play[i] = 1; /* play this sound */
- sound_pos[i] = 0; /* start it from the start */
- }
- }
- }
-
-/* open the audio device if there are sounds to play */
- if(mix_count && audio_fd == -1) {
- audio_fd = open(audioname, O_WRONLY);
- if(audio_fd == -1) goto reset;
-#ifdef OPEN_SOUND_SYSTEM
- i = 0x00020008;
- if(ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i) == -1) {
- fprintf(stderr, "%s: \"%s\": %s (%d): %s\n", progname, audioname, "unable to set fragment size", 512, strerror(errno));
- goto reset;
- }
- if(ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &i) == -1) {
- fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, audioname, "unable to query audio format", strerror(errno));
- goto reset;
- }
- audio_format = (i & AFMT_U8) ? AFMT_U8 : AFMT_MU_LAW; /* prefer 8 bit unsigned and fall back on mu-law */
- i = audio_format;
- if(ioctl(audio_fd, SNDCTL_DSP_SETFMT, &i) == -1) {
- fprintf(stderr, "%s: \"%s\": %s (%d): %s\n", progname, audioname, "unable to set audio format", audio_format, strerror(errno));
- goto reset;
- }
- if(i == AFMT_MU_LAW) {
- audio_format = AUDIO_ULAW;
- } else if(i == AFMT_U8) {
- audio_format = AUDIO_U8;
- } else {
- fprintf(stderr, "%s: \"%s\": %s (%d)\n", progname, audioname, "audio format required by device not supported", i);
- goto reset;
- }
- i = 1;
- if(ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &i) == -1) {
- fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, audioname, "unable to set channels to mono", strerror(errno));
- goto reset;
- }
- if(i != 1) {
- fprintf(stderr, "%s: \"%s\": %s (%d)\n", progname, audioname, "channels required by device not supported", i);
- goto reset;
- }
- i = 8000;
- if(ioctl(audio_fd, SNDCTL_DSP_SPEED, &i) == -1) {
- fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, audioname, "unable to set sampling rate", strerror(errno));
- goto reset;
- }
- sample_rate = i;
- if(ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &i) == -1) {
- fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, audioname, "unable to get block size", strerror(errno));
- goto reset;
- }
- fragment_size = i;
-#else
- if(fcntl(audio_fd, F_SETFL, O_NONBLOCK) == -1) {
- fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, audioname, "unable to make audio non blocking", strerror(errno));
- goto reset;
- }
-#endif /* OPEN_SOUND_SYSTEM */
- audio_buffer = malloc(fragment_size * sizeof(*audio_buffer));
- if(audio_buffer == 0) {
- fprintf(stderr, "%s: %s (%d): %s\n", progname, "unable to malloc audio buffer", fragment_size * sizeof(*audio_buffer), strerror(errno));
- goto fail;
- }
- mix_buffer = malloc(fragment_size * sizeof(*mix_buffer));
- if(mix_buffer == 0) {
- fprintf(stderr, "%s: %s (%d): %s\n", progname, "unable to malloc mixing buffer", fragment_size * sizeof(*mix_buffer), strerror(errno));
- goto fail;
- }
- }
-
-/* close the audio device if no sounds are playing */
- if(mix_count == 0 && audio_fd != -1) {
- close(audio_fd);
- free(audio_buffer);
- free(mix_buffer);
- audio_fd = -1;
- audio_buffer = 0;
- mix_buffer = 0;
- }
-
-/* if we are playing sounds and the audio device is open, mix them */
- if(mix_count && audio_fd != -1) {
-
- memset(mix_buffer, 0, fragment_size * sizeof(*mix_buffer)); /* prepare mix buffer */
-
- for(i = 0; i < mix_count; i++) {
- register short *mix_ptr = mix_buffer;
- register short *sound_ptr = sound_data[mix_play[i]] + sound_pos[mix_play[i]];
- register long count = sound_length[mix_play[i]] - sound_pos[mix_play[i]];
- if(count > fragment_size) count = fragment_size;
- while(count--) *mix_ptr++ += *sound_ptr++; /* mix the sounds in */
- }
- switch(audio_format) {
- case AUDIO_ULAW:
- for(i = 0; i < fragment_size; i++) audio_buffer[i] = linear_to_ulaw[mix_buffer[i] + 32768];
- break;
- case AUDIO_U8:
- for(i = 0; i < fragment_size; i++) audio_buffer[i] = (mix_buffer[i] + 32768) >> 8;
- break;
- }
-
-/* advance sound pointers */
- for(i = 0; i < SAMPLE_MAX; i++) {
- if(sound_play[i]) {
- if(sound_pos[i] + fragment_size < sound_length[i]) {
- sound_pos[i] += fragment_size;
- } else {
- sound_play[i] = 0;
- }
- }
- }
-
-/* send the data to the audio device */
- i = write(audio_fd, audio_buffer, fragment_size);
- if(i == -1) {
- fprintf(stderr, "%s: %s: %s\n", progname, "write error", strerror(errno));
- goto reset;
- }
- if(i != fragment_size) {
- fprintf(stderr, "%s: %s\n", progname, "bad write length");
- goto reset;
- }
- }
- } /* for */
-
-reset:
- if(audio_fd != -1) close(audio_fd);
- if(audio_buffer) free(audio_buffer);
- if(mix_buffer) free(mix_buffer);
- goto loop; /* back to top */
-
-fail:
- if(audio_fd != -1) close(audio_fd);
- if(audio_buffer) free(audio_buffer);
- if(mix_buffer) free(mix_buffer);
- return(0);
-}
-
-int read_sample(char *name, short **data, long *length)
-{
- int result;
- FILE *file = 0;
- short *dataptr = 0;
- long datalength;
-
- int i, actual, ch;
- unsigned char buffer[24];
- unsigned long temp;
-
- file = fopen(name, "rb");
- if(file == 0) {
- fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, name, "open error", strerror(errno));
- result = 1; goto fail;
- }
- actual = fread(buffer, 1, 24, file);
- if(actual == -1) {
- fprintf(stderr, "%s: \"%s\": %s: %s\n", progname, name, "read error", strerror(errno));
- result = 1; goto fail;
- }
- if(actual < 24) {
- fprintf(stderr, "%s: \"%s\": %s\n", progname, name, "premature eof");
- result = 1; goto fail;
- }
- temp = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; /* magic */
- if(temp != 0x2e736e64) {
- fprintf(stderr, "%s: \"%s\": %s\n", progname, name, "unrecognized file format");
- result = 1; goto fail;
- }
- temp = buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7]; /* header length */
- if(temp < 24) {
- fprintf(stderr, "%s: \"%s\": %s\n", progname, name, "bad header length");
- result = 1; goto fail;