mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-29 22:45:36 +00:00
First attempt at OpenAL (thanks to ChrisRobinson)
git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@20 ea6a568a-9f4f-0410-981a-c910a81bb256
This commit is contained in:
parent
fa6f5b81ae
commit
6988814728
21 changed files with 400 additions and 380 deletions
|
@ -37,8 +37,8 @@ Dependencies:
|
|||
Dependencies needed to build OpenMW:
|
||||
|
||||
OGRE 1.4.5 (3d engine)
|
||||
Audiere 1.9.4 (sound engine)
|
||||
OIS-1.0.0 (input system)
|
||||
OpenAL (3d sound system)
|
||||
gcc and g++ (C++ compiler)
|
||||
GNU make (build tool for C++ files)
|
||||
DMD 1.031 (D compiler)
|
||||
|
@ -46,15 +46,15 @@ DMD 1.031 (D compiler)
|
|||
|
||||
|
||||
The above versions are the ones I have tested recently, but other
|
||||
versions might work. OGRE, Audiere and OIS will require their own set
|
||||
of dependencies. I recommend using an automated package tool to
|
||||
install as many of these as possible. On ubuntu, try typing:
|
||||
versions might work. OGRE and OIS will require their own set of
|
||||
dependencies. I recommend using an automated package tool to install
|
||||
as many of these as possible. On ubuntu, try typing:
|
||||
|
||||
sudo apt-get install libogre-dev libaudiere-dev libois-dev build-essential g++ gdc
|
||||
If you want to install Ogre, Audiere or OIS manually, try:
|
||||
sudo apt-get install libogre-dev libalut0 libois-dev build-essential g++ gdc
|
||||
If you want to install Ogre, OpenAL or OIS manually, try:
|
||||
|
||||
OGRE: http://ogre3d.org
|
||||
Audiere: http://audiere.sourceforge.net/
|
||||
OGRE: http://ogre3d.org/
|
||||
Audiere: http://openal.org/
|
||||
OIS: http://sourceforge.net/projects/wgois/
|
||||
|
||||
|
||||
|
@ -87,11 +87,19 @@ installed (a D build tool), type:
|
|||
|
||||
dsss build
|
||||
|
||||
If you do NOT have DSSS, you can compile using the script
|
||||
If you do NOT have DSSS, try using make
|
||||
|
||||
make all
|
||||
|
||||
You might need to edit the Makefile to match your setup. If you are
|
||||
using DMD instead of GDC, try changing the compiler from "gdmd" to
|
||||
"dmd" in the Makefile.
|
||||
|
||||
If all else fails, you can try the build script:
|
||||
|
||||
./build_openmw.sh
|
||||
|
||||
(Currently only works with the GDC compiler)
|
||||
This build method is deprecated and only works with gdc.
|
||||
|
||||
|
||||
|
||||
|
|
77
Makefile
77
Makefile
|
@ -3,28 +3,81 @@
|
|||
# Compiler settings
|
||||
CXX?= g++
|
||||
CXXFLAGS?= -Wall -g
|
||||
DMD=gdmd -version=Posix
|
||||
|
||||
# Some extra flags for niftool and bsatool
|
||||
NIFFLAGS=
|
||||
|
||||
# Compiler settings for Ogre + OIS. Change as needed.
|
||||
OGCC=$(CXX) $(CXXFLAGS) `pkg-config --cflags OGRE OIS`
|
||||
|
||||
# Compiler settings for Audiere
|
||||
AGCC=$(CXX) $(CXXFLAGS) `audiere-config --cxxflags`
|
||||
OGCC=$(CXX) $(CXXFLAGS) `pkg-config --cflags OGRE OIS openal`
|
||||
|
||||
# Ogre C++ files, on the form ogre/cpp_X.cpp. Only the first file is
|
||||
# passed to the compiler, the rest are dependencies.
|
||||
ogre_cpp=ogre framelistener interface overlay bsaarchive
|
||||
|
||||
# Audiere C++ files, on the form sound/cpp_X.cpp.
|
||||
audiere_cpp=audiere
|
||||
|
||||
## The rest of this file is automatic ##
|
||||
ogre_cpp_files=$(ogre_cpp:%=ogre/cpp_%.cpp)
|
||||
audiere_cpp_files=$(audiere_cpp:%=sound/cpp_%.cpp)
|
||||
|
||||
all: cpp_ogre.o cpp_audiere.o
|
||||
ogre_cpp_files=$(ogre_cpp:%=ogre/cpp_%.cpp)
|
||||
|
||||
d_files=$(wildcard */*.d) $(wildcard monster/util/*.d)
|
||||
d_files_nif=$(wildcard nif/*.d) $(wildcard util/*.d) $(wildcard core/memory.d) $(wildcard monster/util/*.d)
|
||||
|
||||
# The NIF object files for niftool and bsatool are put in a separate
|
||||
# directory, since they are built with different flags.
|
||||
d_objs=$(d_files:%.d=objs/%.o)
|
||||
d_objs_nif=$(d_files_nif:%.d=nifobjs/%.o)
|
||||
|
||||
.PHONY: cpp all clean makedirs
|
||||
|
||||
# By default, make will only build the Ogre C++ sources.
|
||||
cpp: cpp_ogre.o
|
||||
|
||||
all: makedirs openmw esmtool niftool bsatool bored
|
||||
|
||||
cpp_ogre.o: $(ogre_cpp_files)
|
||||
$(OGCC) -c $<
|
||||
|
||||
cpp_audiere.o: $(audiere_cpp_files)
|
||||
$(AGCC) -c $<
|
||||
objs/%.o: %.d
|
||||
$(DMD) -c $< -of$@
|
||||
|
||||
nifobjs/%.o: %.d
|
||||
$(DMD) -debug=warnstd -debug=check -debug=statecheck -debug=strict -debug=verbose -c $< -of$@
|
||||
|
||||
# This is a hack for gdmd (dmd-like frontend to gdc), since it does
|
||||
# not automatically create directories as it should.
|
||||
makedirs:
|
||||
mkdir -p objs/bsa
|
||||
mkdir -p objs/core
|
||||
mkdir -p objs/esm
|
||||
mkdir -p objs/input
|
||||
mkdir -p objs/monster/util
|
||||
mkdir -p objs/nif
|
||||
mkdir -p objs/ogre
|
||||
mkdir -p objs/scene
|
||||
mkdir -p objs/sound
|
||||
mkdir -p objs/util
|
||||
mkdir -p nifobjs/nif
|
||||
mkdir -p nifobjs/util
|
||||
mkdir -p nifobjs/core
|
||||
mkdir -p nifobjs/monster/util
|
||||
mkdir -p nifobjs/bsa
|
||||
|
||||
openmw: openmw.d cpp_ogre.o $(d_objs)
|
||||
$(DMD) $^ -of$@ -L-lalut -L-lopenal -L-lOgreMain -L-lOIS
|
||||
|
||||
esmtool: esmtool.d cpp_ogre.o $(d_objs)
|
||||
$(DMD) $^ -of$@ -L-lalut -L-lopenal -L-lOgreMain -L-lOIS
|
||||
|
||||
niftool: niftool.d $(d_objs_nif)
|
||||
$(DMD) $^ -of$@
|
||||
|
||||
bsatool: bsatool.d $(d_objs_nif) bsa/bsafile.d
|
||||
$(DMD) $^ -of$@
|
||||
|
||||
bored: bored.d
|
||||
$(DMD) $^
|
||||
|
||||
clean:
|
||||
-rm cpp_ogre.o
|
||||
-rm openmw esmtool niftool bsatool bored
|
||||
-rm -r objs/ nifobjs/ dsss_objs/
|
||||
|
|
36
README.txt
36
README.txt
|
@ -5,8 +5,8 @@ Written by Nicolay Korslund
|
|||
Email: korslund@gmail.com
|
||||
WWW: http://openmw.snaptoad.com
|
||||
License: See GPL3.txt
|
||||
Current version: 0.3 (still very pre-alpha)
|
||||
Date: 2008 jul. 10
|
||||
Current version: 0.4 (still very pre-alpha)
|
||||
Date: 2008 jul. 12
|
||||
|
||||
|
||||
|
||||
|
@ -18,16 +18,24 @@ Morrowind installed on your system!
|
|||
|
||||
|
||||
|
||||
Release notes for 0.3
|
||||
=====================
|
||||
IMPORTANT: Subversion notes
|
||||
===========================
|
||||
|
||||
As of this release, OpenMW officially builds and runs on Windows. The
|
||||
installation instructions have been split into the files
|
||||
COMPILE-win32.txt and README-win32.txt for the source and binary
|
||||
windows releases respectively, and COMPILE-linux.txt for Linux / Unix
|
||||
systems.
|
||||
The subversion code is currently in the process of switching from
|
||||
Audiere to OpenAL. This means that:
|
||||
|
||||
See the changelog at the end for more changes.
|
||||
- you need to install OpenAL and ALUT
|
||||
- you no longer need Audiere
|
||||
- music does not (currently) work
|
||||
|
||||
Generally true for all SVN versions is that:
|
||||
|
||||
- a given SVN revision is not guaranteed to work or compile
|
||||
- windows compilation scripts are unlikely to work since they are
|
||||
updated less often
|
||||
- README and instructions might be out of date
|
||||
|
||||
See the changelog at the end for an up-to-date list of changes.
|
||||
|
||||
Note: if you are using a localized (non-English) version of Morrowind,
|
||||
the default starting cell (Sud) might not exist, and the esmtool
|
||||
|
@ -105,14 +113,18 @@ Thanks goes out to:
|
|||
|
||||
- Bastien Jansen for continued testing on 64 bit linux.
|
||||
|
||||
- Bethesda Softworks for creating Morrowind!
|
||||
|
||||
- Chris Robinson for OpenAL and ALUT support
|
||||
|
||||
|
||||
|
||||
Changelog:
|
||||
==========
|
||||
|
||||
0.4 (Work in progress)
|
||||
- switched from Audiere to OpenAL (BIG thanks to Chris Robinson)
|
||||
- added complete Makefile (again) as a alternative build tool
|
||||
- cosmetic changes to placate gdc -Wall
|
||||
|
||||
0.3 (2008 jul. 10) - latest release
|
||||
- built and tested on Windows XP
|
||||
- partial support for FreeBSD (exceptions do not work)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
@echo off
|
||||
|
||||
rem See BUILDING-win32.txt for instructions.
|
||||
rem See COMPILE-win32.txt for instructions.
|
||||
|
||||
rem This file assumes it can find Ogre in ..\ogre and
|
||||
rem Audiere in ..\audiere
|
||||
rem This file assumes it can find Ogre in ..\ogro
|
||||
rem TODO: Not updated to OpenAL
|
||||
|
||||
echo Compiling C++ files
|
||||
g++ -c sound\cpp_audiere.cpp -I..\audiere\include
|
||||
|
@ -16,4 +16,4 @@ copy ..\audiere\bin\audiere.dll .
|
|||
copy \windows\system32\d3dx9_30.dll d3dx9d_30.dll
|
||||
|
||||
echo Compiling main program (openmw.exe)
|
||||
gdc openmw.d bsa\*.d core\*.d esm\*.d input\*.d nif\*.d ogre\*.d scene\*.d sound\*.d util\*.d cpp_audiere.o cpp_ogre.o monster\util\*.d ogremain_d.dll ..\audiere\lib\audiere.lib OIS_d.dll -lstdc++ -o openmw.exe
|
||||
gdc -Wall -g openmw.d bsa\*.d core\*.d esm\*.d input\*.d nif\*.d ogre\*.d scene\*.d sound\*.d util\*.d cpp_ogre.o monster\util\*.d ogremain_d.dll OIS_d.dll -lstdc++ -o openmw.exe
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
# See INSTALL-linux.txt for instructions
|
||||
# See COMPILE-linux.txt for instructions
|
||||
|
||||
make || exit 1
|
||||
|
||||
gdc -Wall -Wextra -O2 -g -fversion=Posix -o openmw openmw.d core/*.d ogre/*.d nif/*.d util/*.d bsa/*.d monster/util/*.d input/*.d sound/*.d scene/*.d esm/*.d cpp_*.o -laudiere -lm -lOgreMain -lOIS -lstdc++
|
||||
gdc -Wall -g -fversion=Posix -o openmw openmw.d core/*.d ogre/*.d nif/*.d util/*.d bsa/*.d monster/util/*.d input/*.d sound/*.d scene/*.d esm/*.d cpp_ogre.o -lalut -lopenal -lm -lOgreMain -lOIS -lstdc++
|
||||
|
||||
gdc -Wall -Wextra -O2 -g -fversion=Posix -o esmtool esmtool.d core/*.d ogre/*.d nif/*.d util/*.d bsa/*.d monster/util/*.d input/*.d sound/*.d scene/*.d esm/*.d cpp_*.o -laudiere -lm -lOgreMain -lOIS -lstdc++
|
||||
gdc -Wall -g -fversion=Posix -o esmtool esmtool.d core/*.d ogre/*.d nif/*.d util/*.d bsa/*.d monster/util/*.d input/*.d sound/*.d scene/*.d esm/*.d cpp_ogre.o -lalut -lopenal -lm -lOgreMain -lOIS -lstdc++
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
[openmw.d]
|
||||
# Add libraries and the two C++ object files
|
||||
buildflags = -llOgreMain -llaudiere -llOIS cpp_audiere.o cpp_ogre.o
|
||||
buildflags = -llOgreMain -llalut -llopenal -llOIS cpp_ogre.o
|
||||
|
||||
# Make sure the C++ object files are built first
|
||||
version(Windows) {
|
||||
|
@ -34,7 +34,7 @@ prebuild += dsss clean niftool
|
|||
[esmtool.d]
|
||||
# Because of interdepencies between the ESM code and the resource
|
||||
# manager, we have to include all the C++ stuff.
|
||||
buildflags = -llOgreMain -llaudiere -llOIS cpp_audiere.o cpp_ogre.o
|
||||
buildflags = -llOgreMain -llalut -llopenal -llOIS cpp_ogre.o
|
||||
|
||||
|
||||
|
||||
|
@ -47,6 +47,4 @@ buildflags = -debug=warnstd -debug=check -debug=statecheck -debug=strict -debug=
|
|||
# Clean the nif object files to make sure they are recompiled in debug mode
|
||||
prebuild = dsss clean niftool
|
||||
|
||||
|
||||
|
||||
[bored.d]
|
||||
|
|
|
@ -87,12 +87,12 @@ struct TES3FileContext
|
|||
{
|
||||
char[] filename;
|
||||
uint leftRec, leftSub;
|
||||
size_t leftFile;
|
||||
ulong leftFile;
|
||||
NAME recName, subName;
|
||||
FileType type;
|
||||
Version ver;
|
||||
|
||||
size_t filepos;
|
||||
ulong filepos;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,7 +118,7 @@ struct TES3File
|
|||
|
||||
// These are only used by getRecHeader and getSubHeader for
|
||||
// asserting the file's integrity.
|
||||
uint leftFile; // Number of unread bytes in file
|
||||
ulong leftFile; // Number of unread bytes in file
|
||||
uint leftRec; // Number of unread bytes in record
|
||||
|
||||
// This is used by sub-record readers for integrity checking.
|
||||
|
|
|
@ -154,6 +154,7 @@ void main(char[][] args)
|
|||
case WT.MarksmanThrown: writef("Thrown weapon"); break;
|
||||
case WT.Arrow: writef("Arrow"); break;
|
||||
case WT.Bolt: writef("Bolt"); break;
|
||||
default: assert(0);
|
||||
}
|
||||
writefln(" id '%s': name '%s'", n, m.name);
|
||||
|
||||
|
@ -278,6 +279,7 @@ void printRaw()
|
|||
case FileType.Master: writefln("Master"); break;
|
||||
case FileType.Savegame: writefln("Savegame"); break;
|
||||
case FileType.Unknown: writefln("Unknown"); break;
|
||||
default: assert(0);
|
||||
}
|
||||
writef("Version: ");
|
||||
if(isVer12()) writefln("1.2");
|
||||
|
|
|
@ -309,9 +309,13 @@ extern(C) int d_frameStarted(float time)
|
|||
if(sndCumTime > sndRefresh)
|
||||
{
|
||||
float x, y, z;
|
||||
cpp_getCameraPos(&x, &y, &z);
|
||||
float fx, fy, fz;
|
||||
float ux, uy, uz;
|
||||
|
||||
soundScene.update(x,y,z);
|
||||
cpp_getCameraPos(&x, &y, &z);
|
||||
cpp_getCameraOrientation(&fx, &fy, &fz, &ux, &uy, &uz);
|
||||
|
||||
soundScene.update(x,y,z,fx,fy,fz,ux,uy,uz);
|
||||
sndCumTime -= sndRefresh;
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ class NiAutoNormalParticlesData : ShapeData
|
|||
debug(verbose) writef("Active vertices: ");
|
||||
|
||||
// Number of active vertices (always matches count?)
|
||||
activeCount = nifFile.wgetUshortIs(cast(ushort)vertices.length/3);
|
||||
activeCount = nifFile.wgetUshortIs(cast(ushort)(vertices.length/3));
|
||||
|
||||
nifFile.wgetFloat(); // Active radius (?)
|
||||
nifFile.wgetShort(); // Number of valid entries in the following arrays
|
||||
|
|
|
@ -140,10 +140,11 @@ void cpp_createMesh(
|
|||
// Save a screen shot to the given file name
|
||||
void cpp_screenshot(char *filename);
|
||||
|
||||
// Camera controll
|
||||
// Camera control and information
|
||||
void cpp_rotateCamera(float x, float y);
|
||||
void cpp_moveCamera(float x, float y, float z, float r1, float r2, float r3);
|
||||
void cpp_getCameraPos(float *x, float *y, float *z);
|
||||
void cpp_getCameraOrientation(float *fx, float *fy, float *fz, float *ux, float *uy, float *uz);
|
||||
void cpp_moveCameraRel(float x, float y, float z);
|
||||
|
||||
// Do some debug action. Check the menu for today's specials!
|
||||
|
|
|
@ -132,6 +132,20 @@ extern "C" void cpp_getCameraPos(float *x, float *y, float *z)
|
|||
*z = pos[1];
|
||||
}
|
||||
|
||||
// Get current camera orientation
|
||||
extern "C" void cpp_getCameraOrientation(float *fx, float *fy, float *fz,
|
||||
float *ux, float *uy, float *uz)
|
||||
{
|
||||
Vector3 front = mCamera->getDirection();
|
||||
Vector3 up = mCamera->getUp();
|
||||
*fx = front[0];
|
||||
*fy = -front[2];
|
||||
*fz = front[1];
|
||||
*ux = up[0];
|
||||
*uy = -up[2];
|
||||
*uz = up[1];
|
||||
}
|
||||
|
||||
// Move and rotate camera in place. Transforms Morrowind coordinates
|
||||
// to OGRE coordinates.
|
||||
extern "C" void cpp_moveCamera(float x, float y, float z,
|
||||
|
|
6
openmw.d
6
openmw.d
|
@ -359,9 +359,15 @@ void main(char[][] args)
|
|||
|
||||
// Run it until the user tells us to quit
|
||||
startRendering();
|
||||
|
||||
jukebox.disableMusic();
|
||||
battleMusic.disableMusic();
|
||||
}
|
||||
else debug(verbose) writefln("Skipping rendering");
|
||||
|
||||
soundScene.kill();
|
||||
shutdownSound();
|
||||
|
||||
debug(verbose)
|
||||
{
|
||||
writefln();
|
||||
|
|
|
@ -37,10 +37,7 @@ SoundList soundScene;
|
|||
// very long.
|
||||
struct SoundList
|
||||
{
|
||||
// TODO: This is really just a test, a hack. Will be replaced by a
|
||||
// list or similar later.
|
||||
SoundInstance list[50];
|
||||
int index = 0;
|
||||
SoundInstance[] list;
|
||||
|
||||
// Get a sound instance from a Sound struct
|
||||
static SoundInstance getInstance(Sound *s, bool loop=false)
|
||||
|
@ -57,16 +54,33 @@ struct SoundList
|
|||
|
||||
SoundInstance *insert(Sound *snd, bool loop=false)
|
||||
{
|
||||
if(index == 50) return null;
|
||||
|
||||
SoundInstance *s = &list[index++];
|
||||
*s = getInstance(snd, loop);
|
||||
return s;
|
||||
// Reuse a dead instance if one exists
|
||||
foreach(ref s; list)
|
||||
{
|
||||
if(s.owner == null)
|
||||
{
|
||||
s = getInstance(snd, loop);
|
||||
return &s;
|
||||
}
|
||||
}
|
||||
// Otherwise append a new one
|
||||
list ~= getInstance(snd, loop);
|
||||
return &list[$-1];
|
||||
}
|
||||
|
||||
void update(float x, float y, float z)
|
||||
void update(float x, float y, float z,
|
||||
float frontx, float fronty, float frontz,
|
||||
float upx, float upy, float upz)
|
||||
{
|
||||
foreach(ref s; list[0..index])
|
||||
s.setPlayerPos(x,y,z);
|
||||
SoundInstance.setPlayerPos(x,y,z,frontx,fronty,frontz,upx,upy,upz);
|
||||
}
|
||||
|
||||
void kill()
|
||||
{
|
||||
foreach(ref s; list)
|
||||
{
|
||||
if(s.owner) s.kill();
|
||||
}
|
||||
list = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
module sound.al;
|
||||
|
||||
extern(System):
|
||||
|
||||
//Defines
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
module sound.alc;
|
||||
|
||||
extern(System):
|
||||
|
||||
//Definitions
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.snaptoad.com/
|
||||
|
||||
This file (audiere.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/ .
|
||||
|
||||
*/
|
||||
|
||||
// This file exposes the C++ functions that deal directly with the
|
||||
// sound library. The functions are implemented in cpp_audiere.cpp
|
||||
|
||||
module sound.audiere;
|
||||
|
||||
// A sound resource is the handle that represents the resource,
|
||||
// ie. the file.
|
||||
typedef void* AudiereResource;
|
||||
|
||||
// A sound instance is an instance of this resource. We can have
|
||||
// several instances of the same file playing at once. Each instance
|
||||
// has its own volume, file position, pitch, etc.
|
||||
typedef void* AudiereInstance;
|
||||
|
||||
extern(C)
|
||||
{
|
||||
// Open the music device. Returns 0 on success, 1 on failure.
|
||||
int cpp_openDevice();
|
||||
|
||||
// Open a new sound resource. Returns null on failure.
|
||||
AudiereResource cpp_openSound(char* filename);
|
||||
|
||||
// Close a resource.
|
||||
void cpp_closeSound(AudiereResource sound);
|
||||
|
||||
// Create an instance of a sound.
|
||||
AudiereInstance cpp_createInstance(AudiereResource sound);
|
||||
|
||||
// Create an instance by streaming directly from file, and play it.
|
||||
AudiereInstance cpp_playStream(char* filename, float volume);
|
||||
|
||||
// Destroy a previously created instance
|
||||
void cpp_destroyInstance(AudiereInstance instance);
|
||||
|
||||
// Is this instance currently playing?
|
||||
int cpp_isPlaying(AudiereInstance sound);
|
||||
|
||||
// Adjust parameters for this instance.
|
||||
void cpp_setParams(AudiereInstance sound, float volume, float pan);
|
||||
|
||||
// Play a sound.
|
||||
void cpp_playSound(AudiereInstance sound);
|
||||
|
||||
// Set repeat mode on
|
||||
void cpp_setRepeat(AudiereInstance sound);
|
||||
|
||||
// Stop a sound
|
||||
void cpp_stopSound(AudiereInstance sound);
|
||||
}
|
|
@ -26,7 +26,15 @@ module sound.audio;
|
|||
public import sound.sfx;
|
||||
public import sound.music;
|
||||
|
||||
import sound.audiere;
|
||||
import sound.al;
|
||||
import sound.alc;
|
||||
|
||||
ALCdevice *Device = null;
|
||||
ALCcontext *Context = null;
|
||||
|
||||
// Temporarilly use ALUT for data loading until something better is picked
|
||||
extern (C) ALboolean alutInitWithoutContext(int *argc, char **argv);
|
||||
extern (C) ALboolean alutExit();
|
||||
|
||||
class SoundException : Exception
|
||||
{
|
||||
|
@ -38,9 +46,40 @@ MusicManager battleMusic;
|
|||
|
||||
void initializeSound()
|
||||
{
|
||||
if(cpp_openDevice())
|
||||
Device = alcOpenDevice(null);
|
||||
Context = alcCreateContext(Device, null);
|
||||
|
||||
if(!Device || !Context)
|
||||
throw new SoundException("initializeSound()",
|
||||
"Failed to initialize music device");
|
||||
|
||||
alcMakeContextCurrent(Context);
|
||||
alutInitWithoutContext(null, null);
|
||||
|
||||
// Gross HACK: We should use the default model (inverse distance clamped).
|
||||
// But without a proper rolloff factor, distance attenuation is completely
|
||||
// wrong. This at least makes sure the max distance is the 'silence' point
|
||||
alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
|
||||
|
||||
jukebox.initialize("Main");
|
||||
battleMusic.initialize("Battle");
|
||||
}
|
||||
|
||||
void shutdownSound()
|
||||
{
|
||||
alutExit();
|
||||
alcMakeContextCurrent(null);
|
||||
if(Context) alcDestroyContext(Context);
|
||||
Context = null;
|
||||
if(Device) alcCloseDevice(Device);
|
||||
Device = null;
|
||||
}
|
||||
|
||||
ALenum checkALError()
|
||||
{
|
||||
ALenum err = alGetError();
|
||||
if(err != AL_NO_ERROR)
|
||||
writefln("WARNING: Received AL error (%x): %s", err,
|
||||
toString(alGetString(err)));
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
OpenMW - The completely unofficial reimplementation of Morrowind
|
||||
Copyright (C) 2008 Nicolay Korslund
|
||||
Email: < korslund@gmail.com >
|
||||
WWW: http://openmw.snaptoad.com/
|
||||
|
||||
This file (cpp_audiere.cpp) 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/ .
|
||||
|
||||
*/
|
||||
|
||||
#include <audiere.h>
|
||||
#include <iostream>
|
||||
using namespace audiere;
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* Sound, using Audiere. Creates a very simple C interface for
|
||||
* opening, closing and manipulating sounds.
|
||||
*/
|
||||
|
||||
AudioDevicePtr device;
|
||||
|
||||
extern "C" int32_t cpp_openDevice()
|
||||
{
|
||||
device = OpenDevice("");
|
||||
if (!device) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Opens a new sample buffer from a file
|
||||
extern "C" SampleBuffer *cpp_openSound(char* filename)
|
||||
{
|
||||
SampleSourcePtr sample = OpenSampleSource(filename);
|
||||
if(!sample) return NULL;
|
||||
SampleBufferPtr buf = CreateSampleBuffer(sample);
|
||||
buf->ref();
|
||||
return buf.get();
|
||||
}
|
||||
|
||||
// Delete a sample buffer
|
||||
extern "C" void cpp_closeSound(SampleBuffer *buf)
|
||||
{
|
||||
buf->unref();
|
||||
}
|
||||
|
||||
// Get an output stream from a sample buffer.
|
||||
extern "C" OutputStream *cpp_createInstance(SampleBuffer *buf)
|
||||
{
|
||||
SampleSourcePtr sample = buf->openStream();
|
||||
if(!sample) return NULL;
|
||||
|
||||
OutputStreamPtr sound = OpenSound(device, sample, false);
|
||||
|
||||
sound->ref();
|
||||
return sound.get();
|
||||
}
|
||||
|
||||
// Stream a file directly. Used for music.
|
||||
extern "C" OutputStream *cpp_playStream(char* filename, float volume)
|
||||
{
|
||||
OutputStreamPtr sound = OpenSound(device, filename, true);
|
||||
if(sound)
|
||||
{
|
||||
sound->ref();
|
||||
sound->setVolume(volume);
|
||||
sound->play();
|
||||
}
|
||||
return sound.get();
|
||||
}
|
||||
|
||||
extern "C" void cpp_destroyInstance(OutputStream *sound)
|
||||
{
|
||||
sound->unref();
|
||||
}
|
||||
|
||||
extern "C" int32_t cpp_isPlaying(OutputStream *sound)
|
||||
{
|
||||
if(sound && sound->isPlaying()) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void cpp_setParams(OutputStream *sound, float vol, float pan)
|
||||
{
|
||||
if(sound)
|
||||
{
|
||||
sound->setVolume(vol);
|
||||
sound->setPan(pan);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void cpp_playSound(OutputStream *sound)
|
||||
{
|
||||
sound->play();
|
||||
}
|
||||
|
||||
extern "C" void cpp_setRepeat(OutputStream *sound)
|
||||
{
|
||||
sound->setRepeat(true);
|
||||
}
|
||||
|
||||
// Stop the sound
|
||||
extern "C" void cpp_stopSound(OutputStream *sound)
|
||||
{
|
||||
if(sound) sound->stop();
|
||||
}
|
167
sound/music.d
167
sound/music.d
|
@ -23,34 +23,29 @@
|
|||
|
||||
module sound.music;
|
||||
|
||||
import sound.audiere;
|
||||
import sound.audio;
|
||||
import sound.al;
|
||||
|
||||
import std.string;
|
||||
|
||||
import core.config;
|
||||
import core.resource;
|
||||
|
||||
extern (C) ALuint alutCreateBufferFromFile(char *filename);
|
||||
extern (C) ALenum alutGetError();
|
||||
extern (C) ALchar *alutGetErrorString(ALenum err);
|
||||
|
||||
// Simple music player, has a playlist and can pause/resume music.
|
||||
struct MusicManager
|
||||
{
|
||||
private:
|
||||
|
||||
// How often we check if the music has died.
|
||||
const float pollInterval = 2.0;
|
||||
|
||||
// Max file size to load. Files larger than this are streamed.
|
||||
const int loadSize = 1024*1024;
|
||||
|
||||
// How much to add to the volume each second when fading
|
||||
const float fadeInRate = 0.10;
|
||||
const float fadeOutRate = 0.35;
|
||||
|
||||
// Volume
|
||||
float volume, maxVolume;
|
||||
|
||||
// Time since last time we polled
|
||||
float sumTime;
|
||||
ALfloat volume, maxVolume;
|
||||
|
||||
char[] name;
|
||||
|
||||
|
@ -73,7 +68,10 @@ struct MusicManager
|
|||
int index; // Index of next song to play
|
||||
|
||||
bool musicOn;
|
||||
AudiereInstance music;
|
||||
ALuint sID;
|
||||
ALuint bIDs[1];
|
||||
|
||||
ubyte[] readData;
|
||||
|
||||
// Which direction are we currently fading, if any
|
||||
enum Fade { None = 0, In, Out }
|
||||
|
@ -85,6 +83,8 @@ struct MusicManager
|
|||
void initialize(char[] name)
|
||||
{
|
||||
this.name = name;
|
||||
sID = 0;
|
||||
foreach(ref b; bIDs) b = 0;
|
||||
musicOn = false;
|
||||
updateVolume();
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ struct MusicManager
|
|||
// a fade. Even if we are fading, though, the volume should never
|
||||
// be over the max.
|
||||
if(fading == Fade.None || volume > maxVolume) volume = maxVolume;
|
||||
cpp_setParams(music, volume, 0.0);
|
||||
alSourcef(sID, AL_GAIN, volume);
|
||||
}
|
||||
|
||||
// Give a music play list
|
||||
|
@ -120,7 +120,8 @@ struct MusicManager
|
|||
{
|
||||
if(playlist.length < 2) return;
|
||||
|
||||
char[] last = playlist[0];
|
||||
// Get the name of the last song played
|
||||
char[] last = playlist[(index==0) ? ($-1) : (index-1)];
|
||||
|
||||
int left = playlist.length;
|
||||
rndList.length = left;
|
||||
|
@ -166,13 +167,25 @@ struct MusicManager
|
|||
// If music is disabled, do nothing
|
||||
if(!musicOn) return;
|
||||
|
||||
// Kill current track
|
||||
if(music) cpp_destroyInstance(music);
|
||||
music = null;
|
||||
|
||||
// No tracks to play?
|
||||
if(!playlist.length) return;
|
||||
|
||||
// Generate a source to play back with if needed
|
||||
if(!sID)
|
||||
{
|
||||
alGenSources(1, &sID);
|
||||
if(checkALError() != AL_NO_ERROR)
|
||||
return;
|
||||
alSourcei(sID, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
}
|
||||
|
||||
// Kill current track
|
||||
alSourceStop(sID);
|
||||
alSourcei(sID, AL_BUFFER, 0);
|
||||
alDeleteBuffers(bIDs.length, bIDs.ptr);
|
||||
foreach(ref b; bIDs) b = 0;
|
||||
checkALError();
|
||||
|
||||
// End of list? Randomize and start over
|
||||
if(index == playlist.length)
|
||||
{
|
||||
|
@ -180,9 +193,35 @@ struct MusicManager
|
|||
index = 0;
|
||||
}
|
||||
|
||||
music = cpp_playStream(toStringz(playlist[index]), volume);
|
||||
readData.length = 128*1024 / bIDs.length;
|
||||
|
||||
if(!music) fail("Unable to start music track " ~ playlist[index]);
|
||||
// FIXME: Should load up and queue 3 or 4 buffers here instead of trying to
|
||||
// load it all into one (when we switch away from ALUT).
|
||||
char *fname = toStringz(playlist[index]);
|
||||
bIDs[0] = alutCreateBufferFromFile(fname);
|
||||
if(!bIDs[0])
|
||||
{
|
||||
writefln("Unable to load music track %s: %s", playlist[index],
|
||||
toString(alutGetErrorString(alutGetError())));
|
||||
alDeleteSources(1, &sID);
|
||||
checkALError();
|
||||
sID = 0;
|
||||
index++;
|
||||
return;
|
||||
}
|
||||
|
||||
alSourcei(sID, AL_BUFFER, bIDs[0]);
|
||||
alSourcePlay(sID);
|
||||
if(checkALError() != AL_NO_ERROR)
|
||||
{
|
||||
writefln("Unable to start music track %s", playlist[index]);
|
||||
alSourceStop(sID);
|
||||
alDeleteSources(1, &sID);
|
||||
alDeleteBuffers(bIDs.length, bIDs.ptr);
|
||||
checkALError();
|
||||
sID = 0;
|
||||
foreach(ref b; bIDs) b = 0;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
@ -192,7 +231,6 @@ struct MusicManager
|
|||
{
|
||||
if(!config.useMusic) return;
|
||||
|
||||
sumTime = 0;
|
||||
musicOn = true;
|
||||
volume = maxVolume;
|
||||
fading = Fade.None;
|
||||
|
@ -202,9 +240,16 @@ struct MusicManager
|
|||
// Disable music
|
||||
void disableMusic()
|
||||
{
|
||||
if(music) cpp_destroyInstance(music);
|
||||
music = null;
|
||||
musicOn = false;
|
||||
if(sID)
|
||||
{
|
||||
alSourceStop(sID);
|
||||
alDeleteSources(1, &sID);
|
||||
alDeleteBuffers(bIDs.length, bIDs.ptr);
|
||||
checkALError();
|
||||
sID = 0;
|
||||
foreach(ref b; bIDs) b = 0;
|
||||
}
|
||||
musicOn = false;
|
||||
}
|
||||
|
||||
// Pause current track
|
||||
|
@ -218,29 +263,67 @@ struct MusicManager
|
|||
{
|
||||
if(!config.useMusic) return;
|
||||
|
||||
sumTime = 0;
|
||||
volume = 0.0;
|
||||
fading = Fade.In;
|
||||
musicOn = true;
|
||||
if(music) cpp_playSound(music);
|
||||
if(sID) addTime(0);
|
||||
else playNext();
|
||||
}
|
||||
|
||||
// Add time since last frame to the counter. If the accumulated time
|
||||
// has passed the polling interval, then check if the music has
|
||||
// died. The Audiere library has a callback functionality, but it
|
||||
// turned out not to be terribly reliable. Sometimes it was never
|
||||
// called at all. So we have to poll at regular intervals .. :( This
|
||||
// function is also used for fading.
|
||||
// Checks if a stream is playing, filling more data as needed, and restarting
|
||||
// if it stalled or was paused.
|
||||
private bool isPlaying()
|
||||
{
|
||||
if(!sID) return false;
|
||||
/* Use this when we can do streaming..
|
||||
ALint count;
|
||||
alGetSourcei(sID, AL_BUFFERS_PROCESSED, &count);
|
||||
if(checkALError() != AL_NO_ERROR) return false;
|
||||
|
||||
for(int i = 0;i < count;i++)
|
||||
{
|
||||
int length = GetData(readData.ptr, readData.length);
|
||||
if(length <= 0)
|
||||
{
|
||||
if(i == 0)
|
||||
{
|
||||
ALint state;
|
||||
alGetSourcei(sID, AL_SOURCE_STATE, &state);
|
||||
if(checkALError() != AL_NO_ERROR || state == AL_STOPPED)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ALuint bid;
|
||||
alSourceUnqueueBuffers(sID, 1, &bid);
|
||||
if(checkALError() == AL_NO_ERROR)
|
||||
{
|
||||
alBufferData(bid, dataFreq, dataFormat, length, readData.ptr);
|
||||
alSourceQueueBuffers(sID, 1, &bid);
|
||||
checkALError();
|
||||
}
|
||||
}
|
||||
|
||||
ALint state = AL_PLAYING;
|
||||
alGetSourcei(sID, AL_SOURCE_STATE, &state);
|
||||
if(state != AL_PLAYING) alSourcePlay(sID);
|
||||
return (checkALError() == AL_NO_ERROR);
|
||||
*/
|
||||
ALint state;
|
||||
alGetSourcei(sID, AL_SOURCE_STATE, &state);
|
||||
if(checkALError() != AL_NO_ERROR || state == AL_STOPPED) return false;
|
||||
|
||||
if(state != AL_PLAYING) alSourcePlay(sID);
|
||||
return (checkALError() == AL_NO_ERROR);
|
||||
}
|
||||
|
||||
// Check if the music has died. This function is also used for fading.
|
||||
void addTime(float time)
|
||||
{
|
||||
if(!musicOn) return;
|
||||
sumTime += time;
|
||||
if(sumTime > pollInterval)
|
||||
{
|
||||
sumTime = 0;
|
||||
if(!cpp_isPlaying(music)) playNext();
|
||||
}
|
||||
|
||||
if(!isPlaying()) playNext();
|
||||
|
||||
if(fading)
|
||||
{
|
||||
|
@ -263,14 +346,16 @@ struct MusicManager
|
|||
fading = Fade.None;
|
||||
volume = 0.0;
|
||||
|
||||
// We are done fading out, disable music.
|
||||
cpp_stopSound(music);
|
||||
// We are done fading out, disable music. Don't call
|
||||
// enableMusic (or isPlaying) unless you want it to start
|
||||
// again.
|
||||
if(sID) alSourcePause(sID);
|
||||
musicOn = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the new volume
|
||||
cpp_setParams(music, volume, 0.0);
|
||||
if(sID) alSourcef(sID, AL_GAIN, volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
136
sound/sfx.d
136
sound/sfx.d
|
@ -23,14 +23,16 @@
|
|||
|
||||
module sound.sfx;
|
||||
|
||||
import sound.audiere;
|
||||
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,
|
||||
|
@ -39,10 +41,10 @@ import std.string;
|
|||
// file, when to kill resources, etc.
|
||||
struct SoundFile
|
||||
{
|
||||
AudiereResource res;
|
||||
ALuint bID;
|
||||
char[] name;
|
||||
bool loaded;
|
||||
|
||||
|
||||
private int refs;
|
||||
|
||||
private void fail(char[] msg)
|
||||
|
@ -53,36 +55,44 @@ struct SoundFile
|
|||
// 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);
|
||||
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;
|
||||
si.inst = cpp_createInstance(res);
|
||||
if(!si.inst) fail("Failed to instantiate sound resource");
|
||||
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(AudiereInstance inst)
|
||||
private void returnInstance(ALuint sid)
|
||||
{
|
||||
refs--;
|
||||
cpp_destroyInstance(inst);
|
||||
alSourceStop(sid);
|
||||
alDeleteSources(1, &sid);
|
||||
if(refs == 0) unload();
|
||||
}
|
||||
|
||||
|
@ -90,38 +100,34 @@ struct SoundFile
|
|||
void unload()
|
||||
{
|
||||
loaded = false;
|
||||
cpp_closeSound(res);
|
||||
alDeleteBuffers(1, &bID);
|
||||
}
|
||||
}
|
||||
|
||||
struct SoundInstance
|
||||
{
|
||||
AudiereInstance inst;
|
||||
ALuint 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);
|
||||
owner = null;
|
||||
}
|
||||
|
||||
// Start playing a sound.
|
||||
void play()
|
||||
{
|
||||
playing = true;
|
||||
cpp_playSound(inst);
|
||||
if(repeat) cpp_setRepeat(inst);
|
||||
alSourcePlay(inst);
|
||||
checkALError();
|
||||
}
|
||||
|
||||
// Go buy a cookie
|
||||
void stop()
|
||||
{
|
||||
cpp_stopSound(inst);
|
||||
playing = false;
|
||||
alSourceStop(inst);
|
||||
checkALError();
|
||||
}
|
||||
|
||||
// Set parameters such as max volume and range
|
||||
|
@ -132,71 +138,35 @@ struct SoundInstance
|
|||
}
|
||||
body
|
||||
{
|
||||
this.volume = volume;
|
||||
min = minRange;
|
||||
max = maxRange;
|
||||
this.repeat = repeat;
|
||||
playing = false;
|
||||
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 sound
|
||||
// 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)
|
||||
{
|
||||
xx = x;
|
||||
yy = y;
|
||||
zz = z;
|
||||
alSource3f(inst, AL_POSITION, x, z, -y);
|
||||
checkALError();
|
||||
}
|
||||
|
||||
// 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)
|
||||
static void setPlayerPos(float x, float y, float z,
|
||||
float frontx, float fronty, float frontz,
|
||||
float upx, float upy, float upz)
|
||||
{
|
||||
//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);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue