A 3d fps game made in OpenGL
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
Symmetry/src/game/sound.c

318 lines
8.2 KiB

#include "sound.h"
#include "../common/log.h"
#include "../common/array.h"
#include "../common/hashmap.h"
#include "../common/variant.h"
#include "../common/string_utils.h"
#include "file_io.h"
#include <assert.h>
#include <stdio.h>
#include <soloud_c.h>
struct Sound_Source_Buffer
{
int type;
union
{
Wav* wav;
WavStream* wavstream;
};
};
struct Sound_State
{
Soloud* soloud_context;
float volume;
};
static struct Sound_State sound_state =
{
.soloud_context = NULL,
.volume = 1.f
};
static struct Hashmap* sound_sources = NULL;
bool sound_init(void)
{
sound_sources = hashmap_new();
sound_state.soloud_context = Soloud_create();
if(!sound_state.soloud_context)
{
log_error("sound:init", "Failed to create sound context");
return false;
}
Soloud_initEx(sound_state.soloud_context, SOLOUD_CLIP_ROUNDOFF | SOLOUD_ENABLE_VISUALIZATION, SOLOUD_AUTO, SOLOUD_AUTO, SOLOUD_AUTO, SOLOUD_AUTO);
Soloud_setGlobalVolume(sound_state.soloud_context, 4);
Soloud_set3dListenerParameters(sound_state.soloud_context,
0.f, 0.f, 0.f, // Position
0.f, 0.f, -1.f, // At
0.f, 1.f, 0.f); // Up
log_message("Sound initialized with %s", Soloud_getBackendString(sound_state.soloud_context));
return true;
}
void sound_listener_update(float apos_x, float apos_y, float apos_z,
float afwd_x, float afwd_y, float afwd_z,
float aup_x, float aup_y, float aup_z)
{
Soloud_set3dListenerParameters(sound_state.soloud_context,
apos_x, apos_y, apos_z, // Position
afwd_x, afwd_y, afwd_z, // At
aup_x, aup_y, aup_z); // Up
}
void sound_volume_set(float volume)
{
if(volume < 0.f) volume = 0.f;
sound_state.volume = volume;
Soloud_setGlobalVolume(sound_state.soloud_context, sound_state.volume);
}
void sound_update_3d(void)
{
Soloud_update3dAudio(sound_state.soloud_context);
}
void sound_cleanup(void)
{
char* key = NULL;
struct Variant* value = NULL;
HASHMAP_FOREACH(sound_sources, key, value)
{
struct Sound_Source_Buffer* source = value->val_voidptr;
sound_source_stop_all(source);
switch(source->type)
{
case ST_WAV: Wav_destroy(source->wav); break;
case ST_WAV_STREAM: WavStream_destroy(source->wavstream); break;
}
free(source);
}
hashmap_free(sound_sources);
Soloud_deinit(sound_state.soloud_context);
Soloud_destroy(sound_state.soloud_context);
sound_state.volume = 0.f;
sound_state.soloud_context = NULL;
}
void sound_source_instance_destroy(uint source_instance)
{
Soloud_stop(sound_state.soloud_context, source_instance);
}
void sound_source_instance_update_position(uint source_instance, float apos_x, float apos_y, float apos_z)
{
Soloud_set3dSourceParameters(sound_state.soloud_context, source_instance, apos_x, apos_y, apos_z);
}
uint sound_source_instance_create(struct Sound_Source_Buffer* source, bool is3d)
{
assert(source);
uint source_instance = 0;
if(is3d)
{
source_instance = Soloud_play3dEx(sound_state.soloud_context,
source->type == ST_WAV ? source->wav : source->wavstream,
0.f, 0.f, 0.f,
0.f, 0.f, 0.f,
1.f,
true,
0);
}
else
{
source_instance = Soloud_playEx(sound_state.soloud_context, source->type == ST_WAV ? source->wav : source->wavstream, 1.f, 0.0f, true, 0);
}
return source_instance;
}
void sound_source_instance_volume_set(uint source_instance, float volume)
{
if(volume < 0.f) volume = 0.f;
Soloud_setVolume(sound_state.soloud_context, source_instance, volume);
}
void sound_source_instance_loop_set(uint source_instance, bool loop)
{
Soloud_setLooping(sound_state.soloud_context, source_instance, loop);
}
void sound_source_instance_play(uint source_instance)
{
Soloud_setPause(sound_state.soloud_context, source_instance, false);
}
void sound_source_instance_pause(uint source_instance)
{
Soloud_setPause(sound_state.soloud_context, source_instance, true);
}
void sound_source_instance_rewind(uint source_instance)
{
Soloud_seek(sound_state.soloud_context, source_instance, 0.0);
}
void sound_source_instance_stop(uint source_instance)
{
Soloud_stop(sound_state.soloud_context, source_instance);
}
void sound_source_instance_min_max_distance_set(uint source_instance, float min_distance, float max_distance)
{
Soloud_set3dSourceMinMaxDistance(sound_state.soloud_context, source_instance, min_distance, max_distance);
}
void sound_source_instance_attenuation_set(uint source_instance, int attenuation_type, float rolloff_factor)
{
Soloud_set3dSourceAttenuation(sound_state.soloud_context, source_instance, attenuation_type, rolloff_factor);
}
float sound_source_instance_volume_get(uint source_instance)
{
return Soloud_getVolume(sound_state.soloud_context, source_instance);
}
bool sound_source_instance_loop_get(uint source_instance)
{
return Soloud_getLooping(sound_state.soloud_context, source_instance);
}
bool sound_source_instance_is_paused(uint source_instance)
{
return Soloud_getPause(sound_state.soloud_context, source_instance);
}
struct Sound_Source_Buffer* sound_source_create(const char* filename, int type)
{
if(!filename) return NULL;
struct Sound_Source_Buffer* source = NULL;
long size = 0L;
char* memory = io_file_read(DIRT_INSTALL, filename, "rb", &size);
//See if we've already loaded this file
if(hashmap_value_exists(sound_sources, filename))
{
source = (struct Sound_Source_Buffer*)hashmap_ptr_get(sound_sources, filename);
return source;
}
source = malloc(sizeof(*source));
if(!source)
{
log_error("sound:source_create", "Out of memory!");
return NULL;
}
switch(type)
{
case ST_WAV:
{
Wav* wave = Wav_create();
int rc = Wav_loadMem(wave, memory, (uint)size);
if(rc != 0)
{
log_error("sound:source_create", "Failed to load %s, Soloud: %s", filename, Soloud_getErrorString(sound_state.soloud_context, rc));
free(source);
return 0;
}
source->type = ST_WAV;
source->wav = wave;
}
break;
case ST_WAV_STREAM:
{
WavStream* wave_stream = WavStream_create();
int rc = WavStream_loadMem(wave_stream, memory, (uint)size);
if(rc != 0)
{
log_error("sound:source_create", "Failed to load %s, Soloud: %s", filename, Soloud_getErrorString(sound_state.soloud_context, rc));
free(source);
return 0;
}
source->type = ST_WAV_STREAM;
}
break;
default: log_error("sound:source_create", "Invalid source type %d", type); return 0;
}
hashmap_ptr_set(sound_sources, filename, (void*)source);
return source;
}
struct Sound_Source_Buffer* sound_source_get(const char* name)
{
struct Sound_Source_Buffer* source = NULL;
if(hashmap_value_exists(sound_sources, name))
{
source = (struct Sound_Source_Buffer*)hashmap_ptr_get(sound_sources, name);
}
return source;
}
void sound_source_destroy(const char* name)
{
struct Sound_Source_Buffer* source = sound_source_get(name);
if(source)
{
sound_source_stop_all(source);
switch(source->type)
{
case ST_WAV: Wav_destroy(source->wav); break;
case ST_WAV_STREAM: WavStream_destroy(source->wavstream); break;
}
free(source);
}
hashmap_value_remove(sound_sources, name);
}
void sound_source_volume_set(struct Sound_Source_Buffer* source, float volume)
{
assert(source);
switch(source->type)
{
case ST_WAV: Wav_setVolume(source->wav, volume); break;
case ST_WAV_STREAM: WavStream_setVolume(source->wavstream, volume); break;
}
}
void sound_source_loop_set(struct Sound_Source_Buffer* source, bool loop)
{
assert(source);
switch(source->type)
{
case ST_WAV: Wav_setLooping(source->wav, loop); break;
case ST_WAV_STREAM: WavStream_setLooping(source->wavstream, loop); break;
}
}
void sound_source_stop_all(struct Sound_Source_Buffer* source)
{
assert(source);
switch(source->type)
{
case ST_WAV: Soloud_stopAudioSource(sound_state.soloud_context, source->wav); break;
case ST_WAV_STREAM: Soloud_stopAudioSource(sound_state.soloud_context, source->wavstream); break;
}
}
void sound_source_min_max_distance_set(struct Sound_Source_Buffer* source, float min_distance, float max_distance)
{
assert(source);
switch(source->type)
{
case ST_WAV: Wav_set3dMinMaxDistance(source->wav, min_distance, max_distance); break;
case ST_WAV_STREAM: WavStream_set3dMinMaxDistance(source->wavstream, min_distance, max_distance); break;
}
}