1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-07 12:54:00 +00:00
OpenMW/sound/sfx.d
nkorslund 055d1b1dd6 Added trunk
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@4 ea6a568a-9f4f-0410-981a-c910a81bb256
2008-06-22 18:32:58 +00:00

203 lines
4.3 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.audiere;
import sound.audio;
import core.config;
import core.resource;
import std.string;
// 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
{
AudiereResource res;
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)
{
// Make sure the string is null terminated
assert(*(file.ptr+file.length) == 0);
name = file;
loaded = true;
refs = 0;
res = cpp_openSound(file.ptr);
if(!res) fail("Failed to open sound file " ~ file);
}
// Get an instance of this resource.
SoundInstance getInstance()
{
SoundInstance si;
si.owner = this;
si.inst = cpp_createInstance(res);
if(!si.inst) fail("Failed to instantiate sound resource");
refs++;
return si;
}
// Return the sound instance when you're done with it
private void returnInstance(AudiereInstance inst)
{
refs--;
cpp_destroyInstance(inst);
if(refs == 0) unload();
}
// Unload the resource.
void unload()
{
loaded = false;
cpp_closeSound(res);
}
}
struct SoundInstance
{
AudiereInstance inst;
SoundFile *owner;
float volume, min, max;
float xx, yy, zz; // 3D position
bool playing;
bool repeat;
// Return this instance to the owner
void kill()
{
owner.returnInstance(inst);
}
// Start playing a sound.
void play()
{
playing = true;
cpp_playSound(inst);
if(repeat) cpp_setRepeat(inst);
}
// Go buy a cookie
void stop()
{
cpp_stopSound(inst);
playing = false;
}
// 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
{
this.volume = volume;
min = minRange;
max = maxRange;
this.repeat = repeat;
playing = false;
}
// Set 3D position of sound
void setPos(float x, float y, float z)
{
xx = x;
yy = y;
zz = z;
}
// Currently VERY experimental, panning disabled. At some point we
// will likely switch to OpenAL with built-in 3D sound and dump this
// entirely.
void setPlayerPos(float x, float y, float z)
{
//writef("{%s %s %s} ", x, y, z);
// Distance squared
x -= xx;
y -= yy;
z -= zz;
//writef("[%s %s %s] ", x, y, z);
float r2 = (x*x + y*y + z*z);
//writefln(r2, " (%s)", max*max);
// If outside range, disable
if(r2 > max*max)
{
// We just moved out of range
if(playing)
{
//writefln("Out of range");
stop();
}
}
else
{
// We just moved into range
if(!playing)
{
//writefln("In range!");
play();
}
}
if(!playing) return;
// Invert distance
if(r2 < 1) r2 = 1;
else r2 = 1/r2;
float vol = 2*r2*min*min;
float pan = 0;//80*x*r2;
//writefln("x=%s, vol=%s, pan=%s", x, vol, pan);
if(vol>1.0) vol = 1.0;
if(pan<-1.0) pan = -1.0;
else if(pan > 1.0) pan = 1.0;
//writefln("vol=", vol, " volume=", vol*volume*config.calcSfxVolume());
cpp_setParams(inst, vol*volume*config.calcSfxVolume(), pan);
}
}