[Change] Re-wrote entire sound system with SDL_mixer.
This commit is contained in:
parent
ae1cc7c494
commit
897bc36111
12
bin/Makefile
12
bin/Makefile
@ -1,6 +1,6 @@
|
||||
# OPTIONS.
|
||||
DEBUG = 1
|
||||
#DEBUG_PARANOID = 0
|
||||
#DEBUG_PARANOID = 1
|
||||
|
||||
OS := LINUX
|
||||
#OS := WIN32
|
||||
@ -22,10 +22,8 @@ CLUA = -I../lib/lua
|
||||
CSDL = $(shell sdl-config --cflags)
|
||||
CXML = $(shell xml2-config --cflags)
|
||||
CTTF = $(shell freetype-config --cflags)
|
||||
CAL = -lopenal $(shell freealut-config --cflags)
|
||||
CVORBIS =
|
||||
CGL =
|
||||
CFLAGS = $(CLUA) $(CPLUTO) $(CSDL) $(CXML) $(CTTF) $(CGL) $(CAL) $(CVORBIS) $(VERSION) -D$(OS)
|
||||
CFLAGS = $(CLUA) $(CSDL) $(CXML) $(CTTF) $(CGL) $(VERSION) -D$(OS)
|
||||
ifeq ($(OS),LINUX)
|
||||
CFLAGS += -D_POSIX_SOURCE
|
||||
endif
|
||||
@ -42,14 +40,12 @@ endif
|
||||
|
||||
# LDFLAGS.
|
||||
LDLUA = ../lib/lua/liblua.a
|
||||
LDSDL = $(shell sdl-config --libs) -lSDL_image
|
||||
LDSDL = $(shell sdl-config --libs) -lSDL_image -lSDL_mixer
|
||||
LDXML = $(shell xml2-config --libs)
|
||||
LDTTF = $(shell freetype-config --libs)
|
||||
LDGL = -lGL
|
||||
LDAL = -lopenal $(shell freealut-config --libs)
|
||||
LDVORBIS = -lvorbisfile
|
||||
LDPNG = -lpng
|
||||
LDFLAGS = -lm $(LDLUA) $(LDPLUTO) $(LDSDL) $(LDXML) $(LDTTF) $(LDGL) $(LDPNG) $(LDAL) $(LDVORBIS)
|
||||
LDFLAGS = -lm $(LDLUA) $(LDSDL) $(LDXML) $(LDTTF) $(LDGL) $(LDPNG)
|
||||
|
||||
# This is just for gstat to run some analysis on performance.
|
||||
ifdef DEBUG
|
||||
|
@ -261,7 +261,7 @@ void conf_parseCLI(int argc, char** argv) {
|
||||
music_volume(atof(optarg));
|
||||
break;
|
||||
case 's':
|
||||
sound_volume(atof(optarg));
|
||||
/*sound_volume(atof(optarg));*/
|
||||
break;
|
||||
case 'G':
|
||||
nebu_forceGenerate();
|
||||
|
@ -129,12 +129,13 @@ int main(int argc, char** argv) {
|
||||
gtime = SDL_GetTicks();
|
||||
|
||||
/* OpenAL sound. */
|
||||
if(nosound)
|
||||
if(nosound) {
|
||||
LOG("Sound is disabled!");
|
||||
else {
|
||||
if(sound_init()) WARN("Problem setting up sound!");
|
||||
music_choose("load");
|
||||
sound_disabled = 1;
|
||||
music_disabled = 1;
|
||||
}
|
||||
if(sound_init()) WARN("Problem setting up sound!");
|
||||
music_choose("load");
|
||||
|
||||
/* Input. */
|
||||
if((indjoystick >= 0) || (namjoystick != NULL)) {
|
||||
@ -301,8 +302,6 @@ void unload_all(void) {
|
||||
* @brief Split main loop from main() for secondary loop hack in toolkit.c.
|
||||
*/
|
||||
void main_loop(void) {
|
||||
sound_update(); /* Do sound stuff. */
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
fps_control(); /* Everyone loves fps control.. */
|
||||
|
320
src/music.c
320
src/music.c
@ -1,6 +1,4 @@
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
#include <SDL_mixer.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#include "llua.h"
|
||||
@ -12,28 +10,12 @@
|
||||
#include "pack.h"
|
||||
#include "music.h"
|
||||
|
||||
#define MUSIC_STOPPED (1<<1)
|
||||
#define MUSIC_PLAYING (1<<2)
|
||||
#define MUSIC_KILL (1<<9)
|
||||
#define music_is(f) (music_state & f)
|
||||
#define music_set(f) (music_state |= f)
|
||||
#define music_rm(f) (music_state ^= f)
|
||||
|
||||
#define MUSIC_PREFIX "../snd/music/"
|
||||
#define MUSIC_SUFFIX ".ogg"
|
||||
|
||||
#define BUFFER_SIZE (4096 * 8)
|
||||
|
||||
#define soundLock() SDL_mutexP(sound_lock)
|
||||
#define soundUnlock() SDL_mutexV(sound_lock)
|
||||
|
||||
#define musicLock() SDL_mutexP(music_vorbis_lock)
|
||||
#define musicUnlock() SDL_mutexV(music_vorbis_lock)
|
||||
|
||||
#define MUSIC_LUA_PATH "../snd/music.lua"
|
||||
|
||||
/* Gobal sound mutex. */
|
||||
extern SDL_mutex* sound_lock;
|
||||
int music_disabled = 0;
|
||||
|
||||
/* Global music lua. */
|
||||
static lua_State* music_lua = NULL;
|
||||
@ -41,237 +23,67 @@ static lua_State* music_lua = NULL;
|
||||
static int musicL_load(lua_State* L);
|
||||
static int musicL_play(lua_State* L);
|
||||
static int musicL_stop(lua_State* L);
|
||||
static int musicL_get(lua_State* L);
|
||||
static const luaL_reg music_methods[] = {
|
||||
{ "load", musicL_load },
|
||||
{ "play", musicL_play },
|
||||
{ "stop", musicL_stop },
|
||||
{ "get", musicL_get },
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
/* Saves the music to ram in this structure. */
|
||||
typedef struct alMusic_ {
|
||||
char name[64]; /* Name. */
|
||||
Packfile file;
|
||||
OggVorbis_File stream;
|
||||
vorbis_info* info;
|
||||
ALenum format;
|
||||
} alMusic;
|
||||
|
||||
/* Song currently playing. */
|
||||
static SDL_mutex* music_vorbis_lock;
|
||||
static alMusic music_vorbis;
|
||||
static ALuint music_buffer[2]; /* Front and back buffer. */
|
||||
static ALuint music_source = 0;
|
||||
|
||||
/* What is available? */
|
||||
static char** music_selection = NULL;
|
||||
static int nmusic_selection = 0;
|
||||
|
||||
/* Volume */
|
||||
static ALfloat mvolume = 1.;
|
||||
|
||||
/* Vorbis suff. */
|
||||
static size_t ovpack_read(void* ptr, size_t size,
|
||||
size_t nmemb, void* datasource) {
|
||||
return (ssize_t) pack_read(datasource, ptr, size*nmemb);
|
||||
}
|
||||
|
||||
static int ovpack_retneg(void) { return -1; } /* Must return -1. */
|
||||
static int ovpack_retzero(void) { return 0; } /* Must return 0. */
|
||||
ov_callbacks ovcall = {
|
||||
.read_func = ovpack_read,
|
||||
.seek_func = (int(*)(void*, ogg_int64_t, int)) ovpack_retneg,
|
||||
.close_func = (int(*)(void*))ovpack_retzero,
|
||||
.tell_func = (long(*)(void*))ovpack_retneg
|
||||
};
|
||||
static void* music_data = NULL;
|
||||
static SDL_RWops* music_rw = NULL;
|
||||
static Mix_Music* music_music = NULL;
|
||||
|
||||
/* Music stuff. */
|
||||
static int stream_loadBuffer(ALuint buffer);
|
||||
static int music_find(void);
|
||||
static int music_loadOGG(const char* filename);
|
||||
static void music_free(void);
|
||||
/* Lua stuff. */
|
||||
static void music_rechoose(void);
|
||||
static int music_luaInit(void);
|
||||
static void music_luaQuit(void);
|
||||
|
||||
/* The thread. */
|
||||
static unsigned int music_state = 0;
|
||||
int music_thread(void* unused) {
|
||||
(void)unused;
|
||||
|
||||
int active; /* Active buffer. */
|
||||
ALint state;
|
||||
|
||||
/* Main loop. */
|
||||
while(!music_is(MUSIC_KILL)) {
|
||||
if(music_is(MUSIC_PLAYING)) {
|
||||
if(music_vorbis.file.end == 0)
|
||||
music_rm(MUSIC_PLAYING);
|
||||
else {
|
||||
music_rm(MUSIC_STOPPED);
|
||||
|
||||
musicLock(); /* Lock the mutex. */
|
||||
soundLock();
|
||||
|
||||
/* Start playing current song. */
|
||||
active = 0; /* Load first buffer. */
|
||||
if(stream_loadBuffer(music_buffer[active])) music_rm(MUSIC_PLAYING);
|
||||
alSourceQueueBuffers(music_source, 1, &music_buffer[active]);
|
||||
|
||||
/* Start playing with buffer laoaded. */
|
||||
alSourcePlay(music_source);
|
||||
|
||||
active = 1; /* Load the second buffer. */
|
||||
if(stream_loadBuffer(music_buffer[active])) music_rm(MUSIC_PLAYING);
|
||||
alSourceQueueBuffers(music_source, 1, &music_buffer[active]);
|
||||
|
||||
soundUnlock();
|
||||
|
||||
active = 0;
|
||||
}
|
||||
while(music_is(MUSIC_PLAYING)) {
|
||||
soundLock();
|
||||
|
||||
alGetSourcei(music_source, AL_BUFFERS_PROCESSED, &state);
|
||||
|
||||
if(state > 0) {
|
||||
/* Refill active buffer. */
|
||||
alSourceUnqueueBuffers(music_source, 1, &music_buffer[active]);
|
||||
if(stream_loadBuffer(music_buffer[active])) music_rm(MUSIC_PLAYING);
|
||||
alSourceQueueBuffers(music_source, 1, &music_buffer[active]);
|
||||
|
||||
active = 1 - active;
|
||||
}
|
||||
soundUnlock();
|
||||
|
||||
SDL_Delay(0);
|
||||
}
|
||||
soundLock();
|
||||
|
||||
alSourceStop(music_source);
|
||||
alSourceUnqueueBuffers(music_source, 2, music_buffer);
|
||||
|
||||
soundUnlock();
|
||||
musicUnlock();
|
||||
}
|
||||
music_set(MUSIC_STOPPED);
|
||||
SDL_Delay(0); /* We must not kill resources. */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stream_loadBuffer(ALuint buffer) {
|
||||
int size, section, result;
|
||||
char dat[BUFFER_SIZE]; /* Buffer to hold the data. */
|
||||
|
||||
size = 0;
|
||||
while(size < BUFFER_SIZE) {
|
||||
/* Fill up the entire data buffer. */
|
||||
result = ov_read(
|
||||
&music_vorbis.stream, /* Stream. */
|
||||
dat + size, /* Data. */
|
||||
BUFFER_SIZE - size, /* Amount to read. */
|
||||
0, /* Big endian?. */
|
||||
2, /* 16 bit. */
|
||||
1, /* Signed. */
|
||||
§ion); /* Current bitstream. */
|
||||
|
||||
if(result == 0) return 1;
|
||||
else if(result == OV_HOLE) {
|
||||
WARN("OGG: Vorbis hole detected in music!");
|
||||
return 0;
|
||||
}
|
||||
else if(result == OV_EBADLINK) {
|
||||
WARN("OGG: Invalid stream section or corrupt link in music!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size += result;
|
||||
if(size == BUFFER_SIZE) break; /* Buffer is full. */
|
||||
}
|
||||
/* Load the buffer. */
|
||||
alBufferData(buffer, music_vorbis.format, dat, BUFFER_SIZE,
|
||||
music_vorbis.info->rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Init/Exit. */
|
||||
int music_init(void) {
|
||||
music_vorbis_lock = SDL_CreateMutex();
|
||||
music_vorbis.file.end = 0; /* Indication that it's not loaded.. */
|
||||
if(music_disabled) return 0;
|
||||
|
||||
soundLock();
|
||||
|
||||
alGenBuffers(2, music_buffer);
|
||||
alGenSources(1, &music_source);
|
||||
alSourcef(music_source, AL_GAIN, mvolume);
|
||||
alSourcef(music_source, AL_ROLLOFF_FACTOR, 0.);
|
||||
alSourcei(music_source, AL_SOURCE_RELATIVE, AL_FALSE);
|
||||
|
||||
/* Start the lua music stuff. */
|
||||
music_luaInit();
|
||||
|
||||
soundUnlock();
|
||||
if(music_find() < 0) return -1;
|
||||
if(music_luaInit() < 0) return -1;
|
||||
music_volume(0.7);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int music_makeList(void) {
|
||||
return music_find();
|
||||
}
|
||||
|
||||
void music_exit(void) {
|
||||
int i;
|
||||
|
||||
/* Free the music. */
|
||||
alDeleteBuffers(2, music_buffer);
|
||||
alDeleteSources(1, &music_source);
|
||||
music_free();
|
||||
|
||||
/* Free selection */
|
||||
for(i = 0; i < nmusic_selection; i++)
|
||||
free(music_selection[i]);
|
||||
free(music_selection);
|
||||
|
||||
/* Bye bye Lua. */
|
||||
music_luaQuit();
|
||||
|
||||
SDL_DestroyMutex(music_vorbis_lock);
|
||||
}
|
||||
|
||||
/* Internal music loading ruitines. */
|
||||
static int music_loadOGG(const char* filename) {
|
||||
/* Free currently loaded ogg. */
|
||||
music_free();
|
||||
|
||||
musicLock();
|
||||
|
||||
/* Set the new name. */
|
||||
strncpy(music_vorbis.name, filename, 64);
|
||||
music_vorbis.name[64-1] = '\0';
|
||||
|
||||
/* Load the new ogg. */
|
||||
pack_open(&music_vorbis.file, DATA, filename);
|
||||
ov_open_callbacks(&music_vorbis.file, &music_vorbis.stream, NULL, 0, ovcall);
|
||||
music_vorbis.info = ov_info(&music_vorbis.stream, -1);
|
||||
|
||||
if(music_vorbis.info->channels == 1) music_vorbis.format = AL_FORMAT_MONO16;
|
||||
else music_vorbis.format = AL_FORMAT_STEREO16;
|
||||
|
||||
musicUnlock();
|
||||
|
||||
return 0;
|
||||
/* Free the current playing music. */
|
||||
static void music_free(void) {
|
||||
if(music_music != NULL) {
|
||||
Mix_HookMusicFinished(NULL);
|
||||
Mix_HaltMusic();
|
||||
Mix_FreeMusic(music_music);
|
||||
/*SDL_FreeRW(music_rw);*/ /*FreeMusic frees it itself. */
|
||||
free(music_data);
|
||||
music_music = NULL;
|
||||
music_rw = NULL;
|
||||
music_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Internal music loading routines. */
|
||||
static int music_find(void) {
|
||||
char** files;
|
||||
uint32_t nfiles, i;
|
||||
char tmp[64];
|
||||
int len;
|
||||
|
||||
if(music_disabled) return 0;
|
||||
|
||||
/* Get the file list. */
|
||||
files = pack_listfiles(data, &nfiles);
|
||||
|
||||
@ -301,64 +113,45 @@ static int music_find(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void music_free(void) {
|
||||
musicLock();
|
||||
/* Music control functions. */
|
||||
int music_volume(const double vol) {
|
||||
if(music_disabled) return 0;
|
||||
|
||||
if(music_vorbis.file.end != 0) {
|
||||
ov_clear(&music_vorbis.stream);
|
||||
pack_close(&music_vorbis.file);
|
||||
music_vorbis.file.end = 0; /* Somewhat ended. */
|
||||
}
|
||||
|
||||
musicUnlock();
|
||||
}
|
||||
|
||||
void music_volume(const double vol) {
|
||||
if(sound_lock == NULL) return;
|
||||
|
||||
/* Sanity check! */
|
||||
ALfloat fvol = ABS(vol);
|
||||
if(fvol > 1.) fvol = 1.;
|
||||
|
||||
mvolume = fvol;
|
||||
|
||||
/* Only needed if playing! */
|
||||
if(music_set(MUSIC_PLAYING)) {
|
||||
soundLock();
|
||||
alSourcef(music_source, AL_GAIN, fvol);
|
||||
soundUnlock();
|
||||
}
|
||||
return Mix_VolumeMusic(MIX_MAX_VOLUME*vol);
|
||||
}
|
||||
|
||||
/* Music control functions. */
|
||||
void music_load(const char* name) {
|
||||
if(sound_lock == NULL) return;
|
||||
unsigned int size;
|
||||
char filename[PATH_MAX];
|
||||
|
||||
int i;
|
||||
char tmp[64];
|
||||
if(music_disabled) return;
|
||||
|
||||
music_stop();
|
||||
while(!music_is(MUSIC_STOPPED)) SDL_Delay(0);
|
||||
music_free();
|
||||
|
||||
for(i = 0; i < nmusic_selection; i++)
|
||||
if(strcmp(music_selection[i], name)==0) {
|
||||
snprintf(tmp, 64, MUSIC_PREFIX"%s"MUSIC_SUFFIX, name);
|
||||
music_loadOGG(tmp);
|
||||
return;
|
||||
}
|
||||
WARN("Requested load song '%s' but it can't be found in the music stack",name);
|
||||
/* Load the data. */
|
||||
snprintf(filename, PATH_MAX, MUSIC_PREFIX"%s"MUSIC_SUFFIX, name);
|
||||
music_data = pack_readfile(DATA, filename, &size);
|
||||
music_rw = SDL_RWFromMem(music_data, size);
|
||||
music_music = Mix_LoadMUS_RW(music_rw);
|
||||
if(music_music == NULL)
|
||||
WARN("SDL_Mixer: %s", Mix_GetError());
|
||||
|
||||
Mix_HookMusicFinished(music_rechoose);
|
||||
}
|
||||
|
||||
void music_play(void) {
|
||||
if(!music_is(MUSIC_PLAYING)) music_set(MUSIC_PLAYING);
|
||||
if(music_music == NULL) return;
|
||||
|
||||
if(Mix_FadeInMusic(music_music, 0, 500) < 0)
|
||||
WARN("SDL_Mixer: %s", Mix_GetError());
|
||||
}
|
||||
|
||||
void music_stop(void) {
|
||||
if(music_is(MUSIC_PLAYING)) music_rm(MUSIC_PLAYING);
|
||||
}
|
||||
if(music_music == NULL) return;
|
||||
|
||||
void music_kill(void) {
|
||||
if(!music_is(MUSIC_KILL)) music_set(MUSIC_KILL);
|
||||
if(Mix_FadeOutMusic(500) < 0)
|
||||
WARN("SDL_Mixer: %s", Mix_GetError());
|
||||
}
|
||||
|
||||
/* Music lua stuff. */
|
||||
@ -411,7 +204,7 @@ int lua_loadMusic(lua_State* L, int read_only) {
|
||||
}
|
||||
|
||||
int music_choose(char* situation) {
|
||||
if(sound_lock == NULL) return 0;
|
||||
if(music_disabled) return 0;
|
||||
|
||||
lua_getglobal(music_lua, "choose");
|
||||
lua_pushstring(music_lua, situation);
|
||||
@ -423,6 +216,11 @@ int music_choose(char* situation) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Attempt to rechoose the music. */
|
||||
static void music_rechoose(void) {
|
||||
music_choose("idle");
|
||||
}
|
||||
|
||||
/* The music lua functions. */
|
||||
static int musicL_load(lua_State* L) {
|
||||
char* str;
|
||||
@ -448,11 +246,3 @@ static int musicL_stop(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int musicL_get(lua_State* L) {
|
||||
musicLock();
|
||||
lua_pushstring(L, music_vorbis.name);
|
||||
musicUnlock();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,18 @@
|
||||
#pragma once
|
||||
#include "lua.h"
|
||||
|
||||
extern int music_disabled;
|
||||
|
||||
/* Thread. */
|
||||
int music_thread(void* unused);
|
||||
void music_kill(void);
|
||||
|
||||
/* Init/Exit. */
|
||||
int music_init(void);
|
||||
int music_makeList(void);
|
||||
void music_exit(void);
|
||||
|
||||
/* Music control. */
|
||||
void music_volume(const double vol);
|
||||
int music_volume(const double vol);
|
||||
void music_load(const char* name);
|
||||
void music_play(void);
|
||||
void music_stop(void);
|
||||
|
19
src/outfit.c
19
src/outfit.c
@ -377,6 +377,9 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) {
|
||||
xmlNodePtr node;
|
||||
char str[PATH_MAX] = "\0";
|
||||
|
||||
/* Defaults. */
|
||||
tmp->u.blt.sound = -1;
|
||||
|
||||
node = parent->xmlChildrenNode;
|
||||
do {
|
||||
/* Load all the things. */
|
||||
@ -401,13 +404,13 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) {
|
||||
|
||||
#define MELEMENT(o,s) \
|
||||
if (o) WARN("Outfit '%s' missing/invalid '"s"' element", tmp->name)
|
||||
MELEMENT(tmp->u.blt.gfx_space==NULL, "gfx");
|
||||
MELEMENT((sound_lock!=NULL) && (tmp->u.blt.sound==0), "sound");
|
||||
MELEMENT(tmp->u.blt.delay==0, "delay");
|
||||
MELEMENT(tmp->u.blt.speed==0, "speed");
|
||||
MELEMENT(tmp->u.blt.range==0, "range");
|
||||
MELEMENT(tmp->u.blt.accuracy==0, "accuracy");
|
||||
MELEMENT(tmp->u.blt.damage==0, "damage");
|
||||
MELEMENT(tmp->u.blt.gfx_space==NULL, "gfx");
|
||||
MELEMENT((sound_disabled!=NULL) && (tmp->u.blt.sound==0), "sound");
|
||||
MELEMENT(tmp->u.blt.delay==0, "delay");
|
||||
MELEMENT(tmp->u.blt.speed==0, "speed");
|
||||
MELEMENT(tmp->u.blt.range==0, "range");
|
||||
MELEMENT(tmp->u.blt.accuracy==0, "accuracy");
|
||||
MELEMENT(tmp->u.blt.damage==0, "damage");
|
||||
#undef MELEMENT
|
||||
}
|
||||
|
||||
@ -464,7 +467,7 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) {
|
||||
|
||||
#define MELEMENT(o,s) if(o) WARN("Outfit '%s' missing '"s"' element", tmp->name)
|
||||
MELEMENT(tmp->u.amm.gfx_space == NULL, "gfx");
|
||||
MELEMENT((sound_lock != NULL) && (tmp->u.amm.sound == 0), "sound");
|
||||
MELEMENT((sound_disabled != NULL) && (tmp->u.amm.sound == 0), "sound");
|
||||
MELEMENT(tmp->u.amm.thrust==0, "thrust");
|
||||
MELEMENT(tmp->u.amm.turn==0, "turn");
|
||||
MELEMENT(tmp->u.amm.speed==0, "speed");
|
||||
|
10
src/outfit.h
10
src/outfit.h
@ -68,8 +68,8 @@ typedef struct Outfit_ {
|
||||
double damage; /* Damage. */
|
||||
|
||||
glTexture* gfx_space;
|
||||
ALuint sound; /* Sound to play. */
|
||||
int spfx; /* Special effect on hit. */
|
||||
int sound; /* Sound to play. */
|
||||
int spfx; /* Special effect on hit. */
|
||||
} blt;
|
||||
struct { /* Beam. */
|
||||
double range; /* Distance it travels. */
|
||||
@ -94,8 +94,8 @@ typedef struct Outfit_ {
|
||||
double damage; /* Damage. */
|
||||
|
||||
glTexture* gfx_space;
|
||||
ALuint sound; /* Sound to play. */
|
||||
int spfx; /* Special effect on hit. */
|
||||
int sound; /* Sound to play. */
|
||||
int spfx; /* Special effect on hit. */
|
||||
} amm;
|
||||
struct { /* Modification. */
|
||||
/* Movement. */
|
||||
@ -112,7 +112,7 @@ typedef struct Outfit_ {
|
||||
} mod;
|
||||
struct { /* Afterburner. */
|
||||
double rumble; /* Percent of rumble. */
|
||||
ALuint sound; /* Sound of the afterburner. */
|
||||
int sound; /* Sound of the afterburner. */
|
||||
double thrust_perc, thrust_abs; /* Percent and absolute thrust bonus. */
|
||||
double speed_perc, speed_abs; /* Percent and absolute speed bonus. */
|
||||
double energy; /* Energy used while active. */
|
||||
|
26
src/player.c
26
src/player.c
@ -37,10 +37,12 @@
|
||||
#define TARGET_WIDTH 128
|
||||
#define TARGET_HEIGHT 96
|
||||
|
||||
#define PLAYER_RESERVED_CHANNELS 4
|
||||
#define PLAYER_CHANNEL 0
|
||||
|
||||
/* Player stuff. */
|
||||
Pilot* player = NULL; /* extern in pilot.h */
|
||||
static Ship* player_ship = NULL; /* Temp ship to hold when naming it. */
|
||||
static alVoice* player_voice = NULL; /* Player's voice. */
|
||||
static double player_px, player_py, player_vx, player_vy, player_dir;
|
||||
static int player_credits = 0; /* Temp hack. */
|
||||
|
||||
@ -147,7 +149,7 @@ static void player_newMake(void);
|
||||
static void player_newShipMake(char* name);
|
||||
/* Sound. */
|
||||
static void player_initSound(void);
|
||||
static void player_playSound(ALuint sound, int once);
|
||||
static void player_playSound(int sound, int once);
|
||||
static void player_stopSound(void);
|
||||
/* Gui. */
|
||||
static void rect_parse(const xmlNodePtr parent,
|
||||
@ -429,23 +431,17 @@ void player_cleanup(void) {
|
||||
|
||||
/* Initializes the player sound. */
|
||||
static void player_initSound(void) {
|
||||
if(player_voice == NULL) {
|
||||
player_voice = sound_addVoice(0, /* Max priority. */
|
||||
0., 0., 0., 0., 0., /* No properties. */
|
||||
VOICE_LOOPING | VOICE_STATIC);
|
||||
}
|
||||
sound_reserve(PLAYER_RESERVED_CHANNELS);
|
||||
sound_createGroup(PLAYER_CHANNEL, 0, PLAYER_RESERVED_CHANNELS);
|
||||
}
|
||||
|
||||
/* Play a sound. */
|
||||
static void player_playSound(ALuint sound, int once) {
|
||||
unsigned int flags = VOICE_STATIC;
|
||||
|
||||
if(once == 0) flags |= VOICE_LOOPING;
|
||||
voice_buffer(player_voice, sound, flags);
|
||||
static void player_playSound(int sound, int once) {
|
||||
sound_playGroup(PLAYER_CHANNEL, sound, once);
|
||||
}
|
||||
|
||||
static void player_stopSound(void) {
|
||||
voice_stop(player_voice);
|
||||
sound_stopGroup(PLAYER_CHANNEL);
|
||||
}
|
||||
|
||||
void player_message(const char* fmt, ...) {
|
||||
@ -1239,10 +1235,6 @@ void player_think(Pilot* pplayer) {
|
||||
vect_pset(&pplayer->solid->force, pplayer->thrust * player_acc,
|
||||
pplayer->solid->dir);
|
||||
|
||||
/* Set the listener stuff. */
|
||||
sound_listener(pplayer->solid->dir,
|
||||
pplayer->solid->pos.x, pplayer->solid->pos.y,
|
||||
pplayer->solid->vel.x, pplayer->solid->vel.y);
|
||||
}
|
||||
|
||||
/* Modify the radar resolution. */
|
||||
|
@ -52,7 +52,7 @@ typedef struct Ship_ {
|
||||
char* gui;
|
||||
|
||||
/* Sound. */
|
||||
ALuint sound;
|
||||
int sound;
|
||||
|
||||
/* Characteristics. */
|
||||
int crew;
|
||||
|
637
src/sound.c
637
src/sound.c
@ -1,7 +1,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <AL/alc.h>
|
||||
#include <AL/alut.h>
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_mixer.h>
|
||||
#include <SDL_thread.h>
|
||||
|
||||
#include "lephisto.h"
|
||||
@ -10,278 +10,121 @@
|
||||
#include "music.h"
|
||||
#include "sound.h"
|
||||
|
||||
/* ============================================== */
|
||||
/* sound.c controls the routines for using a */
|
||||
/* virtual voice wrapper system around the openal */
|
||||
/* library to get 3D sound. */
|
||||
/* */
|
||||
/* We only use position sound and no doppler effect */
|
||||
/* right now. */
|
||||
/* ============================================== */
|
||||
#define SOUND_CHANNEL_MAX 256 /* Overkill. */
|
||||
|
||||
/* ============================================== */
|
||||
/* Sound Overview: */
|
||||
/* --------------- */
|
||||
/* */
|
||||
/* We use a priority virtual voice system with */
|
||||
/* pre-allocated buffers. */
|
||||
/* */
|
||||
/* Nameing: */
|
||||
/* -- buffer - Sound sample. */
|
||||
/* -- source - openal object that plays sound. */
|
||||
/* -- voice - Virtual object that wants to play sound. */
|
||||
/* */
|
||||
/* First we allocate all the buffers based on what */
|
||||
/* we find inside the datafile. */
|
||||
/* Then we allocate all the possible sources (giving */
|
||||
/* the music system what it needs). */
|
||||
/* Now we allow the user to dynamically create */
|
||||
/* voices, these voices will always try to grab */
|
||||
/* a source from the source pool. If they can't, */
|
||||
/* they will pretend to play the buffer. */
|
||||
/* Every so often we'll check to see if the important */
|
||||
/* voices are being played and take away the sources */
|
||||
/* from the lesser ones. */
|
||||
/* ============================================== */
|
||||
#define SOUND_PREFIX "../snd/sounds/"
|
||||
#define SOUND_SUFFIX ".wav"
|
||||
|
||||
/* Sound parameters - TODO: make it variable per source. */
|
||||
#define SOUND_ROLLOFF_FACTOR 1.
|
||||
#define SOUND_REFERENCE_DIST 500.
|
||||
#define SOUND_MAX_DIST 1000.
|
||||
|
||||
|
||||
#define SOUND_PREFIX "../snd/sounds/"
|
||||
#define SOUND_SUFFIX ".wav"
|
||||
|
||||
#define soundLock() SDL_mutexP(sound_lock)
|
||||
#define soundUnlock() SDL_mutexV(sound_lock)
|
||||
int sound_disabled = 0; /* Whether sound is disabled. */
|
||||
static int sound_reserved = 0; /* Amount of reserved channels. */
|
||||
|
||||
/* Give the buffers a name. */
|
||||
typedef struct alSound_ {
|
||||
char* name; /* Buffers name. */
|
||||
ALuint buffer; /* Associated OpenAL buffer. */
|
||||
char* name; /* Buffers name. */
|
||||
Mix_Chunk* buffer;
|
||||
} alSound;
|
||||
|
||||
/* Voice private flags (public in sound.h). */
|
||||
#define VOICE_PLAYING (1<<0) /* Voice is playing. */
|
||||
#define VOICE_DONE (1<<1) /* Voice is done - must remove. */
|
||||
#define voice_set(v,f) ((v)->flags |= f)
|
||||
#define voice_is(v,f) ((v)->flags & f)
|
||||
|
||||
/* Global sound lock. */
|
||||
SDL_mutex* sound_lock = NULL;
|
||||
|
||||
/* Gobal device and context. */
|
||||
static ALCcontext* al_context = NULL;
|
||||
static ALCdevice* al_device = NULL;
|
||||
|
||||
/* Threads. */
|
||||
static SDL_Thread* music_player = NULL;
|
||||
|
||||
/* List of sounds available (All preloaded into a buffer). */
|
||||
static alSound* sound_list = NULL;
|
||||
static int nsound_list = 0;
|
||||
|
||||
/* Struct to hold all the sources and currently attached voice. */
|
||||
static ALuint* source_stack = NULL; /* And it's stack. */
|
||||
static int source_nstack = 0;
|
||||
|
||||
/* Virtual voice. */
|
||||
struct alVoice {
|
||||
alVoice* next; /* Yes it's a linked list. */
|
||||
|
||||
/*ALuint id; // Unique id for the voice. */
|
||||
|
||||
ALuint source; /* Source itself, 0 if not set. */
|
||||
ALuint buffer; /* Buffer. */
|
||||
|
||||
int priority; /* Base priority. */
|
||||
|
||||
double px, py; /* Position. */
|
||||
/*double vx, vy; // Velocity. */
|
||||
|
||||
unsigned int start; /* time started in ms. */
|
||||
unsigned int flags; /* Flags to set properties. */
|
||||
};
|
||||
static alVoice* voice_start = NULL;
|
||||
static alVoice* voice_end = NULL;
|
||||
|
||||
/* Volume. */
|
||||
static ALfloat svolume = 0.3;
|
||||
static alSound* sound_list = NULL;
|
||||
static int sound_nlist = 0;
|
||||
|
||||
static int sound_makeList(void);
|
||||
static int sound_load(ALuint* buffer, char* filename);
|
||||
static Mix_Chunk* sound_load(char* filename);
|
||||
static void sound_free(alSound* snd);
|
||||
static int voice_getSource(alVoice* voc);
|
||||
static void voice_init(alVoice* voice);
|
||||
static int voice_play(alVoice* voice);
|
||||
static void voice_rm(alVoice* prev, alVoice* voice);
|
||||
static void voice_parseFlags(alVoice* voice, const unsigned int flags);
|
||||
|
||||
/* Init the sound subsystem. */
|
||||
int sound_init(void) {
|
||||
int mem, ret;
|
||||
ALenum err;
|
||||
int frequency;
|
||||
Uint16 format;
|
||||
int channels;
|
||||
SDL_version compile_version;
|
||||
const SDL_version* link_version;
|
||||
|
||||
ret = 0;
|
||||
if(sound_disabled) return 0;
|
||||
|
||||
/* We'll need a mutex. */
|
||||
sound_lock = SDL_CreateMutex();
|
||||
soundLock();
|
||||
|
||||
/* Initialize alut - I think it's worth it. */
|
||||
alutInitWithoutContext(NULL, NULL);
|
||||
|
||||
const ALchar* device = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
|
||||
/* Open the default device. */
|
||||
al_device = alcOpenDevice(NULL);
|
||||
if(al_device == NULL) {
|
||||
WARN("Unable to open default sound device");
|
||||
ret = -1;
|
||||
goto snderr_dev;
|
||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) < 0) {
|
||||
WARN("SDL_Mixer: %s", Mix_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create the OpenAL context. */
|
||||
al_context = alcCreateContext(al_device, NULL);
|
||||
if(sound_lock == NULL) {
|
||||
WARN("Unable to create OpenAL context");
|
||||
ret = -2;
|
||||
goto snderr_ctx;
|
||||
}
|
||||
|
||||
/* Clear the errors. */
|
||||
alGetError();
|
||||
|
||||
/* Set active context. */
|
||||
if(alcMakeContextCurrent(al_context)==AL_FALSE) {
|
||||
WARN("Failure to set default context");
|
||||
ret = -4;
|
||||
goto snderr_act;
|
||||
}
|
||||
|
||||
/* Set the master gain. */
|
||||
alListenerf(AL_GAIN, 1.);
|
||||
|
||||
/* Set the distance model. */
|
||||
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
|
||||
|
||||
/* We can unlock now. */
|
||||
soundUnlock();
|
||||
|
||||
/* Start the music server. */
|
||||
music_init();
|
||||
|
||||
/* Start allocating the sources - music has already taken this. */
|
||||
alGetError(); /* Another error clear. */
|
||||
mem = 0;
|
||||
while(((err = alGetError()) == AL_NO_ERROR) && (source_nstack < 128)) {
|
||||
if(mem < source_nstack+1) {
|
||||
/* Allocate more memory. */
|
||||
mem += 32;
|
||||
source_stack = realloc(source_stack, sizeof(ALuint) * mem);
|
||||
}
|
||||
alGenSources(1, &source_stack[source_nstack]);
|
||||
source_nstack++;
|
||||
}
|
||||
|
||||
/* Use minimal ram. */
|
||||
source_stack = realloc(source_stack, sizeof(ALuint) * source_nstack);
|
||||
Mix_AllocateChannels(SOUND_CHANNEL_MAX);
|
||||
|
||||
/* Debug magic. */
|
||||
DEBUG("OpenAL: %s", device);
|
||||
DEBUG("Sources: %d", source_nstack);
|
||||
DEBUG("Renderer: %s", alGetString(AL_RENDERER));
|
||||
DEBUG("Version: %s", alGetString(AL_VERSION));
|
||||
Mix_QuerySpec(&frequency, &format, &channels);
|
||||
MIX_VERSION(&compile_version);
|
||||
link_version = Mix_Linked_Version();
|
||||
DEBUG("SDL_Mixer: %d.%d.%d [compiled: %d.%d.%d]",
|
||||
compile_version.major, compile_version.minor, compile_version.patch,
|
||||
link_version->major, link_version->minor, link_version->patch);
|
||||
DEBUG("Format: %d HZ %s", frequency, (channels == 2) ? "Sterio" : "Mono");
|
||||
DEBUG();
|
||||
|
||||
/* Load up all the sounds. */
|
||||
sound_makeList();
|
||||
music_makeList(); /* And music. */
|
||||
sound_volume(0.3);
|
||||
|
||||
/* Now start the music thread. */
|
||||
music_player = SDL_CreateThread(music_thread, NULL);
|
||||
/* Init the music. */
|
||||
music_init();
|
||||
|
||||
return 0;
|
||||
|
||||
snderr_act:
|
||||
alcDestroyContext(al_context);
|
||||
snderr_ctx:
|
||||
al_context = NULL;
|
||||
alcCloseDevice(al_device);
|
||||
snderr_dev:
|
||||
al_device = NULL;
|
||||
soundUnlock();
|
||||
SDL_DestroyMutex(sound_lock);
|
||||
sound_lock = NULL;
|
||||
ERR("Sound failed to initialize.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Clean up after the sound system. */
|
||||
void sound_exit(void) {
|
||||
int i;
|
||||
|
||||
/* Free the sounds. */
|
||||
for(i = 0; i < nsound_list; i++)
|
||||
sound_free(&sound_list[i]);
|
||||
sound_free(&sound_list[i]);
|
||||
free(sound_list);
|
||||
sound_list = NULL;
|
||||
nsound_list = 0;
|
||||
|
||||
/* Must stop the music before killing it, */
|
||||
/* then thread should commit suicide. */
|
||||
if(music_player) {
|
||||
music_stop();
|
||||
music_kill();
|
||||
SDL_WaitThread(music_player, NULL);
|
||||
music_exit();
|
||||
}
|
||||
sound_nlist = 0;
|
||||
|
||||
/* Clean up the voices. */
|
||||
while(voice_start != NULL)
|
||||
voice_rm(NULL, voice_start);
|
||||
|
||||
/* Clean up the sources. */
|
||||
if(source_stack)
|
||||
alDeleteSources(source_nstack, source_stack);
|
||||
|
||||
if(sound_lock) {
|
||||
soundLock();
|
||||
|
||||
if(al_context) {
|
||||
alcMakeContextCurrent(NULL);
|
||||
alcDestroyContext(al_context);
|
||||
}
|
||||
if(al_device) alcCloseDevice(al_device);
|
||||
|
||||
soundUnlock();
|
||||
SDL_DestroyMutex(sound_lock);
|
||||
}
|
||||
/* Cya alut! */
|
||||
alutExit();
|
||||
music_exit();
|
||||
}
|
||||
|
||||
/* Get the buffer to sound of [name]. */
|
||||
ALuint sound_get(char* name) {
|
||||
if(sound_lock == NULL) return 0;
|
||||
|
||||
/* Get the buffer to sound of name. */
|
||||
int sound_get(char* name) {
|
||||
int i;
|
||||
for(i = 0; i < nsound_list; i++)
|
||||
|
||||
if(sound_disabled) return 0;
|
||||
|
||||
for(i = 0; i < sound_nlist; i++)
|
||||
if(strcmp(name, sound_list[i].name)==0)
|
||||
return sound_list[i].buffer;
|
||||
return i;
|
||||
|
||||
WARN("Sound '%s' not found in sound list", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Play the sound. */
|
||||
int sound_play(int sound) {
|
||||
int channel;
|
||||
|
||||
if(sound_disabled) return 0;
|
||||
|
||||
if((sound < 0) || (sound > sound_nlist))
|
||||
return -1;
|
||||
|
||||
channel = Mix_PlayChannel(-1, sound_list[sound].buffer, 0);
|
||||
|
||||
if(channel < 0)
|
||||
DEBUG("SDL_Mixer: %s", Mix_GetError());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make list of available sounds. */
|
||||
static int sound_makeList(void) {
|
||||
if(sound_lock == NULL) return 0;
|
||||
|
||||
char** files;
|
||||
uint32_t nfiles, i;
|
||||
char tmp[64];
|
||||
int len;
|
||||
int mem;
|
||||
|
||||
if(sound_disabled) return 0;
|
||||
|
||||
/* Get the file list. */
|
||||
files = pack_listfiles(data, &nfiles);
|
||||
|
||||
@ -293,9 +136,8 @@ static int sound_makeList(void) {
|
||||
SOUND_SUFFIX, strlen(SOUND_SUFFIX))==0)) {
|
||||
|
||||
/* Expand the selection size. */
|
||||
nsound_list++;
|
||||
if(nsound_list > mem) {
|
||||
/* We must grow. */
|
||||
sound_nlist++;
|
||||
if(sound_nlist > mem) { /* We must grow. */
|
||||
mem += 32; /* We'll overallocate most likely. */
|
||||
sound_list = realloc(sound_list, mem*sizeof(alSound));
|
||||
}
|
||||
@ -306,325 +148,122 @@ static int sound_makeList(void) {
|
||||
tmp[len] = '\0';
|
||||
|
||||
/* give it the new name. */
|
||||
sound_list[nsound_list-1].name = strdup(tmp);
|
||||
sound_load(&sound_list[nsound_list-1].buffer, files[i]);
|
||||
sound_list[sound_nlist-1].name = strdup(tmp);
|
||||
sound_list[sound_nlist-1].buffer = sound_load(files[i]);
|
||||
}
|
||||
|
||||
/* Shrink to minimum ram usage. */
|
||||
sound_list = realloc(sound_list, nsound_list*sizeof(alSound));
|
||||
sound_list = realloc(sound_list, sound_nlist*sizeof(alSound));
|
||||
|
||||
/* Free the char* allocated by pack. */
|
||||
for(i = 0; i < nfiles; i++)
|
||||
free(files[i]);
|
||||
free(files);
|
||||
|
||||
DEBUG("Loaded %d sound%s", nsound_list, (nsound_list==1)?"":"s");
|
||||
DEBUG("Loaded %d sound%s", sound_nlist, (sound_nlist==1)?"":"s");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Loads a sound into the sound_list. */
|
||||
static int sound_load(ALuint* buffer, char* filename) {
|
||||
if(sound_lock == NULL) return 0;
|
||||
/* Set the volume. */
|
||||
int sound_volume(const double vol) {
|
||||
if(sound_disabled) return 0;
|
||||
return Mix_Volume(-1, MIX_MAX_VOLUME*vol);
|
||||
}
|
||||
|
||||
/* Loads a sound into the sound_list. */
|
||||
static Mix_Chunk* sound_load(char* filename) {
|
||||
void* wavdata;
|
||||
unsigned int size;
|
||||
ALenum err;
|
||||
SDL_RWops* rw;
|
||||
Mix_Chunk* buffer;
|
||||
|
||||
if(sound_disabled) return NULL;
|
||||
|
||||
/* Get the file data buffer from the packfile. */
|
||||
wavdata = pack_readfile(DATA, filename, &size);
|
||||
|
||||
soundLock();
|
||||
rw = SDL_RWFromMem(wavdata, size);
|
||||
|
||||
/* Bind to OpenAL buffer. */
|
||||
(*buffer) = alutCreateBufferFromFileImage(wavdata, size);
|
||||
if((*buffer) == AL_NONE) WARN("FAILURE: %s", alutGetErrorString(alutGetError()));
|
||||
/*alGenBuffers(1, buffer); */
|
||||
/*alBufferData(*buffer, AL_FORMAT_MONO16, wavdata, size, 22050); */
|
||||
buffer = Mix_LoadWAV_RW(rw, 1);
|
||||
|
||||
/* Errors? */
|
||||
if((err = alGetError()) != AL_NO_ERROR) {
|
||||
WARN("OpenAL erro '%d' loading sound '%s'.", err, filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
soundUnlock();
|
||||
if(buffer == NULL)
|
||||
DEBUG("SDL_Mixer: %s", Mix_GetError());
|
||||
|
||||
/* Finish up. */
|
||||
free(wavdata);
|
||||
return 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void sound_free(alSound* snd) {
|
||||
if(sound_lock) return;
|
||||
|
||||
soundLock();
|
||||
|
||||
/* Free the stuff. */
|
||||
if(snd->name) free(snd->name);
|
||||
alDeleteBuffers(1, &snd->buffer);
|
||||
|
||||
soundUnlock();
|
||||
}
|
||||
|
||||
/* Update the sounds and prioritize them. */
|
||||
void sound_update(void) {
|
||||
ALint state;
|
||||
alVoice* voice, *prev, *next;
|
||||
|
||||
if(sound_lock == NULL) return; /* Sound system is off. */
|
||||
if(voice_start == NULL) return; /* No voices. */
|
||||
|
||||
soundLock();
|
||||
|
||||
/* Update sound. */
|
||||
prev = NULL;
|
||||
voice = voice_start;
|
||||
do {
|
||||
next = voice->next;
|
||||
|
||||
/* Get status. */
|
||||
state = -1;
|
||||
if(voice->source != 0)
|
||||
alGetSourcei(voice->source, AL_SOURCE_STATE, &state);
|
||||
|
||||
if(!voice_is(voice, VOICE_DONE)) { /* Still working. */
|
||||
/* Voice has a source. */
|
||||
if(voice->source != 0) {
|
||||
|
||||
/* Update position. */
|
||||
alSource3f(voice->source, AL_POSITION,
|
||||
voice->px, voice->py, 0.);
|
||||
/*alSource3f(voice->source, AL_VELOCITY,
|
||||
voice->vx, voice->vy, 0.);*/
|
||||
}
|
||||
|
||||
prev = voice;
|
||||
}else {
|
||||
/* Delete them. */
|
||||
if(state != AL_PLAYING)
|
||||
voice_rm(prev, voice); /* Do not set prev to voice. */
|
||||
else
|
||||
prev = voice;
|
||||
}
|
||||
voice = next;
|
||||
} while(voice != NULL);
|
||||
|
||||
soundUnlock();
|
||||
}
|
||||
|
||||
/* Remove a voice. */
|
||||
static void voice_rm(alVoice* prev, alVoice* voice) {
|
||||
ALint state;
|
||||
|
||||
if(voice->source != 0) { /* Source must exist. */
|
||||
/* Stop it if playing. */
|
||||
alGetSourcei(voice->source, AL_SOURCE_STATE, &state);
|
||||
if(state == AL_PLAYING) alSourceStop(voice->source);
|
||||
|
||||
/* Clear it and get rid of it. */
|
||||
source_stack[source_nstack++] = voice->source; /* Throw it back. */
|
||||
if(snd->name) {
|
||||
free(snd->name);
|
||||
snd->name = NULL;
|
||||
}
|
||||
|
||||
/* Delete from linked list. */
|
||||
if(prev == NULL) /* Was the first member. */
|
||||
voice_start = voice->next;
|
||||
else /* Not first memmber. */
|
||||
prev->next = voice->next;
|
||||
if(voice_end == voice) /* Last voice in linked list. */
|
||||
voice_end = prev;
|
||||
free(voice);
|
||||
Mix_FreeChunk(snd->buffer);
|
||||
snd->buffer = NULL;
|
||||
}
|
||||
|
||||
/* Set all the sounds volume to vol. */
|
||||
void sound_volume(const double vol) {
|
||||
if(sound_lock == NULL) return;
|
||||
|
||||
svolume = (ALfloat) vol;
|
||||
}
|
||||
|
||||
/* Attempt to alloc a source for a voice. */
|
||||
static int voice_getSource(alVoice* voc) {
|
||||
/* Reserve num channels. */
|
||||
int sound_reserve(int num) {
|
||||
int ret;
|
||||
|
||||
/* Sound system isn't on. */
|
||||
if(sound_lock == NULL) return -1;
|
||||
if(sound_disabled) return 0;
|
||||
|
||||
ret = 0; /* Default return. */
|
||||
sound_reserved += num;
|
||||
ret = Mix_ReserveChannels(num);
|
||||
|
||||
soundLock();
|
||||
|
||||
/* Try and grab a source. */
|
||||
if(source_nstack > 0) { /* We have the source. */
|
||||
/* We must pull it from the free source vector. */
|
||||
voc->source = source_stack[--source_nstack];
|
||||
|
||||
/* Initialize and play. */
|
||||
voice_init(voc);
|
||||
ret = voice_play(voc);
|
||||
} else
|
||||
voc->source = 0;
|
||||
|
||||
soundUnlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Must lock becore calling. */
|
||||
static void voice_init(alVoice* voice) {
|
||||
/* Distance model. */
|
||||
alSourcef(voice->source, AL_ROLLOFF_FACTOR, SOUND_ROLLOFF_FACTOR);
|
||||
alSourcef(voice->source, AL_MAX_DISTANCE, SOUND_MAX_DIST);
|
||||
alSourcef(voice->source, AL_REFERENCE_DISTANCE, SOUND_REFERENCE_DIST);
|
||||
|
||||
alSourcef(voice->source, AL_GAIN, svolume);
|
||||
alSource3f(voice->source, AL_POSITION, voice->px, voice->py, 0.);
|
||||
/*alSource3f(voice->source, AL_VELOCITY, voice->vx, voice->vy, 0.); */
|
||||
if(voice_is(voice, VOICE_LOOPING))
|
||||
alSourcei(voice->source, AL_LOOPING, AL_TRUE);
|
||||
else
|
||||
alSourcei(voice->source, AL_LOOPING, AL_FALSE);
|
||||
}
|
||||
|
||||
/* Create a dynamic moving piece. */
|
||||
alVoice* sound_addVoice(int priority, double px, double py,
|
||||
double vx, double vy, const ALuint buffer, const unsigned int flags) {
|
||||
|
||||
(void)vx;
|
||||
(void)vy;
|
||||
alVoice* voc;
|
||||
|
||||
if(sound_lock == NULL) return NULL;
|
||||
|
||||
/* Allocate the voice. */
|
||||
voc = malloc(sizeof(alVoice));
|
||||
|
||||
/* Set the data. */
|
||||
voc->next = NULL;
|
||||
voc->priority = priority;
|
||||
voc->start = SDL_GetTicks();
|
||||
voc->buffer = buffer;
|
||||
|
||||
/* Handle positions. */
|
||||
voc->px = px;
|
||||
voc->py = py;
|
||||
/*voc->vx = vx; */
|
||||
/*voc->vy = vy; */
|
||||
|
||||
/* Handle the flags. */
|
||||
voice_parseFlags(voc, flags);
|
||||
|
||||
/* Get the source. */
|
||||
voice_getSource(voc);
|
||||
|
||||
if(voice_start == NULL) {
|
||||
voice_start = voc;
|
||||
voice_end = voc;
|
||||
} else {
|
||||
if(voice_end != NULL)
|
||||
voice_end->next = voc;
|
||||
voice_end = voc;
|
||||
}
|
||||
|
||||
return voc;
|
||||
}
|
||||
|
||||
/* Delete the voice. */
|
||||
void sound_delVoice(alVoice* voice) {
|
||||
if(sound_lock == NULL) return;
|
||||
|
||||
voice_set(voice, VOICE_DONE);
|
||||
}
|
||||
|
||||
/* Update voice position, should be run once per frame. */
|
||||
void voice_update(alVoice* voice, double px, double py, double vx, double vy) {
|
||||
(void) vx;
|
||||
(void) vy;
|
||||
|
||||
if(sound_lock == NULL) return;
|
||||
|
||||
voice->px = px;
|
||||
voice->py = py;
|
||||
/*voice->vx = vx; */
|
||||
/*voice->vy = vy; */
|
||||
}
|
||||
|
||||
/* Changes the voice's buffer. */
|
||||
void voice_buffer(alVoice* voice, const ALuint buffer, const unsigned int flags) {
|
||||
if(voice == NULL) return;
|
||||
|
||||
voice->buffer = buffer;
|
||||
voice_parseFlags(voice, flags);
|
||||
|
||||
/* Start playing. */
|
||||
soundLock();
|
||||
voice_play(voice);
|
||||
soundUnlock();
|
||||
}
|
||||
|
||||
/* Stop playing sound. */
|
||||
void voice_stop(alVoice* voice) {
|
||||
if(voice == NULL) return;
|
||||
|
||||
soundLock();
|
||||
if(voice->source != 0)
|
||||
alSourceStop(voice->source);
|
||||
soundUnlock();
|
||||
}
|
||||
|
||||
/* Handle flags. */
|
||||
static void voice_parseFlags(alVoice* voice, const unsigned int flags) {
|
||||
voice->flags = 0; /* Defaults. */
|
||||
|
||||
/* Looping. */
|
||||
if(flags & VOICE_LOOPING)
|
||||
voice_set(voice, VOICE_LOOPING);
|
||||
|
||||
if(flags & VOICE_STATIC)
|
||||
alSourcei(voice->source, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
else
|
||||
alSourcei(voice->source, AL_SOURCE_RELATIVE, AL_FALSE);
|
||||
}
|
||||
|
||||
/* Make a voice play. Must lock before calling. */
|
||||
static int voice_play(alVoice* voice) {
|
||||
ALenum err;
|
||||
ALint state;
|
||||
|
||||
/* Must have buffer. */
|
||||
if(voice->buffer != 0) {
|
||||
alGetSourcei(voice->source, AL_SOURCE_STATE, &state);
|
||||
if(state == AL_PLAYING)
|
||||
alSourceStop(voice->source);
|
||||
/* Set buffer. */
|
||||
alSourcei(voice->source, AL_BUFFER, voice->buffer);
|
||||
|
||||
/* Try to play the source. */
|
||||
alSourcePlay(voice->source);
|
||||
err = alGetError();
|
||||
if(err == AL_NO_ERROR) voice_set(voice, VOICE_PLAYING);
|
||||
else return 2;
|
||||
if(ret != sound_reserved) {
|
||||
WARN("Unable to reserve %d channels: %s", sound_reserved, Mix_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sound_listener(double dir, double px, double py, double vx, double vy) {
|
||||
(void)vx;
|
||||
(void)vy;
|
||||
/* Create a sound group. */
|
||||
int sound_createGroup(int tag, int start, int size) {
|
||||
int ret;
|
||||
|
||||
if(sound_lock == NULL) return;
|
||||
if(sound_disabled) return 0;
|
||||
|
||||
soundLock();
|
||||
ret = Mix_GroupChannels(start, start+size-1, tag);
|
||||
|
||||
/* Set orientation. */
|
||||
ALfloat ori[] = { 0., 0., 0., 0., 0., 1. };
|
||||
ori[0] = cos(dir);
|
||||
ori[1] = sin(dir);
|
||||
alListenerfv(AL_ORIENTATION, ori);
|
||||
alListener3f(AL_POSITION, px, py, 1.);
|
||||
/*alListener3f(AL_VELOCITY, vx, vy, 0.); */
|
||||
if(ret != size) {
|
||||
WARN("Unable to create sound group: %s", Mix_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
soundUnlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Play a sound in a group. */
|
||||
int sound_playGroup(int group, int sound, int once) {
|
||||
int ret, channel;
|
||||
|
||||
if(sound_disabled) return 0;
|
||||
|
||||
channel = Mix_GroupAvailable(group);
|
||||
|
||||
ret = Mix_PlayChannel(channel, sound_list[sound].buffer,
|
||||
(once == 0) ? -1 : 0);
|
||||
|
||||
if(ret < 0) {
|
||||
WARN("Unable to play sound %d for group %d: %s",
|
||||
sound, group, Mix_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Stop all the sounds in a group. */
|
||||
void sound_stopGroup(int group) {
|
||||
if(sound_disabled) return;
|
||||
|
||||
Mix_FadeOutGroup(group, 100);
|
||||
}
|
||||
|
||||
|
31
src/sound.h
31
src/sound.h
@ -1,32 +1,19 @@
|
||||
#pragma once
|
||||
#include <AL/al.h>
|
||||
#include "physics.h"
|
||||
|
||||
#define VOICE_LOOPING (1<<10) /* Voice loops. */
|
||||
#define VOICE_STATIC (1<<11) /* Voice isn't relative. */
|
||||
|
||||
struct alVoice;
|
||||
typedef struct alVoice alVoice;
|
||||
extern int sound_disabled;
|
||||
|
||||
/* Sound subsystem. */
|
||||
int sound_init(void);
|
||||
void sound_exit(void);
|
||||
void sound_update(void);
|
||||
|
||||
/* Sound manupulation functions. */
|
||||
ALuint sound_get(char* name);
|
||||
void sound_volume(const double vol);
|
||||
int sound_get(char* name);
|
||||
int sound_volume(const double vol);
|
||||
int sound_play(int sound);
|
||||
|
||||
/* Voice manipulation function. */
|
||||
alVoice* sound_addVoice(int priority, double px, double py,
|
||||
double vx, double vy, const ALuint buffer, const unsigned int flags);
|
||||
|
||||
void sound_delVoice(alVoice* voice); /* Delete voice. */
|
||||
|
||||
void voice_update(alVoice* voice, double px, double py, double vx, double vy);
|
||||
void voice_buffer(alVoice* voice, const ALuint buffer, const unsigned int flags);
|
||||
void voice_stop(alVoice* voice);
|
||||
|
||||
/* Listener manipulation. */
|
||||
void sound_listener(double dir, double px, double py, double vx, double vy);
|
||||
/* Group functions. */
|
||||
int sound_reserve(int num);
|
||||
int sound_createGroup(int tag, int start, int size);
|
||||
int sound_playGroup(int group, int sound, int once);
|
||||
void sound_stopGroup(int group);
|
||||
|
||||
|
22
src/weapon.c
22
src/weapon.c
@ -15,10 +15,6 @@
|
||||
|
||||
#define weapon_isSmart(w) (w->think != NULL)
|
||||
|
||||
#define VOICE_PRIORITY_BOLT 10 /* Default. */
|
||||
#define VOICE_PRIORITY_AMMO 8 /* Higher. */
|
||||
#define VOICE_PRIORITY_BEAM 6 /* Even higher. */
|
||||
|
||||
#define WEAPON_CHUNK 128 /* Size to increment array with. */
|
||||
|
||||
/* Weapon status. */
|
||||
@ -47,8 +43,6 @@ typedef struct Weapon_ {
|
||||
double lockon; /* Some weapons have a lockon delay. */
|
||||
double timer; /* Mainly used to see when the weapon was fired. */
|
||||
|
||||
alVoice* voice; /* Virtual voise. */
|
||||
|
||||
/* Update position and render. */
|
||||
void(*update)(struct Weapon_*, const double, WeaponLayer); /* Position update and render. */
|
||||
void(*think)(struct Weapon_*, const double); /* Some missiles need to be inteligent.a */
|
||||
@ -350,11 +344,6 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
|
||||
if(weapon_isSmart(w)) (*w->think)(w,dt);
|
||||
|
||||
(*w->solid->update)(w->solid, dt);
|
||||
|
||||
/* Update the sound. */
|
||||
if(w->voice)
|
||||
voice_update(w->voice, w->solid->pos.x, w->solid->pos.y,
|
||||
w->solid->vel.x, w->solid->vel.y);
|
||||
}
|
||||
|
||||
/* Good shot. */
|
||||
@ -439,10 +428,7 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
|
||||
vect_cadd(&v, outfit->u.blt.speed*cos(rdir), outfit->u.blt.speed*sin(rdir));
|
||||
w->timer += outfit->u.blt.range/outfit->u.blt.speed;
|
||||
w->solid = solid_create(mass, rdir, pos, &v);
|
||||
w->voice = sound_addVoice(VOICE_PRIORITY_BOLT,
|
||||
w->solid->pos.x, w->solid->pos.y,
|
||||
w->solid->vel.x, w->solid->vel.y,
|
||||
w->outfit->u.blt.sound, 0);
|
||||
sound_play(w->outfit->u.blt.sound);
|
||||
break;
|
||||
|
||||
/* Treat seekers togther. */
|
||||
@ -452,9 +438,6 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
|
||||
w->lockon = outfit->u.amm.lockon;
|
||||
w->timer = outfit->u.amm.duration;
|
||||
w->solid = solid_create(mass, dir, pos, vel);
|
||||
w->voice = sound_addVoice(VOICE_PRIORITY_AMMO,
|
||||
w->solid->pos.x, w->solid->pos.y,
|
||||
w->solid->vel.x, w->solid->vel.y, w->outfit->u.amm.sound, 0);
|
||||
|
||||
/* If they are seeking a pilot, increment lockon counter. */
|
||||
pilot_target = pilot_get(target);
|
||||
@ -467,11 +450,11 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2*
|
||||
w->think = think_seeker;
|
||||
else if(outfit->type == OUTFIT_TYPE_MISSILE_SEEK_SMART_AMMO)
|
||||
w->think = think_smart;*/
|
||||
sound_play(w->outfit->u.amm.sound);
|
||||
break;
|
||||
|
||||
/* Just dump it where the player is. */
|
||||
default:
|
||||
w->voice = NULL;
|
||||
w->solid = solid_create(mass, dir, pos, vel);
|
||||
break;
|
||||
}
|
||||
@ -562,7 +545,6 @@ static void weapon_destroy(Weapon* w, WeaponLayer layer) {
|
||||
|
||||
/* Clear the weapon. */
|
||||
static void weapon_free(Weapon* w) {
|
||||
sound_delVoice(w->voice);
|
||||
solid_free(w->solid);
|
||||
free(w);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user