Initial commit
This commit is contained in:
429
engines/sword25/sfx/soundengine.cpp
Normal file
429
engines/sword25/sfx/soundengine.cpp
Normal file
@@ -0,0 +1,429 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sword25/sword25.h"
|
||||
#include "sword25/sfx/soundengine.h"
|
||||
#include "sword25/package/packagemanager.h"
|
||||
#include "sword25/kernel/resource.h"
|
||||
#include "sword25/kernel/inputpersistenceblock.h"
|
||||
#include "sword25/kernel/outputpersistenceblock.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/vorbis.h"
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/config-manager.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
class SoundResource : public Resource {
|
||||
public:
|
||||
SoundResource(const Common::String &fileName) : Resource(fileName, Resource::TYPE_SOUND), _fname(fileName) {}
|
||||
~SoundResource() override {
|
||||
debugC(1, kDebugSound, "SoundResource: Unloading file %s", _fname.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
Common::String _fname;
|
||||
};
|
||||
|
||||
|
||||
SoundEngine::SoundEngine(Kernel *pKernel) : ResourceService(pKernel) {
|
||||
if (!registerScriptBindings())
|
||||
error("Script bindings could not be registered.");
|
||||
else
|
||||
debugC(kDebugSound, "Script bindings registered.");
|
||||
|
||||
_mixer = g_system->getMixer();
|
||||
|
||||
_maxHandleId = 1;
|
||||
|
||||
// Get the selected "music device" (defaults to MT_AUTO device)
|
||||
// as set from Audio > Music Device dropdown setting, which commonly is for MIDI driver selection.
|
||||
// Since this engine does not use MIDI, but the setting is still available from the "Global Options... > Audio"
|
||||
// and the specific game options (Game Options... > Audio), we respect only the option "No Music" to avoid end user confusion.
|
||||
// All other options for this dropdown will result in music playing and are treated as irrelevant.
|
||||
Common::String selDevStr = ConfMan.hasKey("music_driver") ? ConfMan.get("music_driver") : Common::String("auto");
|
||||
_noMusic = (selDevStr.compareToIgnoreCase(Common::String("null")) == 0);
|
||||
|
||||
if (_noMusic) {
|
||||
warning("AUDIO: MUSIC IS FORCED TO OFF (BY THE MIDI DRIVER SETTING - music_driver was set to \"null\")");
|
||||
ConfMan.setInt("music_volume", 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool SoundEngine::init(uint sampleRate, uint channels) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoundEngine::update() {
|
||||
}
|
||||
|
||||
void SoundEngine::setVolume(float volume, SOUND_TYPES type) {
|
||||
int val = (int)(255 * volume);
|
||||
|
||||
switch (type) {
|
||||
case SoundEngine::MUSIC:
|
||||
if (!_noMusic) {
|
||||
ConfMan.setInt("music_volume", val);
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, val);
|
||||
}
|
||||
break;
|
||||
case SoundEngine::SPEECH:
|
||||
ConfMan.setInt("speech_volume", val);
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, val);
|
||||
break;
|
||||
case SoundEngine::SFX:
|
||||
ConfMan.setInt("sfx_volume", val);
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, val);
|
||||
break;
|
||||
default:
|
||||
error("Unknown SOUND_TYPE");
|
||||
}
|
||||
}
|
||||
|
||||
float SoundEngine::getVolume(SOUND_TYPES type) {
|
||||
int val = 0;
|
||||
|
||||
switch (type) {
|
||||
case SoundEngine::MUSIC:
|
||||
val = _noMusic ? 0 : ConfMan.getInt("music_volume");
|
||||
break;
|
||||
case SoundEngine::SPEECH:
|
||||
val = ConfMan.getInt("speech_volume");
|
||||
break;
|
||||
case SoundEngine::SFX:
|
||||
val = ConfMan.getInt("sfx_volume");
|
||||
break;
|
||||
default:
|
||||
error("Unknown SOUND_TYPE");
|
||||
}
|
||||
|
||||
return (float)val / 255.0f;
|
||||
}
|
||||
|
||||
void SoundEngine::pauseAll() {
|
||||
debugC(1, kDebugSound, "SoundEngine::pauseAll()");
|
||||
|
||||
_mixer->pauseAll(true);
|
||||
}
|
||||
|
||||
void SoundEngine::resumeAll() {
|
||||
debugC(1, kDebugSound, "SoundEngine::resumeAll()");
|
||||
|
||||
_mixer->pauseAll(false);
|
||||
}
|
||||
|
||||
void SoundEngine::pauseLayer(uint layer) {
|
||||
// Not used in the game
|
||||
|
||||
warning("SoundEngine::pauseLayer(%d)", layer);
|
||||
}
|
||||
|
||||
void SoundEngine::resumeLayer(uint layer) {
|
||||
// Not used in the game
|
||||
|
||||
warning("SoundEngine::resumeLayer(%d)", layer);
|
||||
}
|
||||
|
||||
SndHandle *SoundEngine::getHandle(uint *id) {
|
||||
|
||||
for (uint i = 0; i < SOUND_HANDLES; i++) {
|
||||
if (_handles[i].type != kFreeHandle && !_mixer->isSoundHandleActive(_handles[i].handle)) {
|
||||
debugC(1, kDebugSound, "Handle %d has finished playing", _handles[i].id);
|
||||
_handles[i].type = kFreeHandle;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < SOUND_HANDLES; i++) {
|
||||
if (_handles[i].type == kFreeHandle) {
|
||||
debugC(1, kDebugSound, "Allocated handle %d", _handles[i].id);
|
||||
_handles[i].id = _maxHandleId;
|
||||
_handles[i].type = kAllocatedHandle;
|
||||
|
||||
if (id)
|
||||
*id = _maxHandleId;
|
||||
|
||||
_maxHandleId++;
|
||||
|
||||
return &_handles[i];
|
||||
}
|
||||
}
|
||||
|
||||
error("Sound::getHandle(): Too many sound handles");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SndHandle *SoundEngine::findHandle(uint id) {
|
||||
for (uint i = 0; i < SOUND_HANDLES; i++) {
|
||||
if (_handles[i].id == id)
|
||||
return &_handles[i];
|
||||
}
|
||||
|
||||
warning("Sound::findHandle(): Unknown handle");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Audio::Mixer::SoundType getType(SoundEngine::SOUND_TYPES type) {
|
||||
switch (type) {
|
||||
case SoundEngine::MUSIC:
|
||||
return Audio::Mixer::kMusicSoundType;
|
||||
case SoundEngine::SPEECH:
|
||||
return Audio::Mixer::kSpeechSoundType;
|
||||
case SoundEngine::SFX:
|
||||
return Audio::Mixer::kSFXSoundType;
|
||||
default:
|
||||
error("Unknown SOUND_TYPE");
|
||||
}
|
||||
|
||||
return Audio::Mixer::kPlainSoundType;
|
||||
}
|
||||
|
||||
bool SoundEngine::playSound(const Common::String &fileName, SOUND_TYPES type, float volume, float pan, bool loop, int loopStart, int loopEnd, uint layer) {
|
||||
debugC(1, kDebugSound, "SoundEngine::playSound(filename='%s', type=%d, volume=%f, pan=%f, loop=%d, loopStart=%d, loopEnd=%d, layer=%d)", fileName.c_str(), type, volume, pan, loop, loopStart, loopEnd, layer);
|
||||
|
||||
playSoundEx(fileName, type, volume, pan, loop, loopStart, loopEnd, layer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint SoundEngine::playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume, float pan, bool loop, int loopStart, int loopEnd, uint layer, uint handleId) {
|
||||
if (type == MUSIC && _noMusic)
|
||||
return 0;
|
||||
|
||||
uint id = handleId;
|
||||
SndHandle *handle;
|
||||
|
||||
if (handleId == 0x1337)
|
||||
handle = getHandle(&id);
|
||||
else
|
||||
handle = &_handles[handleId];
|
||||
|
||||
handle->fileName = fileName;
|
||||
handle->sndType = type;
|
||||
handle->volume = volume;
|
||||
handle->pan = pan;
|
||||
handle->loop = loop;
|
||||
handle->loopStart = loopStart;
|
||||
handle->loopEnd = loopEnd;
|
||||
handle->layer = layer;
|
||||
|
||||
debugC(1, kDebugSound, "SoundEngine::playSoundEx(fileName='%s', type=%d, volume=%f, pan=%f, loop=%d, loopStart=%d, loopEnd=%d, layer=%d)", fileName.c_str(), type, volume, pan, loop, loopStart, loopEnd, layer);
|
||||
|
||||
#ifdef USE_VORBIS
|
||||
Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(fileName);
|
||||
|
||||
Audio::SeekableAudioStream *stream = Audio::makeVorbisStream(in, DisposeAfterUse::YES);
|
||||
|
||||
if (loop) {
|
||||
Audio::AudioStream *audio = new Audio::LoopingAudioStream(stream, 0, DisposeAfterUse::YES);
|
||||
|
||||
_mixer->playStream(getType(type), &(handle->handle), audio, -1, (byte)(volume * 255), (int8)(pan * 127));
|
||||
} else {
|
||||
_mixer->playStream(getType(type), &(handle->handle), stream, -1, (byte)(volume * 255), (int8)(pan * 127));
|
||||
}
|
||||
#endif
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void SoundEngine::setSoundVolume(uint handle, float volume) {
|
||||
debugC(1, kDebugSound, "SoundEngine::setSoundVolume(%d, %f)", handle, volume);
|
||||
|
||||
SndHandle* sndHandle = findHandle(handle);
|
||||
if (sndHandle != NULL) {
|
||||
sndHandle->volume = volume;
|
||||
_mixer->setChannelVolume(sndHandle->handle, (byte)(volume * 255));
|
||||
}
|
||||
}
|
||||
|
||||
void SoundEngine::setSoundPanning(uint handle, float pan) {
|
||||
debugC(1, kDebugSound, "SoundEngine::setSoundPanning(%d, %f)", handle, pan);
|
||||
|
||||
SndHandle* sndHandle = findHandle(handle);
|
||||
if (sndHandle != NULL) {
|
||||
sndHandle->pan = pan;
|
||||
_mixer->setChannelBalance(sndHandle->handle, (int8)(pan * 127));
|
||||
}
|
||||
}
|
||||
|
||||
void SoundEngine::pauseSound(uint handle) {
|
||||
debugC(1, kDebugSound, "SoundEngine::pauseSound(%d)", handle);
|
||||
|
||||
SndHandle* sndHandle = findHandle(handle);
|
||||
if (sndHandle != NULL)
|
||||
_mixer->pauseHandle(sndHandle->handle, true);
|
||||
}
|
||||
|
||||
void SoundEngine::resumeSound(uint handle) {
|
||||
debugC(1, kDebugSound, "SoundEngine::resumeSound(%d)", handle);
|
||||
|
||||
SndHandle* sndHandle = findHandle(handle);
|
||||
if (sndHandle != NULL)
|
||||
_mixer->pauseHandle(sndHandle->handle, false);
|
||||
}
|
||||
|
||||
void SoundEngine::stopSound(uint handle) {
|
||||
debugC(1, kDebugSound, "SoundEngine::stopSound(%d)", handle);
|
||||
|
||||
SndHandle* sndHandle = findHandle(handle);
|
||||
if (sndHandle != NULL)
|
||||
_mixer->stopHandle(sndHandle->handle);
|
||||
}
|
||||
|
||||
bool SoundEngine::isSoundPaused(uint handle) {
|
||||
// Not used in the game
|
||||
|
||||
warning("SoundEngine::isSoundPaused(%d)", handle);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SoundEngine::isSoundPlaying(uint handle) {
|
||||
debugC(1, kDebugSound, "SoundEngine::isSoundPlaying(%d)", handle);
|
||||
|
||||
SndHandle* sndHandle = findHandle(handle);
|
||||
if (sndHandle == NULL)
|
||||
return false;
|
||||
return _mixer->isSoundHandleActive(sndHandle->handle);
|
||||
}
|
||||
|
||||
float SoundEngine::getSoundVolume(uint handle) {
|
||||
debugC(1, kDebugSound, "SoundEngine::getSoundVolume(%d)", handle);
|
||||
|
||||
SndHandle* sndHandle = findHandle(handle);
|
||||
if (sndHandle == NULL)
|
||||
return 0.f;
|
||||
return (float)_mixer->getChannelVolume(sndHandle->handle) / 255.0f;
|
||||
}
|
||||
|
||||
float SoundEngine::getSoundPanning(uint handle) {
|
||||
debugC(1, kDebugSound, "SoundEngine::getSoundPanning(%d)", handle);
|
||||
|
||||
SndHandle* sndHandle = findHandle(handle);
|
||||
if (sndHandle == NULL)
|
||||
return 0.f;
|
||||
return (float)_mixer->getChannelBalance(sndHandle->handle) / 127.0f;
|
||||
}
|
||||
|
||||
Resource *SoundEngine::loadResource(const Common::String &fileName) {
|
||||
return new SoundResource(fileName);
|
||||
}
|
||||
|
||||
bool SoundEngine::canLoadResource(const Common::String &fileName) {
|
||||
Common::String fname = fileName;
|
||||
|
||||
debugC(1, kDebugSound, "SoundEngine::canLoadResource(%s)", fileName.c_str());
|
||||
|
||||
fname.toLowercase();
|
||||
|
||||
return fname.hasSuffix(".ogg");
|
||||
}
|
||||
|
||||
bool SoundEngine::persist(OutputPersistenceBlock &writer) {
|
||||
writer.write(_maxHandleId);
|
||||
|
||||
for (uint i = 0; i < SOUND_HANDLES; i++) {
|
||||
writer.write(_handles[i].id);
|
||||
|
||||
// Don't restart sounds which already finished playing.
|
||||
if (_handles[i].type != kFreeHandle && !_mixer->isSoundHandleActive(_handles[i].handle))
|
||||
_handles[i].type = kFreeHandle;
|
||||
|
||||
writer.writeString(_handles[i].fileName);
|
||||
if (_handles[i].type == kFreeHandle)
|
||||
writer.write((int32)-1);
|
||||
else
|
||||
writer.write(_handles[i].sndType);
|
||||
writer.write(_handles[i].volume);
|
||||
writer.write(_handles[i].pan);
|
||||
writer.write(_handles[i].loop);
|
||||
writer.write(_handles[i].loopStart);
|
||||
writer.write(_handles[i].loopEnd);
|
||||
writer.write(_handles[i].layer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundEngine::unpersist(InputPersistenceBlock &reader) {
|
||||
_mixer->stopAll();
|
||||
|
||||
if (reader.getVersion() < 2)
|
||||
return true;
|
||||
|
||||
reader.read(_maxHandleId);
|
||||
|
||||
for (uint i = 0; i < SOUND_HANDLES; i++) {
|
||||
reader.read(_handles[i].id);
|
||||
|
||||
Common::String fileName;
|
||||
int32 sndType;
|
||||
float volume;
|
||||
float pan;
|
||||
bool loop;
|
||||
int32 loopStart;
|
||||
int32 loopEnd;
|
||||
uint32 layer;
|
||||
|
||||
reader.readString(fileName);
|
||||
reader.read(sndType);
|
||||
reader.read(volume);
|
||||
reader.read(pan);
|
||||
reader.read(loop);
|
||||
reader.read(loopStart);
|
||||
reader.read(loopEnd);
|
||||
reader.read(layer);
|
||||
|
||||
if (reader.isGood()) {
|
||||
if (sndType != -1)
|
||||
playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i);
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
return reader.isGood();
|
||||
}
|
||||
|
||||
SndHandle::SndHandle() :
|
||||
type(kFreeHandle),
|
||||
id(0),
|
||||
sndType(-1),
|
||||
volume(0),
|
||||
pan(0),
|
||||
loop(false),
|
||||
loopStart(0),
|
||||
loopEnd(0),
|
||||
layer(0) {
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
269
engines/sword25/sfx/soundengine.h
Normal file
269
engines/sword25/sfx/soundengine.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* BS_SoundEngine
|
||||
* -------------
|
||||
* This is the sound engine interface that contains all the methods a sound
|
||||
* engine must implement.
|
||||
* Implementations of the sound engine have to be derived from this class.
|
||||
* It should be noted that a sound engine must maintain a list of all the
|
||||
* samples it uses, and that these samples should be released when the
|
||||
* destructor is called.
|
||||
*
|
||||
* Autor: Malte Thiesen
|
||||
*/
|
||||
|
||||
#ifndef SWORD25_SOUNDENGINE_H
|
||||
#define SWORD25_SOUNDENGINE_H
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/resservice.h"
|
||||
#include "sword25/kernel/persistable.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
#define SOUND_HANDLES 32
|
||||
|
||||
enum sndHandleType {
|
||||
kFreeHandle,
|
||||
kAllocatedHandle
|
||||
};
|
||||
|
||||
struct SndHandle {
|
||||
Audio::SoundHandle handle;
|
||||
sndHandleType type;
|
||||
uint32 id;
|
||||
|
||||
Common::String fileName;
|
||||
int32 sndType;
|
||||
float volume;
|
||||
float pan;
|
||||
bool loop;
|
||||
int32 loopStart;
|
||||
int32 loopEnd;
|
||||
uint32 layer;
|
||||
|
||||
SndHandle();
|
||||
};
|
||||
|
||||
|
||||
class SoundEngine : public ResourceService, public Persistable {
|
||||
public:
|
||||
enum SOUND_TYPES {
|
||||
MUSIC = 0,
|
||||
SPEECH = 1,
|
||||
SFX = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* The callback function of PlayDynamicSoundEx
|
||||
* @param UserData User-specified pointer
|
||||
* @param Data Pointer to the data buffer
|
||||
* @param DataLength Length of the data to be written in bytes
|
||||
*/
|
||||
typedef void (*DynamicSoundReadCallback)(void *UserData, void *Data, uint DataLength);
|
||||
|
||||
SoundEngine(Kernel *pKernel);
|
||||
~SoundEngine() override {}
|
||||
|
||||
/**
|
||||
* Initializes the sound engine
|
||||
* @param SampleRate Specifies the sample rate to use.
|
||||
* @param Channels The maximum number of channels. The default is 32.
|
||||
* @return Returns true on success, otherwise false.
|
||||
* @remark Calls to other methods may take place only if this
|
||||
* method was called successfully.
|
||||
*/
|
||||
bool init(uint sampleRate, uint channels = 32);
|
||||
|
||||
/**
|
||||
* Performs a "tick" of the sound engine
|
||||
*
|
||||
* This method should be called once per frame. It can be used by implementations
|
||||
* of the sound engine that are not running in their own thread, or to perform
|
||||
* additional administrative tasks that are needed.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Sets the default volume for the different sound types
|
||||
* @param Volume The default volume level (0 = off, 1 = full volume)
|
||||
* @param Type The SoundType whose volume is to be changed
|
||||
*/
|
||||
void setVolume(float volume, SOUND_TYPES type);
|
||||
|
||||
/**
|
||||
* Specifies the default volume of different sound types
|
||||
* @param Type The SoundType
|
||||
* @return Returns the standard sound volume for the given type
|
||||
* (0 = off, 1 = full volume).
|
||||
*/
|
||||
float getVolume(SOUND_TYPES type);
|
||||
|
||||
/**
|
||||
* Pauses all the sounds that are playing.
|
||||
*/
|
||||
void pauseAll();
|
||||
|
||||
/**
|
||||
* Resumes all currently stopped sounds
|
||||
*/
|
||||
void resumeAll();
|
||||
|
||||
/**
|
||||
* Pauses all sounds of a given layer.
|
||||
* @param Layer The Sound Layer
|
||||
*/
|
||||
void pauseLayer(uint layer);
|
||||
|
||||
/**
|
||||
* Resumes all the sounds in a layer that was previously stopped with PauseLayer()
|
||||
* @param Layer The Sound Layer
|
||||
*/
|
||||
void resumeLayer(uint layer);
|
||||
|
||||
/**
|
||||
* Plays a sound
|
||||
* @param FileName The filename of the sound to be played
|
||||
* @param Type The type of sound
|
||||
* @param Volume The volume of the sound (0 = off, 1 = full volume)
|
||||
* @param Pan Panning (-1 = full left, 1 = right)
|
||||
* @param Loop Indicates whether the sound should be looped
|
||||
* @param LoopStart Indicates the starting loop point. If a value less than 0 is passed, the start
|
||||
* of the sound is used.
|
||||
* @param LoopEnd Indicates the ending loop point. If a avlue is passed less than 0, the end of
|
||||
* the sound is used.
|
||||
* @param Layer The sound layer
|
||||
* @return Returns true if the playback of the sound was started successfully.
|
||||
* @remark If more control is needed over the playing, eg. changing the sound parameters
|
||||
* for Volume and Panning, then PlaySoundEx should be used.
|
||||
*/
|
||||
bool playSound(const Common::String &fileName, SOUND_TYPES type, float volume = 1.0f, float pan = 0.0f, bool loop = false, int loopStart = -1, int loopEnd = -1, uint layer = 0);
|
||||
|
||||
/**
|
||||
* Plays a sound
|
||||
* @param Type The type of sound
|
||||
* @param Volume The volume of the sound (0 = off, 1 = full volume)
|
||||
* @param Pan Panning (-1 = full left, 1 = right)
|
||||
* @param Loop Indicates whether the sound should be looped
|
||||
* @param LoopStart Indicates the starting loop point. If a value less than 0 is passed, the start
|
||||
* of the sound is used.
|
||||
* @param LoopEnd Indicates the ending loop point. If a avlue is passed less than 0, the end of
|
||||
* the sound is used.
|
||||
* @param Layer The sound layer
|
||||
* @return Returns a handle to the sound. With this handle, the sound can be manipulated during playback.
|
||||
* @remark If more control is needed over the playing, eg. changing the sound parameters
|
||||
* for Volume and Panning, then PlaySoundEx should be used.
|
||||
*/
|
||||
uint playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume = 1.0f, float pan = 0.0f, bool loop = false, int loopStart = -1, int loopEnd = -1, uint layer = 0, uint handleId = 0x1337);
|
||||
|
||||
/**
|
||||
* Sets the volume of a playing sound
|
||||
* @param Handle The sound handle
|
||||
* @param Volume The volume of the sound (0 = off, 1 = full volume)
|
||||
*/
|
||||
void setSoundVolume(uint handle, float volume);
|
||||
|
||||
/**
|
||||
* Sets the panning of a playing sound
|
||||
* @param Handle The sound handle
|
||||
* @param Pan Panning (-1 = full left, 1 = right)
|
||||
*/
|
||||
void setSoundPanning(uint handle, float pan);
|
||||
|
||||
/**
|
||||
* Pauses a playing sound
|
||||
* @param Handle The sound handle
|
||||
*/
|
||||
void pauseSound(uint handle);
|
||||
|
||||
/**
|
||||
* Resumes a paused sound
|
||||
* @param Handle The sound handle
|
||||
*/
|
||||
void resumeSound(uint handle);
|
||||
|
||||
/**
|
||||
* Stops a playing sound
|
||||
* @param Handle The sound handle
|
||||
* @remark Calling this method invalidates the passed handle; it can no longer be used.
|
||||
*/
|
||||
void stopSound(uint handle);
|
||||
|
||||
/**
|
||||
* Returns whether a sound is paused
|
||||
* @param Handle The sound handle
|
||||
* @return Returns true if the sound is paused, false otherwise.
|
||||
*/
|
||||
bool isSoundPaused(uint handle);
|
||||
|
||||
/**
|
||||
* Returns whether a sound is still playing.
|
||||
* @param Handle The sound handle
|
||||
* @return Returns true if the sound is playing, false otherwise.
|
||||
*/
|
||||
bool isSoundPlaying(uint handle);
|
||||
|
||||
/**
|
||||
* Returns the volume of a playing sound (0 = off, 1 = full volume)
|
||||
*/
|
||||
float getSoundVolume(uint handle);
|
||||
|
||||
/**
|
||||
* Returns the panning of a playing sound (-1 = full left, 1 = right)
|
||||
*/
|
||||
float getSoundPanning(uint handle);
|
||||
|
||||
Resource *loadResource(const Common::String &fileName) override;
|
||||
bool canLoadResource(const Common::String &fileName) override;
|
||||
|
||||
bool persist(OutputPersistenceBlock &writer) override;
|
||||
bool unpersist(InputPersistenceBlock &reader) override;
|
||||
|
||||
private:
|
||||
bool registerScriptBindings();
|
||||
SndHandle *getHandle(uint *id);
|
||||
SndHandle *findHandle(uint id);
|
||||
|
||||
private:
|
||||
Audio::Mixer *_mixer;
|
||||
SndHandle _handles[SOUND_HANDLES];
|
||||
|
||||
uint32 _maxHandleId;
|
||||
|
||||
bool _noMusic;
|
||||
};
|
||||
|
||||
} // End of namespace Sword25
|
||||
|
||||
#endif
|
||||
361
engines/sword25/sfx/soundengine_script.cpp
Normal file
361
engines/sword25/sfx/soundengine_script.cpp
Normal file
@@ -0,0 +1,361 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Broken Sword 2.5 engine
|
||||
*
|
||||
* Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
|
||||
*
|
||||
* Licensed under GNU GPL v2
|
||||
*
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Includes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "sword25/kernel/common.h"
|
||||
#include "sword25/kernel/kernel.h"
|
||||
#include "sword25/script/script.h"
|
||||
#include "sword25/script/luabindhelper.h"
|
||||
|
||||
#include "sword25/sfx/soundengine.h"
|
||||
|
||||
namespace Sword25 {
|
||||
|
||||
static int init(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
if (lua_gettop(L) == 0)
|
||||
lua_pushbooleancpp(L, pSfx->init(44100, 32));
|
||||
else if (lua_gettop(L) == 1)
|
||||
lua_pushbooleancpp(L, pSfx->init(static_cast<uint>(luaL_checknumber(L, 1)), 32));
|
||||
else
|
||||
lua_pushbooleancpp(L, pSfx->init(static_cast<uint>(luaL_checknumber(L, 1)), static_cast<uint>(luaL_checknumber(L, 2))));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int update(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->update();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setVolume(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->setVolume(static_cast<float>(luaL_checknumber(L, 1)),
|
||||
static_cast<SoundEngine::SOUND_TYPES>(static_cast<uint>(luaL_checknumber(L, 2))));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getVolume(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
lua_pushnumber(L, pSfx->getVolume(static_cast<SoundEngine::SOUND_TYPES>(static_cast<uint>(luaL_checknumber(L, 1)))));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pauseAll(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->pauseAll();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resumeAll(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->resumeAll();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pauseLayer(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->pauseLayer(static_cast<int>(luaL_checknumber(L, 1)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resumeLayer(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->resumeLayer(static_cast<int>(luaL_checknumber(L, 1)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void processPlayParams(lua_State *L, Common::String &fileName, SoundEngine::SOUND_TYPES &type, float &volume, float &pan, bool &loop, int &loopStart, int &loopEnd, uint &layer) {
|
||||
fileName = luaL_checkstring(L, 1);
|
||||
|
||||
type = static_cast<SoundEngine::SOUND_TYPES>(static_cast<uint>(luaL_checknumber(L, 2)));
|
||||
|
||||
if (lua_gettop(L) < 3 || lua_isnil(L, 3))
|
||||
volume = 1.0f;
|
||||
else
|
||||
volume = static_cast<float>(luaL_checknumber(L, 3));
|
||||
|
||||
if (lua_gettop(L) < 4 || lua_isnil(L, 4))
|
||||
pan = 0.0f;
|
||||
else
|
||||
pan = static_cast<float>(luaL_checknumber(L, 4));
|
||||
|
||||
if (lua_gettop(L) < 5 || lua_isnil(L, 5))
|
||||
loop = false;
|
||||
else
|
||||
loop = lua_tobooleancpp(L, 5);
|
||||
|
||||
if (lua_gettop(L) < 6 || lua_isnil(L, 6))
|
||||
loopStart = -1;
|
||||
else
|
||||
loopStart = static_cast<int>(luaL_checknumber(L, 6));
|
||||
|
||||
if (lua_gettop(L) < 7 || lua_isnil(L, 7))
|
||||
loopEnd = -1;
|
||||
else
|
||||
loopEnd = static_cast<int>(luaL_checknumber(L, 7));
|
||||
|
||||
if (lua_gettop(L) < 8 || lua_isnil(L, 8))
|
||||
layer = 0;
|
||||
else
|
||||
layer = static_cast<uint>(luaL_checknumber(L, 8));
|
||||
}
|
||||
|
||||
static int playSound(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
Common::String fileName;
|
||||
SoundEngine::SOUND_TYPES type;
|
||||
float volume;
|
||||
float pan;
|
||||
bool loop;
|
||||
int loopStart;
|
||||
int loopEnd;
|
||||
uint layer;
|
||||
processPlayParams(L, fileName, type, volume, pan, loop, loopStart, loopEnd, layer);
|
||||
|
||||
lua_pushbooleancpp(L, pSfx->playSound(fileName, type, volume, pan, loop, loopStart, loopEnd, layer));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int playSoundEx(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
Common::String fileName;
|
||||
SoundEngine::SOUND_TYPES type;
|
||||
float volume;
|
||||
float pan;
|
||||
bool loop;
|
||||
int loopStart;
|
||||
int loopEnd;
|
||||
uint layer;
|
||||
processPlayParams(L, fileName, type, volume, pan, loop, loopStart, loopEnd, layer);
|
||||
|
||||
lua_pushnumber(L, pSfx->playSoundEx(fileName, type, volume, pan, loop, loopStart, loopEnd, layer));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int setSoundVolume(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->setSoundVolume(static_cast<uint>(luaL_checknumber(L, 1)), static_cast<float>(luaL_checknumber(L, 2)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setSoundPanning(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->setSoundPanning(static_cast<uint>(luaL_checknumber(L, 1)), static_cast<float>(luaL_checknumber(L, 2)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pauseSound(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->pauseSound(static_cast<uint>(luaL_checknumber(L, 1)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resumeSound(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->resumeSound(static_cast<uint>(luaL_checknumber(L, 1)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stopSound(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
pSfx->stopSound(static_cast<uint>(luaL_checknumber(L, 1)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isSoundPaused(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
lua_pushbooleancpp(L, pSfx->isSoundPaused(static_cast<uint>(luaL_checknumber(L, 1))));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int isSoundPlaying(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
lua_pushbooleancpp(L, pSfx->isSoundPlaying(static_cast<uint>(luaL_checknumber(L, 1))));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getSoundVolume(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
lua_pushnumber(L, pSfx->getSoundVolume(static_cast<uint>(luaL_checknumber(L, 1))));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getSoundPanning(lua_State *L) {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
SoundEngine *pSfx = pKernel->getSfx();
|
||||
assert(pSfx);
|
||||
|
||||
lua_pushnumber(L, pSfx->getSoundPanning(static_cast<uint>(luaL_checknumber(L, 1))));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *SFX_LIBRARY_NAME = "Sfx";
|
||||
|
||||
static const luaL_reg SFX_FUNCTIONS[] = {
|
||||
{"Init", init},
|
||||
{"Update", update},
|
||||
{"__SetVolume", setVolume},
|
||||
{"__GetVolume", getVolume},
|
||||
{"PauseAll", pauseAll},
|
||||
{"ResumeAll", resumeAll},
|
||||
{"PauseLayer", pauseLayer},
|
||||
{"ResumeLayer", resumeLayer},
|
||||
{"__PlaySound", playSound},
|
||||
{"__PlaySoundEx", playSoundEx},
|
||||
{"__SetSoundVolume", setSoundVolume},
|
||||
{"__SetSoundPanning", setSoundPanning},
|
||||
{"__PauseSound", pauseSound},
|
||||
{"__ResumeSound", resumeSound},
|
||||
{"__StopSound", stopSound},
|
||||
{"__IsSoundPaused", isSoundPaused},
|
||||
{"__IsSoundPlaying", isSoundPlaying},
|
||||
{"__GetSoundVolume", getSoundVolume},
|
||||
{"__GetSoundPanning", getSoundPanning},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static const lua_constant_reg SFX_CONSTANTS[] = {
|
||||
{"MUSIC", SoundEngine::MUSIC},
|
||||
{"SPEECH", SoundEngine::SPEECH},
|
||||
{"SFX", SoundEngine::SFX},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
bool SoundEngine::registerScriptBindings() {
|
||||
Kernel *pKernel = Kernel::getInstance();
|
||||
assert(pKernel);
|
||||
ScriptEngine *pScript = pKernel->getScript();
|
||||
assert(pScript);
|
||||
lua_State *L = static_cast<lua_State *>(pScript->getScriptObject());
|
||||
assert(L);
|
||||
|
||||
if (!LuaBindhelper::addFunctionsToLib(L, SFX_LIBRARY_NAME, SFX_FUNCTIONS)) return false;
|
||||
if (!LuaBindhelper::addConstantsToLib(L, SFX_LIBRARY_NAME, SFX_CONSTANTS)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Sword25
|
||||
Reference in New Issue
Block a user