mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-07 12:54:00 +00:00
055d1b1dd6
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@4 ea6a568a-9f4f-0410-981a-c910a81bb256
203 lines
4.3 KiB
D
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);
|
|
}
|
|
}
|