[Add] Basic audio framework and some sounds. Give me another 30 mins and it will work. :)

This commit is contained in:
Allanis 2013-02-22 01:59:19 +00:00
parent ab4d06a707
commit afd612ef17
18 changed files with 411 additions and 3 deletions

View File

@ -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)

View File

@ -37,6 +37,7 @@
</general>
<specific type="6">
<gfx>missile</gfx>
<sound>missile</sound>
<duration>5</duration>
<thrust>1200</thrust>
<turn>200</turn>

View File

@ -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

Binary file not shown.

BIN
snd/music/agriculture.ogg Normal file

Binary file not shown.

Binary file not shown.

BIN
snd/music/liftoff.ogg Normal file

Binary file not shown.

BIN
snd/sounds/engine.wav Normal file

Binary file not shown.

BIN
snd/sounds/laser.wav Normal file

Binary file not shown.

BIN
snd/sounds/missile.wav Normal file

Binary file not shown.

View File

@ -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;

View File

@ -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
View 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.
&section); // 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
View 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);

View File

@ -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.

View File

@ -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
View 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
View 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))