[Add] Basic audio framework and some sounds. Give me another 30 mins and it will work. :)
This commit is contained in:
parent
ab4d06a707
commit
afd612ef17
@ -42,7 +42,7 @@ endif
|
||||
DATA_AI = $(shell find ../scripts/ai/ -name '*.lua')
|
||||
DATA_GFX = $(shell find ../gfx/ -name '*.png')
|
||||
DATA_XML = $(shell find ../dat/ -name '*.xml' -o -name '*.ttf')
|
||||
DATA_SND = $(shell find ../snd/ -name '*.ogg')
|
||||
DATA_SND = $(shell find ../snd/ -name '*.ogg' -o -name '*.wav')
|
||||
DATA = data
|
||||
DATAFILES = $(VERSIONFILE) $(DATA_AI) $(DATA_GFX) $(DATA_XML) $(DATA_SND)
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
</general>
|
||||
<specific type="6">
|
||||
<gfx>missile</gfx>
|
||||
<sound>missile</sound>
|
||||
<duration>5</duration>
|
||||
<thrust>1200</thrust>
|
||||
<turn>200</turn>
|
||||
|
@ -3,6 +3,7 @@
|
||||
<ship name="Merchant Ship">
|
||||
<GFX>ship</GFX>
|
||||
<GUI>minimal</GUI>
|
||||
<sound>engine</sound>
|
||||
<class>1</class>
|
||||
<movement>
|
||||
<thrust>320</thrust>
|
||||
@ -30,6 +31,7 @@
|
||||
<ship name = "Leapard">
|
||||
<GFX>leapard</GFX>
|
||||
<GUI>minimal</GUI>
|
||||
<sound>engine</sound>
|
||||
<class>1</class>
|
||||
<movement>
|
||||
<thrust>400</thrust>
|
||||
@ -57,6 +59,7 @@
|
||||
<ship name="Lancer">
|
||||
<GFX>ship1</GFX>
|
||||
<GUI>minimal</GUI>
|
||||
<sound>engine</sound>
|
||||
<class>2</class>
|
||||
<movement>
|
||||
<thrust>180</thrust>
|
||||
|
BIN
snd/music/Machina.ogg
Normal file
BIN
snd/music/Machina.ogg
Normal file
Binary file not shown.
BIN
snd/music/agriculture.ogg
Normal file
BIN
snd/music/agriculture.ogg
Normal file
Binary file not shown.
BIN
snd/music/galacticbattle.ogg
Normal file
BIN
snd/music/galacticbattle.ogg
Normal file
Binary file not shown.
BIN
snd/music/liftoff.ogg
Normal file
BIN
snd/music/liftoff.ogg
Normal file
Binary file not shown.
BIN
snd/sounds/engine.wav
Normal file
BIN
snd/sounds/engine.wav
Normal file
Binary file not shown.
BIN
snd/sounds/laser.wav
Normal file
BIN
snd/sounds/laser.wav
Normal file
Binary file not shown.
BIN
snd/sounds/missile.wav
Normal file
BIN
snd/sounds/missile.wav
Normal file
Binary file not shown.
12
src/land.c
12
src/land.c
@ -2,6 +2,7 @@
|
||||
#include "pause.h"
|
||||
#include "player.h"
|
||||
#include "rng.h"
|
||||
#include "music.h"
|
||||
#include "land.h"
|
||||
|
||||
// Global/main window.
|
||||
@ -22,6 +23,9 @@
|
||||
#define COMMODITY_WIDTH 400
|
||||
#define COMMODITY_HEIGHT 400
|
||||
|
||||
#define MUSIC_TAKEOFF "liftoff"
|
||||
#define MUSIC_LAND "agriculture"
|
||||
|
||||
int landed = 0;
|
||||
|
||||
static int land_wid = 0; // Primary land window.
|
||||
@ -97,6 +101,11 @@ static void news_close(char* str) {
|
||||
// Land the player.
|
||||
void land(Planet* p) {
|
||||
if(landed) return;
|
||||
|
||||
// Change music.
|
||||
music_load(MUSIC_LAND);
|
||||
music_play();
|
||||
|
||||
planet = p;
|
||||
land_wid = window_create(p->name, -1, -1, LAND_WIDTH, LAND_HEIGHT);
|
||||
|
||||
@ -139,6 +148,9 @@ void land(Planet* p) {
|
||||
void takeoff(void) {
|
||||
if(!landed) return;
|
||||
|
||||
music_load(MUSIC_TAKEOFF);
|
||||
music_play();
|
||||
|
||||
int sw, sh;
|
||||
sw = planet->gfx_space->w;
|
||||
sh = planet->gfx_space->h;
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "pause.h"
|
||||
#include "toolkit.h"
|
||||
#include "pilot.h"
|
||||
#include "sound.h"
|
||||
#include "music.h"
|
||||
|
||||
#define XML_START_ID "Start"
|
||||
#define START_DATA "../dat/start.xml"
|
||||
@ -99,6 +101,11 @@ int main(int argc, char** argv) {
|
||||
|
||||
window_caption();
|
||||
|
||||
// OpenAL sound.
|
||||
if(sound_init()) WARN("Problem setting up sound!");
|
||||
music_load("Machina");
|
||||
music_play();
|
||||
|
||||
// Input.
|
||||
if((indjoystick >= 0) || (namjoystick != NULL)) {
|
||||
if(joystick_init())
|
||||
@ -193,6 +200,8 @@ int main(int argc, char** argv) {
|
||||
joystick_exit(); // Release joystick.
|
||||
input_exit(); // Clean up keybindings.
|
||||
gl_exit(); // Kills video output.
|
||||
sound_exit(); // Kills the sound.
|
||||
SDL_Quit(); // Quits SDL.
|
||||
|
||||
// All is good.
|
||||
exit(EXIT_SUCCESS);
|
||||
|
250
src/music.c
Normal file
250
src/music.c
Normal file
@ -0,0 +1,250 @@
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
#include "SDL.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "log.h"
|
||||
#include "pack.h"
|
||||
#include "music.h"
|
||||
|
||||
#define MUSIC_PLAYING (2<<0)
|
||||
#define MUSIC_KILL (9<<0)
|
||||
#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)
|
||||
|
||||
// Saves the music to ram in this structure.
|
||||
typedef struct {
|
||||
char name[32]; // 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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
ov_callbacks ovcall = {
|
||||
.read_func = ovpack_read,
|
||||
.seek_func = NULL,
|
||||
.close_func = NULL,
|
||||
.tell_func = NULL
|
||||
};
|
||||
|
||||
static int stream_loadBuffer(ALuint buffer);
|
||||
static int music_find(void);
|
||||
static int music_loadOGG(const char* filename);
|
||||
static void music_free(void);
|
||||
|
||||
// The thread.
|
||||
static unsigned int music_state = 0;
|
||||
int music_thread(void* unused) {
|
||||
(void)unused;
|
||||
|
||||
int active; // Active buffer.
|
||||
ALint stat;
|
||||
|
||||
// Main loop.
|
||||
while(!music_is(MUSIC_KILL)) {
|
||||
if(music_is(MUSIC_PLAYING)) {
|
||||
SDL_mutexP(music_vorbis_lock); // Lock the mutex.
|
||||
|
||||
// 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 the buffer loaded.
|
||||
alSourcePlay(music_source);
|
||||
|
||||
active = 1; // Load second buffer.
|
||||
if(stream_loadBuffer(music_buffer[active])) music_rm(MUSIC_PLAYING);
|
||||
alSourceQueueBuffers(music_source, 1, &music_buffer[active]);
|
||||
|
||||
active = 0; // dive into the loop.
|
||||
while(music_is(MUSIC_PLAYING)) {
|
||||
alGetSourcei(music_source, AL_BUFFERS_PROCESSED, &stat);
|
||||
if(stat > 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;
|
||||
}
|
||||
SDL_Delay(0);
|
||||
}
|
||||
alSourceStop(music_source);
|
||||
alSourceUnqueueBuffers(music_source, 2, music_buffer);
|
||||
|
||||
SDL_mutexV(music_vorbis_lock);
|
||||
}
|
||||
SDL_Delay(0); // We must not kill resources.
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stream_loadBuffer(ALuint buffer) {
|
||||
int size, section, result;
|
||||
char data[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.
|
||||
data + size, // Data.
|
||||
BUFFER_SIZE - size, // Amount to read.
|
||||
0, // Big endian?.
|
||||
2, // 16 bit.
|
||||
1, // Signed.
|
||||
§ion); // Current bitstream.
|
||||
|
||||
if(result == 0) return 1;
|
||||
|
||||
size += result;
|
||||
if(size == BUFFER_SIZE) break; // Buffer is full.
|
||||
}
|
||||
alBufferData(buffer, AL_FORMAT_STEREO16, data, size, music_vorbis.info->rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Init/Exit.
|
||||
int music_init(void) {
|
||||
music_vorbis_lock = SDL_CreateMutex();
|
||||
music_find();
|
||||
music_vorbis.file.fd = 0; // Indication that it's not loaded..
|
||||
alGenBuffers(2, music_buffer);
|
||||
alGenSources(1, &music_source);
|
||||
alSourcef(music_source, AL_ROLLOFF_FACTOR, 0.);
|
||||
alSourcei(music_source, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Internal music loading ruitines.
|
||||
static int music_loadOGG(const char* filename) {
|
||||
// Free currently loaded ogg.
|
||||
music_free();
|
||||
|
||||
SDL_mutexP(music_vorbis_lock);
|
||||
|
||||
// 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;
|
||||
|
||||
SDL_mutexV(music_vorbis_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int music_find(void) {
|
||||
char** files;
|
||||
uint32_t nfiles, i;
|
||||
char tmp[64];
|
||||
int len;
|
||||
|
||||
// Get the file list.
|
||||
files = pack_listfiles(data, &nfiles);
|
||||
|
||||
// Load the profiles.
|
||||
for(i = 0; i < nfiles; i++)
|
||||
if((strncmp(files[i], MUSIC_PREFIX, strlen(MUSIC_PREFIX))==0) &&
|
||||
(strncmp(files[i] + strlen(files[i]) - strlen(MUSIC_SUFFIX),
|
||||
MUSIC_SUFFIX, strlen(MUSIC_SUFFIX))==0)) {
|
||||
|
||||
// Grow the selection size.
|
||||
music_selection = realloc(music_selection, ++nmusic_selection*sizeof(char*));
|
||||
|
||||
// Remove the prefix and suffix.
|
||||
len = strlen(files[i]) - strlen(MUSIC_SUFFIX MUSIC_PREFIX);
|
||||
strncpy(tmp, files[i] + strlen(MUSIC_PREFIX), len);
|
||||
tmp[len] = '\0';
|
||||
|
||||
music_selection[nmusic_selection-1] = strdup(tmp);
|
||||
}
|
||||
// Free the char* allocated by pack.
|
||||
for(i = 0; i < nfiles; i++)
|
||||
free(files[i]);
|
||||
free(files);
|
||||
|
||||
DEBUG("Loaded %d song%c", nmusic_selection, (nmusic_selection==1)?' ':'s');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void music_free(void) {
|
||||
SDL_mutexP(music_vorbis_lock);
|
||||
|
||||
if(music_vorbis.file.fd != 0) {
|
||||
ov_clear(&music_vorbis.stream);
|
||||
pack_close(&music_vorbis.file);
|
||||
}
|
||||
|
||||
SDL_mutexV(music_vorbis_lock);
|
||||
}
|
||||
|
||||
// Music control functions.
|
||||
void music_load(const char* name) {
|
||||
int i;
|
||||
char tmp[64];
|
||||
|
||||
music_stop();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void music_play(void) {
|
||||
music_set(MUSIC_PLAYING);
|
||||
}
|
||||
|
||||
void music_stop(void) {
|
||||
music_rm(MUSIC_PLAYING);
|
||||
}
|
||||
|
||||
void music_kill(void) {
|
||||
music_set(MUSIC_KILL);
|
||||
}
|
||||
|
15
src/music.h
Normal file
15
src/music.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
// Thread.
|
||||
int music_thread(void* unused);
|
||||
void music_kill(void);
|
||||
|
||||
// Init/Exit.
|
||||
int music_init(void);
|
||||
void music_exit(void);
|
||||
|
||||
// Music control.
|
||||
void music_load(const char* name);
|
||||
void music_play(void);
|
||||
void music_stop(void);
|
||||
|
@ -532,8 +532,7 @@ int gl_init(void) {
|
||||
|
||||
// Clean up our mess.
|
||||
void gl_exit(void) {
|
||||
//SDL_ShowCursor(SDL_ENABLE);
|
||||
SDL_Quit();
|
||||
|
||||
}
|
||||
|
||||
// Saves a png.
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "rng.h"
|
||||
#include "land.h"
|
||||
#include "toolkit.h"
|
||||
#include "sound.h"
|
||||
#include "player.h"
|
||||
|
||||
#define XML_GUI_ID "GUIs" // XML section identifier.
|
||||
|
102
src/sound.c
Normal file
102
src/sound.c
Normal file
@ -0,0 +1,102 @@
|
||||
#include <sys/stat.h>
|
||||
#include <AL/alc.h>
|
||||
#include "SDL.h"
|
||||
#include "SDL_thread.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "log.h"
|
||||
#include "pack.h"
|
||||
#include "music.h"
|
||||
#include "sound.h"
|
||||
|
||||
// This isn't always set?
|
||||
#ifndef AL_FORMAT_VORBIS_EXT
|
||||
#define AL_FORMAT_VORBIS_EXT 0x10003
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
ALfloat x, y;
|
||||
} alVector;
|
||||
|
||||
static ALCcontext* al_context = NULL;
|
||||
static ALCdevice* al_device = NULL;
|
||||
|
||||
static SDL_Thread* music_player = NULL;
|
||||
|
||||
int sound_init(void) {
|
||||
// Open the default device.
|
||||
al_device = alcOpenDevice(NULL);
|
||||
if(al_device == NULL) {
|
||||
WARN("Unable to open default sound device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create the OpenAL context.
|
||||
al_context = alcCreateContext(al_device, NULL);
|
||||
if(al_context == NULL) {
|
||||
WARN("Unable to create OpenAL context");
|
||||
return -2;
|
||||
}
|
||||
|
||||
// We use the vorbis extension for AL to load it easily.
|
||||
if(alIsExtensionPresent("AL_EXT_vorbis") == AL_FALSE) {
|
||||
WARN("AL_EXT_vorbis not available in OpenAL context!");
|
||||
return -3;
|
||||
}
|
||||
|
||||
// Set active context.
|
||||
if(alcMakeContextCurrent(al_context)==AL_FALSE) {
|
||||
WARN("Failure to set default context");
|
||||
return -4;
|
||||
}
|
||||
|
||||
music_init();
|
||||
music_player = SDL_CreateThread(music_thread, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Clean up after the sound system.
|
||||
void sound_exit(void) {
|
||||
music_stop();
|
||||
music_kill();
|
||||
SDL_WaitThread(music_player, NULL);
|
||||
music_exit();
|
||||
|
||||
if(al_context) {
|
||||
alcMakeContextCurrent(NULL);
|
||||
alcDestroyContext(al_context);
|
||||
}
|
||||
if(al_device) alcCloseDevice(al_device);
|
||||
}
|
||||
|
||||
// Loads a vorbis file.
|
||||
ALuint sound_sndCreate(char* filename) {
|
||||
void* ovdata;
|
||||
unsigned int size;
|
||||
ALenum err;
|
||||
ALuint buf;
|
||||
|
||||
// Get the file data buffer from the packfile.
|
||||
ovdata = pack_readfile(DATA, filename, &size);
|
||||
|
||||
// Bind to OpenAL buffer.
|
||||
alGenBuffers(1, &buf);
|
||||
alBufferData(buf, AL_FORMAT_VORBIS_EXT, ovdata, size, 44800);
|
||||
|
||||
// Errors?
|
||||
if((err = alGetError()) != AL_NO_ERROR) {
|
||||
WARN("OpenAL erro '%d' loading sound '%s'.", err, filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Finish up.
|
||||
free(ovdata);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void sound_sndFree(const ALuint snd) {
|
||||
alDeleteBuffers(1, &snd);
|
||||
}
|
||||
|
16
src/sound.h
Normal file
16
src/sound.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include <AL/al.h>
|
||||
#include "physics.h"
|
||||
|
||||
// Sound subsystem.
|
||||
int sound_init(void);
|
||||
void sound_exit(void);
|
||||
|
||||
// Sound manupulation functions.
|
||||
ALuint sound_sndCreate(char* filename);
|
||||
void sound_sndFree(const ALuint snd);
|
||||
|
||||
// Source manipulation function.
|
||||
#define sound_initSource(s) (alGenSources(1, &(s)))
|
||||
#define sound_delSource(s) (alDeleteSources(1, &(s))
|
||||
|
Loading…
Reference in New Issue
Block a user