sdlbomber/src/sound.c

180 lines
3.6 KiB
C

#include <SDL_audio.h>
#include <SDL_error.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "sound.h"
#ifndef DATADIR
#define DATADIR "data"
#endif
int sound_enabled = 1;
static char dirlist[] = DATADIR;
static int readsound(int num);
#define NUMSOUNDS ((int) (sizeof(soundnames) / sizeof(char*)))
#define MIXMAX 16
#define SOUND_QUIET -1
static const char* soundnames[] = {
"bomb1.raw",
"power1.raw",
"death.raw",
"drop.raw",
"bomb2.raw",
"power2.raw",
};
typedef struct sample {
char* data;
int len;
} sample;
#define SNDFRAGMENT 1024
static sample samples[NUMSOUNDS];
static int soundworking = 0;
static int fragment;
// static int soundwrite,soundread;
static int* soundbuffer;
static int soundbufferlen;
static unsigned char sndclip[8192];
#define MAXSOUNDCOMMANDS 32
static char soundcommands[MAXSOUNDCOMMANDS];
static int soundtake, soundput;
static int sndplaying[MIXMAX], sndposition[MIXMAX];
static void fillaudio(void* udata, Uint8* buffer, int len) {
char com, *p;
int i, j, *ip;
int which;
(void) udata;
while (soundtake != soundput) {
com = soundcommands[soundtake];
soundtake = (soundtake + 1) & (MAXSOUNDCOMMANDS - 1);
if (com == SOUND_QUIET) {
memset(sndposition, 0, sizeof(sndposition));
continue;
}
if (com < NUMSOUNDS) {
for (i = 0; i < MIXMAX; ++i)
if (!sndposition[i]) {
sndposition[i] = 1;
sndplaying[i] = com;
break;
}
}
}
memset(soundbuffer, 0, soundbufferlen);
for (i = 0; i < MIXMAX; ++i) {
if (!sndposition[i]) continue;
which = sndplaying[i];
if (sndposition[i] == samples[which].len) {
sndposition[i] = 0;
continue;
}
p = samples[which].data;
if (!p) continue;
p += len * (sndposition[i]++ - 1);
ip = soundbuffer;
j = len;
while (j--) *ip++ += *p++;
}
j = len;
ip = soundbuffer;
;
while (j--) *buffer++ = sndclip[4096 + *ip++];
}
int soundopen(void) {
SDL_AudioSpec wanted;
int i, j;
soundtake = soundput = 0;
memset(sndposition, 0, sizeof(sndposition));
memset(sndplaying, 0, sizeof(sndplaying));
fragment = SNDFRAGMENT << 1;
soundbufferlen = fragment * sizeof(int);
soundbuffer = malloc(soundbufferlen);
if (!soundbuffer) return -2;
memset(&wanted, 0, sizeof(wanted));
wanted.freq = 22050;
wanted.channels = 2;
wanted.format = AUDIO_U8;
wanted.samples = fragment >> 1;
wanted.callback = fillaudio;
wanted.userdata = 0;
if (SDL_OpenAudio(&wanted, 0) < 0) {
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
return -1;
}
soundworking = 1;
for (i = 0; i < 8192; i++) {
j = i - 4096;
sndclip[i] = j > 127 ? 255 : (j < -128 ? 0 : j + 128);
}
for (i = 0; i < NUMSOUNDS; ++i) readsound(i);
SDL_PauseAudio(0);
return 0;
}
void soundclose(void) {
if (soundworking) {
SDL_CloseAudio();
soundworking = 0;
}
}
int readsound(int num) {
char name[256], *p1, *p2, ch;
int file, size, len;
p1 = dirlist;
for (;;) {
p2 = name;
while (*p1 && (ch = *p1++) != ',') *p2++ = ch;
if (p2 > name && p2[-1] != '/') *p2++ = '/';
strcpy(p2, soundnames[num]);
file = open(name, O_RDONLY);
if (file >= 0) break;
if (!*p1) {
samples[num].len = -1;
return 0;
}
}
size = lseek(file, 0, SEEK_END);
lseek(file, 0, SEEK_SET);
len = samples[num].len = (size + fragment - 1) / fragment;
len *= fragment;
p1 = samples[num].data = malloc(len);
if (p1) {
read(file, p1, size);
if (len - size) memset(p1 + size, 0, len - size);
while (size--) *p1++ ^= 0x80;
} else
samples[num].data = 0;
close(file);
return 0;
}
void playsound(int n) {
if (sound_enabled) {
soundcommands[soundput] = n;
soundput = (soundput + 1) & (MAXSOUNDCOMMANDS - 1);
}
}