forked from 0ad/0ad
Enables audio on OS X, refs #685, #931. Fixes music not playing after a game, refs #946. This was SVN commit r12428.
This commit is contained in:
parent
2c260660e6
commit
011ba8255e
@ -96,7 +96,12 @@ skycolor = "0 0 0"
|
||||
|
||||
; GENERAL PREFERENCES:
|
||||
|
||||
sound.mastergain = 0.5
|
||||
sound.mastergain = 0.9
|
||||
sound.musicgain = 0.2
|
||||
sound.ambientgain = 0.6
|
||||
sound.actiongain = 0.7
|
||||
sound.bufferCount = 50
|
||||
sound.bufferSize = 65536
|
||||
|
||||
; Camera control settings
|
||||
view.scroll.speed = 120.0
|
||||
|
@ -8,6 +8,7 @@
|
||||
<ConeOuter>360</ConeOuter>
|
||||
<Looping>0</Looping>
|
||||
<RandOrder>1</RandOrder>
|
||||
<Distanceless>1</Distanceless>
|
||||
<RandGain>1</RandGain>
|
||||
<GainUpper>1</GainUpper>
|
||||
<GainLower>0.8</GainLower>
|
||||
|
@ -8,6 +8,7 @@
|
||||
<ConeOuter>360</ConeOuter>
|
||||
<Looping>0</Looping>
|
||||
<RandOrder>1</RandOrder>
|
||||
<Distanceless>1</Distanceless>
|
||||
<RandGain>1</RandGain>
|
||||
<GainUpper>1</GainUpper>
|
||||
<GainLower>0.8</GainLower>
|
||||
|
@ -8,6 +8,7 @@
|
||||
<ConeOuter>360</ConeOuter>
|
||||
<Looping>0</Looping>
|
||||
<RandOrder>1</RandOrder>
|
||||
<Distanceless>1</Distanceless>
|
||||
<RandGain>1</RandGain>
|
||||
<GainUpper>1</GainUpper>
|
||||
<GainLower>0.8</GainLower>
|
||||
|
@ -66,6 +66,20 @@ function newRandomSound(soundType, soundSubType, soundPrePath)
|
||||
|
||||
//console.write("Playing " + randomSoundPath + " ...");
|
||||
|
||||
switch (soundType)
|
||||
{
|
||||
case "music":
|
||||
return new MusicSound(randomSoundPath);
|
||||
break;
|
||||
case "ambient":
|
||||
return new AmbientSound(randomSoundPath);
|
||||
break;
|
||||
case "effect":
|
||||
console.write("am loading effect '*"+randomSoundPath+"*'");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return new Sound(randomSoundPath);
|
||||
}
|
||||
|
||||
|
@ -78,8 +78,8 @@ Music.prototype.updateState = function()
|
||||
case this.states.OFF:
|
||||
if (this.isPlaying())
|
||||
{
|
||||
this.currentMusic.fade(-1, 0.0, 3.0);
|
||||
this.currentMusic = null;
|
||||
var thePlayer = SoundPlayer();
|
||||
thePlayer.stopMusic();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -146,13 +146,7 @@ Music.prototype.getRandomTrack = function(tracks)
|
||||
|
||||
Music.prototype.switchMusic = function(track, fadeInPeriod, isLooping)
|
||||
{
|
||||
if (this.currentMusic)
|
||||
{
|
||||
this.currentMusic.fade(-1, 0.0, 5.0);
|
||||
this.currentMusic = null;
|
||||
}
|
||||
|
||||
this.currentMusic = new Sound(this.RELATIVE_MUSIC_PATH + track);
|
||||
this.currentMusic = new MusicSound(this.RELATIVE_MUSIC_PATH + track);
|
||||
|
||||
if (this.currentMusic)
|
||||
{
|
||||
@ -160,9 +154,6 @@ Music.prototype.switchMusic = function(track, fadeInPeriod, isLooping)
|
||||
this.currentMusic.loop();
|
||||
else
|
||||
this.currentMusic.play();
|
||||
|
||||
if (fadeInPeriod)
|
||||
this.currentMusic.fade(0.0, this.musicGain, fadeInPeriod);
|
||||
}
|
||||
};
|
||||
|
||||
@ -180,6 +171,8 @@ Music.prototype.isPlaying = function()
|
||||
|
||||
Music.prototype.start = function()
|
||||
{
|
||||
var thePlayer = SoundPlayer();
|
||||
thePlayer.startMusic();
|
||||
this.setState(this.states.PEACE);
|
||||
};
|
||||
|
||||
|
@ -297,7 +297,8 @@ function checkPlayerState()
|
||||
if (playerState.state == "defeated")
|
||||
{
|
||||
g_GameEnded = true;
|
||||
global.music.setState(global.music.states.DEFEAT_CUE);
|
||||
// TODO: DEFEAT_CUE is missing?
|
||||
global.music.setState(global.music.states.DEFEAT);
|
||||
|
||||
closeMenu();
|
||||
closeOpenDialogs();
|
||||
@ -551,12 +552,11 @@ function playRandomAmbient(type)
|
||||
// currentAmbient = newRandomSound("ambient", "temperate_", "dayscape");
|
||||
|
||||
const AMBIENT = "audio/ambient/dayscape/day_temperate_gen_03.ogg";
|
||||
currentAmbient = new Sound(AMBIENT);
|
||||
currentAmbient = new AmbientSound(AMBIENT);
|
||||
|
||||
if (currentAmbient)
|
||||
{
|
||||
currentAmbient.loop();
|
||||
currentAmbient.setGain(0.8);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -571,7 +571,7 @@ function stopAmbient()
|
||||
{
|
||||
if (currentAmbient)
|
||||
{
|
||||
currentAmbient.fade(-1, 0.0, 5.0);
|
||||
currentAmbient.free();
|
||||
currentAmbient = null;
|
||||
}
|
||||
}
|
||||
|
@ -212,13 +212,6 @@ function RunDetection(settings)
|
||||
dialog_warnings.push("You are using 260.19.* series NVIDIA drivers, which may crash the game. Please upgrade to 260.19.21 or later.");
|
||||
}
|
||||
|
||||
// http://trac.wildfiregames.com/ticket/685
|
||||
if (os_macosx)
|
||||
{
|
||||
warnings.push("Audio has been disabled, due to problems with OpenAL on OS X.");
|
||||
disable_audio = true;
|
||||
}
|
||||
|
||||
// http://trac.wildfiregames.com/ticket/684
|
||||
// https://bugs.freedesktop.org/show_bug.cgi?id=24047
|
||||
// R600 drivers will advertise support for S3TC but not actually support it,
|
||||
|
@ -535,7 +535,10 @@ function setup_all_libs ()
|
||||
"ps/Network",
|
||||
"ps/GameSetup",
|
||||
"ps/XML",
|
||||
"sound",
|
||||
"soundmanager",
|
||||
"soundmanager/data",
|
||||
"soundmanager/items",
|
||||
"soundmanager/js",
|
||||
"scripting",
|
||||
"maths",
|
||||
"maths/scripting",
|
||||
@ -548,8 +551,14 @@ function setup_all_libs ()
|
||||
"zlib",
|
||||
"boost",
|
||||
"enet",
|
||||
"libcurl",
|
||||
"libcurl"
|
||||
}
|
||||
|
||||
if not _OPTIONS["without-audio"] then
|
||||
table.insert(extern_libs, "openal")
|
||||
table.insert(extern_libs, "vorbis")
|
||||
end
|
||||
|
||||
setup_static_lib_project("engine", source_dirs, extern_libs, {})
|
||||
|
||||
|
||||
@ -569,7 +578,6 @@ function setup_all_libs ()
|
||||
end
|
||||
setup_static_lib_project("graphics", source_dirs, extern_libs, {})
|
||||
|
||||
|
||||
source_dirs = {
|
||||
"tools/atlas/GameInterface",
|
||||
"tools/atlas/GameInterface/Handlers"
|
||||
@ -610,7 +618,6 @@ function setup_all_libs ()
|
||||
"lib/posix",
|
||||
"lib/res",
|
||||
"lib/res/graphics",
|
||||
"lib/res/sound",
|
||||
"lib/sysdep",
|
||||
"lib/tex"
|
||||
}
|
||||
@ -625,11 +632,6 @@ function setup_all_libs ()
|
||||
"cxxtest",
|
||||
}
|
||||
|
||||
if not _OPTIONS["without-audio"] then
|
||||
table.insert(extern_libs, "openal")
|
||||
table.insert(extern_libs, "vorbis")
|
||||
end
|
||||
|
||||
-- CPU architecture-specific
|
||||
if arch == "amd64" then
|
||||
table.insert(source_dirs, "lib/sysdep/arch/amd64");
|
||||
|
@ -1,287 +0,0 @@
|
||||
#include "precompiled.h"
|
||||
#include "ogg.h"
|
||||
|
||||
#if CONFIG2_AUDIO
|
||||
|
||||
#include "lib/external_libraries/openal.h"
|
||||
#include "lib/external_libraries/vorbis.h"
|
||||
|
||||
#include "lib/byte_order.h"
|
||||
#include "lib/file/io/io.h"
|
||||
#include "lib/file/file_system.h"
|
||||
|
||||
|
||||
static Status LibErrorFromVorbis(int err)
|
||||
{
|
||||
switch(err)
|
||||
{
|
||||
case 0:
|
||||
return INFO::OK;
|
||||
case OV_HOLE:
|
||||
return ERR::AGAIN;
|
||||
case OV_EREAD:
|
||||
return ERR::IO;
|
||||
case OV_EFAULT:
|
||||
return ERR::LOGIC;
|
||||
case OV_EIMPL:
|
||||
return ERR::NOT_SUPPORTED;
|
||||
case OV_EINVAL:
|
||||
return ERR::INVALID_PARAM;
|
||||
case OV_ENOTVORBIS:
|
||||
return ERR::NOT_SUPPORTED;
|
||||
case OV_EBADHEADER:
|
||||
return ERR::CORRUPTED;
|
||||
case OV_EVERSION:
|
||||
return ERR::INVALID_VERSION;
|
||||
case OV_ENOTAUDIO:
|
||||
return ERR::_1;
|
||||
case OV_EBADPACKET:
|
||||
return ERR::_2;
|
||||
case OV_EBADLINK:
|
||||
return ERR::_3;
|
||||
case OV_ENOSEEK:
|
||||
return ERR::_4;
|
||||
default:
|
||||
return ERR::FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class VorbisFileAdapter
|
||||
{
|
||||
public:
|
||||
VorbisFileAdapter(const PFile& openedFile)
|
||||
: file(openedFile)
|
||||
, size(FileSize(openedFile->Pathname()))
|
||||
, offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
static size_t Read(void* bufferToFill, size_t itemSize, size_t numItems, void* context)
|
||||
{
|
||||
VorbisFileAdapter* adapter = (VorbisFileAdapter*)context;
|
||||
const off_t sizeRequested = numItems*itemSize;
|
||||
const off_t sizeRemaining = adapter->size - adapter->offset;
|
||||
const size_t sizeToRead = (size_t)std::min(sizeRequested, sizeRemaining);
|
||||
|
||||
io::Operation op(*adapter->file.get(), bufferToFill, sizeToRead, adapter->offset);
|
||||
if(io::Run(op) == INFO::OK)
|
||||
{
|
||||
adapter->offset += sizeToRead;
|
||||
return sizeToRead;
|
||||
}
|
||||
|
||||
errno = EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Seek(void* context, ogg_int64_t offset, int whence)
|
||||
{
|
||||
VorbisFileAdapter* adapter = (VorbisFileAdapter*)context;
|
||||
|
||||
off_t origin = 0;
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
origin = 0;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
origin = adapter->offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
origin = adapter->size+1;
|
||||
break;
|
||||
NODEFAULT;
|
||||
}
|
||||
|
||||
adapter->offset = Clamp(off_t(origin+offset), off_t(0), adapter->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Close(void* context)
|
||||
{
|
||||
VorbisFileAdapter* adapter = (VorbisFileAdapter*)context;
|
||||
adapter->file.reset();
|
||||
return 0; // return value is ignored
|
||||
}
|
||||
|
||||
static long Tell(void* context)
|
||||
{
|
||||
VorbisFileAdapter* adapter = (VorbisFileAdapter*)context;
|
||||
return adapter->offset;
|
||||
}
|
||||
|
||||
private:
|
||||
PFile file;
|
||||
off_t size;
|
||||
off_t offset;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class VorbisBufferAdapter
|
||||
{
|
||||
public:
|
||||
VorbisBufferAdapter(const shared_ptr<u8>& buffer, size_t size)
|
||||
: buffer(buffer)
|
||||
, size(size)
|
||||
, offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
static size_t Read(void* bufferToFill, size_t itemSize, size_t numItems, void* context)
|
||||
{
|
||||
VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
|
||||
const off_t sizeRequested = numItems*itemSize;
|
||||
const off_t sizeRemaining = adapter->size - adapter->offset;
|
||||
const size_t sizeToRead = (size_t)std::min(sizeRequested, sizeRemaining);
|
||||
|
||||
memcpy(bufferToFill, adapter->buffer.get() + adapter->offset, sizeToRead);
|
||||
|
||||
adapter->offset += sizeToRead;
|
||||
return sizeToRead;
|
||||
}
|
||||
|
||||
static int Seek(void* context, ogg_int64_t offset, int whence)
|
||||
{
|
||||
VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
|
||||
|
||||
off_t origin = 0;
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
origin = 0;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
origin = adapter->offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
origin = adapter->size+1;
|
||||
break;
|
||||
NODEFAULT;
|
||||
}
|
||||
|
||||
adapter->offset = Clamp(off_t(origin+offset), off_t(0), adapter->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Close(void* context)
|
||||
{
|
||||
VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
|
||||
adapter->buffer.reset();
|
||||
return 0; // return value is ignored
|
||||
}
|
||||
|
||||
static long Tell(void* context)
|
||||
{
|
||||
VorbisBufferAdapter* adapter = (VorbisBufferAdapter*)context;
|
||||
return adapter->offset;
|
||||
}
|
||||
|
||||
private:
|
||||
shared_ptr<u8> buffer;
|
||||
off_t size;
|
||||
off_t offset;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template <typename Adapter>
|
||||
class OggStreamImpl : public OggStream
|
||||
{
|
||||
public:
|
||||
OggStreamImpl(const Adapter& adapter)
|
||||
: adapter(adapter)
|
||||
{
|
||||
}
|
||||
|
||||
Status Open()
|
||||
{
|
||||
ov_callbacks callbacks;
|
||||
callbacks.read_func = Adapter::Read;
|
||||
callbacks.close_func = Adapter::Close;
|
||||
callbacks.seek_func = Adapter::Seek;
|
||||
callbacks.tell_func = Adapter::Tell;
|
||||
const int ret = ov_open_callbacks(&adapter, &vf, 0, 0, callbacks);
|
||||
if(ret != 0)
|
||||
WARN_RETURN(LibErrorFromVorbis(ret));
|
||||
|
||||
const int link = -1; // retrieve info for current bitstream
|
||||
info = ov_info(&vf, link);
|
||||
if(!info)
|
||||
WARN_RETURN(ERR::INVALID_HANDLE);
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
virtual ALenum Format()
|
||||
{
|
||||
return (info->channels == 1)? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
|
||||
}
|
||||
|
||||
virtual ALsizei SamplingRate()
|
||||
{
|
||||
return info->rate;
|
||||
}
|
||||
|
||||
virtual Status GetNextChunk(u8* buffer, size_t size)
|
||||
{
|
||||
// we may have to call ov_read multiple times because it
|
||||
// treats the buffer size "as a limit and not a request"
|
||||
size_t bytesRead = 0;
|
||||
for(;;)
|
||||
{
|
||||
const int isBigEndian = (BYTE_ORDER == BIG_ENDIAN);
|
||||
const int wordSize = sizeof(i16);
|
||||
const int isSigned = 1;
|
||||
int bitstream; // unused
|
||||
const int ret = ov_read(&vf, (char*)buffer+bytesRead, int(size-bytesRead), isBigEndian, wordSize, isSigned, &bitstream);
|
||||
if(ret == 0) // EOF
|
||||
return (Status)bytesRead;
|
||||
else if(ret < 0)
|
||||
WARN_RETURN(LibErrorFromVorbis(ret));
|
||||
else // success
|
||||
{
|
||||
bytesRead += ret;
|
||||
if(bytesRead == size)
|
||||
return (Status)bytesRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Adapter adapter;
|
||||
OggVorbis_File vf;
|
||||
vorbis_info* info;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Status OpenOggStream(const OsPath& pathname, OggStreamPtr& stream)
|
||||
{
|
||||
PFile file(new File);
|
||||
RETURN_STATUS_IF_ERR(file->Open(pathname, L'r'));
|
||||
|
||||
shared_ptr<OggStreamImpl<VorbisFileAdapter> > tmp(new OggStreamImpl<VorbisFileAdapter>(VorbisFileAdapter(file)));
|
||||
RETURN_STATUS_IF_ERR(tmp->Open());
|
||||
stream = tmp;
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
Status OpenOggNonstream(const PIVFS& vfs, const VfsPath& pathname, OggStreamPtr& stream)
|
||||
{
|
||||
shared_ptr<u8> contents;
|
||||
size_t size;
|
||||
RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, contents, size));
|
||||
|
||||
shared_ptr<OggStreamImpl<VorbisBufferAdapter> > tmp(new OggStreamImpl<VorbisBufferAdapter>(VorbisBufferAdapter(contents, size)));
|
||||
RETURN_STATUS_IF_ERR(tmp->Open());
|
||||
stream = tmp;
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
#endif // CONFIG2_AUDIO
|
@ -1,36 +0,0 @@
|
||||
#ifndef INCLUDED_OGG
|
||||
#define INCLUDED_OGG
|
||||
|
||||
#include "lib/config2.h"
|
||||
|
||||
#if CONFIG2_AUDIO
|
||||
|
||||
#include "lib/external_libraries/openal.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
|
||||
class OggStream
|
||||
{
|
||||
public:
|
||||
virtual ~OggStream() { }
|
||||
virtual ALenum Format() = 0;
|
||||
virtual ALsizei SamplingRate() = 0;
|
||||
|
||||
/**
|
||||
* @return bytes read (<= size) or a (negative) Status
|
||||
**/
|
||||
virtual Status GetNextChunk(u8* buffer, size_t size) = 0;
|
||||
};
|
||||
|
||||
typedef shared_ptr<OggStream> OggStreamPtr;
|
||||
|
||||
extern Status OpenOggStream(const OsPath& pathname, OggStreamPtr& stream);
|
||||
|
||||
/**
|
||||
* A non-streaming OggStream (reading the whole file in advance)
|
||||
* that can cope with archived/compressed files.
|
||||
*/
|
||||
extern Status OpenOggNonstream(const PIVFS& vfs, const VfsPath& pathname, OggStreamPtr& stream);
|
||||
|
||||
#endif // CONFIG2_AUDIO
|
||||
|
||||
#endif // INCLUDED_OGG
|
File diff suppressed because it is too large
Load Diff
@ -1,373 +0,0 @@
|
||||
/* Copyright (c) 2010 Wildfire Games
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OpenAL sound engine. handles sound I/O, buffer suballocation and
|
||||
* voice management/prioritization.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SND_MGR
|
||||
#define INCLUDED_SND_MGR
|
||||
|
||||
#include "lib/res/handle.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
|
||||
/**
|
||||
|
||||
overview
|
||||
--------
|
||||
|
||||
this module provides a moderately high-level sound interface. basic usage
|
||||
is opening a sound and requesting it be played; it is closed automatically
|
||||
when playback has finished (fire and forget).
|
||||
any number of sound play requests may be issued; the most 'important' ones
|
||||
are actually played (necessary due to limited hardware mixing capacity).
|
||||
3d positional sounds (heard to emanate from a given spot) are supported.
|
||||
active sound instances are referenced by Handles, so changing volume etc.
|
||||
during playback is possible (useful for fadeout).
|
||||
|
||||
|
||||
sound setup
|
||||
-----------
|
||||
|
||||
OpenAL provides portable access to the underlying sound hardware, and
|
||||
falls back to software mixing if no acceleration is provided.
|
||||
we allow the user to specify the device to use (in case the default
|
||||
has problems) and maximum number of sources (to reduce mixing cost).
|
||||
|
||||
|
||||
performance
|
||||
-----------
|
||||
much effort has been invested in efficiency: all sound data is cached,
|
||||
so every open() after the first is effectively free. large sound files are
|
||||
streamed from disk to reduce load time and memory usage. hardware mixing
|
||||
resources are suballocated to avoid delays when starting to play.
|
||||
therefore, the user can confidently fire off hundreds of sound requests.
|
||||
finally, lengthy initialization steps are delayed until the sound engine
|
||||
is actually needed (i.e. upon first open()). perceived startup time is
|
||||
therefore reduced - the user sees e.g. our main menu earlier.
|
||||
|
||||
|
||||
terminology
|
||||
-----------
|
||||
|
||||
"hardware voice" refers to mixing resources on the DSP. strictly
|
||||
speaking, we mean 'OpenAL source', but this term is more clear.
|
||||
voice ~= source, unless expensive effects (e.g. EAX) are enabled.
|
||||
note: software mixing usually doesn't have a fixed 'source' cap.
|
||||
"gain" is quantified volume. 1 is unattenuated, 0.5 corresponds to -6 dB,
|
||||
and 0 is silence. this can be set per-source as well as globally.
|
||||
"position" of a sound is within the app's coordinate system,
|
||||
the orientation of which is passed to snd_update.
|
||||
"importance" of a sound derives from the app-assigned priority
|
||||
(e.g. voiceover must not be skipped in favor of seagulls) and
|
||||
distance from the listener. it's calculated by our prioritizer.
|
||||
"virtual source" denotes a sound play request issued by the app.
|
||||
this is in contrast to an actual AL source, which will be mixed
|
||||
into the output channel. the most important VSrc receive an al_src.
|
||||
"sound instances" store playback parameters (e.g. position), and
|
||||
reference the (centrally cached) "sound data" that will be played.
|
||||
|
||||
**/
|
||||
|
||||
|
||||
//
|
||||
// device enumeration
|
||||
//
|
||||
|
||||
/**
|
||||
* prepare to enumerate all device names (this resets the list returned by
|
||||
* snd_dev_next).
|
||||
* may be called each time the device list is needed.
|
||||
*
|
||||
* @return Status; fails iff the requisite OpenAL extension isn't available.
|
||||
* in that case, a "cannot enum device" message should be displayed, but
|
||||
* snd_dev_set need not be called; OpenAL will use its default device.
|
||||
**/
|
||||
extern Status snd_dev_prepare_enum();
|
||||
|
||||
/**
|
||||
* get next device name in list.
|
||||
*
|
||||
* do not call unless snd_dev_prepare_enum succeeded!
|
||||
* not thread-safe! (static data from snd_dev_prepare_enum is used)
|
||||
*
|
||||
* @return device name string, or 0 if all have been returned.
|
||||
**/
|
||||
extern const char* snd_dev_next();
|
||||
|
||||
|
||||
//
|
||||
// sound system setup
|
||||
//
|
||||
|
||||
/**
|
||||
* tell OpenAL to use the specified device in future.
|
||||
*
|
||||
* @param alc_new_dev_name device name string. if 0, revert to
|
||||
* OpenAL's default choice, which will also be used if
|
||||
* this routine is never called.
|
||||
* the device name is typically taken from a config file at init-time;
|
||||
* the snd_dev* enumeration routines above are used to present a list
|
||||
* of choices to the user in the options screen.
|
||||
*
|
||||
* if OpenAL hasn't yet been initialized (i.e. no sounds have been opened),
|
||||
* this just stores the device name for use when init does occur.
|
||||
* note: we can't check now if it's invalid (if so, init will fail).
|
||||
* otherwise, we shut OpenAL down (thereby stopping all sounds) and
|
||||
* re-initialize with the new device. that's fairly time-consuming,
|
||||
* so preferably call this routine before sounds are loaded.
|
||||
*
|
||||
* @return Status (the status returned by OpenAL re-init)
|
||||
**/
|
||||
extern Status snd_dev_set(const char* alc_new_dev_name);
|
||||
|
||||
/**
|
||||
* Set maximum number of voices to play simultaneously;
|
||||
* this can be used to reduce mixing cost on low-end systems.
|
||||
*
|
||||
* @param limit Maximum number of voices. Ignored if higher than
|
||||
* an implementation-defined limit anyway.
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_set_max_voices(size_t limit);
|
||||
|
||||
/**
|
||||
* set amplitude modifier, which is effectively applied to all sounds.
|
||||
* this is akin to a global "volume" control.
|
||||
*
|
||||
* @param gain amplitude modifier. must be non-negative;
|
||||
* 1 -> unattenuated, 0.5 -> -6 dB, 0 -> silence.
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_set_master_gain(float gain);
|
||||
|
||||
|
||||
//
|
||||
// sound instance
|
||||
//
|
||||
|
||||
/**
|
||||
* Open and return a handle to a sound instance.
|
||||
* This loads the sound data and makes it ready for other snd_* APIs.
|
||||
*
|
||||
* @param vfs
|
||||
* @param pathname If a text file (extension ".txt"), it is
|
||||
* assumed to be a definition file containing the sound file name and
|
||||
* its gain (0.0 .. 1.0).
|
||||
* Otherwise, it is taken to be the sound file name and
|
||||
* gain is set to the default of 1.0 (no attenuation).
|
||||
* @return Handle or Status
|
||||
**/
|
||||
extern Handle snd_open(const PIVFS& vfs, const VfsPath& pathname);
|
||||
|
||||
/**
|
||||
* Close the sound instance. If it was playing, it will be stopped.
|
||||
*
|
||||
* Rationale: sounds are already closed automatically when done playing;
|
||||
* this API is provided for completeness only.
|
||||
*
|
||||
* @param hvs Handle to sound instance. Zeroed afterwards.
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_free(Handle& hvs);
|
||||
|
||||
/**
|
||||
* Start playing the sound.
|
||||
*
|
||||
* Notes:
|
||||
* - once done playing, the sound is automatically closed (allows
|
||||
* fire-and-forget play code).
|
||||
* - if no hardware voice is available, this sound may not be
|
||||
* played at all, or in the case of looped sounds, start later.
|
||||
*
|
||||
* @param hvs Handle to VSrc.
|
||||
* @param static_pri (min 0 .. max 1, default 0) indicates which sounds are
|
||||
* considered more important (i.e. will override others when no hardware
|
||||
* voices are available). the static priority is attenuated by
|
||||
* distance to the listener; see snd_update.
|
||||
*
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_play(Handle hvs, float static_pri = 0.0f);
|
||||
|
||||
/**
|
||||
* Change 3d position of the sound source.
|
||||
*
|
||||
* May be called at any time; fails with invalid handle return if
|
||||
* the sound has already been closed (e.g. it never played).
|
||||
*
|
||||
* @param hvs Handle to the sound.
|
||||
* @param x,y,z
|
||||
* @param relative treat (x,y,z) as relative to the listener;
|
||||
* if false (the default), it is the position in world coordinates.
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_set_pos(Handle hvs, float x, float y, float z, bool relative = false);
|
||||
|
||||
/**
|
||||
* change gain (amplitude modifier) of the sound source.
|
||||
*
|
||||
* should not be called during a fade (see note in implementation);
|
||||
* fails with invalid handle return if the sound has already been
|
||||
* closed (e.g. it never played).
|
||||
*
|
||||
* @param gain amplitude modifier. must be non-negative;
|
||||
* 1 -\> unattenuated, 0.5 -\> -6 dB, 0 -\> silence.
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_set_gain(Handle hs, float gain);
|
||||
|
||||
/**
|
||||
* change pitch shift of the sound source.
|
||||
*
|
||||
* may be called at any time; fails with invalid handle return if
|
||||
* the sound has already been closed (e.g. it never played).
|
||||
*
|
||||
* @param pitch shift: 1.0 means no change; each doubling/halving equals a
|
||||
* pitch shift of +/-12 semitones (one octave). zero is invalid.
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_set_pitch(Handle hs, float pitch);
|
||||
|
||||
/**
|
||||
* Enable/disable looping on the sound source.
|
||||
* Used to implement variable-length sounds (e.g. while building).
|
||||
*
|
||||
* May be called at any time; fails with invalid handle return if
|
||||
* the sound has already been closed (e.g. it never played).
|
||||
*
|
||||
* Notes:
|
||||
* - looping sounds are not discarded if they cannot be played for
|
||||
* - lack of a hardware voice at the moment play was requested.
|
||||
* - once looping is again disabled and the sound has reached its end,
|
||||
* the sound instance is freed automatically (as if never looped).
|
||||
*
|
||||
* @param hvs Handle to the sound.
|
||||
* @param loop Boolean to enable/disable lopping on the sound.
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_set_loop(Handle hvs, bool loop);
|
||||
|
||||
/// types of fade in/out operations
|
||||
enum FadeType
|
||||
{
|
||||
FT_NONE, /// currently no fade in progres
|
||||
FT_LINEAR, /// f(t) = t
|
||||
FT_EXPONENTIAL, /// f(t) = t**3
|
||||
FT_S_CURVE, /// cosine curve
|
||||
|
||||
FT_ABORT /// abort and mark pending fade as complete
|
||||
};
|
||||
|
||||
/**
|
||||
* Fade the sound source in or out over time.
|
||||
*
|
||||
* May be called at any time; fails with invalid handle return if
|
||||
* the sound has already been closed (e.g. it never played).
|
||||
*
|
||||
* Gain starts at \<initial_gain\> (immediately) and is moved toward
|
||||
* \<final_gain\> over \<length\> seconds.
|
||||
*
|
||||
* @param hvs Handle to the sound.
|
||||
* @param initial_gain
|
||||
* @param final_gain
|
||||
* @param length
|
||||
* @param type Type of fade curve: linear, exponential or S-curve.
|
||||
*
|
||||
* For guidance on which to use, see
|
||||
* http://www.transom.org/tools/editing_mixing/200309.stupidfadetricks.html
|
||||
* you can also pass FT_ABORT to stop fading (if in progress) and
|
||||
* set gain to the current \<final_gain\> parameter.
|
||||
* Special cases:
|
||||
* - if \<initial_gain\> \< 0 (an otherwise illegal value), the sound's
|
||||
* current gain is used as the start value (useful for fading out).
|
||||
* - if \<final_gain\> is 0, the sound is freed when the fade completes or
|
||||
* is aborted, thus allowing fire-and-forget fadeouts. no cases are
|
||||
* foreseen where this is undesirable, and it is easier to implement
|
||||
* than an extra set-free-after-fade-flag function.
|
||||
*
|
||||
* Note that this function doesn't busy-wait until the fade is complete;
|
||||
* any number of fades may be active at a time (allows cross-fading).
|
||||
* Each snd_update calculates a new gain value for all pending fades.
|
||||
* It is safe to start another fade on the same sound source while
|
||||
* one is already in progress; the old one will be discarded.
|
||||
*
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_fade(Handle hvs, float initial_gain, float final_gain,
|
||||
float length, FadeType type);
|
||||
|
||||
|
||||
//
|
||||
// sound engine
|
||||
//
|
||||
|
||||
/**
|
||||
* (temporarily) disable all sound output.
|
||||
*
|
||||
* because it causes future snd_open calls to immediately abort before they
|
||||
* demand-initialize OpenAL, startup is sped up considerably (500..1000ms).
|
||||
* therefore, this must be called before the first snd_open to have
|
||||
* any effect; otherwise, the cat will already be out of the bag and
|
||||
* we raise a warning.
|
||||
*
|
||||
* rationale: this is a quick'n dirty way of speeding up startup during
|
||||
* development without having to change the game's sound code.
|
||||
*
|
||||
* can later be called to reactivate sound; all settings ever changed
|
||||
* will be applied and subsequent sound load / play requests will work.
|
||||
*
|
||||
* @param disabled
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_disable(bool disabled);
|
||||
|
||||
/**
|
||||
* Perform housekeeping (e.g. streaming); call once a frame.
|
||||
*
|
||||
* All parameters are expressed in world coordinates. they can all be NULL
|
||||
* to avoid updating the listener data; this is useful when the game world
|
||||
* has not been initialized yet.
|
||||
* @param pos listener's position
|
||||
* @param dir listener view direction
|
||||
* @param up listener's local up vector
|
||||
* @return Status
|
||||
**/
|
||||
extern Status snd_update(const float* pos, const float* dir, const float* up);
|
||||
|
||||
/**
|
||||
* find out if a sound is still playing
|
||||
*
|
||||
* @param hvs Handle to the snd to check.
|
||||
* @return bool true if playing
|
||||
**/
|
||||
extern bool snd_is_playing(Handle hvs);
|
||||
|
||||
|
||||
/**
|
||||
* free all resources and shut down the sound system.
|
||||
* call before h_mgr_shutdown.
|
||||
**/
|
||||
extern void snd_shutdown();
|
||||
|
||||
#endif // #ifndef INCLUDED_SND_MGR
|
@ -39,7 +39,6 @@ that of Atlas depending on commandline parameters.
|
||||
#include "lib/ogl.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/external_libraries/libsdl.h"
|
||||
#include "lib/res/sound/snd_mgr.h"
|
||||
|
||||
#include "ps/ArchiveBuilder.h"
|
||||
#include "ps/CConsole.h"
|
||||
@ -320,7 +319,7 @@ static void Frame()
|
||||
// If we are not running a multiplayer game, disable updates when the game is
|
||||
// minimized or out of focus and relinquish the CPU a bit, in order to make
|
||||
// debugging easier.
|
||||
if( g_PauseOnFocusLoss && !g_NetClient && !g_app_has_focus )
|
||||
if(g_PauseOnFocusLoss && !g_NetClient && !g_app_has_focus)
|
||||
{
|
||||
PROFILE3("non-focus delay");
|
||||
need_update = false;
|
||||
@ -375,28 +374,6 @@ static void Frame()
|
||||
g_Game->Update(realTimeSinceLastFrame);
|
||||
|
||||
g_Game->GetView()->Update(float(realTimeSinceLastFrame));
|
||||
|
||||
CCamera* camera = g_Game->GetView()->GetCamera();
|
||||
CMatrix3D& orientation = camera->m_Orientation;
|
||||
float* pos = &orientation._data[12];
|
||||
float* dir = &orientation._data[8];
|
||||
float* up = &orientation._data[4];
|
||||
// HACK: otherwise sound effects are L/R flipped. No idea what else
|
||||
// is going wrong, because the listener and camera are supposed to
|
||||
// coincide in position and orientation.
|
||||
float down[3] = { -up[0], -up[1], -up[2] };
|
||||
|
||||
{
|
||||
PROFILE3("sound update");
|
||||
if (snd_update(pos, dir, down) < 0)
|
||||
debug_printf(L"snd_update failed\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PROFILE3("sound update (0)");
|
||||
if (snd_update(0, 0, 0) < 0)
|
||||
debug_printf(L"snd_update (pos=0 version) failed\n");
|
||||
}
|
||||
|
||||
// Immediately flush any messages produced by simulation code
|
||||
@ -480,8 +457,6 @@ static void RunGameOrAtlas(int argc, const char* argv[])
|
||||
// run non-visual simulation replay if requested
|
||||
if (args.Has("replay"))
|
||||
{
|
||||
snd_disable(true);
|
||||
|
||||
Paths paths(args);
|
||||
g_VFS = CreateVfs(20 * MiB);
|
||||
g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "graphics/LOSTexture.h"
|
||||
#include "graphics/ParticleManager.h"
|
||||
#include "graphics/UnitManager.h"
|
||||
#include "gui/GUIManager.h"
|
||||
#include "lib/timer.h"
|
||||
#include "network/NetClient.h"
|
||||
#include "network/NetServer.h"
|
||||
@ -44,8 +45,7 @@
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpPlayer.h"
|
||||
#include "simulation2/components/ICmpPlayerManager.h"
|
||||
|
||||
#include "gui/GUIManager.h"
|
||||
#include "soundmanager/SoundManager.h"
|
||||
|
||||
extern bool g_GameRestarted;
|
||||
|
||||
@ -294,6 +294,7 @@ bool CGame::Update(const double deltaRealTime, bool doInterpolate)
|
||||
if (doInterpolate)
|
||||
{
|
||||
m_TurnManager->Interpolate(deltaSimTime, deltaRealTime);
|
||||
g_SoundManager->IdleTask();
|
||||
}
|
||||
|
||||
// TODO: maybe we should add a CCmpParticleInterface that passes the interpolation commands
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -17,13 +17,13 @@
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include "ps/ConfigDB.h"
|
||||
#include "ps/CConsole.h"
|
||||
#include "ps/GameSetup/CmdLineArgs.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/res/sound/snd_mgr.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include "soundmanager/SoundManager.h"
|
||||
|
||||
// (these variables are documented in the header.)
|
||||
|
||||
@ -83,9 +83,26 @@ static void LoadGlobals()
|
||||
CFG_GET_USER_VAL("silhouettes", Bool, g_Silhouettes);
|
||||
|
||||
float gain = -1.0f;
|
||||
float musicGain = -1.0f;
|
||||
float ambientGain = -1.0f;
|
||||
float actionGain = -1.0f;
|
||||
int bufferCount = 50;
|
||||
unsigned long bufferSize = 65536;
|
||||
|
||||
CFG_GET_USER_VAL("sound.mastergain", Float, gain);
|
||||
if(gain >= 0.0f)
|
||||
WARN_IF_ERR(snd_set_master_gain(gain));
|
||||
CFG_GET_USER_VAL("sound.musicgain", Float, musicGain);
|
||||
CFG_GET_USER_VAL("sound.ambientgain", Float, ambientGain);
|
||||
CFG_GET_USER_VAL("sound.actiongain", Float, actionGain);
|
||||
|
||||
CFG_GET_USER_VAL("sound.bufferCount", Int, bufferCount);
|
||||
CFG_GET_USER_VAL("sound.bufferSize", UnsignedLong, bufferSize);
|
||||
|
||||
g_SoundManager->SetMasterGain(gain);
|
||||
g_SoundManager->SetMusicGain(musicGain);
|
||||
g_SoundManager->SetAmbientGain(ambientGain);
|
||||
g_SoundManager->SetActionGain(actionGain);
|
||||
|
||||
g_SoundManager->SetMemoryUsage(bufferSize, bufferCount);
|
||||
}
|
||||
|
||||
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "lib/file/common/file_stats.h"
|
||||
#include "lib/res/h_mgr.h"
|
||||
#include "lib/res/graphics/cursor.h"
|
||||
#include "lib/res/sound/snd_mgr.h"
|
||||
#include "lib/sysdep/cursor.h"
|
||||
#include "lib/sysdep/cpu.h"
|
||||
#include "lib/sysdep/gfx.h"
|
||||
@ -35,12 +34,34 @@
|
||||
#include "lib/sysdep/os/win/wversion.h"
|
||||
#endif
|
||||
|
||||
#include "graphics/CinemaTrack.h"
|
||||
#include "graphics/GameView.h"
|
||||
#include "graphics/LightEnv.h"
|
||||
#include "graphics/MapReader.h"
|
||||
#include "graphics/MaterialManager.h"
|
||||
#include "graphics/TerrainTextureManager.h"
|
||||
#include "gui/GUI.h"
|
||||
#include "gui/GUIManager.h"
|
||||
#include "gui/scripting/JSInterface_IGUIObject.h"
|
||||
#include "gui/scripting/JSInterface_GUITypes.h"
|
||||
#include "gui/scripting/ScriptFunctions.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "maths/scripting/JSInterface_Vector3D.h"
|
||||
#include "network/NetServer.h"
|
||||
#include "network/NetClient.h"
|
||||
|
||||
#include "ps/CConsole.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/ConfigDB.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Font.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/GameSetup/Atlas.h"
|
||||
#include "ps/GameSetup/GameSetup.h"
|
||||
#include "ps/GameSetup/Paths.h"
|
||||
#include "ps/GameSetup/Config.h"
|
||||
#include "ps/GameSetup/CmdLineArgs.h"
|
||||
#include "ps/GameSetup/HWDetect.h"
|
||||
#include "ps/Globals.h"
|
||||
#include "ps/Hotkey.h"
|
||||
#include "ps/Joystick.h"
|
||||
@ -49,60 +70,26 @@
|
||||
#include "ps/Profile.h"
|
||||
#include "ps/ProfileViewer.h"
|
||||
#include "ps/Profiler2.h"
|
||||
#include "ps/Pyrogenesis.h" // psSetLogDir
|
||||
#include "ps/scripting/JSInterface_Console.h"
|
||||
#include "ps/TouchInput.h"
|
||||
#include "ps/UserReport.h"
|
||||
#include "ps/Util.h"
|
||||
#include "ps/VideoMode.h"
|
||||
#include "ps/World.h"
|
||||
|
||||
#include "graphics/CinemaTrack.h"
|
||||
#include "graphics/GameView.h"
|
||||
#include "graphics/LightEnv.h"
|
||||
#include "graphics/MapReader.h"
|
||||
#include "graphics/MaterialManager.h"
|
||||
#include "graphics/TerrainTextureManager.h"
|
||||
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/VertexBufferManager.h"
|
||||
#include "renderer/ModelRenderer.h"
|
||||
|
||||
#include "maths/MathUtil.h"
|
||||
|
||||
#include "simulation2/Simulation2.h"
|
||||
|
||||
#include "scripting/ScriptingHost.h"
|
||||
#include "scripting/ScriptGlue.h"
|
||||
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
#include "scriptinterface/ScriptStats.h"
|
||||
|
||||
#include "maths/scripting/JSInterface_Vector3D.h"
|
||||
|
||||
#include "ps/scripting/JSInterface_Console.h"
|
||||
|
||||
#include "gui/GUI.h"
|
||||
#include "gui/GUIManager.h"
|
||||
#include "gui/scripting/JSInterface_IGUIObject.h"
|
||||
#include "gui/scripting/JSInterface_GUITypes.h"
|
||||
#include "gui/scripting/ScriptFunctions.h"
|
||||
|
||||
#include "sound/JSI_Sound.h"
|
||||
|
||||
#include "network/NetServer.h"
|
||||
#include "network/NetClient.h"
|
||||
|
||||
#include "ps/Pyrogenesis.h" // psSetLogDir
|
||||
#include "ps/GameSetup/Atlas.h"
|
||||
#include "ps/GameSetup/GameSetup.h"
|
||||
#include "ps/GameSetup/Paths.h"
|
||||
#include "ps/GameSetup/Config.h"
|
||||
#include "ps/GameSetup/CmdLineArgs.h"
|
||||
#include "ps/GameSetup/HWDetect.h"
|
||||
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "soundmanager/SoundManager.h"
|
||||
#include "tools/atlas/GameInterface/GameLoop.h"
|
||||
#include "tools/atlas/GameInterface/View.h"
|
||||
|
||||
|
||||
#if !(OS_WIN || OS_MACOSX || OS_ANDROID) // assume all other platforms use X11 for wxWidgets
|
||||
#define MUST_INIT_X11 1
|
||||
#include <X11/Xlib.h>
|
||||
@ -203,6 +190,8 @@ void Render()
|
||||
{
|
||||
PROFILE3("render");
|
||||
|
||||
g_SoundManager->IdleTask();
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
g_Profiler2.RecordGPUFrameStart();
|
||||
@ -331,15 +320,15 @@ static void RegisterJavascriptInterfaces()
|
||||
// maths
|
||||
JSI_Vector3D::init();
|
||||
|
||||
// sound
|
||||
CSoundManager::ScriptingInit();
|
||||
|
||||
// graphics
|
||||
CGameView::ScriptingInit();
|
||||
|
||||
// renderer
|
||||
CRenderer::ScriptingInit();
|
||||
|
||||
// sound
|
||||
JSI_Sound::ScriptingInit();
|
||||
|
||||
// ps
|
||||
JSI_Console::init();
|
||||
|
||||
@ -695,7 +684,7 @@ void Shutdown(int UNUSED(flags))
|
||||
// resource
|
||||
// first shut down all resource owners, and then the handle manager.
|
||||
TIMER_BEGIN(L"resource modules");
|
||||
snd_shutdown();
|
||||
delete g_SoundManager;
|
||||
|
||||
g_VFS.reset();
|
||||
|
||||
@ -872,6 +861,8 @@ void Init(const CmdLineArgs& args, int UNUSED(flags))
|
||||
g_ScriptStatsTable = new CScriptStatsTable;
|
||||
g_ProfileViewer.AddRootTable(g_ScriptStatsTable);
|
||||
|
||||
g_SoundManager = new CSoundManager();
|
||||
|
||||
InitScripting(); // before GUI
|
||||
|
||||
// g_ConfigDB, command line args, globals
|
||||
@ -934,7 +925,7 @@ void InitGraphics(const CmdLineArgs& args, int flags)
|
||||
// speed up startup by disabling all sound
|
||||
// (OpenAL init will be skipped).
|
||||
// must be called before first snd_open.
|
||||
snd_disable(true);
|
||||
g_SoundManager->SetEnabled(false);
|
||||
}
|
||||
|
||||
g_GUI = new CGUIManager(g_ScriptingHost.GetScriptInterface());
|
||||
|
@ -492,8 +492,6 @@ void TerrainRenderer::RenderTerrainShader(const CShaderDefines& context, ShadowM
|
||||
if (visiblePatches.empty() && visibleDecals.empty())
|
||||
return;
|
||||
|
||||
CShaderManager& shaderManager = g_Renderer.GetShaderManager();
|
||||
|
||||
// render the solid black sides of the map first
|
||||
CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect("gui_solid");
|
||||
techSolid->BeginPass();
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "simulation2/MessageTypes.h"
|
||||
#include "simulation2/components/ICmpPosition.h"
|
||||
#include "simulation2/components/ICmpRangeManager.h"
|
||||
#include "sound/SoundGroup.h"
|
||||
#include "soundmanager/js/SoundGroup.h"
|
||||
|
||||
class CCmpSoundManager : public ICmpSoundManager
|
||||
{
|
||||
|
@ -1,200 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "JSI_Sound.h"
|
||||
#include "maths/Vector3D.h"
|
||||
|
||||
#include "lib/utf8.h"
|
||||
#include "lib/res/sound/snd_mgr.h"
|
||||
#include "lib/res/h_mgr.h" // h_filename
|
||||
#include "ps/Filesystem.h"
|
||||
|
||||
|
||||
JSI_Sound::JSI_Sound(const VfsPath& pathname)
|
||||
{
|
||||
m_Handle = snd_open(g_VFS, pathname);
|
||||
|
||||
// if open failed, we still have to return a valid non-null object to
|
||||
// the script, so just reset the handle to 0 so all subsequent method
|
||||
// calls will do nothing
|
||||
if (m_Handle < 0)
|
||||
{
|
||||
m_Handle = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
(void)snd_set_pos(m_Handle, 0,0,0, true);
|
||||
}
|
||||
|
||||
JSI_Sound::~JSI_Sound()
|
||||
{
|
||||
(void)this->Free(0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
bool JSI_Sound::SetGain(JSContext* cx, uintN argc, jsval* argv)
|
||||
{
|
||||
if (! m_Handle)
|
||||
return false;
|
||||
|
||||
ENSURE(argc >= 1); // FIXME
|
||||
float gain;
|
||||
if (! ToPrimitive<float>(cx, argv[0], gain))
|
||||
return false;
|
||||
|
||||
(void)snd_set_gain(m_Handle, gain);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSI_Sound::SetPitch(JSContext* cx, uintN argc, jsval* argv)
|
||||
{
|
||||
if (! m_Handle)
|
||||
return false;
|
||||
|
||||
ENSURE(argc >= 1); // FIXME
|
||||
float pitch;
|
||||
if (! ToPrimitive<float>(cx, argv[0], pitch))
|
||||
return false;
|
||||
|
||||
(void)snd_set_pitch(m_Handle, pitch);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSI_Sound::SetPosition(JSContext* cx, uintN argc, jsval* argv)
|
||||
{
|
||||
if (! m_Handle)
|
||||
return false;
|
||||
|
||||
ENSURE(argc >= 1); // FIXME
|
||||
|
||||
CVector3D pos;
|
||||
// absolute world coords
|
||||
if (ToPrimitive<CVector3D>(cx, argv[0], pos))
|
||||
(void)snd_set_pos(m_Handle, pos[0], pos[1], pos[2]);
|
||||
// relative, 0 offset - right on top of the listener
|
||||
// (we don't need displacement from the listener, e.g. always behind)
|
||||
else
|
||||
(void)snd_set_pos(m_Handle, 0,0,0, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool JSI_Sound::Fade(JSContext* cx, uintN argc, jsval* argv)
|
||||
{
|
||||
if (! m_Handle)
|
||||
return false;
|
||||
|
||||
ENSURE(argc >= 3); // FIXME
|
||||
float initial_gain, final_gain;
|
||||
float length;
|
||||
if (! (ToPrimitive<float>(cx, argv[0], initial_gain)
|
||||
&& ToPrimitive<float>(cx, argv[1], final_gain)
|
||||
&& ToPrimitive<float>(cx, argv[2], length)))
|
||||
return false;
|
||||
|
||||
(void)snd_fade(m_Handle, initial_gain, final_gain, length, FT_S_CURVE);
|
||||
|
||||
// HACK: snd_fade causes <m_Handle> to be automatically freed when a
|
||||
// fade to 0 has completed. however, we're still holding on to a
|
||||
// reference, which will cause a double-free warning when Free() is
|
||||
// called from the dtor. solution is to neuter our Handle by
|
||||
// setting it to 0 (ok since it'll be freed). this does mean that
|
||||
// no further operations can be carried out during that final fade.
|
||||
if (final_gain == 0.0f)
|
||||
m_Handle = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// start playing the sound (one-shot).
|
||||
// it will automatically be freed when done.
|
||||
bool JSI_Sound::Play(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
if (! m_Handle)
|
||||
return false;
|
||||
|
||||
(void)snd_play(m_Handle);
|
||||
// We can't do anything else with this sound now, since it's impossible to
|
||||
// know whether or not it's still valid (since it might have finished playing
|
||||
// already). So set it to 0, so we don't try doing anything (like freeing it)
|
||||
// in the future.
|
||||
m_Handle = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// request the sound be played until free() is called. returns immediately.
|
||||
bool JSI_Sound::Loop(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
if (! m_Handle)
|
||||
return false;
|
||||
|
||||
(void)snd_set_loop(m_Handle, true);
|
||||
(void)snd_play(m_Handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
// stop sound if currently playing and free resources.
|
||||
// doesn't need to be called unless played via loop() -
|
||||
// sounds are freed automatically when done playing.
|
||||
bool JSI_Sound::Free(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
if (! m_Handle)
|
||||
return false;
|
||||
|
||||
(void)snd_free(m_Handle); // resets it to 0
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Script-bound functions
|
||||
|
||||
|
||||
void JSI_Sound::ScriptingInit()
|
||||
{
|
||||
AddMethod<CStr, &JSI_Sound::ToString>("toString", 0);
|
||||
AddMethod<bool, &JSI_Sound::Play>("play", 0);
|
||||
AddMethod<bool, &JSI_Sound::Loop>("loop", 0);
|
||||
AddMethod<bool, &JSI_Sound::Free>("free", 0);
|
||||
AddMethod<bool, &JSI_Sound::SetGain>("setGain", 0);
|
||||
AddMethod<bool, &JSI_Sound::SetPitch>("setPitch", 0);
|
||||
AddMethod<bool, &JSI_Sound::SetPosition>("setPosition", 0);
|
||||
AddMethod<bool, &JSI_Sound::Fade>("fade", 0);
|
||||
|
||||
CJSObject<JSI_Sound>::ScriptingInit("Sound", &JSI_Sound::Construct, 1);
|
||||
}
|
||||
|
||||
CStr JSI_Sound::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
return "[object Sound: " + (m_Handle ? utf8_from_wstring(h_filename(m_Handle).string()) : "(null)") + "]";
|
||||
}
|
||||
|
||||
JSBool JSI_Sound::Construct(JSContext* cx, uintN argc, jsval* vp)
|
||||
{
|
||||
JSU_REQUIRE_MIN_PARAMS(1);
|
||||
|
||||
CStrW filename;
|
||||
if (! ToPrimitive<CStrW>(cx, JS_ARGV(cx, vp)[0], filename))
|
||||
return JS_FALSE;
|
||||
|
||||
JSI_Sound* newObject = new JSI_Sound(filename);
|
||||
newObject->m_EngineOwned = false;
|
||||
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
PLAYING AMBIENT SOUND WHEN CAMERA IS OVER BUILDING
|
||||
==================================================
|
||||
|
||||
data flow:
|
||||
C++ JS
|
||||
> list of visible entities (1)
|
||||
< list of sound requests and their weights
|
||||
list of changed sounds
|
||||
|
||||
C++ code generates list of entities on screen
|
||||
rationale: done in C++ for performance and to avoid having to expose the "patch" subdivision scheme to JS.
|
||||
UPDATE: this is much thornier than expected.
|
||||
1) we only want stuff that is visible to be played. hearing things off screen would be distressing and weird
|
||||
2) don't play sound for buildings in FoW, to prevent "audio spying"
|
||||
most straightforward way is simply scan all entities; if building, check against visible frustum.
|
||||
if inside AND within 3d distance cutoff of viewer pos, add to visible_building
|
||||
optimization for later: get all patches within 3d distance cutoff; discard all not within frustum; only test
|
||||
entities within those remaining patches.
|
||||
pass that to JS decideWhatToPlay
|
||||
it returns list of sounds it wants playing
|
||||
format: see AmbientSoundReq below
|
||||
C++ sound engine compares its list of currently sounds;
|
||||
fades out those no longer wanted and starts new ones immediately
|
||||
|
||||
|
||||
new entity properties needed:
|
||||
-----------------------------
|
||||
- ambientGroup: a soundGroup of several sounds; one is picked at random to be played (see below)
|
||||
- priority: to determine which entity should trump the others in a crowded city.
|
||||
|
||||
|
||||
// weight is so that we can play several ambient sounds at a time, but ones for buildings at edge of screen are quieter
|
||||
// values: 0..1; probably calculated from distance to camera
|
||||
type AmbientSoundReq = (SoundGroupString, weight)
|
||||
|
||||
// (suggestion only; may be revised if too much cacophony/constant sound results)
|
||||
JS_decideWhatToPlay(in HEntity visible_ents[], out AmbientSoundReq desired_ambient_sounds[])
|
||||
{
|
||||
// * "important" means the building is at center of attention and should mostly override the other sounds.
|
||||
// this is complicated as well. the camera may have any orientation, especially in cinematic mode;
|
||||
// that means we can't just rely on casting a ray from viewer through middle screen pixel to terrain.
|
||||
// our building list already covers only the visible ones, so we can use 3d distance from viewer
|
||||
// (without worrying about including buildings behind us i.e. out of sight).
|
||||
// important := fairly small distance (covers the case where users zoom really close to a building) OR
|
||||
// building is close to center of screen (as determined via ray cast method; skip this if the camera
|
||||
// is weird, i.e. looking above the horizon, in which case the ray cast would fail).
|
||||
// note: not playing sounds when looking down vertically at the town but zoomed out very far is ok (desirable even).
|
||||
if an entity is important(*)
|
||||
desired_ambient_sounds[i++] = ent.ambientGroup
|
||||
|
||||
forall ambient types (farm, dock etc.) in decreasing order of priority
|
||||
stop if >= 3 sounds in list
|
||||
if enough buildings on screen
|
||||
desired_ambient_sounds[i++] = ent.ambientGroup
|
||||
|
||||
maybe add some random variation to spice things up? (i.e. also play some other building sounds;
|
||||
don't always have one building override the others)
|
||||
}
|
||||
|
||||
|
||||
C++ code keeps a list of all active sounds:
|
||||
type ActiveSound = (Handle, SoundGroupString)
|
||||
ActiveSound active_sound_list[]
|
||||
|
||||
Handle startPlayingAmbient(soundGroup, weight)
|
||||
{
|
||||
filename = soundGroup.pickRandom()
|
||||
return snd_play(filename, globalAmbientVolume*soundGroup.volume*weight)
|
||||
}
|
||||
|
||||
updateAmbientSounds(desired_ambient_sounds)
|
||||
{
|
||||
for all in desired_ambient_sounds but not active_sound_list:
|
||||
handle = startPlayingAmbient(amb.group, amb.weight)
|
||||
active_sound_list[i++] = (handle, amb.group)
|
||||
|
||||
for all in active_sound_list but not desired_ambient_sounds:
|
||||
snd_fade(OUT, active.handle)
|
||||
}
|
||||
|
||||
|
||||
|
||||
RANDOMIZED SOUNDS
|
||||
==================================================
|
||||
(needed for ambient and normal battle sounds)
|
314
source/soundmanager/SoundManager.cpp
Normal file
314
source/soundmanager/SoundManager.cpp
Normal file
@ -0,0 +1,314 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "SoundManager.h"
|
||||
|
||||
#include "soundmanager/data/SoundData.h"
|
||||
#include "soundmanager/items/CSoundItem.h"
|
||||
#include "soundmanager/items/CBufferItem.h"
|
||||
#include "soundmanager/items/CStreamItem.h"
|
||||
#include "soundmanager/js/SoundPlayer.h"
|
||||
#include "soundmanager/js/AmbientSound.h"
|
||||
#include "soundmanager/js/MusicSound.h"
|
||||
#include "soundmanager/js/Sound.h"
|
||||
|
||||
CSoundManager* g_SoundManager;
|
||||
|
||||
void CSoundManager::ScriptingInit()
|
||||
{
|
||||
JAmbientSound::ScriptingInit();
|
||||
JMusicSound::ScriptingInit();
|
||||
JSound::ScriptingInit();
|
||||
JSoundPlayer::ScriptingInit();
|
||||
}
|
||||
|
||||
CSoundManager::CSoundManager()
|
||||
{
|
||||
m_Items = new ItemsList;
|
||||
m_CurrentEnvirons = 0;
|
||||
m_CurrentTune = 0;
|
||||
m_Gain = 1;
|
||||
m_MusicGain = 1;
|
||||
m_AmbientGain = 1;
|
||||
m_ActionGain = 1;
|
||||
m_Enabled = true;
|
||||
m_BufferCount = 50;
|
||||
m_BufferSize = 65536;
|
||||
m_MusicEnabled = true;
|
||||
AlcInit();
|
||||
}
|
||||
|
||||
CSoundManager::~CSoundManager()
|
||||
{
|
||||
ItemsList::iterator lstr = m_Items->begin();
|
||||
while (lstr != m_Items->end())
|
||||
{
|
||||
(*lstr)->Stop();
|
||||
delete *lstr;
|
||||
lstr++;
|
||||
}
|
||||
|
||||
alcDestroyContext(m_Context);
|
||||
alcCloseDevice(m_Device);
|
||||
|
||||
delete m_Items;
|
||||
m_Items = 0L;
|
||||
m_CurrentEnvirons = 0;
|
||||
m_CurrentTune = 0;
|
||||
}
|
||||
|
||||
|
||||
Status CSoundManager::AlcInit()
|
||||
{
|
||||
Status ret = INFO::OK;
|
||||
|
||||
m_Device = alcOpenDevice(NULL);
|
||||
if(m_Device)
|
||||
{
|
||||
m_Context = alcCreateContext(m_Device, 0); // no attrlist needed
|
||||
if(m_Context)
|
||||
alcMakeContextCurrent(m_Context);
|
||||
}
|
||||
|
||||
// check if init succeeded.
|
||||
// some OpenAL implementations don't indicate failure here correctly;
|
||||
// we need to check if the device and context pointers are actually valid.
|
||||
ALCenum err = alcGetError(m_Device);
|
||||
if(err != ALC_NO_ERROR || !m_Device || !m_Context)
|
||||
{
|
||||
#if OS_UNIX
|
||||
ret = INFO::OK;
|
||||
#else
|
||||
ret = ERR::FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* dev_name = (const char*)alcGetString(m_Device, ALC_DEVICE_SPECIFIER);
|
||||
wchar_t buf[200];
|
||||
swprintf(buf, ARRAY_SIZE(buf), L"SND| alc_init: success, using %hs\n", dev_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
void CSoundManager::SetMemoryUsage(long bufferSize, int bufferCount)
|
||||
{
|
||||
m_BufferCount = bufferCount;
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
long CSoundManager::GetBufferCount()
|
||||
{
|
||||
return m_BufferCount;
|
||||
}
|
||||
long CSoundManager::GetBufferSize()
|
||||
{
|
||||
return m_BufferSize;
|
||||
}
|
||||
|
||||
|
||||
void CSoundManager::SetMasterGain(float gain)
|
||||
{
|
||||
m_Gain = gain;
|
||||
}
|
||||
void CSoundManager::SetMusicGain(float gain)
|
||||
{
|
||||
m_MusicGain = gain;
|
||||
}
|
||||
void CSoundManager::SetAmbientGain(float gain)
|
||||
{
|
||||
m_AmbientGain = gain;
|
||||
}
|
||||
void CSoundManager::SetActionGain(float gain)
|
||||
{
|
||||
m_ActionGain = gain;
|
||||
}
|
||||
|
||||
|
||||
ISoundItem* CSoundManager::LoadItem(const VfsPath* itemPath)
|
||||
{
|
||||
CSoundData* itemData = CSoundData::SoundDataFromFile(itemPath);
|
||||
ISoundItem* answer = NULL;
|
||||
|
||||
if (itemData != NULL)
|
||||
{
|
||||
if (itemData->IsOneShot())
|
||||
{
|
||||
if (itemData->GetBufferCount() == 1)
|
||||
answer = new CSoundItem(itemData);
|
||||
else
|
||||
answer = new CBufferItem(itemData);
|
||||
}
|
||||
else
|
||||
{
|
||||
answer = new CStreamItem(itemData);
|
||||
}
|
||||
|
||||
if (answer != NULL)
|
||||
m_Items->push_back(answer);
|
||||
}
|
||||
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
unsigned long CSoundManager::Count()
|
||||
{
|
||||
return m_Items->size();
|
||||
}
|
||||
|
||||
void CSoundManager::IdleTask()
|
||||
{
|
||||
if (m_Items)
|
||||
{
|
||||
ItemsList::iterator lstr = m_Items->begin();
|
||||
ItemsList deadItemList;
|
||||
ItemsList* nextItemList = new ItemsList;
|
||||
|
||||
|
||||
while (lstr != m_Items->end()) {
|
||||
if ((*lstr)->IdleTask())
|
||||
nextItemList->push_back(*lstr);
|
||||
else
|
||||
deadItemList.push_back(*lstr);
|
||||
lstr++;
|
||||
}
|
||||
delete m_Items;
|
||||
m_Items = nextItemList;
|
||||
|
||||
ItemsList::iterator deadItems = deadItemList.begin();
|
||||
while (deadItems != deadItemList.end())
|
||||
{
|
||||
delete *deadItems;
|
||||
deadItems++;
|
||||
}
|
||||
}
|
||||
if (m_CurrentTune)
|
||||
m_CurrentTune->EnsurePlay();
|
||||
if (m_CurrentEnvirons)
|
||||
m_CurrentEnvirons->EnsurePlay();
|
||||
}
|
||||
|
||||
void CSoundManager::DeleteItem(long itemNum)
|
||||
{
|
||||
ItemsList::iterator lstr = m_Items->begin();
|
||||
lstr += itemNum;
|
||||
|
||||
delete *lstr;
|
||||
|
||||
m_Items->erase(lstr);
|
||||
}
|
||||
|
||||
ISoundItem* CSoundManager::GetSoundItem(unsigned long itemRow)
|
||||
{
|
||||
return (*m_Items)[itemRow];
|
||||
}
|
||||
|
||||
void CSoundManager::InitListener()
|
||||
{
|
||||
ALfloat listenerPos[]={0.0,0.0,0.0};
|
||||
ALfloat listenerVel[]={0.0,0.0,0.0};
|
||||
ALfloat listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};
|
||||
|
||||
alListenerfv(AL_POSITION,listenerPos);
|
||||
alListenerfv(AL_VELOCITY,listenerVel);
|
||||
alListenerfv(AL_ORIENTATION,listenerOri);
|
||||
|
||||
alDistanceModel(AL_EXPONENT_DISTANCE);
|
||||
}
|
||||
|
||||
void CSoundManager::SetEnabled(bool doEnable)
|
||||
{
|
||||
m_Enabled = doEnable;
|
||||
}
|
||||
|
||||
void CSoundManager::PlayActionItem(ISoundItem* anItem)
|
||||
{
|
||||
if (anItem)
|
||||
{
|
||||
if (m_Enabled && (m_ActionGain > 0))
|
||||
{
|
||||
anItem->SetGain(m_Gain * m_ActionGain);
|
||||
anItem->Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
void CSoundManager::PlayGroupItem(ISoundItem* anItem, ALfloat groupGain)
|
||||
{
|
||||
if (anItem)
|
||||
{
|
||||
if (m_Enabled && (m_ActionGain > 0)) {
|
||||
anItem->SetGain(m_Gain * groupGain);
|
||||
anItem->Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSoundManager::SetMusicEnabled (bool isEnabled)
|
||||
{
|
||||
if (m_CurrentTune && !isEnabled)
|
||||
{
|
||||
m_CurrentTune->FadeAndDelete(1.00);
|
||||
m_CurrentTune = 0L;
|
||||
}
|
||||
m_MusicEnabled = isEnabled;
|
||||
}
|
||||
|
||||
void CSoundManager::SetMusicItem(ISoundItem* anItem)
|
||||
{
|
||||
if (m_CurrentTune)
|
||||
{
|
||||
m_CurrentTune->FadeAndDelete(3.00);
|
||||
m_CurrentTune = 0L;
|
||||
}
|
||||
IdleTask();
|
||||
if (anItem)
|
||||
{
|
||||
if (m_MusicEnabled && m_Enabled)
|
||||
{
|
||||
m_CurrentTune = anItem;
|
||||
m_CurrentTune->SetGain(0);
|
||||
m_CurrentTune->PlayLoop();
|
||||
m_CurrentTune->FadeToIn(m_Gain * m_MusicGain, 2.00);
|
||||
}
|
||||
else
|
||||
{
|
||||
anItem->StopAndDelete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSoundManager::SetAmbientItem(ISoundItem* anItem)
|
||||
{
|
||||
if (m_CurrentEnvirons)
|
||||
{
|
||||
m_CurrentEnvirons->FadeAndDelete(3.00);
|
||||
m_CurrentEnvirons = 0L;
|
||||
}
|
||||
IdleTask();
|
||||
|
||||
if (anItem)
|
||||
{
|
||||
if (m_Enabled && (m_AmbientGain > 0))
|
||||
{
|
||||
m_CurrentEnvirons = anItem;
|
||||
m_CurrentEnvirons->SetGain(0);
|
||||
m_CurrentEnvirons->PlayLoop();
|
||||
m_CurrentEnvirons->FadeToIn(m_Gain * m_AmbientGain, 2.00);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
91
source/soundmanager/SoundManager.h
Normal file
91
source/soundmanager/SoundManager.h
Normal file
@ -0,0 +1,91 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SOUNDMANAGER_H
|
||||
#define INCLUDED_SOUNDMANAGER_H
|
||||
|
||||
#include "soundmanager/items/ISoundItem.h"
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
typedef std::vector<ISoundItem*> ItemsList;
|
||||
|
||||
|
||||
class CSoundManager
|
||||
{
|
||||
protected:
|
||||
|
||||
ALuint m_ALEnvironment;
|
||||
ALCcontext* m_Context;
|
||||
ALCdevice* m_Device;
|
||||
ISoundItem* m_CurrentTune;
|
||||
ISoundItem* m_CurrentEnvirons;
|
||||
ItemsList* m_Items;
|
||||
float m_Gain;
|
||||
float m_MusicGain;
|
||||
float m_AmbientGain;
|
||||
float m_ActionGain;
|
||||
bool m_Enabled;
|
||||
long m_BufferSize;
|
||||
int m_BufferCount;
|
||||
bool m_MusicEnabled;
|
||||
|
||||
public:
|
||||
CSoundManager();
|
||||
virtual ~CSoundManager();
|
||||
|
||||
ISoundItem* LoadItem(const VfsPath* itemPath);
|
||||
|
||||
static void ScriptingInit();
|
||||
|
||||
void SetMusicEnabled (bool isEnabled);
|
||||
|
||||
ISoundItem* ItemFromWAV(VfsPath& fname);
|
||||
ISoundItem* ItemFromOgg(VfsPath& fname);
|
||||
|
||||
ISoundItem* GetSoundItem(unsigned long itemRow);
|
||||
unsigned long Count();
|
||||
void IdleTask();
|
||||
void DeleteItem(long itemNum);
|
||||
|
||||
void SetMemoryUsage(long bufferSize, int bufferCount);
|
||||
long GetBufferCount();
|
||||
long GetBufferSize();
|
||||
|
||||
void SetMusicItem(ISoundItem* anItem);
|
||||
void SetAmbientItem(ISoundItem* anItem);
|
||||
void PlayActionItem(ISoundItem* anItem);
|
||||
void PlayGroupItem(ISoundItem* anItem, ALfloat groupGain);
|
||||
|
||||
void SetMasterGain(float gain);
|
||||
void SetMusicGain(float gain);
|
||||
void SetAmbientGain(float gain);
|
||||
void SetActionGain(float gain);
|
||||
|
||||
void SetEnabled(bool doEnable);
|
||||
protected:
|
||||
void InitListener();
|
||||
virtual Status AlcInit();
|
||||
|
||||
};
|
||||
|
||||
extern CSoundManager* g_SoundManager;
|
||||
|
||||
|
||||
#endif // INCLUDED_SOUNDMANAGER_H
|
163
source/soundmanager/data/OggData.cpp
Normal file
163
source/soundmanager/data/OggData.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "OggData.h"
|
||||
|
||||
#include "soundmanager/SoundManager.h"
|
||||
|
||||
#include <wchar.h>
|
||||
#include <iostream>
|
||||
|
||||
COggData::COggData()
|
||||
{
|
||||
m_OneShot = false;
|
||||
}
|
||||
|
||||
COggData::~COggData()
|
||||
{
|
||||
alDeleteBuffers(m_BuffersUsed, m_Buffer);
|
||||
ov_clear(&m_vf);
|
||||
}
|
||||
|
||||
void COggData::SetFormatAndFreq(int form, ALsizei freq)
|
||||
{
|
||||
m_Format = form;
|
||||
m_Frequency = freq;
|
||||
}
|
||||
|
||||
bool COggData::InitOggFile(const wchar_t* fileLoc)
|
||||
{
|
||||
int buffersToStart = g_SoundManager->GetBufferCount();
|
||||
char nameH[300];
|
||||
sprintf(nameH, "%ls", fileLoc);
|
||||
|
||||
FILE* f = fopen(nameH, "rb");
|
||||
m_current_section = 0;
|
||||
int err = ov_open_callbacks(f, &m_vf, NULL, 0, OV_CALLBACKS_DEFAULT);
|
||||
if (err < 0)
|
||||
{
|
||||
fprintf(stderr,"Input does not appear to be an Ogg bitstream :%d :%d.\n", err, ferror(f));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_FileName = CStrW(fileLoc);
|
||||
|
||||
m_FileFinished = false;
|
||||
SetFormatAndFreq((m_vf.vi->channels == 1)? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16 , (ALsizei)m_vf.vi->rate);
|
||||
|
||||
alGetError(); /* clear error */
|
||||
alGenBuffers(buffersToStart, m_Buffer);
|
||||
|
||||
if(alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
printf("- Error creating initial buffer !!\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_BuffersUsed = FetchDataIntoBuffer(buffersToStart, m_Buffer);
|
||||
if (m_FileFinished)
|
||||
{
|
||||
m_OneShot = true;
|
||||
if (m_BuffersUsed < buffersToStart)
|
||||
{
|
||||
alDeleteBuffers(buffersToStart - m_BuffersUsed, &m_Buffer[m_BuffersUsed]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ALsizei COggData::GetBufferCount()
|
||||
{
|
||||
return m_BuffersUsed;
|
||||
}
|
||||
|
||||
bool COggData::IsFileFinished()
|
||||
{
|
||||
return m_FileFinished;
|
||||
}
|
||||
|
||||
void COggData::ResetFile()
|
||||
{
|
||||
ov_time_seek(&m_vf, 0);
|
||||
m_current_section = 0;
|
||||
m_FileFinished = false;
|
||||
}
|
||||
|
||||
bool COggData::IsOneShot()
|
||||
{
|
||||
return m_OneShot;
|
||||
}
|
||||
|
||||
int COggData::FetchDataIntoBuffer(int count, ALuint* buffers)
|
||||
{
|
||||
long bufferSize = g_SoundManager->GetBufferSize();
|
||||
|
||||
char* pcmout = new char[bufferSize + 5000];
|
||||
int buffersWritten = 0;
|
||||
|
||||
for (int i = 0; (i < count) && !m_FileFinished; i++)
|
||||
{
|
||||
char* readDest = pcmout;
|
||||
long totalRet = 0;
|
||||
while (totalRet < bufferSize)
|
||||
{
|
||||
long ret=ov_read(&m_vf,readDest, 4096,0,2,1, &m_current_section);
|
||||
if (ret == 0)
|
||||
{
|
||||
m_FileFinished=true;
|
||||
break;
|
||||
}
|
||||
else if (ret < 0)
|
||||
{
|
||||
/* error in the stream. Not a problem, just reporting it in
|
||||
case we (the app) cares. In this case, we don't. */
|
||||
}
|
||||
else
|
||||
{
|
||||
totalRet += ret;
|
||||
readDest += ret;
|
||||
}
|
||||
}
|
||||
if (totalRet > 0)
|
||||
{
|
||||
buffersWritten++;
|
||||
alBufferData(buffers[i], m_Format, pcmout, (ALsizei)totalRet, (int)m_Frequency);
|
||||
}
|
||||
}
|
||||
delete[] pcmout;
|
||||
return buffersWritten;
|
||||
}
|
||||
|
||||
|
||||
ALuint COggData::GetBuffer()
|
||||
{
|
||||
return m_Buffer[0];
|
||||
}
|
||||
|
||||
ALuint* COggData::GetBufferPtr()
|
||||
{
|
||||
return m_Buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
57
source/soundmanager/data/OggData.h
Normal file
57
source/soundmanager/data/OggData.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_OGGDATA_H
|
||||
#define INCLUDED_OGGDATA_H
|
||||
|
||||
#include "SoundData.h"
|
||||
#include "lib/external_libraries/openal.h"
|
||||
#include "vorbis/vorbisfile.h"
|
||||
|
||||
class COggData : public CSoundData
|
||||
{
|
||||
ALuint m_Format;
|
||||
long m_Frequency;
|
||||
|
||||
public:
|
||||
COggData();
|
||||
virtual ~COggData();
|
||||
|
||||
virtual bool InitOggFile(const wchar_t* fileLoc);
|
||||
virtual bool IsFileFinished();
|
||||
virtual bool IsOneShot();
|
||||
|
||||
virtual int FetchDataIntoBuffer(int count, ALuint* buffers);
|
||||
virtual void ResetFile();
|
||||
|
||||
protected:
|
||||
OggVorbis_File m_vf;
|
||||
int m_current_section;
|
||||
bool m_FileFinished;
|
||||
bool m_OneShot;
|
||||
ALuint m_Buffer[100];
|
||||
int m_BuffersUsed;
|
||||
|
||||
bool AddDataBuffer(char* data, long length);
|
||||
void SetFormatAndFreq(int form, ALsizei freq);
|
||||
ALsizei GetBufferCount();
|
||||
ALuint GetBuffer();
|
||||
ALuint* GetBufferPtr();
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDED_OGGDATA_H
|
142
source/soundmanager/data/SoundData.cpp
Normal file
142
source/soundmanager/data/SoundData.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "SoundData.h"
|
||||
|
||||
#include "OggData.h"
|
||||
#include "lib/file/vfs/vfs_util.h"
|
||||
#include "ps/Filesystem.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
DataMap* CSoundData::sSoundData = NULL;
|
||||
|
||||
CSoundData::CSoundData()
|
||||
{
|
||||
InitProperties();
|
||||
}
|
||||
|
||||
CSoundData::~CSoundData()
|
||||
{
|
||||
if (m_ALBuffer != 0)
|
||||
alDeleteBuffers(1, &m_ALBuffer);
|
||||
}
|
||||
|
||||
void CSoundData::InitProperties()
|
||||
{
|
||||
m_ALBuffer = 0;
|
||||
m_RetentionCount = 0;
|
||||
}
|
||||
|
||||
void CSoundData::ReleaseSoundData(CSoundData* theData)
|
||||
{
|
||||
DataMap::iterator itemFind;
|
||||
|
||||
if (theData->DecrementCount())
|
||||
{
|
||||
if ((itemFind = CSoundData::sSoundData->find(theData->GetFileName())) != sSoundData->end())
|
||||
{
|
||||
CSoundData* dier = itemFind->second;
|
||||
CSoundData::sSoundData->erase(itemFind);
|
||||
delete dier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CSoundData* CSoundData::SoundDataFromFile(const VfsPath* itemPath)
|
||||
{
|
||||
if (CSoundData::sSoundData == NULL)
|
||||
CSoundData::sSoundData = new DataMap;
|
||||
|
||||
Path fExt = itemPath->Extension();
|
||||
DataMap::iterator itemFind;
|
||||
CSoundData* answer = NULL;
|
||||
|
||||
|
||||
if ((itemFind = CSoundData::sSoundData->find(itemPath->string())) != sSoundData->end())
|
||||
{
|
||||
answer = itemFind->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fExt == ".ogg")
|
||||
answer = SoundDataFromOgg(itemPath);
|
||||
|
||||
if (answer && answer->IsOneShot())
|
||||
(*CSoundData::sSoundData)[itemPath->string()] = answer;
|
||||
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
bool CSoundData::IsOneShot()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
CSoundData* CSoundData::SoundDataFromOgg(const VfsPath* itemPath)
|
||||
{
|
||||
CSoundData* answer = NULL;
|
||||
COggData* oggAnswer = new COggData();
|
||||
|
||||
OsPath realPath;
|
||||
Status ret = g_VFS->GetRealPath(*itemPath, realPath);
|
||||
if (ret == INFO::OK)
|
||||
{
|
||||
if (oggAnswer->InitOggFile(realPath.string().c_str()))
|
||||
{
|
||||
answer = oggAnswer;
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
ALsizei CSoundData::GetBufferCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
CStrW CSoundData::GetFileName()
|
||||
{
|
||||
return m_FileName;
|
||||
}
|
||||
|
||||
CSoundData* CSoundData::IncrementCount()
|
||||
{
|
||||
m_RetentionCount++;
|
||||
return this;
|
||||
}
|
||||
|
||||
bool CSoundData::DecrementCount()
|
||||
{
|
||||
m_RetentionCount--;
|
||||
|
||||
return (m_RetentionCount <= 0);
|
||||
}
|
||||
|
||||
ALuint CSoundData::GetBuffer()
|
||||
{
|
||||
return m_ALBuffer;
|
||||
}
|
||||
ALuint* CSoundData::GetBufferPtr()
|
||||
{
|
||||
return &m_ALBuffer;
|
||||
}
|
||||
|
64
source/soundmanager/data/SoundData.h
Normal file
64
source/soundmanager/data/SoundData.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SOUNDDATA_H
|
||||
#define INCLUDED_SOUNDDATA_H
|
||||
|
||||
#include "lib/external_libraries/openal.h"
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
#include "lib/os_path.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class CSoundData;
|
||||
typedef std::map<std::wstring, CSoundData*> DataMap;
|
||||
|
||||
|
||||
class CSoundData
|
||||
{
|
||||
public:
|
||||
static CSoundData* SoundDataFromFile(const VfsPath* itemPath);
|
||||
static CSoundData* SoundDataFromOgg(const VfsPath* itemPath);
|
||||
|
||||
static void ReleaseSoundData(CSoundData* theData);
|
||||
|
||||
CSoundData();
|
||||
CSoundData(ALuint dataSource);
|
||||
virtual ~CSoundData();
|
||||
|
||||
CSoundData* IncrementCount();
|
||||
bool DecrementCount();
|
||||
void InitProperties();
|
||||
virtual bool IsOneShot();
|
||||
|
||||
|
||||
virtual ALuint GetBuffer();
|
||||
virtual ALsizei GetBufferCount();
|
||||
CStrW GetFileName();
|
||||
virtual ALuint* GetBufferPtr();
|
||||
|
||||
protected:
|
||||
static DataMap* sSoundData;
|
||||
|
||||
ALuint m_ALBuffer;
|
||||
int m_RetentionCount;
|
||||
CStrW m_FileName;
|
||||
|
||||
};
|
||||
|
||||
#endif // INCLUDED_SOUNDDATA_H
|
90
source/soundmanager/items/CBufferItem.cpp
Normal file
90
source/soundmanager/items/CBufferItem.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "CBufferItem.h"
|
||||
|
||||
#include "soundmanager/data/SoundData.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
CBufferItem::CBufferItem(CSoundData* sndData)
|
||||
{
|
||||
ResetVars();
|
||||
if (InitOpenAL())
|
||||
Attach(sndData);
|
||||
}
|
||||
|
||||
|
||||
CBufferItem::~CBufferItem()
|
||||
{
|
||||
Stop();
|
||||
int num_processed;
|
||||
alGetSourcei(m_ALSource, AL_BUFFERS_PROCESSED, &num_processed);
|
||||
|
||||
if (num_processed > 0)
|
||||
{
|
||||
ALuint* al_buf = new ALuint[num_processed];
|
||||
alSourceUnqueueBuffers(m_ALSource, num_processed, al_buf);
|
||||
|
||||
delete[] al_buf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CBufferItem::IdleTask()
|
||||
{
|
||||
HandleFade();
|
||||
|
||||
if (m_LastPlay)
|
||||
{
|
||||
int proc_state;
|
||||
alGetSourceiv(m_ALSource, AL_SOURCE_STATE, &proc_state);
|
||||
return (proc_state != AL_STOPPED);
|
||||
}
|
||||
|
||||
if (GetLooping())
|
||||
{
|
||||
int num_processed;
|
||||
alGetSourcei(m_ALSource, AL_BUFFERS_PROCESSED, &num_processed);
|
||||
|
||||
for (int i = 0; i < num_processed; i++)
|
||||
{
|
||||
ALuint al_buf;
|
||||
alSourceUnqueueBuffers(m_ALSource, 1, &al_buf);
|
||||
alSourceQueueBuffers(m_ALSource, 1, &al_buf);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBufferItem::Attach(CSoundData* itemData)
|
||||
{
|
||||
if (itemData != NULL)
|
||||
{
|
||||
m_SoundData = itemData->IncrementCount();
|
||||
alSourceQueueBuffers(m_ALSource, m_SoundData->GetBufferCount(),(const ALuint *) m_SoundData->GetBufferPtr());
|
||||
}
|
||||
}
|
||||
|
||||
void CBufferItem::SetLooping(bool loops)
|
||||
{
|
||||
m_Looping = loops;
|
||||
}
|
||||
|
39
source/soundmanager/items/CBufferItem.h
Normal file
39
source/soundmanager/items/CBufferItem.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_CBUFFERITEM_H
|
||||
#define INCLUDED_CBUFFERITEM_H
|
||||
|
||||
#include "CSoundBase.h"
|
||||
|
||||
class CBufferItem : public CSoundBase
|
||||
{
|
||||
public:
|
||||
CBufferItem(CSoundData* sndData);
|
||||
virtual ~CBufferItem();
|
||||
|
||||
virtual void SetLooping(bool loops);
|
||||
virtual bool IdleTask();
|
||||
|
||||
protected:
|
||||
virtual void Attach(CSoundData* itemData);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDED_CBUFFERITEM_H
|
276
source/soundmanager/items/CSoundBase.cpp
Normal file
276
source/soundmanager/items/CSoundBase.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "CSoundBase.h"
|
||||
|
||||
#include "lib/timer.h"
|
||||
#include "soundmanager/SoundManager.h"
|
||||
#include "soundmanager/data/SoundData.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
CSoundBase::CSoundBase()
|
||||
{
|
||||
ResetVars();
|
||||
}
|
||||
|
||||
CSoundBase::~CSoundBase()
|
||||
{
|
||||
Stop();
|
||||
if (m_ALSource != 0)
|
||||
{
|
||||
alDeleteSources(1, &m_ALSource);
|
||||
m_ALSource = 0;
|
||||
}
|
||||
if (m_SoundData != 0)
|
||||
{
|
||||
CSoundData::ReleaseSoundData(m_SoundData);
|
||||
m_SoundData = 0;
|
||||
}
|
||||
if (m_Name)
|
||||
delete m_Name;
|
||||
}
|
||||
|
||||
void CSoundBase::ResetVars()
|
||||
{
|
||||
m_ALSource = 0;
|
||||
m_SoundData = 0;
|
||||
m_LastPlay = false;
|
||||
m_Looping = false;
|
||||
m_StartFadeTime = 0;
|
||||
m_EndFadeTime = 0;
|
||||
m_StartVolume = 0;
|
||||
m_EndVolume = 0;
|
||||
|
||||
ResetFade();
|
||||
m_Name = new std::string("sound name");
|
||||
}
|
||||
|
||||
void CSoundBase::ResetFade()
|
||||
{
|
||||
m_StartFadeTime = 0;
|
||||
m_EndFadeTime = 0;
|
||||
m_StartVolume = 0;
|
||||
m_EndVolume = 0;
|
||||
m_ShouldBePlaying = false;
|
||||
}
|
||||
|
||||
void CSoundBase::SetGain(ALfloat gain)
|
||||
{
|
||||
alSourcef(m_ALSource, AL_GAIN, gain);
|
||||
}
|
||||
|
||||
void CSoundBase::SetRollOff(ALfloat rolls)
|
||||
{
|
||||
alSourcef(m_ALSource, AL_ROLLOFF_FACTOR, rolls);
|
||||
}
|
||||
|
||||
void CSoundBase::EnsurePlay()
|
||||
{
|
||||
if (m_ShouldBePlaying && !IsPlaying())
|
||||
Play();
|
||||
}
|
||||
|
||||
void CSoundBase::SetCone(ALfloat innerCone, ALfloat outerCone, ALfloat coneGain)
|
||||
{
|
||||
alSourcef(m_ALSource, innerCone, AL_CONE_INNER_ANGLE);
|
||||
alSourcef(m_ALSource, outerCone, AL_CONE_OUTER_ANGLE);
|
||||
alSourcef(m_ALSource, coneGain, AL_CONE_OUTER_GAIN);
|
||||
}
|
||||
|
||||
void CSoundBase::SetPitch(ALfloat pitch)
|
||||
{
|
||||
alSourcef(m_ALSource, AL_PITCH, pitch);
|
||||
}
|
||||
|
||||
void CSoundBase::SetDirection(const CVector3D& direction)
|
||||
{
|
||||
alSourcefv(m_ALSource, AL_DIRECTION, direction.GetFloatArray());
|
||||
}
|
||||
|
||||
bool CSoundBase::InitOpenAL()
|
||||
{
|
||||
alGetError(); /* clear error */
|
||||
alGenSources(1, &m_ALSource);
|
||||
long anErr = alGetError();
|
||||
if (anErr != AL_NO_ERROR)
|
||||
{
|
||||
printf("- Error creating sources %ld !!\n", anErr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ALfloat source0Pos[]={ -2.0, 0.0, 0.0};
|
||||
ALfloat source0Vel[]={ 0.0, 0.0, 0.0};
|
||||
|
||||
alSourcef(m_ALSource,AL_PITCH,1.0f);
|
||||
alSourcef(m_ALSource,AL_GAIN,1.0f);
|
||||
alSourcefv(m_ALSource,AL_POSITION,source0Pos);
|
||||
alSourcefv(m_ALSource,AL_VELOCITY,source0Vel);
|
||||
alSourcei(m_ALSource,AL_LOOPING,AL_FALSE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSoundBase::IsPlaying()
|
||||
{
|
||||
int proc_state;
|
||||
alGetSourceiv(m_ALSource, AL_SOURCE_STATE, &proc_state);
|
||||
|
||||
return (proc_state == AL_PLAYING);
|
||||
}
|
||||
|
||||
void CSoundBase::SetLastPlay(bool last)
|
||||
{
|
||||
m_LastPlay = last;
|
||||
}
|
||||
|
||||
bool CSoundBase::IdleTask()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSoundBase::SetLocation (const CVector3D& position)
|
||||
{
|
||||
alSourcefv(m_ALSource,AL_POSITION, position.GetFloatArray());
|
||||
}
|
||||
|
||||
bool CSoundBase::HandleFade()
|
||||
{
|
||||
if (m_StartFadeTime != 0)
|
||||
{
|
||||
double currTime = timer_Time();
|
||||
double pctDone = std::min(1.0, (currTime - m_StartFadeTime) / (m_EndFadeTime - m_StartFadeTime));
|
||||
pctDone = std::max(0.0, pctDone);
|
||||
ALfloat curGain = ((m_EndVolume - m_StartVolume) * pctDone) + m_StartVolume;
|
||||
|
||||
if (curGain == 0)
|
||||
Stop();
|
||||
else if (curGain == m_EndVolume)
|
||||
{
|
||||
alSourcef(m_ALSource, AL_GAIN, curGain);
|
||||
ResetFade();
|
||||
}
|
||||
else
|
||||
alSourcef(m_ALSource, AL_GAIN, curGain);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSoundBase::GetLooping()
|
||||
{
|
||||
return m_Looping;
|
||||
}
|
||||
|
||||
void CSoundBase::SetLooping(bool loops)
|
||||
{
|
||||
m_Looping = loops;
|
||||
alSourcei(m_ALSource, AL_LOOPING, loops ? AL_TRUE : AL_FALSE);
|
||||
}
|
||||
|
||||
void CSoundBase::Play()
|
||||
{
|
||||
m_ShouldBePlaying = true;
|
||||
if (m_ALSource != 0)
|
||||
alSourcePlay(m_ALSource);
|
||||
}
|
||||
|
||||
void CSoundBase::PlayAndDelete()
|
||||
{
|
||||
SetLastPlay(true);
|
||||
Play();
|
||||
}
|
||||
|
||||
void CSoundBase::FadeAndDelete(double fadeTime)
|
||||
{
|
||||
SetLastPlay(true);
|
||||
FadeToIn(0, fadeTime);
|
||||
}
|
||||
|
||||
void CSoundBase::StopAndDelete()
|
||||
{
|
||||
SetLastPlay(true);
|
||||
Stop();
|
||||
}
|
||||
|
||||
void CSoundBase::PlayLoop()
|
||||
{
|
||||
if (m_ALSource != 0)
|
||||
{
|
||||
SetLooping(true);
|
||||
Play();
|
||||
}
|
||||
}
|
||||
|
||||
void CSoundBase::FadeToIn(ALfloat newVolume, double fadeDuration)
|
||||
{
|
||||
int proc_state;
|
||||
alGetSourceiv(m_ALSource, AL_SOURCE_STATE, &proc_state);
|
||||
if (proc_state == AL_PLAYING)
|
||||
{
|
||||
m_StartFadeTime = timer_Time();
|
||||
m_EndFadeTime = m_StartFadeTime + fadeDuration;
|
||||
alGetSourcef(m_ALSource, AL_GAIN, &m_StartVolume);
|
||||
m_EndVolume = newVolume;
|
||||
}
|
||||
}
|
||||
|
||||
void CSoundBase::PlayAsMusic()
|
||||
{
|
||||
g_SoundManager->SetMusicItem(this);
|
||||
}
|
||||
|
||||
void CSoundBase::PlayAsAmbient()
|
||||
{
|
||||
g_SoundManager->SetAmbientItem(this);
|
||||
}
|
||||
|
||||
void CSoundBase::Stop()
|
||||
{
|
||||
m_ShouldBePlaying = false;
|
||||
if (m_ALSource != 0)
|
||||
{
|
||||
int proc_state;
|
||||
alSourcei(m_ALSource, AL_LOOPING, AL_FALSE);
|
||||
alGetSourceiv(m_ALSource, AL_SOURCE_STATE, &proc_state);
|
||||
if (proc_state == AL_PLAYING)
|
||||
alSourceStop(m_ALSource);
|
||||
}
|
||||
}
|
||||
|
||||
const char* CSoundBase::Name()
|
||||
{
|
||||
return m_Name->c_str();
|
||||
}
|
||||
|
||||
std::string CSoundBase::GetName()
|
||||
{
|
||||
return std::string(m_Name->c_str());
|
||||
}
|
||||
|
||||
void CSoundBase::SetNameFromPath(char* fileLoc)
|
||||
{
|
||||
std::string anst(fileLoc);
|
||||
size_t pos = anst.find_last_of("/");
|
||||
if(pos != std::wstring::npos)
|
||||
m_Name->assign(anst.begin() + pos + 1, anst.end());
|
||||
else
|
||||
m_Name->assign(anst.begin(), anst.end());
|
||||
}
|
||||
|
89
source/soundmanager/items/CSoundBase.h
Normal file
89
source/soundmanager/items/CSoundBase.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_CSOUNDBASE_H
|
||||
#define INCLUDED_CSOUNDBASE_H
|
||||
|
||||
#include "lib/external_libraries/openal.h"
|
||||
#include "soundmanager/items/ISoundItem.h"
|
||||
#include "soundmanager/data/SoundData.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CSoundBase : public ISoundItem
|
||||
{
|
||||
protected:
|
||||
|
||||
ALuint m_ALSource;
|
||||
CSoundData* m_SoundData;
|
||||
|
||||
std::string* m_Name;
|
||||
bool m_LastPlay;
|
||||
bool m_Looping;
|
||||
bool m_ShouldBePlaying;
|
||||
|
||||
double m_StartFadeTime;
|
||||
double m_EndFadeTime;
|
||||
ALfloat m_StartVolume;
|
||||
ALfloat m_EndVolume;
|
||||
|
||||
public:
|
||||
CSoundBase();
|
||||
|
||||
virtual ~CSoundBase();
|
||||
|
||||
virtual bool InitOpenAL();
|
||||
virtual void ResetVars();
|
||||
virtual void EnsurePlay();
|
||||
|
||||
virtual void SetGain(ALfloat gain);
|
||||
virtual void SetRollOff(ALfloat gain);
|
||||
virtual void SetPitch(ALfloat pitch);
|
||||
virtual void SetDirection(const CVector3D& direction);
|
||||
virtual void SetCone(ALfloat innerCone, ALfloat outerCone, ALfloat coneGain);
|
||||
virtual void SetLastPlay(bool last);
|
||||
|
||||
void Play();
|
||||
void PlayAndDelete();
|
||||
bool IdleTask();
|
||||
void PlayLoop();
|
||||
void Stop();
|
||||
void StopAndDelete();
|
||||
void FadeToIn(ALfloat newVolume, double fadeDuration);
|
||||
|
||||
void PlayAsMusic();
|
||||
void PlayAsAmbient();
|
||||
|
||||
const char* Name();
|
||||
std::string GetName();
|
||||
|
||||
virtual bool GetLooping();
|
||||
virtual void SetLooping(bool loops);
|
||||
virtual bool IsPlaying();
|
||||
virtual void SetLocation(const CVector3D& position);
|
||||
virtual void FadeAndDelete(double fadeTime);
|
||||
|
||||
protected:
|
||||
|
||||
void SetNameFromPath(char* fileLoc);
|
||||
void ResetFade();
|
||||
bool HandleFade();
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // INCLUDED_CSOUNDBASE_H
|
67
source/soundmanager/items/CSoundItem.cpp
Normal file
67
source/soundmanager/items/CSoundItem.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "CSoundItem.h"
|
||||
|
||||
#include "soundmanager/data/SoundData.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
CSoundItem::CSoundItem()
|
||||
{
|
||||
ResetVars();
|
||||
}
|
||||
|
||||
CSoundItem::CSoundItem(CSoundData* sndData)
|
||||
{
|
||||
ResetVars();
|
||||
if (InitOpenAL())
|
||||
Attach(sndData);
|
||||
}
|
||||
|
||||
CSoundItem::~CSoundItem()
|
||||
{
|
||||
ALuint al_buf;
|
||||
|
||||
Stop();
|
||||
alSourceUnqueueBuffers(m_ALSource, 1, &al_buf);
|
||||
}
|
||||
|
||||
bool CSoundItem::IdleTask()
|
||||
{
|
||||
HandleFade();
|
||||
|
||||
if (m_LastPlay)
|
||||
{
|
||||
int proc_state;
|
||||
alGetSourceiv(m_ALSource, AL_SOURCE_STATE, &proc_state);
|
||||
return (proc_state != AL_STOPPED);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSoundItem::Attach(CSoundData* itemData)
|
||||
{
|
||||
if (itemData != NULL)
|
||||
{
|
||||
m_SoundData = itemData->IncrementCount();
|
||||
alSourcei(m_ALSource, AL_BUFFER, m_SoundData->GetBuffer());
|
||||
}
|
||||
}
|
37
source/soundmanager/items/CSoundItem.h
Normal file
37
source/soundmanager/items/CSoundItem.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_CSOUNDITEM_H
|
||||
#define INCLUDED_CSOUNDITEM_H
|
||||
|
||||
#include "CSoundBase.h"
|
||||
#include "soundmanager/data/SoundData.h"
|
||||
|
||||
|
||||
class CSoundItem : public CSoundBase
|
||||
{
|
||||
public:
|
||||
CSoundItem();
|
||||
CSoundItem(CSoundData* sndData);
|
||||
|
||||
virtual ~CSoundItem();
|
||||
void Attach(CSoundData* itemData);
|
||||
bool IdleTask();
|
||||
|
||||
};
|
||||
|
||||
#endif // INCLUDED_CSOUNDITEM_H
|
99
source/soundmanager/items/CStreamItem.cpp
Normal file
99
source/soundmanager/items/CStreamItem.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "CStreamItem.h"
|
||||
|
||||
#include "soundmanager/data/OggData.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
CStreamItem::CStreamItem(CSoundData* sndData)
|
||||
{
|
||||
ResetVars();
|
||||
if (InitOpenAL())
|
||||
Attach(sndData);
|
||||
}
|
||||
|
||||
CStreamItem::~CStreamItem()
|
||||
{
|
||||
Stop();
|
||||
|
||||
int num_processed;
|
||||
alGetSourcei(m_ALSource, AL_BUFFERS_PROCESSED, &num_processed);
|
||||
|
||||
if (num_processed > 0)
|
||||
{
|
||||
ALuint* al_buf = new ALuint[num_processed];
|
||||
alSourceUnqueueBuffers(m_ALSource, num_processed, al_buf);
|
||||
delete[] al_buf;
|
||||
}
|
||||
}
|
||||
|
||||
bool CStreamItem::IdleTask()
|
||||
{
|
||||
HandleFade();
|
||||
|
||||
int proc_state;
|
||||
alGetSourceiv(m_ALSource, AL_SOURCE_STATE, &proc_state);
|
||||
|
||||
if (proc_state == AL_STOPPED)
|
||||
{
|
||||
if (m_LastPlay)
|
||||
return (proc_state != AL_STOPPED);
|
||||
}
|
||||
else
|
||||
{
|
||||
COggData* tmp = (COggData*)m_SoundData;
|
||||
|
||||
if (! tmp->IsFileFinished())
|
||||
{
|
||||
int num_processed;
|
||||
alGetSourcei(m_ALSource, AL_BUFFERS_PROCESSED, &num_processed);
|
||||
|
||||
if (num_processed > 0)
|
||||
{
|
||||
ALuint* al_buf = new ALuint[num_processed];
|
||||
alSourceUnqueueBuffers(m_ALSource, num_processed, al_buf);
|
||||
int didWrite = tmp->FetchDataIntoBuffer(num_processed, al_buf);
|
||||
alSourceQueueBuffers(m_ALSource, didWrite, al_buf);
|
||||
delete[] al_buf;
|
||||
}
|
||||
}
|
||||
else if (GetLooping())
|
||||
{
|
||||
tmp->ResetFile();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CStreamItem::Attach(CSoundData* itemData)
|
||||
{
|
||||
if (itemData != NULL)
|
||||
{
|
||||
m_SoundData = itemData->IncrementCount();
|
||||
alSourceQueueBuffers(m_ALSource, m_SoundData->GetBufferCount(), (const ALuint *)m_SoundData->GetBufferPtr());
|
||||
}
|
||||
}
|
||||
|
||||
void CStreamItem::SetLooping(bool loops)
|
||||
{
|
||||
m_Looping = loops;
|
||||
}
|
||||
|
38
source/soundmanager/items/CStreamItem.h
Normal file
38
source/soundmanager/items/CStreamItem.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_CSTREAMITEM_H
|
||||
#define INCLUDED_CSTREAMITEM_H
|
||||
|
||||
#include "soundmanager/data/SoundData.h"
|
||||
#include "CSoundBase.h"
|
||||
|
||||
class CStreamItem : public CSoundBase
|
||||
{
|
||||
public:
|
||||
CStreamItem(CSoundData* sndData);
|
||||
virtual ~CStreamItem();
|
||||
|
||||
virtual void SetLooping(bool loops);
|
||||
virtual bool IdleTask();
|
||||
|
||||
protected:
|
||||
virtual void Attach(CSoundData* itemData);
|
||||
|
||||
};
|
||||
|
||||
#endif // INCLUDED_CSTREAMITEM_H
|
60
source/soundmanager/items/ISoundItem.h
Normal file
60
source/soundmanager/items/ISoundItem.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_ISOUNDITEM_H
|
||||
#define INCLUDED_ISOUNDITEM_H
|
||||
|
||||
#include "lib/external_libraries/openal.h"
|
||||
#include "maths/Vector3D.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ISoundItem
|
||||
{
|
||||
|
||||
public:
|
||||
virtual ~ISoundItem(){};
|
||||
virtual bool GetLooping() = 0;
|
||||
virtual void SetLooping(bool loop) = 0;
|
||||
virtual bool IsPlaying() = 0;
|
||||
|
||||
|
||||
virtual std::string GetName() = 0;
|
||||
virtual bool IdleTask() = 0;
|
||||
|
||||
virtual void Play() = 0;
|
||||
virtual void Stop() = 0;
|
||||
|
||||
virtual void EnsurePlay() = 0;
|
||||
virtual void PlayAsMusic() = 0;
|
||||
virtual void PlayAsAmbient() = 0;
|
||||
|
||||
virtual void PlayAndDelete() = 0;
|
||||
virtual void StopAndDelete() = 0;
|
||||
virtual void FadeToIn(ALfloat newVolume, double fadeDuration) = 0;
|
||||
virtual void FadeAndDelete(double fadeTime) = 0;
|
||||
virtual void PlayLoop() = 0;
|
||||
|
||||
virtual void SetCone(ALfloat innerCone, ALfloat outerCone, ALfloat coneGain) = 0;
|
||||
virtual void SetPitch(ALfloat pitch) = 0;
|
||||
virtual void SetGain(ALfloat gain) = 0;
|
||||
virtual void SetLocation(const CVector3D& position) = 0;
|
||||
virtual void SetRollOff(ALfloat gain) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDED_ISOUNDITEM_H
|
107
source/soundmanager/js/AmbientSound.cpp
Normal file
107
source/soundmanager/js/AmbientSound.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "AmbientSound.h"
|
||||
|
||||
#include "lib/utf8.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "ps/Filesystem.h"
|
||||
|
||||
#include "soundmanager/SoundManager.h"
|
||||
|
||||
JAmbientSound::JAmbientSound(const VfsPath& pathname)
|
||||
{
|
||||
m_FileName = new VfsPath(pathname.string().c_str());
|
||||
}
|
||||
|
||||
JAmbientSound::~JAmbientSound()
|
||||
{
|
||||
delete m_FileName;
|
||||
}
|
||||
|
||||
|
||||
// start playing the sound, all ambient sounds loop
|
||||
bool JAmbientSound::Play(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
ISoundItem* aSnd = g_SoundManager->LoadItem(m_FileName);
|
||||
|
||||
if (aSnd)
|
||||
aSnd->PlayAsAmbient();
|
||||
else
|
||||
debug_printf(L"sound item could not be loaded to play at: %hs\n", m_FileName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// start playing the sound, all ambient sounds loop
|
||||
bool JAmbientSound::Loop(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
ISoundItem* aSnd = g_SoundManager->LoadItem(m_FileName);
|
||||
|
||||
if (aSnd)
|
||||
aSnd->PlayAsAmbient();
|
||||
else
|
||||
debug_printf(L"sound item could not be loaded to loop at: %hs\n", m_FileName);
|
||||
|
||||
return true;
|
||||
}
|
||||
bool JAmbientSound::Free(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
g_SoundManager->SetAmbientItem(0L);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Script-bound functions
|
||||
|
||||
|
||||
void JAmbientSound::ScriptingInit()
|
||||
{
|
||||
AddMethod<CStr, &JAmbientSound::ToString>("toString", 0);
|
||||
AddMethod<bool, &JAmbientSound::Play>("play", 0);
|
||||
AddMethod<bool, &JAmbientSound::Loop>("loop", 0);
|
||||
AddMethod<bool, &JAmbientSound::Free>("free", 0);
|
||||
|
||||
CJSObject<JAmbientSound>::ScriptingInit("AmbientSound", &JAmbientSound::Construct, 1);
|
||||
}
|
||||
|
||||
CStr JAmbientSound::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
std::ostringstream stringStream;
|
||||
stringStream << "[object AmbientSound: ";
|
||||
stringStream << m_FileName->string().c_str();
|
||||
|
||||
return stringStream.str();
|
||||
}
|
||||
|
||||
JSBool JAmbientSound::Construct(JSContext* cx, uintN UNUSED(argc), jsval* vp)
|
||||
{
|
||||
// JSU_REQUIRE_MIN_PARAMS(1);
|
||||
|
||||
CStrW filename;
|
||||
if (! ToPrimitive<CStrW>(cx, JS_ARGV(cx, vp)[0], filename))
|
||||
return JS_FALSE;
|
||||
|
||||
JAmbientSound* newObject = new JAmbientSound(filename);
|
||||
newObject->m_EngineOwned = false;
|
||||
|
||||
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
51
source/soundmanager/js/AmbientSound.h
Normal file
51
source/soundmanager/js/AmbientSound.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_JAMBIENTSOUND
|
||||
#define INCLUDED_JAMBIENTSOUND
|
||||
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "soundmanager/items/ISoundItem.h"
|
||||
|
||||
class JAmbientSound : public CJSObject<JAmbientSound>
|
||||
{
|
||||
public:
|
||||
JAmbientSound(const VfsPath& pathname);
|
||||
virtual ~JAmbientSound();
|
||||
|
||||
|
||||
CStr ToString(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
bool Play(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
bool Loop(JSContext* cx, uintN argc, jsval* argv);
|
||||
bool Free(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
bool SetGain(JSContext* cx, uintN argc, jsval* argv);
|
||||
bool SetPitch(JSContext* cx, uintN argc, jsval* argv);
|
||||
bool Fade(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
|
||||
void clearSoundItem();
|
||||
static void ScriptingInit();
|
||||
protected:
|
||||
|
||||
VfsPath* m_FileName;
|
||||
|
||||
};
|
||||
|
||||
#endif // #ifndef INCLUDED_JAMBIENTSOUND
|
86
source/soundmanager/js/MusicSound.cpp
Normal file
86
source/soundmanager/js/MusicSound.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "MusicSound.h"
|
||||
|
||||
#include "lib/utf8.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "soundmanager/SoundManager.h"
|
||||
|
||||
|
||||
JMusicSound::JMusicSound(const VfsPath& pathname)
|
||||
{
|
||||
m_FileName = new VfsPath(pathname.string().c_str());
|
||||
}
|
||||
|
||||
JMusicSound::~JMusicSound()
|
||||
{
|
||||
delete m_FileName;
|
||||
}
|
||||
|
||||
bool JMusicSound::Play(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
ISoundItem* aSnd = g_SoundManager->LoadItem(m_FileName);
|
||||
if (aSnd != NULL)
|
||||
aSnd->PlayAsMusic();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// request the sound be played until free() is called. returns immediately.
|
||||
bool JMusicSound::Loop(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
ISoundItem* aSnd = g_SoundManager->LoadItem(m_FileName);
|
||||
if (aSnd != NULL)
|
||||
aSnd->PlayAsMusic();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void JMusicSound::ScriptingInit()
|
||||
{
|
||||
AddMethod<CStr, &JMusicSound::ToString>("toString", 0);
|
||||
AddMethod<bool, &JMusicSound::Play>("play", 0);
|
||||
AddMethod<bool, &JMusicSound::Loop>("loop", 0);
|
||||
|
||||
CJSObject<JMusicSound>::ScriptingInit("MusicSound", &JMusicSound::Construct, 1);
|
||||
}
|
||||
|
||||
CStr JMusicSound::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
std::ostringstream stringStream;
|
||||
stringStream << "[object MusicSound: ";
|
||||
stringStream << m_FileName->string().c_str();
|
||||
|
||||
return stringStream.str();
|
||||
}
|
||||
|
||||
JSBool JMusicSound::Construct(JSContext* cx, uintN UNUSED(argc), jsval* vp)
|
||||
{
|
||||
CStrW filename;
|
||||
if (! ToPrimitive<CStrW>(cx, JS_ARGV(cx, vp)[0], filename))
|
||||
return JS_FALSE;
|
||||
|
||||
JMusicSound* newObject = new JMusicSound(filename);
|
||||
newObject->m_EngineOwned = false;
|
||||
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
59
source/soundmanager/js/MusicSound.h
Normal file
59
source/soundmanager/js/MusicSound.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// JS sound binding
|
||||
|
||||
// interface rationale:
|
||||
// - can't just expose fire and forget playSound to script code:
|
||||
// we sometimes need to loop until a certain condition is met
|
||||
// (e.g. building is complete) => need means of access (Handle) to sound.
|
||||
//
|
||||
// - the current 64-bit Handle can't be stored as-is by JS code;
|
||||
// we could make it 32 bit, but that limits its usefulness
|
||||
// (barely enough tag bits).
|
||||
//
|
||||
// - instead, we provide a thin class wrapper (using scriptableobject.h)
|
||||
// on top of the snd API that encapsulates the Handle.
|
||||
|
||||
#ifndef INCLUDED_MUSICSOUND_H
|
||||
#define INCLUDED_MUSICSOUND_H
|
||||
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "soundmanager/items/ISoundItem.h"
|
||||
|
||||
class JMusicSound : public CJSObject<JMusicSound>
|
||||
{
|
||||
public:
|
||||
JMusicSound(const VfsPath& pathname);
|
||||
virtual ~JMusicSound();
|
||||
|
||||
// Script-bound functions
|
||||
|
||||
CStr ToString(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
bool Play(JSContext* cx, uintN argc, jsval* argv);
|
||||
bool Loop(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
static void ScriptingInit();
|
||||
|
||||
protected:
|
||||
VfsPath* m_FileName;
|
||||
};
|
||||
|
||||
#endif // #ifndef INCLUDED_MUSICSOUND_H
|
174
source/soundmanager/js/Sound.cpp
Normal file
174
source/soundmanager/js/Sound.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Sound.h"
|
||||
|
||||
#include "lib/utf8.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "soundmanager/SoundManager.h"
|
||||
|
||||
|
||||
JSound::JSound(const VfsPath& pathname)
|
||||
{
|
||||
m_SndItem = g_SoundManager->LoadItem(&pathname);
|
||||
}
|
||||
|
||||
JSound::~JSound()
|
||||
{
|
||||
if (m_SndItem)
|
||||
{
|
||||
m_SndItem->FadeAndDelete(0.2);
|
||||
m_SndItem = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool JSound::ClearSoundItem()
|
||||
{
|
||||
m_SndItem = 0L;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSound::SetGain(JSContext* cx, uintN UNUSED(argc), jsval* argv)
|
||||
{
|
||||
if (! m_SndItem)
|
||||
return false;
|
||||
|
||||
float gain;
|
||||
if (! ToPrimitive<float>(cx, argv[0], gain))
|
||||
return false;
|
||||
|
||||
m_SndItem->SetGain(gain);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSound::SetPitch(JSContext* cx, uintN UNUSED(argc), jsval* argv)
|
||||
{
|
||||
if (! m_SndItem)
|
||||
return false;
|
||||
|
||||
float pitch;
|
||||
if (! ToPrimitive<float>(cx, argv[0], pitch))
|
||||
return false;
|
||||
|
||||
m_SndItem->SetPitch(pitch);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSound::SetPosition(JSContext* cx, uintN argc, jsval* argv)
|
||||
{
|
||||
if (! m_SndItem)
|
||||
return false;
|
||||
|
||||
ENSURE(argc >= 1); // FIXME
|
||||
|
||||
CVector3D pos;
|
||||
// absolute world coords
|
||||
if (!ToPrimitive<CVector3D>(cx, argv[0], pos))
|
||||
return false;
|
||||
|
||||
m_SndItem->SetLocation(pos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool JSound::Fade(JSContext* cx, uintN UNUSED(argc), jsval* argv)
|
||||
{
|
||||
if (! m_SndItem)
|
||||
return false;
|
||||
|
||||
// ENSURE(argc >= 3); // FIXME
|
||||
float initial_gain, final_gain;
|
||||
float length;
|
||||
if (! (ToPrimitive<float>(cx, argv[0], initial_gain)
|
||||
&& ToPrimitive<float>(cx, argv[1], final_gain)
|
||||
&& ToPrimitive<float>(cx, argv[2], length)))
|
||||
return false;
|
||||
|
||||
m_SndItem->SetGain(initial_gain);
|
||||
m_SndItem->FadeToIn(final_gain, length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSound::Play(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
if (! m_SndItem)
|
||||
return false;
|
||||
|
||||
m_SndItem->Play();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSound::Loop(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
if (! m_SndItem)
|
||||
return false;
|
||||
|
||||
m_SndItem->PlayLoop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSound::Free(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
if (m_SndItem)
|
||||
{
|
||||
m_SndItem->FadeAndDelete(0.2);
|
||||
m_SndItem = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void JSound::ScriptingInit()
|
||||
{
|
||||
AddMethod<CStr, &JSound::ToString>("toString", 0);
|
||||
AddMethod<bool, &JSound::Play>("play", 0);
|
||||
AddMethod<bool, &JSound::Loop>("loop", 0);
|
||||
AddMethod<bool, &JSound::Free>("free", 0);
|
||||
AddMethod<bool, &JSound::SetGain>("setGain", 0);
|
||||
AddMethod<bool, &JSound::SetPitch>("setPitch", 0);
|
||||
AddMethod<bool, &JSound::SetPosition>("setPosition", 0);
|
||||
AddMethod<bool, &JSound::Fade>("fade", 0);
|
||||
|
||||
CJSObject<JSound>::ScriptingInit("Sound", &JSound::Construct, 1);
|
||||
}
|
||||
|
||||
CStr JSound::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
return "[object Sound: " + (m_SndItem ? m_SndItem->GetName() : "(null)") + "]";
|
||||
}
|
||||
|
||||
JSBool JSound::Construct(JSContext* cx, uintN UNUSED(argc), jsval* vp)
|
||||
{
|
||||
// JSU_REQUIRE_MIN_PARAMS(1);
|
||||
|
||||
CStrW filename;
|
||||
if (! ToPrimitive<CStrW>(cx, JS_ARGV(cx, vp)[0], filename))
|
||||
return JS_FALSE;
|
||||
|
||||
JSound* newObject = new JSound(filename);
|
||||
newObject->m_EngineOwned = false;
|
||||
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -29,50 +29,39 @@
|
||||
// - instead, we provide a thin class wrapper (using scriptableobject.h)
|
||||
// on top of the snd API that encapsulates the Handle.
|
||||
|
||||
#ifndef INCLUDED_JSI_SOUND
|
||||
#define INCLUDED_JSI_SOUND
|
||||
#ifndef INCLUDED_JSOUND
|
||||
#define INCLUDED_JSOUND
|
||||
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "lib/res/handle.h"
|
||||
#include "soundmanager/items/ISoundItem.h"
|
||||
|
||||
class JSI_Sound : public CJSObject<JSI_Sound>
|
||||
class JSound : public CJSObject<JSound>
|
||||
{
|
||||
public:
|
||||
|
||||
Handle m_Handle;
|
||||
|
||||
|
||||
// note: filename is stored by handle manager; no need to keep a copy here.
|
||||
|
||||
JSI_Sound(const VfsPath& pathname);
|
||||
~JSI_Sound();
|
||||
|
||||
// Script-bound functions
|
||||
|
||||
|
||||
JSound(const VfsPath& pathname);
|
||||
virtual ~JSound();
|
||||
|
||||
CStr ToString(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
// start playing the sound (one-shot).
|
||||
// it will automatically be freed when done.
|
||||
|
||||
bool Play(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
// request the sound be played until free() is called. returns immediately.
|
||||
bool Loop(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
// stop sound if currently playing and free resources.
|
||||
// doesn't need to be called unless played via loop() -
|
||||
// sounds are freed automatically when done playing.
|
||||
|
||||
bool Free(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
bool SetGain(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
bool SetPitch(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
bool SetPosition(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
bool ClearSoundItem();
|
||||
|
||||
bool Fade(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
|
||||
static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
static void ScriptingInit();
|
||||
|
||||
protected:
|
||||
ISoundItem* m_SndItem;
|
||||
};
|
||||
|
||||
#endif // #ifndef INCLUDED_JSI_SOUND
|
||||
#endif // #ifndef INCLUDED_JSOUND
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -17,24 +17,33 @@
|
||||
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : SoundGroup.cpp
|
||||
* Project : 0 A.D.
|
||||
* File : SoundGroup.cpp
|
||||
* Project : 0 A.D.
|
||||
* Description : Loads up a group of sound files with shared properties,
|
||||
* and provides a simple interface for playing them.
|
||||
* and provides a simple interface for playing them.
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "SoundGroup.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "graphics/Camera.h"
|
||||
#include "graphics/GameView.h"
|
||||
#include "lib/rand.h"
|
||||
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Util.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "soundmanager/items/ISoundItem.h"
|
||||
#include "soundmanager/SoundManager.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
extern CGame *g_Game;
|
||||
|
||||
#define PI 3.14126f
|
||||
|
||||
|
||||
static const bool DISABLE_INTENSITY = true; // disable for now since it's broken
|
||||
@ -53,7 +62,7 @@ void CSoundGroup::SetDefaultValues()
|
||||
m_CurTime = 0.0f;
|
||||
|
||||
// sane defaults; will probably be replaced by the values read during LoadSoundGroup.
|
||||
SetGain(0.5f);
|
||||
SetGain(0.7f);
|
||||
m_Pitch = 1.0f;
|
||||
m_Priority = 60;
|
||||
m_PitchUpper = 1.1f;
|
||||
@ -90,150 +99,163 @@ static float RandFloat(float min, float max)
|
||||
return float(rand(min*100.0f, max*100.0f) / 100.0f);
|
||||
}
|
||||
|
||||
void CSoundGroup::UploadPropertiesAndPlay(Handle hSound, const CVector3D& position)
|
||||
float CSoundGroup::RadiansOffCenter(const CVector3D& position, bool& onScreen, float& itemRollOff)
|
||||
{
|
||||
// interface/UI sounds should always be played at the listener's
|
||||
// position, which is achieved by setting position to 0 and
|
||||
// having that treated as relative to the listener.
|
||||
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||
bool relative = true;
|
||||
if(!TestFlag(eOmnipresent))
|
||||
float x, y;
|
||||
float answer = 0.0;
|
||||
const size_t screenWidth = g_Game->GetView()->GetCamera()->GetViewPort().m_Width;
|
||||
const size_t screenHeight = g_Game->GetView()->GetCamera()->GetViewPort().m_Height;
|
||||
float bufferSize = screenWidth * 0.10;
|
||||
const size_t audioWidth = screenWidth;
|
||||
float radianCap = PI / 3;
|
||||
|
||||
g_Game->GetView()->GetCamera()->GetScreenCoordinates(position, x, y);
|
||||
|
||||
onScreen = true;
|
||||
|
||||
if (x < -bufferSize)
|
||||
{
|
||||
x = position.X;
|
||||
y = position.Y;
|
||||
z = position.Z;
|
||||
relative = false;
|
||||
onScreen = false;
|
||||
answer = -radianCap;
|
||||
}
|
||||
else if (x > screenWidth + bufferSize)
|
||||
{
|
||||
onScreen = false;
|
||||
answer = radianCap;
|
||||
}
|
||||
else {
|
||||
if ((x < 0) || (x > screenWidth))
|
||||
{
|
||||
itemRollOff = 0.5;
|
||||
}
|
||||
float pixPerRadian = audioWidth / (radianCap * 2);
|
||||
answer = (x - (screenWidth/2)) / pixPerRadian;
|
||||
}
|
||||
|
||||
snd_set_pos(hSound, x, y, z, relative);
|
||||
if (y < -bufferSize)
|
||||
{
|
||||
onScreen = false;
|
||||
}
|
||||
else if (y > screenHeight + bufferSize)
|
||||
{
|
||||
onScreen = false;
|
||||
}
|
||||
else {
|
||||
if ((y < 0) || (y > screenHeight))
|
||||
{
|
||||
itemRollOff = 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
float gain = TestFlag(eRandGain)? RandFloat(m_GainLower, m_GainUpper) : m_Gain;
|
||||
gain = std::min(gain, 1.0f); // guard against roundoff error in RandFloat or too high m_GainUpper
|
||||
snd_set_gain(hSound, gain);
|
||||
|
||||
// debug_printf(L"do play at x portion:%f pts x:%f, y=%f at radians=%f\n\n", answer, x, y, answer);
|
||||
|
||||
const float pitch = TestFlag(eRandPitch)? RandFloat(m_PitchLower, m_PitchUpper) : m_Pitch;
|
||||
snd_set_pitch(hSound, pitch);
|
||||
return answer;
|
||||
}
|
||||
|
||||
snd_play(hSound, m_Priority);
|
||||
void CSoundGroup::UploadPropertiesAndPlay(int theIndex, const CVector3D& position)
|
||||
{
|
||||
bool isOnscreen;
|
||||
ALfloat initialRolllOff = 0.02f;
|
||||
ALfloat itemRollOff = initialRolllOff;
|
||||
|
||||
float offSet = RadiansOffCenter(position, isOnscreen, itemRollOff);
|
||||
|
||||
if (isOnscreen || TestFlag(eDistanceless) || TestFlag(eOmnipresent))
|
||||
{
|
||||
if (snd_group.size() == 0)
|
||||
Reload();
|
||||
|
||||
ISoundItem* hSound = snd_group[theIndex];
|
||||
CVector3D origin = g_Game->GetView()->GetCamera()->GetOrientation().GetTranslation();
|
||||
float sndDist = origin.Y;
|
||||
|
||||
if (!TestFlag(eOmnipresent))
|
||||
{
|
||||
hSound->SetLocation(CVector3D((sndDist * sin(offSet)), 0, sndDist * cos(offSet)));
|
||||
if (TestFlag(eDistanceless))
|
||||
hSound->SetRollOff(initialRolllOff);
|
||||
else
|
||||
hSound->SetRollOff(itemRollOff);
|
||||
}
|
||||
|
||||
if (TestFlag(eRandPitch))
|
||||
hSound->SetPitch(RandFloat(m_PitchLower, m_PitchUpper));
|
||||
else
|
||||
hSound->SetPitch(m_Pitch);
|
||||
|
||||
ALfloat theGain = m_Gain;
|
||||
if (TestFlag(eRandGain))
|
||||
theGain = RandFloat(m_GainLower, m_GainUpper);
|
||||
|
||||
hSound->SetCone(m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain);
|
||||
|
||||
g_SoundManager->PlayGroupItem(hSound, theGain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void HandleError(const std::wstring& message, const VfsPath& pathname, Status err)
|
||||
static void HandleError(const CStrW& message, const VfsPath& pathname, Status err)
|
||||
{
|
||||
if(err == ERR::AGAIN)
|
||||
if (err == ERR::AGAIN)
|
||||
return; // open failed because sound is disabled (don't log this)
|
||||
LOGERROR(L"%ls: pathname=%ls, error=%ls", message.c_str(), pathname.string().c_str(), ErrorString(err));
|
||||
}
|
||||
|
||||
void CSoundGroup::PlayNext(const CVector3D& position)
|
||||
{
|
||||
if(m_Intensity >= m_IntensityThreshold && !DISABLE_INTENSITY)
|
||||
{
|
||||
if(!snd_is_playing(m_hReplacement))
|
||||
{
|
||||
// load up replacement file
|
||||
const VfsPath pathname(m_filepath / m_intensity_file);
|
||||
m_hReplacement = snd_open(g_VFS, pathname);
|
||||
if(m_hReplacement < 0)
|
||||
{
|
||||
HandleError(L"PlayNext: snd_open for replacement file failed", pathname, (Status)m_hReplacement);
|
||||
return;
|
||||
}
|
||||
|
||||
UploadPropertiesAndPlay(m_hReplacement, position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if no sounds, return
|
||||
if (filenames.size() == 0)
|
||||
return;
|
||||
|
||||
// try loading on the fly only when we need the sound to see if that fixes release problems...
|
||||
if(TestFlag(eRandOrder))
|
||||
m_index = (size_t)rand(0, (size_t)filenames.size());
|
||||
// (note: previously snd_group[m_index] was used in place of hs)
|
||||
const VfsPath pathname(m_filepath / filenames[m_index]);
|
||||
Handle hs = snd_open(g_VFS, pathname);
|
||||
if(hs < 0)
|
||||
{
|
||||
HandleError(L"PlayNext: snd_open failed", pathname, (Status)hs);
|
||||
return;
|
||||
}
|
||||
|
||||
UploadPropertiesAndPlay(hs, position);
|
||||
}
|
||||
// if no sounds, return
|
||||
if (filenames.size() == 0)
|
||||
return;
|
||||
|
||||
playtimes.at(m_index) = 0.0f;
|
||||
m_index++;
|
||||
m_Intensity++;
|
||||
if(m_Intensity > m_IntensityThreshold)
|
||||
m_Intensity = m_IntensityThreshold;
|
||||
|
||||
if(m_index >= filenames.size())
|
||||
Reload();
|
||||
m_index = (size_t)rand(0, (size_t)filenames.size());
|
||||
UploadPropertiesAndPlay(m_index, position);
|
||||
}
|
||||
|
||||
void CSoundGroup::Reload()
|
||||
{
|
||||
m_index = 0; // reset our index
|
||||
// get rid of the used handles
|
||||
snd_group.clear();
|
||||
// clear out the old timers
|
||||
playtimes.clear();
|
||||
//Reload the sounds
|
||||
/*for(size_t i = 0; i < filenames.size(); i++)
|
||||
{
|
||||
string szTemp = m_filepath + filenames[i];
|
||||
Handle temp = snd_open(m_filepath + filenames[i]);
|
||||
snd_set_gain(temp, m_Gain);
|
||||
snd_set_pitch(temp, m_Pitch);
|
||||
snd_set_cone(temp, m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain);
|
||||
snd_group.push_back(temp);
|
||||
|
||||
}*/
|
||||
while(playtimes.size() < filenames.size())
|
||||
playtimes.push_back(-1.0f);
|
||||
//if(TestFlag(eRandOrder))
|
||||
//random_shuffle(snd_group.begin(), snd_group.end());
|
||||
snd_group.clear();
|
||||
|
||||
for (size_t i = 0; i < filenames.size(); i++)
|
||||
{
|
||||
VfsPath thePath = m_filepath/filenames[i];
|
||||
ISoundItem* temp = g_SoundManager->LoadItem(&thePath);
|
||||
|
||||
if (temp == NULL)
|
||||
HandleError(L"error loading sound", thePath, NULL);
|
||||
else
|
||||
snd_group.push_back(temp);
|
||||
}
|
||||
|
||||
if (TestFlag(eRandOrder))
|
||||
random_shuffle(snd_group.begin(), snd_group.end());
|
||||
}
|
||||
|
||||
void CSoundGroup::ReleaseGroup()
|
||||
{
|
||||
for(size_t i = m_index; i<snd_group.size(); i++)
|
||||
for (size_t i = 0; i < snd_group.size(); i++)
|
||||
{
|
||||
//if(!snd_is_playing(snd_group[i]))
|
||||
snd_free(snd_group[i]);
|
||||
snd_group[i]->FadeAndDelete(0.2);
|
||||
}
|
||||
snd_group.clear();
|
||||
playtimes.clear();
|
||||
//if(snd_is_playing(m_hReplacement))
|
||||
// snd_free(m_hReplacement);
|
||||
m_index = 0;
|
||||
|
||||
}
|
||||
|
||||
void CSoundGroup::Update(float TimeSinceLastFrame)
|
||||
void CSoundGroup::Update(float UNUSED(TimeSinceLastFrame))
|
||||
{
|
||||
for(size_t i = 0; i < playtimes.size(); i++)
|
||||
{
|
||||
if(playtimes[i] >= 0.0f)
|
||||
playtimes[i] += TimeSinceLastFrame;
|
||||
|
||||
if(playtimes[i] >= m_Decay)
|
||||
{
|
||||
playtimes[i] = -1.0f;
|
||||
m_Intensity--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CSoundGroup::LoadSoundGroup(const VfsPath& pathnameXML)
|
||||
{
|
||||
// LOGERROR(L"loading new sound group '%ls'", pathnameXML.string().c_str());
|
||||
|
||||
CXeromyces XeroFile;
|
||||
if (XeroFile.Load(g_VFS, pathnameXML) != PSRETURN_OK)
|
||||
{
|
||||
HandleError(L"error loading file", pathnameXML, NULL);
|
||||
return false;
|
||||
|
||||
}
|
||||
// Define elements used in XML file
|
||||
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
||||
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
|
||||
@ -241,6 +263,7 @@ bool CSoundGroup::LoadSoundGroup(const VfsPath& pathnameXML)
|
||||
EL(gain);
|
||||
EL(looping);
|
||||
EL(omnipresent);
|
||||
EL(distanceless);
|
||||
EL(pitch);
|
||||
EL(priority);
|
||||
EL(randorder);
|
||||
@ -257,7 +280,6 @@ bool CSoundGroup::LoadSoundGroup(const VfsPath& pathnameXML)
|
||||
EL(path);
|
||||
EL(threshold);
|
||||
EL(decay);
|
||||
EL(replacement);
|
||||
#undef AT
|
||||
#undef EL
|
||||
|
||||
@ -288,6 +310,11 @@ bool CSoundGroup::LoadSoundGroup(const VfsPath& pathnameXML)
|
||||
if(child.GetText().ToInt() == 1)
|
||||
SetFlag(eOmnipresent);
|
||||
}
|
||||
else if(child_name == el_distanceless)
|
||||
{
|
||||
if(child.GetText().ToInt() == 1)
|
||||
SetFlag(eDistanceless);
|
||||
}
|
||||
else if(child_name == el_pitch)
|
||||
{
|
||||
this->m_Pitch = child.GetText().ToFloat();
|
||||
@ -355,12 +382,7 @@ bool CSoundGroup::LoadSoundGroup(const VfsPath& pathnameXML)
|
||||
{
|
||||
m_Decay = child.GetText().ToFloat();
|
||||
}
|
||||
else if(child_name == el_replacement)
|
||||
{
|
||||
m_intensity_file = child.GetText().FromUTF8();
|
||||
}
|
||||
}
|
||||
|
||||
Reload();
|
||||
return true;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -17,10 +17,10 @@
|
||||
|
||||
/**
|
||||
* =========================================================================
|
||||
* File : SoundGroup.h
|
||||
* Project : 0 A.D.
|
||||
* File : SoundGroup.h
|
||||
* Project : 0 A.D.
|
||||
* Description : Loads up a group of sound files with shared properties,
|
||||
* and provides a simple interface for playing them.
|
||||
* and provides a simple interface for playing them.
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
@ -49,24 +49,24 @@ Example SoundGroup.xml
|
||||
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SOUNDGROUP
|
||||
#define INCLUDED_SOUNDGROUP
|
||||
#ifndef INCLUDED_SOUNDGROUP_H
|
||||
#define INCLUDED_SOUNDGROUP_H
|
||||
|
||||
#include "lib/res/handle.h"
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "lib/res/sound/snd_mgr.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class CVector3D;
|
||||
class ISoundItem;
|
||||
|
||||
enum eSndGrpFlags
|
||||
{
|
||||
eRandOrder = 0x01,
|
||||
eRandGain = 0x02,
|
||||
eRandPitch = 0x04,
|
||||
eLoop = 0x08,
|
||||
eOmnipresent = 0x10
|
||||
eRandOrder = 0x01,
|
||||
eRandGain = 0x02,
|
||||
eRandPitch = 0x04,
|
||||
eLoop = 0x08,
|
||||
eOmnipresent = 0x10,
|
||||
eDistanceless = 0x20
|
||||
};
|
||||
|
||||
|
||||
@ -75,14 +75,16 @@ class CSoundGroup
|
||||
NONCOPYABLE(CSoundGroup);
|
||||
public:
|
||||
CSoundGroup(const VfsPath& pathnameXML);
|
||||
CSoundGroup(void);
|
||||
~CSoundGroup(void);
|
||||
CSoundGroup();
|
||||
~CSoundGroup();
|
||||
|
||||
// Play next sound in group
|
||||
// @param position world position of the entity generating the sound
|
||||
// (ignored if the eOmnipresent flag is set)
|
||||
void PlayNext(const CVector3D& position);
|
||||
|
||||
float RadiansOffCenter(const CVector3D& position, bool& onScreen, float& itemRollOff);
|
||||
|
||||
// Load a group
|
||||
bool LoadSoundGroup(const VfsPath& pathnameXML);
|
||||
|
||||
@ -102,18 +104,15 @@ public:
|
||||
|
||||
private:
|
||||
void SetGain(float gain);
|
||||
void UploadPropertiesAndPlay(Handle hSound, const CVector3D& position);
|
||||
void UploadPropertiesAndPlay(int theIndex, const CVector3D& position);
|
||||
void SetDefaultValues();
|
||||
|
||||
size_t m_index; // index of the next sound to play
|
||||
|
||||
Handle m_hReplacement;
|
||||
|
||||
std::vector<Handle> snd_group; // we store the handles so we can load now and play later
|
||||
|
||||
std::vector<ISoundItem*> snd_group; // we store the handles so we can load now and play later
|
||||
std::vector<std::wstring> filenames; // we need the filenames so we can reload when necessary.
|
||||
std::vector<float> playtimes; // it would be better to store this in with the Handles perhaps?
|
||||
|
||||
VfsPath m_filepath; // the file path for the list of sound file resources
|
||||
std::wstring m_intensity_file; // the replacement aggregate 'intense' sound
|
||||
|
||||
float m_CurTime; // Time elapsed since soundgroup was created
|
||||
float m_TimeWindow; // The Intensity Threshold Window
|
||||
@ -134,4 +133,4 @@ private:
|
||||
float m_ConeOuterAngle;
|
||||
};
|
||||
|
||||
#endif //#ifndef INCLUDED_SOUNDGROUP
|
||||
#endif //#ifndef INCLUDED_SOUNDGROUP_H
|
75
source/soundmanager/js/SoundPlayer.cpp
Normal file
75
source/soundmanager/js/SoundPlayer.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "SoundPlayer.h"
|
||||
|
||||
#include "lib/utf8.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "soundmanager/SoundManager.h"
|
||||
|
||||
|
||||
JSoundPlayer::JSoundPlayer()
|
||||
{
|
||||
}
|
||||
|
||||
JSoundPlayer::~JSoundPlayer()
|
||||
{
|
||||
}
|
||||
|
||||
bool JSoundPlayer::StartMusic(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
g_SoundManager->SetMusicEnabled(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// request the sound be played until free() is called. returns immediately.
|
||||
bool JSoundPlayer::StopMusic(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
g_SoundManager->SetMusicEnabled(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void JSoundPlayer::ScriptingInit()
|
||||
{
|
||||
AddMethod<CStr, &JSoundPlayer::ToString>("toString", 0);
|
||||
AddMethod<bool, &JSoundPlayer::StartMusic>("startMusic", 0);
|
||||
AddMethod<bool, &JSoundPlayer::StopMusic>("stopMusic", 0);
|
||||
|
||||
CJSObject<JSoundPlayer>::ScriptingInit("SoundPlayer", &JSoundPlayer::Construct, 1);
|
||||
}
|
||||
|
||||
JSBool JSoundPlayer::Construct(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* vp)
|
||||
{
|
||||
JSoundPlayer* newObject = new JSoundPlayer();
|
||||
newObject->m_EngineOwned = false;
|
||||
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
CStr JSoundPlayer::ToString(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
||||
{
|
||||
std::ostringstream stringStream;
|
||||
stringStream << "[object MusicPlayer]";
|
||||
|
||||
return stringStream.str();
|
||||
}
|
||||
|
58
source/soundmanager/js/SoundPlayer.h
Normal file
58
source/soundmanager/js/SoundPlayer.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. 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
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// JS sound binding
|
||||
|
||||
// interface rationale:
|
||||
// - can't just expose fire and forget playSound to script code:
|
||||
// we sometimes need to loop until a certain condition is met
|
||||
// (e.g. building is complete) => need means of access (Handle) to sound.
|
||||
//
|
||||
// - the current 64-bit Handle can't be stored as-is by JS code;
|
||||
// we could make it 32 bit, but that limits its usefulness
|
||||
// (barely enough tag bits).
|
||||
//
|
||||
// - instead, we provide a thin class wrapper (using scriptableobject.h)
|
||||
// on top of the snd API that encapsulates the Handle.
|
||||
|
||||
#ifndef INCLUDED_JSOUNDPLAYER
|
||||
#define INCLUDED_JSOUNDPLAYER
|
||||
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "soundmanager/items/ISoundItem.h"
|
||||
|
||||
class JSoundPlayer : public CJSObject<JSoundPlayer>
|
||||
{
|
||||
public:
|
||||
JSoundPlayer();
|
||||
virtual ~JSoundPlayer();
|
||||
|
||||
// Script-bound functions
|
||||
|
||||
CStr ToString(JSContext* cx, uintN argc, jsval* argv);
|
||||
|
||||
bool StartMusic(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv));
|
||||
bool StopMusic(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv));
|
||||
|
||||
static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
|
||||
static void ScriptingInit();
|
||||
|
||||
protected:
|
||||
VfsPath* m_FileName;
|
||||
};
|
||||
|
||||
#endif // #ifndef INCLUDED_JSOUNDPLAYER
|
Loading…
Reference in New Issue
Block a user