You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
4.2 KiB
D
173 lines
4.2 KiB
D
/*
|
|
OpenMW - The completely unofficial reimplementation of Morrowind
|
|
Copyright (C) 2008 Nicolay Korslund
|
|
Email: < korslund@gmail.com >
|
|
WWW: http://openmw.snaptoad.com/
|
|
|
|
This file (sfx.d) is part of the OpenMW package.
|
|
|
|
OpenMW is distributed as free software: you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License
|
|
version 3, as published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
version 3 along with this program. If not, see
|
|
http://www.gnu.org/licenses/ .
|
|
|
|
*/
|
|
|
|
module sound.sfx;
|
|
|
|
import sound.audio;
|
|
import sound.al;
|
|
|
|
import core.config;
|
|
import core.resource;
|
|
|
|
import std.string;
|
|
|
|
extern (C) ALuint alutCreateBufferFromFile(char *filename);
|
|
|
|
// Handle for a sound resource. This struct represents one sound
|
|
// effect file (not a music file, those are handled differently
|
|
// because of their size.) From this handle we may get instances,
|
|
// which may be played and managed independently of each other. TODO:
|
|
// Let the resource manager worry about only opening one resource per
|
|
// file, when to kill resources, etc.
|
|
struct SoundFile
|
|
{
|
|
ALuint bID;
|
|
char[] name;
|
|
bool loaded;
|
|
|
|
private int refs;
|
|
|
|
private void fail(char[] msg)
|
|
{
|
|
throw new SoundException(format("SoundFile '%s'", name), msg);
|
|
}
|
|
|
|
// Load a sound resource.
|
|
void load(char[] file)
|
|
{
|
|
name = file;
|
|
|
|
loaded = true;
|
|
refs = 0;
|
|
|
|
bID = alutCreateBufferFromFile(toStringz(file));
|
|
if(!bID) fail("Failed to open sound file " ~ file);
|
|
}
|
|
|
|
// Get an instance of this resource.
|
|
// FIXME: Should not call fail() here since it's quite possible for this to
|
|
// fail (on hardware drivers). When it does, it should check for an existing
|
|
// sound it doesn't need and kill it, then try again
|
|
SoundInstance getInstance()
|
|
{
|
|
SoundInstance si;
|
|
si.owner = this;
|
|
alGenSources(1, &si.inst);
|
|
if(checkALError() != AL_NO_ERROR || !si.inst)
|
|
fail("Failed to instantiate sound resource");
|
|
|
|
alSourcei(si.inst, AL_BUFFER, cast(ALint)bID);
|
|
if(checkALError() != AL_NO_ERROR)
|
|
{
|
|
alDeleteSources(1, &si.inst);
|
|
fail("Failed to load sound resource");
|
|
}
|
|
refs++;
|
|
|
|
return si;
|
|
}
|
|
|
|
// Return the sound instance when you're done with it
|
|
private void returnInstance(ALuint sid)
|
|
{
|
|
refs--;
|
|
alSourceStop(sid);
|
|
alDeleteSources(1, &sid);
|
|
if(refs == 0) unload();
|
|
}
|
|
|
|
// Unload the resource.
|
|
void unload()
|
|
{
|
|
loaded = false;
|
|
alDeleteBuffers(1, &bID);
|
|
}
|
|
}
|
|
|
|
struct SoundInstance
|
|
{
|
|
ALuint inst;
|
|
SoundFile *owner;
|
|
|
|
// Return this instance to the owner
|
|
void kill()
|
|
{
|
|
owner.returnInstance(inst);
|
|
owner = null;
|
|
}
|
|
|
|
// Start playing a sound.
|
|
void play()
|
|
{
|
|
alSourcePlay(inst);
|
|
checkALError();
|
|
}
|
|
|
|
// Go buy a cookie
|
|
void stop()
|
|
{
|
|
alSourceStop(inst);
|
|
checkALError();
|
|
}
|
|
|
|
// Set parameters such as max volume and range
|
|
void setParams(float volume, float minRange, float maxRange, bool repeat=false)
|
|
in
|
|
{
|
|
assert(volume >= 0 && volume <= 1.0, "Volume out of range");
|
|
}
|
|
body
|
|
{
|
|
alSourcef(inst, AL_GAIN, volume);
|
|
alSourcef(inst, AL_REFERENCE_DISTANCE, minRange);
|
|
alSourcef(inst, AL_MAX_DISTANCE, maxRange);
|
|
alSourcei(inst, AL_LOOPING, repeat ? AL_TRUE : AL_FALSE);
|
|
alSourcePlay(inst);
|
|
checkALError();
|
|
}
|
|
|
|
// Set 3D position of sounds. Need to convert from app's world coords to
|
|
// standard left-hand coords
|
|
void setPos(float x, float y, float z)
|
|
{
|
|
alSource3f(inst, AL_POSITION, x, z, -y);
|
|
checkALError();
|
|
}
|
|
|
|
static void setPlayerPos(float x, float y, float z,
|
|
float frontx, float fronty, float frontz,
|
|
float upx, float upy, float upz)
|
|
{
|
|
ALfloat orient[6];
|
|
orient[0] = frontx;
|
|
orient[1] = frontz;
|
|
orient[2] =-fronty;
|
|
orient[3] = upx;
|
|
orient[4] = upz;
|
|
orient[5] =-upy;
|
|
alListener3f(AL_POSITION, x, z, -y);
|
|
alListenerfv(AL_ORIENTATION, orient.ptr);
|
|
checkALError();
|
|
}
|
|
}
|