aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/sfx
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword25/sfx')
-rwxr-xr-xengines/sword25/sfx/fmodexchannel.cpp299
-rwxr-xr-xengines/sword25/sfx/fmodexchannel.h69
-rwxr-xr-xengines/sword25/sfx/fmodexexception.h51
-rwxr-xr-xengines/sword25/sfx/fmodexresource.cpp170
-rwxr-xr-xengines/sword25/sfx/fmodexresource.h56
-rwxr-xr-xengines/sword25/sfx/fmodexsound.cpp889
-rwxr-xr-xengines/sword25/sfx/fmodexsound.h142
-rwxr-xr-xengines/sword25/sfx/soundengine.cpp36
-rwxr-xr-xengines/sword25/sfx/soundengine.h253
-rwxr-xr-xengines/sword25/sfx/soundengine_script.cpp397
10 files changed, 2362 insertions, 0 deletions
diff --git a/engines/sword25/sfx/fmodexchannel.cpp b/engines/sword25/sfx/fmodexchannel.cpp
new file mode 100755
index 0000000000..88ad9640c5
--- /dev/null
+++ b/engines/sword25/sfx/fmodexchannel.cpp
@@ -0,0 +1,299 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 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.
+//
+// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Logging
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "FMODEXCHANNEL"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "fmod.h"
+#include "fmodexexception.h"
+#include "fmodexchannel.h"
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Destruktion
+// -----------------------------------------------------------------------------
+
+BS_FMODExChannel::BS_FMODExChannel(FMOD_CHANNEL * ChannelPtr, FMOD_SOUND * SoundPtr) :
+ m_ChannelPtr(ChannelPtr),
+ m_SoundPtr(SoundPtr)
+{
+}
+
+// -----------------------------------------------------------------------------
+
+BS_FMODExChannel::~BS_FMODExChannel()
+{
+ if (m_ChannelPtr) FMOD_Channel_Stop(m_ChannelPtr);
+ if (m_SoundPtr) FMOD_Sound_Release(m_SoundPtr);
+}
+
+// -----------------------------------------------------------------------------
+// FMOD Ex macht alle Kanäle ungültig, sobald sie nicht mehr abgespielt werden,
+// oder wenn der Kanal in der zwischenzeit neu vergeben wurde.
+// Dann führen alle Aufrufe von Funktionen dieser Kanäle zu dem Fehlern
+// FMOD_ERR_INVALID_HANDLE oder FMOD_ERR_CHANNEL_STOLEN
+// Dieses Soundsystem entfernt aber nur jeden Frame alle toten Kanäle. Daher
+// kann es vorkommen, dass an einem bereits toten Kanal Aufrufe getätigt werden.
+// Diese Fehler werden daher von den folgenden Methoden ignoriert.
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ bool IsImportantError(FMOD_RESULT Result)
+ {
+ return Result != FMOD_OK && Result != FMOD_ERR_INVALID_HANDLE && Result != FMOD_ERR_CHANNEL_STOLEN;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Setter
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExChannel::SetPaused(bool Paused)
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ FMOD_RESULT Result = FMOD_Channel_SetPaused(m_ChannelPtr, Paused ? 1 : 0);
+ if (IsImportantError(Result))
+ {
+ BS_FMODExException("FMOD_Channel_SetPaused()", Result).Log();
+ return false;
+ }
+ else
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExChannel::SetVolume(float Volume)
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ FMOD_RESULT Result = FMOD_Channel_SetVolume(m_ChannelPtr, Volume);
+ if (IsImportantError(Result))
+ {
+ BS_FMODExException("FMOD_Channel_SetVolume()", Result).Log();
+ return false;
+ }
+ else
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExChannel::SetPanning(float Panning)
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ FMOD_RESULT Result = FMOD_Channel_SetPan(m_ChannelPtr, Panning);
+ if (IsImportantError(Result))
+ {
+ BS_FMODExException("FMOD_Channel_SetPan()", Result).Log();
+ return false;
+ }
+ else
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExChannel::SetLoop(bool Loop)
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ FMOD_RESULT Result = FMOD_Channel_SetLoopCount(m_ChannelPtr, Loop ? -1 : 0);
+ if (IsImportantError(Result))
+ {
+ BS_FMODExException("FMOD_Channel_SetLoopCount()", Result).Log();
+ return false;
+ }
+ else
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExChannel::SetLoopPoints(unsigned int LoopStart, unsigned int LoopEnd)
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ FMOD_RESULT Result = FMOD_Channel_SetLoopPoints(m_ChannelPtr, LoopStart, FMOD_TIMEUNIT_PCM, LoopEnd, FMOD_TIMEUNIT_PCM);
+ if (IsImportantError(Result))
+ {
+ BS_FMODExException("FMOD_Channel_SetLoopPoints()", Result).Log();
+ return false;
+ }
+ else
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExChannel::SetPosition(unsigned int Position)
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ FMOD_RESULT Result = FMOD_Channel_SetPosition(m_ChannelPtr, Position, FMOD_TIMEUNIT_PCM);
+ if (IsImportantError(Result))
+ {
+ BS_FMODExException("FMOD_Channel_SetPosition()", Result).Log();
+ return false;
+ }
+ else
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExChannel::Stop()
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ FMOD_RESULT Result = FMOD_Channel_Stop(m_ChannelPtr);
+ if (IsImportantError(Result))
+ {
+ BS_FMODExException("FMOD_Channel_Stop()", Result).Log();
+ return false;
+ }
+ else
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+// Getter
+// -----------------------------------------------------------------------------
+
+float BS_FMODExChannel::GetVolume()
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ float Volume = 0;
+ FMOD_RESULT Result = FMOD_Channel_GetVolume(m_ChannelPtr, &Volume);
+ if (IsImportantError(Result)) BS_FMODExException("FMOD_Channel_GetVolume()", Result).Log();
+
+ return Volume;
+}
+
+// -----------------------------------------------------------------------------
+
+float BS_FMODExChannel::GetPanning()
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ float Panning = 0;
+ FMOD_RESULT Result = FMOD_Channel_GetPan(m_ChannelPtr, &Panning);
+ if (IsImportantError(Result)) BS_FMODExException("FMOD_Channel_GetPan()", Result).Log();
+
+ return Panning;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_FMODExChannel::GetPosition()
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ unsigned int Position = 0;
+ FMOD_RESULT Result = FMOD_Channel_GetPosition(m_ChannelPtr, &Position, FMOD_TIMEUNIT_PCM);
+ if (IsImportantError(Result)) BS_FMODExException("FMOD_Channel_GetPosition()", Result).Log();
+
+ return Position;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_FMODExChannel::GetTime()
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ unsigned int Time = 0;
+ FMOD_RESULT Result = FMOD_Channel_GetPosition(m_ChannelPtr, &Time, FMOD_TIMEUNIT_MS);
+ if (IsImportantError(Result)) BS_FMODExException("FMOD_Channel_GetPosition()", Result).Log();
+
+ return Time;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_FMODExChannel::GetLoopStart()
+{
+ BS_ASSERT(m_ChannelPtr);
+ unsigned int LoopStart = 0;
+ FMOD_RESULT Result = FMOD_Channel_GetLoopPoints(m_ChannelPtr, &LoopStart, FMOD_TIMEUNIT_PCM, 0, FMOD_TIMEUNIT_PCM);
+ if (IsImportantError(Result)) BS_FMODExException("FMOD_Channel_GetLoopPoints()", Result).Log();
+
+ return LoopStart;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_FMODExChannel::GetLoopEnd()
+{
+ BS_ASSERT(m_ChannelPtr);
+ unsigned int LoopEnd = 0;
+ FMOD_RESULT Result = FMOD_Channel_GetLoopPoints(m_ChannelPtr, 0, FMOD_TIMEUNIT_PCM, &LoopEnd, FMOD_TIMEUNIT_PCM);
+ if (IsImportantError(Result)) BS_FMODExException("FMOD_Channel_GetLoopPoints()", Result).Log();
+
+ return LoopEnd;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExChannel::IsLooping()
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ int LoopCount = 0;
+ FMOD_RESULT Result = FMOD_Channel_GetLoopCount(m_ChannelPtr, &LoopCount);
+ if (IsImportantError(Result)) BS_FMODExException("FMOD_Channel_GetLoopCount()", Result).Log();
+
+ return LoopCount == -1;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExChannel::IsPaused()
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ FMOD_BOOL Paused = 0;
+ FMOD_RESULT Result = FMOD_Channel_GetPaused(m_ChannelPtr, &Paused);
+ if (IsImportantError(Result)) BS_FMODExException("FMOD_Channel_GetPaused()", Result).Log();
+
+ return Paused != 0;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExChannel::IsPlaying()
+{
+ BS_ASSERT(m_ChannelPtr);
+
+ FMOD_BOOL Playing = 0;
+ FMOD_RESULT Result = FMOD_Channel_IsPlaying(m_ChannelPtr, &Playing);
+ if (IsImportantError(Result)) BS_FMODExException("FMOD_Channel_IsPlaying()", Result).Log();
+
+ return Playing != 0;
+}
diff --git a/engines/sword25/sfx/fmodexchannel.h b/engines/sword25/sfx/fmodexchannel.h
new file mode 100755
index 0000000000..9ebf674ff2
--- /dev/null
+++ b/engines/sword25/sfx/fmodexchannel.h
@@ -0,0 +1,69 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 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.
+//
+// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+#ifndef FMODEXCHANNEL_H
+#define FMODEXCHANNEL_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+
+// -----------------------------------------------------------------------------
+// Forward Declarations
+// -----------------------------------------------------------------------------
+
+struct FMOD_CHANNEL;
+struct FMOD_SOUND;
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_FMODExChannel
+{
+public:
+ BS_FMODExChannel(FMOD_CHANNEL * ChannelPtr, FMOD_SOUND * SoundPtr);
+ virtual ~BS_FMODExChannel();
+
+ bool SetPaused(bool Paused);
+ bool SetVolume(float Volume);
+ bool SetPanning(float Panning);
+ bool SetLoop(bool Loop);
+ bool SetLoopPoints(unsigned int LoopStart, unsigned int LoopEnd);
+ bool SetPosition(unsigned int Position);
+ bool Stop();
+
+ float GetVolume();
+ float GetPanning();
+ unsigned int GetPosition();
+ unsigned int GetTime();
+ unsigned int GetLoopStart();
+ unsigned int GetLoopEnd();
+ bool IsLooping();
+ bool IsPaused();
+ bool IsPlaying();
+
+private:
+ FMOD_CHANNEL * m_ChannelPtr;
+ FMOD_SOUND * m_SoundPtr;
+};
+
+#endif
diff --git a/engines/sword25/sfx/fmodexexception.h b/engines/sword25/sfx/fmodexexception.h
new file mode 100755
index 0000000000..c0541f6d3c
--- /dev/null
+++ b/engines/sword25/sfx/fmodexexception.h
@@ -0,0 +1,51 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 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.
+//
+// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+#ifndef BS_FMODEXEXCEPTION_H
+#define BS_FMODEXEXCEPTION_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "fmod_errors.h"
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_FMODExException
+{
+public:
+ BS_FMODExException(const char * Function_, FMOD_RESULT Result_) :
+ Function(Function_),
+ Result(Result_) {}
+
+ const char * Function;
+ FMOD_RESULT Result;
+
+ void Log()
+ {
+ BS_LOG_ERROR("Call to %s failed.", Function);
+ BS_LOGLN(" FMOD error: %s(%d)", FMOD_ErrorString(Result), Result);
+ }
+};
+
+#endif
diff --git a/engines/sword25/sfx/fmodexresource.cpp b/engines/sword25/sfx/fmodexresource.cpp
new file mode 100755
index 0000000000..3e15dbb260
--- /dev/null
+++ b/engines/sword25/sfx/fmodexresource.cpp
@@ -0,0 +1,170 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 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.
+//
+// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Logging
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "FMODEXRESOURCE"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include <memory>
+#include "fmod.h"
+#include "fmodexexception.h"
+#include "fmodexchannel.h"
+#include "package/packagemanager.h"
+#include "fmodexresource.h"
+
+// -----------------------------------------------------------------------------
+// Konstanten
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const unsigned int MAX_SAMPLE_SIZE = 100 * 1024; // Die Dateigröße in Byte ab der ein Sound als Stream abgespielt wird
+}
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Destruktion
+// -----------------------------------------------------------------------------
+
+
+BS_FMODExResource::BS_FMODExResource(const std::string& FileName, FMOD_SYSTEM * FMOD, bool & Success) :
+ m_SoundPtr(0),
+ m_SoundDataPtr(0),
+ BS_Resource(FileName, BS_Resource::TYPE_SOUND)
+{
+ BS_ASSERT(FMOD);
+
+ // Von Misserfolg ausgehen
+ Success = false;
+
+ // Pointer auf den Package-Manager bekommen
+ BS_PackageManager * PackagePtr = BS_Kernel::GetInstance()->GetPackage();
+ if (!PackagePtr)
+ {
+ BS_LOG_ERRORLN("Package manager not found.");
+ return;
+ }
+
+ // Datei laden
+ unsigned int FileSize;
+ char * FileDataPtr = (char*) PackagePtr->GetFile(GetFileName(), &FileSize);
+ if (!FileDataPtr)
+ {
+ BS_LOG_ERRORLN("File \"%s\" could not be loaded.", GetFileName().c_str());
+ return;
+ }
+
+ // Ob die Sounddatei als Sample oder als Stream behandelt wird, ist abhängig von der Dateigröße.
+ // Samples werden sofort intialisiert.
+ // Für Streams wird hingegen bei jedem Abspielen ein neuer Sound erstellt. Dieses Vorgehen ist notwendig, da FMOD Ex Samples beliebig oft
+ // gleichzeitig abspielen kann, Streams jedoch nur ein mal.
+ if (FileSize <= MAX_SAMPLE_SIZE)
+ {
+ FMOD_CREATESOUNDEXINFO ExInfo;
+ memset(&ExInfo, 0, sizeof(ExInfo));
+ ExInfo.cbsize = sizeof(ExInfo);
+ ExInfo.length = FileSize;
+
+ FMOD_RESULT Result = FMOD_System_CreateSound(FMOD, FileDataPtr,
+ FMOD_CREATESAMPLE | FMOD_OPENMEMORY | FMOD_SOFTWARE | FMOD_2D | FMOD_LOOP_NORMAL,
+ &ExInfo,
+ &m_SoundPtr);
+ if (Result != FMOD_OK) BS_FMODExException("FMOD_System_CreateSound()", Result).Log();
+
+ Success = Result == FMOD_OK;
+
+ delete FileDataPtr;
+ }
+ else
+ {
+ m_SoundDataPtr = FileDataPtr;
+ m_SoundDataSize = FileSize;
+
+ Success = true;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+BS_FMODExResource::~BS_FMODExResource()
+{
+ // Sound freigeben, solange des Soundsystem noch läuft.
+ // Sollte das Soundsystem beendet worden sein müssen und können Sounds nicht mehr freigegeben werden.
+ if (m_SoundPtr && BS_Kernel::GetInstance()->GetService("sfx")) FMOD_Sound_Release(m_SoundPtr);
+ if (m_SoundDataPtr) delete [] m_SoundDataPtr;
+}
+
+// -----------------------------------------------------------------------------
+// Abspielen
+// -----------------------------------------------------------------------------
+
+BS_FMODExChannel * BS_FMODExResource::StartSound(FMOD_SYSTEM * FMOD)
+{
+ BS_ASSERT(FMOD);
+
+ FMOD_CHANNEL * NewChannelPtr;
+ FMOD_SOUND * NewSoundPtr = 0;
+
+ // Sample können sofort abgespielt werden.
+ if (m_SoundPtr)
+ {
+ FMOD_RESULT Result = FMOD_System_PlaySound(FMOD, FMOD_CHANNEL_FREE, m_SoundPtr, 1, &NewChannelPtr);
+ if (Result != FMOD_OK)
+ {
+ BS_FMODExException("FMOD_System_PlaySound()", Result).Log();
+ return 0;
+ }
+ }
+ // Für Streams muss ein neuer Sound erstellt werden.
+ else
+ {
+ FMOD_CREATESOUNDEXINFO ExInfo;
+ memset(&ExInfo, 0, sizeof(ExInfo));
+ ExInfo.cbsize = sizeof(ExInfo);
+ ExInfo.length = m_SoundDataSize;
+
+ FMOD_RESULT Result;
+ Result = FMOD_System_CreateSound(FMOD,
+ m_SoundDataPtr,
+ FMOD_CREATESTREAM | FMOD_OPENMEMORY_POINT | FMOD_SOFTWARE | FMOD_2D | FMOD_LOOP_NORMAL,
+ &ExInfo,
+ &NewSoundPtr);
+ if (Result != FMOD_OK)
+ {
+ BS_FMODExException("FMOD_System_CreateSound()", Result).Log();
+ return 0;
+ }
+
+ Result = FMOD_System_PlaySound(FMOD, FMOD_CHANNEL_FREE, NewSoundPtr, 1, &NewChannelPtr);
+ if (Result != FMOD_OK)
+ {
+ BS_FMODExException("FMOD_System_PlaySound()", Result).Log();
+ return 0;
+ }
+ }
+
+ // Der Channel und der Sound (bei Streams) werden an ein BS_FMODExChannel-Objekt übergeben.
+ // Dieses Sorgt auch dafür, dass Channel und Sound korrekt zerstört werden.
+ return new BS_FMODExChannel(NewChannelPtr, NewSoundPtr);
+}
diff --git a/engines/sword25/sfx/fmodexresource.h b/engines/sword25/sfx/fmodexresource.h
new file mode 100755
index 0000000000..43ff93e380
--- /dev/null
+++ b/engines/sword25/sfx/fmodexresource.h
@@ -0,0 +1,56 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 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.
+//
+// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+#ifndef BS_FMODRESOURCE_H
+#define BS_FMODRESOURCE_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/resource.h"
+
+// -----------------------------------------------------------------------------
+// Forward Declarations
+// -----------------------------------------------------------------------------
+
+class BS_FMODExChannel;
+struct FMOD_SOUND;
+struct FMOD_SYSTEM;
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_FMODExResource : public BS_Resource
+{
+public:
+ BS_FMODExResource(const std::string& FileName, FMOD_SYSTEM * FMOD, bool & Success);
+ virtual ~BS_FMODExResource();
+
+ BS_FMODExChannel * StartSound(FMOD_SYSTEM * FMOD);
+
+private:
+ FMOD_SOUND * m_SoundPtr;
+ char * m_SoundDataPtr;
+ unsigned int m_SoundDataSize;
+};
+
+#endif
diff --git a/engines/sword25/sfx/fmodexsound.cpp b/engines/sword25/sfx/fmodexsound.cpp
new file mode 100755
index 0000000000..346d55086b
--- /dev/null
+++ b/engines/sword25/sfx/fmodexsound.cpp
@@ -0,0 +1,889 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 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.
+//
+// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+// Die von der Engine ausgegebenen Soundhandles werden intern auf FMOD Ex Handles gemapped.
+// Diese Handles sind nur solange gültig, wie der Sound spielt. Falls danach versucht wird manipulierend auf den Sound zuzugreifen,
+// schlägt dieses ohne Fehlermeldung fehl.
+
+// -----------------------------------------------------------------------------
+// Logging
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "FMODEXSOUND"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "fmod.h"
+#include "fmod_errors.h"
+#include "fmodexexception.h"
+#include "fmodexchannel.h"
+#include "fmodexresource.h"
+#include "kernel/string.h"
+#include "kernel/inputpersistenceblock.h"
+#include "kernel/outputpersistenceblock.h"
+#include "package/packagemanager.h"
+#include "fmodexsound.h"
+
+// -----------------------------------------------------------------------------
+// Konstanten und lokale Funktionen
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const float DEFAULT_MUSIC_VOLUME = 1.0f;
+ const float DEFAULT_SPEECH_VOLUME = 1.0f;
+ const float DEFAULT_SFX_VOLUME = 1.0f;
+ const unsigned int SOUNDTYPE_COUNT = 3;
+ const unsigned int INVALID_SOUND_HANDLE = 0xffffffff;
+
+ // -------------------------------------------------------------------------
+
+ inline float NormalizePanning(float Panning)
+ {
+ bool Corrected = false;
+ float Result = Panning;
+ if (Result > 1.0f)
+ {
+ Result = 1.0f;
+ Corrected = true;
+ }
+ if (Result < -1.0f)
+ {
+ Result = -1.0f;
+ Corrected = true;
+ }
+
+ if (Corrected) BS_LOG_WARNINGLN("Tried to set an invalid panning value of %.2f. It was corrected to %.2f", Panning, Result);
+
+ return Result;
+ }
+
+ // -------------------------------------------------------------------------
+
+ inline float NormalizeVolume(float Volume)
+ {
+ bool Corrected = false;
+ float Result = Volume;
+ if (Result> 1.0f)
+ {
+ Result = 1.0f;
+ Corrected = true;
+ }
+ if (Result < 0.0f)
+ {
+ Result = 0.0f;
+ Corrected = true;
+ }
+
+ if (Corrected) BS_LOG_WARNINGLN("Tried to set an invalid volume value of %.2f. It was corrected to %.2f", Volume, Result);
+
+ return Result;
+ }
+
+ // -------------------------------------------------------------------------
+
+ inline FMOD_SOUND_FORMAT BitsPerSampleToFMODExSoundFormat(unsigned int BitsPerSample)
+ {
+ switch (BitsPerSample)
+ {
+ case 8: return FMOD_SOUND_FORMAT_PCM8;
+ case 16: return FMOD_SOUND_FORMAT_PCM16;
+ case 24: return FMOD_SOUND_FORMAT_PCM24;
+ case 32: return FMOD_SOUND_FORMAT_PCM32;
+ default: return FMOD_SOUND_FORMAT_NONE;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Konstruktion / Destruktion
+// -----------------------------------------------------------------------------
+
+BS_FMODExSound::BS_FMODExSound(BS_Kernel* pKernel) :
+ BS_SoundEngine(pKernel),
+ m_FMOD(0),
+ m_NextHandle(1)
+{
+ // Lautstärkeneinstellungen auf die Standardwerte setzen
+ m_Volumes[MUSIC] = DEFAULT_MUSIC_VOLUME;
+ m_Volumes[SPEECH] = DEFAULT_SPEECH_VOLUME;
+ m_Volumes[SFX] = DEFAULT_SFX_VOLUME;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_FMODExSound::~BS_FMODExSound()
+{
+ // Alle noch spielenden Sounds stoppen und die Ressourcen freigeben
+ for (PSM_ITER it = m_PlayingSoundsMap.begin(); it != m_PlayingSoundsMap.end(); ++it)
+ {
+ if (it->second.ChannelPtr) delete it->second.ChannelPtr;
+ if (it->second.ResourcePtr) it->second.ResourcePtr->Release();
+ }
+
+ // FMOD Ex deinitialisieren
+ if (m_FMOD) FMOD_System_Release(m_FMOD);
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Service * BS_FMODExSound_CreateObject(BS_Kernel* pKernel) { return new BS_FMODExSound(pKernel); }
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExSound::Init(unsigned int SampleRate, unsigned int Channels)
+{
+ // Eine Warnung ausgeben, wenn dieser Service schon initialisiert wurde.
+ // Allerdings wird trotzdem true zurückgegeben, weil kein Fehler aufgetreten ist, der Service ist noch benutzbar.
+ if (m_FMOD)
+ {
+ BS_LOG_WARNINGLN("Tried to initialize again. Call ignored.");
+ return true;
+ }
+ else
+ {
+ try
+ {
+ // Die FMOD Ex mit den übergebenen Werte initialisieren
+ FMOD_RESULT Result = FMOD_System_Create(&m_FMOD);
+ if (Result != FMOD_OK) throw(BS_FMODExException("FMOD_System_Create()", Result));
+
+ Result = FMOD_System_SetSoftwareFormat(m_FMOD, SampleRate, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR);
+ if (Result != FMOD_OK) throw(BS_FMODExException("FMOD_System_SetSoftwareFormat()", Result));
+
+ Result = FMOD_System_Init(m_FMOD, Channels, FMOD_INIT_NORMAL, 0);
+ if (Result != FMOD_OK) throw(BS_FMODExException("FMOD_System_Init()", Result));
+ }
+
+ catch(BS_FMODExException Ex)
+ {
+ Ex.Log();
+ BS_LOG_ERRORLN("FMOD Ex could not be initialized.");
+
+ if (m_FMOD)
+ {
+ FMOD_System_Release(m_FMOD);
+ m_FMOD = 0;
+ }
+
+ return false;
+ }
+
+ BS_LOGLN("FMOD Ex initialized. Sample rate: %d / Channels: %d", SampleRate, Channels);
+ return true;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::Update()
+{
+ BS_ASSERT(m_FMOD);
+
+ FMOD_RESULT Result = FMOD_System_Update(m_FMOD);
+ if (Result != FMOD_OK) BS_FMODExException("FMOD_System_Update()", Result).Log();
+
+ RemoveInactiveSounds();
+}
+
+// -----------------------------------------------------------------------------
+// Sounds abspielen
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExSound::PlaySound(const std::string& FileName,
+ SOUND_TYPES Type,
+ float Volume,
+ float Pan,
+ bool Loop,
+ int LoopStart, int LoopEnd,
+ unsigned int Layer)
+{
+ return PlaySoundInternal(FileName, Type, Volume, Pan, Loop, LoopStart, LoopEnd, Layer, 0, 0) != 0;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_FMODExSound::PlaySoundEx(const std::string& FileName,
+ SOUND_TYPES Type,
+ float Volume,
+ float Pan,
+ bool Loop,
+ int LoopStart, int LoopEnd,
+ unsigned int Layer)
+{
+ return PlaySoundInternal(FileName, Type, Volume, Pan, Loop, LoopStart, LoopEnd, Layer, 0, 0);
+}
+
+// -------------------------------------------------------------------------
+
+FMOD_RESULT F_CALLBACK BS_FMODExSound::FMODExDynamicSoundSetPosCallback(FMOD_SOUND *sound, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
+{
+ // In dynamischen Sounds wird nicht gesprungen, daher tut dieses Funktion nichts.
+ return FMOD_OK;
+}
+
+// -------------------------------------------------------------------------
+
+FMOD_RESULT F_CALLBACK BS_FMODExSound::FMODExDynamicSoundReadCallback(FMOD_SOUND *sound, void *data, unsigned int datalen)
+{
+ // Handle auf das aktuelle Soundsystem holen, dies ist wohl dieses hier.
+ BS_FMODExSound * t = reinterpret_cast<BS_FMODExSound *>(BS_Kernel::GetInstance()->GetSfx());
+
+ // Handle auf den richtigen Sound holen, wurde als FMOD Ex Benutzerdaten gesetzt.
+ unsigned int Handle;
+ FMOD_RESULT Result = FMOD_Sound_GetUserData(sound, reinterpret_cast<void **>(&Handle));
+ if (Result != FMOD_OK)
+ {
+ BS_FMODExException("FMOD_Sound_GetUserData()", Result).Log();
+ return FMOD_OK;
+ }
+
+ // Sounddaten holen und Callbackfunktion aufrufen.
+ PlayingSoundData * PSD = t->GetPlayingSoundDataByHandle(Handle);
+ if (PSD) PSD->ReadCallback(PSD->UserData, data, datalen);
+
+ return FMOD_OK;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_FMODExSound::PlayDynamicSoundEx(DynamicSoundReadCallback ReadCallback,
+ void * UserData,
+ SOUND_TYPES Type,
+ unsigned int SampleRate,
+ unsigned int BitsPerSample,
+ unsigned int Channels,
+ float Volume,
+ float Pan,
+ unsigned int Layer)
+{
+ // Parameter überprüfen
+ if (BitsPerSampleToFMODExSoundFormat(BitsPerSample) == FMOD_SOUND_FORMAT_NONE)
+ {
+ BS_LOG_ERRORLN("Cannot create a dynamic sound with %d bits per sample.", BitsPerSample);
+ return 0;
+ }
+ if (Channels == 0 || Channels > 2)
+ {
+ BS_LOG_ERRORLN("Cannot create a dynamic sound with %d channels.", Channels);
+ return 0;
+ }
+
+ // Zu vergebendes Handle bestimmen
+ unsigned int Handle = m_NextHandle++;
+
+ // Sound in die Sound-Map eintragen mit all den Informationen, die wir bisher haben.
+ // Dies muss für dynamische Sounds so früh geschehen, da sofort nach dem Aufruf von FMOD_System_CreateSound der Callback aufgerufen wird um
+ // den Decode-Buffer zu füllen. Unser Callback liest den BS-Callback aus der Sound-Map. Wenn wir den Sound später hinzufügen würden, würde der
+ // BS-Callback zu diesem Sound nicht in der Map stehen und nicht aufgerufen werden können.
+ // Den fehlenden ChannelPtr tragen wir später in dieser Funktion ein.
+ m_PlayingSoundsMap[Handle] = PlayingSoundData(0, 0, Type, Layer, Volume, ReadCallback, UserData);
+
+ // Dynamischen FMOD Ex Sound erstellen
+ FMOD_CREATESOUNDEXINFO CreateSoundExInfo;
+ memset(&CreateSoundExInfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
+ CreateSoundExInfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
+ CreateSoundExInfo.length = 0xffffffff;
+ CreateSoundExInfo.numchannels = Channels;
+ CreateSoundExInfo.defaultfrequency = SampleRate;
+ CreateSoundExInfo.format = BitsPerSampleToFMODExSoundFormat(BitsPerSample);
+ CreateSoundExInfo.pcmreadcallback = FMODExDynamicSoundReadCallback;
+ CreateSoundExInfo.pcmsetposcallback = FMODExDynamicSoundSetPosCallback;
+ CreateSoundExInfo.userdata = reinterpret_cast<void *>(Handle);
+
+ FMOD_SOUND * FMODExSoundPtr;
+ FMOD_RESULT Result = FMOD_System_CreateSound(m_FMOD,
+ 0,
+ FMOD_2D | FMOD_OPENUSER | FMOD_LOOP_NORMAL | FMOD_HARDWARE | FMOD_CREATESTREAM,
+ &CreateSoundExInfo,
+ &FMODExSoundPtr);
+ if (Result != FMOD_OK)
+ {
+ BS_FMODExException("FMOD_System_CreateSound() from PlayDynamicSoundEx()", Result).Log();
+ return 0;
+ }
+
+ // Neu erstellten Sound einem Kanal zuweisen
+ FMOD_CHANNEL * FMODExChannelPtr;
+ Result = FMOD_System_PlaySound(m_FMOD, FMOD_CHANNEL_FREE, FMODExSoundPtr, 1, &FMODExChannelPtr);
+ if (Result != FMOD_OK)
+ {
+ BS_FMODExException("FMOD_System_PlaySound() from PlayDynamicSoundEx()", Result).Log();
+ return 0;
+ }
+
+ // FMOD Ex Kanal an einen BS_FMODExChannel binden und abspielen
+ BS_FMODExChannel * ChannelPtr = new BS_FMODExChannel(FMODExChannelPtr, FMODExSoundPtr);
+ ChannelPtr->SetPaused(false);
+
+ // ChannelPtr in die PlayingSoundData-Struktur eintragen
+ PlayingSoundData * PSD = GetPlayingSoundDataByHandle(Handle);
+ if (PSD) PSD->ChannelPtr = ChannelPtr;
+
+ return Handle;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_FMODExSound::PlaySoundInternal(const std::string& FileName,
+ SOUND_TYPES Type,
+ float Volume,
+ float Pan,
+ bool Loop,
+ int LoopStart, int LoopEnd,
+ unsigned int Layer,
+ unsigned int Position,
+ unsigned int Handle)
+{
+ BS_ASSERT(m_FMOD);
+ BS_ASSERT(Type < SOUNDTYPE_COUNT);
+
+ // Resource anfordern
+ BS_Resource * ResourcePtr = BS_Kernel::GetInstance()->GetResourceManager()->RequestResource(FileName);
+ if (!ResourcePtr)
+ {
+ BS_LOG_ERRORLN("Could not request resource \"%s\".", FileName.c_str());
+ return 0;
+ }
+ if (ResourcePtr->GetType() != BS_Resource::TYPE_SOUND)
+ {
+ BS_LOG_ERRORLN("Requested resource \"%s\" is not a sound.", FileName.c_str());
+ return 0;
+ }
+ BS_FMODExResource * SoundResourcePtr = static_cast<BS_FMODExResource *>(ResourcePtr);
+
+ // Sound im Pause-Modus starten
+ BS_FMODExChannel * ChannelPtr = SoundResourcePtr->StartSound(m_FMOD);
+
+ if (ChannelPtr)
+ {
+ try
+ {
+ // Falls der Sound gelooped wird, Loop-Points setzen
+ if (Loop)
+ {
+ // Bestimmen, welche Loop-Points benutzt werden. Falls ein Loop-Point als Parameter nicht spezifiziert wurde (Wert -1),
+ // wird der Loop-Point von FMOD Ex benutzt.
+ unsigned int RealLoopStart = (LoopStart > 0) ? LoopStart : ChannelPtr->GetLoopStart();
+ unsigned int RealLoopEnd = (LoopEnd > 0) ? LoopEnd : ChannelPtr->GetLoopEnd();
+
+ // Loop-Points auf Gültigkeit überprüfen
+ if (RealLoopStart > RealLoopEnd)
+ {
+ BS_LOG_ERRORLN("Loop start (%d) was placed after loop end (%d) for sound \"%s\".",
+ RealLoopStart, RealLoopEnd,
+ SoundResourcePtr->GetFileName().c_str());
+ throw(0);
+ }
+ if (RealLoopStart > ChannelPtr->GetLoopEnd())
+ {
+ BS_LOG_ERRORLN("Loop start (%d) was placed after end (%d) of sound \"%s\".",
+ RealLoopStart,
+ ChannelPtr->GetLoopEnd(),
+ SoundResourcePtr->GetFileName().c_str());
+ throw(0);
+ }
+ if (RealLoopEnd > ChannelPtr->GetLoopEnd())
+ {
+ BS_LOG_ERRORLN("Loop end (%d) was placed after end (%d) of sound \"%s\".",
+ RealLoopEnd,
+ ChannelPtr->GetLoopEnd(),
+ SoundResourcePtr->GetFileName().c_str());
+ throw(0);
+ }
+
+ // Loop-Points setzen
+ if (!ChannelPtr->SetLoopPoints(RealLoopStart, RealLoopEnd)) throw(0);
+ }
+
+ // Sound-Parameter gemäß der Übergabeparameter setzen
+ if (!ChannelPtr->SetVolume(NormalizeVolume(Volume) * m_Volumes[Type])) throw(0);
+ if (!ChannelPtr->SetPanning(NormalizePanning(Pan))) throw(0);
+ if (!ChannelPtr->SetLoop(Loop)) throw(0);
+ if (!ChannelPtr->SetPosition(Position)) throw(0);
+ }
+ catch (...)
+ {
+ delete ChannelPtr;
+ SoundResourcePtr->Release();
+ return 0;
+ }
+
+ unsigned int MyLoopStart = ChannelPtr->GetLoopStart();
+ unsigned int MyLoopEnd = ChannelPtr->GetLoopEnd();
+ ChannelPtr->SetLoopPoints(MyLoopStart, MyLoopEnd);
+
+ // Sound abspielen
+ ChannelPtr->SetPaused(false);
+
+ // Sound in die Sound-Map eintragen
+ unsigned int NewHandle = (Handle != 0) ? Handle : m_NextHandle++;
+ m_PlayingSoundsMap[NewHandle] = PlayingSoundData(SoundResourcePtr, ChannelPtr, Type, Layer, Volume);
+
+ return NewHandle;
+ }
+ else
+ {
+ SoundResourcePtr->Release();
+ return 0;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Sonstige Methoden
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::SetVolume(float Volume, SOUND_TYPES Type)
+{
+ BS_ASSERT(m_FMOD);
+ BS_ASSERT(Type < SOUNDTYPE_COUNT);
+ m_Volumes[Type] = NormalizeVolume(Volume);
+
+ // Alle Volumen der Sounds der Kategorie aktualisieren
+ PSM_CONST_ITER it = m_PlayingSoundsMap.begin();
+ while (it != m_PlayingSoundsMap.end())
+ {
+ const PlayingSoundData & PSD = it->second;
+ if (PSD.ChannelPtr && PSD.Type == Type) PSD.ChannelPtr->SetVolume(Volume * PSD.Volume);
+
+ ++it;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+float BS_FMODExSound::GetVolume(SOUND_TYPES Type)
+{
+ BS_ASSERT(m_FMOD);
+ BS_ASSERT(Type < SOUNDTYPE_COUNT);
+ return m_Volumes[Type];
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::PauseAll()
+{
+ BS_ASSERT(m_FMOD);
+
+ // Alle Sounds durchgehen und alle pausieren.
+ // Diese werden dann markiert, damit ResumeAll() feststellen kann, welche Sounds mit PauseAll() pausiert wurden.
+ // ResumeAll() setzt dann nur diejenigen fort, die nur über PauseAll() pausiert wurden.
+ PSM_ITER it = m_PlayingSoundsMap.begin();
+ while (it != m_PlayingSoundsMap.end())
+ {
+ PlayingSoundData & PSD = it->second;
+
+ if (PSD.ChannelPtr) PSD.ChannelPtr->SetPaused(true);
+ PSD.PausedGlobal = true;
+
+ ++it;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::ResumeAll()
+{
+ BS_ASSERT(m_FMOD);
+
+ // Alle Sounds durchgehen, die gloable Pause aufheben und diejenigen fortsetzen,
+ // die keine Pause mehr haben (weder explizit, über den Layer oder global).
+ PSM_ITER it = m_PlayingSoundsMap.begin();
+ while (it != m_PlayingSoundsMap.end())
+ {
+ PlayingSoundData & PSD = it->second;
+
+ if (PSD.PausedGlobal)
+ {
+ PSD.PausedGlobal = false;
+ if (PSD.ChannelPtr && !PSD.PausedLayer && !PSD.Paused) PSD.ChannelPtr->SetPaused(false);
+ }
+
+ ++it;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::PauseLayer(unsigned int Layer)
+{
+ BS_ASSERT(m_FMOD);
+
+ // Alle Sounds durchgehen und alle pausieren, die sich auf den angegebenen Layer befinden.
+ // Diese werden dann markiert, damit ResumeLayer() feststellen kann, welche Sounds mit PauseLayer() pausiert wurden.
+ // ResumeLayer() setzt dann nur diejenigen fort, die nur über PauseLayer() mit der entsprechenden Layer-Nummer pausiert wurden.
+ PSM_ITER it = m_PlayingSoundsMap.begin();
+ while (it != m_PlayingSoundsMap.end())
+ {
+ PlayingSoundData & PSD = it->second;
+
+ if (PSD.Layer == Layer)
+ {
+ if (PSD.ChannelPtr) PSD.ChannelPtr->SetPaused(true);
+ PSD.PausedLayer = true;
+ }
+
+ ++it;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::ResumeLayer(unsigned int Layer)
+{
+ BS_ASSERT(m_FMOD);
+
+ // Alle Sounds durchgehen, die Layer-Pause aufheben und diejenigen fortsetzen,
+ // die keine Pause mehr haben (weder explizit, über den Layer oder global).
+ PSM_ITER it = m_PlayingSoundsMap.begin();
+ while (it != m_PlayingSoundsMap.end())
+ {
+ PlayingSoundData & PSD = it->second;
+
+ if (PSD.PausedLayer && PSD.Layer == Layer)
+ {
+ PSD.PausedLayer = false;
+ if (PSD.ChannelPtr && !PSD.PausedGlobal && !PSD.Paused) PSD.ChannelPtr->SetPaused(false);
+ }
+
+ ++it;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Sound Setter
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::SetSoundVolume(unsigned int Handle, float Volume)
+{
+ BS_ASSERT(m_FMOD);
+ PlayingSoundData * PSDPtr = GetPlayingSoundDataByHandle(Handle);
+ if (PSDPtr) if (PSDPtr->ChannelPtr && PSDPtr->ChannelPtr->SetVolume(NormalizeVolume(Volume) * m_Volumes[PSDPtr->Type])) PSDPtr->Volume = Volume;
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::SetSoundPanning(unsigned int Handle, float Pan)
+{
+ BS_ASSERT(m_FMOD);
+ PlayingSoundData * PSDPtr = GetPlayingSoundDataByHandle(Handle);
+ if (PSDPtr && PSDPtr->ChannelPtr) PSDPtr->ChannelPtr->SetPanning(NormalizePanning(Pan));
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::PauseSound(unsigned int Handle)
+{
+ BS_ASSERT(m_FMOD);
+ PlayingSoundData * PSDPtr = GetPlayingSoundDataByHandle(Handle);
+ if (PSDPtr)
+ {
+ PSDPtr->Paused = true;
+ if (PSDPtr->ChannelPtr) PSDPtr->ChannelPtr->SetPaused(true);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::ResumeSound(unsigned int Handle)
+{
+ BS_ASSERT(m_FMOD);
+ PlayingSoundData * PSDPtr = GetPlayingSoundDataByHandle(Handle);
+ if (PSDPtr)
+ {
+ PSDPtr->Paused = false;
+ if (PSDPtr->ChannelPtr && !PSDPtr->PausedGlobal && !PSDPtr->PausedLayer) PSDPtr->ChannelPtr->SetPaused(false);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::StopSound(unsigned int Handle)
+{
+ BS_ASSERT(m_FMOD);
+ PlayingSoundData * PSDPtr = GetPlayingSoundDataByHandle(Handle);
+ if (PSDPtr && PSDPtr->ChannelPtr) PSDPtr->ChannelPtr->Stop();
+}
+
+// -----------------------------------------------------------------------------
+// Sound Getter
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExSound::IsSoundPaused(unsigned int Handle)
+{
+ BS_ASSERT(m_FMOD);
+ PlayingSoundData * PSDPtr = GetPlayingSoundDataByHandle(Handle);
+ if (PSDPtr && PSDPtr->ChannelPtr) return PSDPtr->ChannelPtr->IsPaused();
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExSound::IsSoundPlaying(unsigned int Handle)
+{
+ BS_ASSERT(m_FMOD);
+ PlayingSoundData * PSDPtr = GetPlayingSoundDataByHandle(Handle);
+ if (PSDPtr && PSDPtr->ChannelPtr) return PSDPtr->ChannelPtr->IsPlaying();
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+float BS_FMODExSound::GetSoundVolume(unsigned int Handle)
+{
+ BS_ASSERT(m_FMOD);
+ PlayingSoundData * PSDPtr = GetPlayingSoundDataByHandle(Handle);
+ if (PSDPtr) return PSDPtr->Volume;
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+float BS_FMODExSound::GetSoundPanning(unsigned int Handle)
+{
+ BS_ASSERT(m_FMOD);
+ PlayingSoundData * PSDPtr = GetPlayingSoundDataByHandle(Handle);
+ if (PSDPtr && PSDPtr->ChannelPtr) return PSDPtr->ChannelPtr->GetPanning();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+float BS_FMODExSound::GetSoundTime(unsigned int Handle)
+{
+ BS_ASSERT(m_FMOD);
+ PlayingSoundData * PSDPtr = GetPlayingSoundDataByHandle(Handle);
+ if (PSDPtr && PSDPtr->ChannelPtr) return static_cast<float>(PSDPtr->ChannelPtr->GetTime()) / 1000.0f;
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+// Hilfsmethoden
+// -----------------------------------------------------------------------------
+
+void BS_FMODExSound::RemoveInactiveSounds()
+{
+ PSM_ITER it = m_PlayingSoundsMap.begin();
+ while (it != m_PlayingSoundsMap.end())
+ {
+ if (!it->second.ChannelPtr || !it->second.ChannelPtr->IsPlaying())
+ {
+ PlayingSoundData & PSD = it->second;
+
+ delete PSD.ChannelPtr;
+ if (PSD.ResourcePtr) PSD.ResourcePtr->Release();
+
+ it = m_PlayingSoundsMap.erase(it);
+ }
+ else
+ ++it;
+ }
+
+ /*
+ static size_t lastActiveChannels = 0;
+ if (m_PlayingSoundsMap.size() != lastActiveChannels)
+ {
+ BS_LOGLN("Aktive Kanaele: %d", m_PlayingSoundsMap.size());
+ lastActiveChannels = m_PlayingSoundsMap.size();
+ }
+ */
+}
+
+// -----------------------------------------------------------------------------
+
+BS_FMODExSound::PlayingSoundData * BS_FMODExSound::GetPlayingSoundDataByHandle(unsigned int Handle)
+{
+ // Zum Soundhandle gehörige Daten in der Hash-Map finden
+ PSM_ITER it = m_PlayingSoundsMap.find(Handle);
+ // Falls die Daten nicht gefunden werden konnten, Fehler zurückgebene, ansonsten ein Pointer auf die Daten.
+ if (it == m_PlayingSoundsMap.end()) return 0;
+ return &((*it).second);
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_FMODExSound::CountPlayingDynamicSounds()
+{
+ unsigned int Result = 0;
+ for (PSM_CONST_ITER it = m_PlayingSoundsMap.begin(); it != m_PlayingSoundsMap.end(); ++it) if (!it->second.ResourcePtr) ++Result;
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+// Ressourcen-Verwaltung
+// -----------------------------------------------------------------------------
+
+BS_Resource * BS_FMODExSound::LoadResource(const std::string& FileName)
+{
+ BS_ASSERT(m_FMOD);
+ BS_ASSERT(CanLoadResource(FileName));
+
+ bool Success;
+ BS_FMODExResource * ResourcePtr = new BS_FMODExResource(FileName, m_FMOD, Success);
+ if (Success)
+ return ResourcePtr;
+ else
+ {
+ delete ResourcePtr;
+ return 0;
+ }
+}
+bool BS_FMODExSound::CanLoadResource(const std::string& FileName)
+{
+ if (FileName.size() >= 4)
+ {
+ std::string Extension(FileName.end() - 4, FileName.end());
+ BS_String::ToLower(Extension);
+
+ return Extension == ".wav" ||
+ Extension == ".ogg" ||
+ Extension == ".mp3";
+ }
+ else
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+// Persistenz
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExSound::Persist(BS_OutputPersistenceBlock & Writer)
+{
+ BS_ASSERT(m_FMOD);
+
+ // Alle inaktiven Sounds entfernen, damit kein unnötiger Ballast gespeichert wird
+ RemoveInactiveSounds();
+
+ // Warnung ausgeben, wenn dynamische Sounds abgespielt werden
+ unsigned int PlayingDynamicSounds = CountPlayingDynamicSounds();
+ if (PlayingDynamicSounds) BS_LOG_WARNINGLN("There are currently dynamic sounds playing. These will not be persisted.");
+
+ // Nächstes Handle speichern
+ Writer.Write(m_NextHandle);
+
+ // Anzahl spielender (nicht dynamischer) Sounds speichern
+ Writer.Write(m_PlayingSoundsMap.size() - PlayingDynamicSounds);
+
+ // Informationen für jeden spielenden (nicht dynamischen) Sound speichern
+ PSM_CONST_ITER it = m_PlayingSoundsMap.begin();
+ while (it != m_PlayingSoundsMap.end())
+ {
+ const PlayingSoundData & PSD = it->second;
+
+ if (PSD.ResourcePtr)
+ {
+ // Handle speichern
+ Writer.Write(it->first);
+
+ // Soundeigenschaften speichern
+ Writer.Write(PSD.ResourcePtr->GetFileName());
+ Writer.Write(static_cast<unsigned int>(PSD.Type));
+ Writer.Write(PSD.Layer);
+
+ Writer.Write(PSD.Volume);
+ Writer.Write(PSD.ChannelPtr->GetPanning());
+ Writer.Write(PSD.ChannelPtr->IsLooping());
+ Writer.Write(PSD.ChannelPtr->GetLoopStart());
+ Writer.Write(PSD.ChannelPtr->GetLoopEnd());
+ Writer.Write(PSD.ChannelPtr->GetPosition());
+ Writer.Write(PSD.Paused);
+ Writer.Write(PSD.PausedLayer);
+ Writer.Write(PSD.PausedGlobal);
+ }
+
+ ++it;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_FMODExSound::Unpersist(BS_InputPersistenceBlock & Reader)
+{
+ BS_ASSERT(m_FMOD);
+
+ // Alle Sounds stoppen
+ PSM_ITER it = m_PlayingSoundsMap.begin();
+ while (it != m_PlayingSoundsMap.end())
+ {
+ const PlayingSoundData & PSD = it->second;
+ if (PSD.ChannelPtr) delete PSD.ChannelPtr;
+ if (PSD.ResourcePtr) PSD.ResourcePtr->Release();
+ ++it;
+ }
+
+ // Sound-Map leeren
+ m_PlayingSoundsMap.clear();
+
+ // Nächstes Handle laden
+ Reader.Read(m_NextHandle);
+
+ // Soundanzahl einlesen
+ unsigned int SoundCount = 0;
+ Reader.Read(SoundCount);
+
+ // Informationen über jeden spielenden Sound einlesen und ihn mit den Parametern abspielen
+ for (unsigned int i = 0; i < SoundCount; ++i)
+ {
+ unsigned int Handle;
+ std::string FileName;
+ unsigned int Type;
+ unsigned int Layer;
+
+ float Volume;
+ float Pan;
+ bool Loop;
+ unsigned int LoopStart;
+ unsigned int LoopEnd;
+ unsigned int Position;
+ bool Paused;
+ bool PausedLayer;
+ bool PausedGlobal;
+
+ Reader.Read(Handle);
+ Reader.Read(FileName);
+ Reader.Read(Type);
+ Reader.Read(Layer);
+
+ Reader.Read(Volume);
+ Reader.Read(Pan);
+ Reader.Read(Loop);
+ Reader.Read(LoopStart);
+ Reader.Read(LoopEnd);
+ Reader.Read(Position);
+ Reader.Read(Paused);
+ Reader.Read(PausedLayer);
+ Reader.Read(PausedGlobal);
+
+ if (Reader.IsGood())
+ {
+ PlaySoundInternal(FileName, (SOUND_TYPES) Type, Volume, Pan, Loop, LoopStart, LoopEnd, Layer, Position, Handle);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return Reader.IsGood();
+}
diff --git a/engines/sword25/sfx/fmodexsound.h b/engines/sword25/sfx/fmodexsound.h
new file mode 100755
index 0000000000..4c0d8fc448
--- /dev/null
+++ b/engines/sword25/sfx/fmodexsound.h
@@ -0,0 +1,142 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 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.
+//
+// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+#ifndef FMODEXSOUND_H
+#define FMODEXSOUND_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/memlog_off.h"
+#include <vector>
+#include <map>
+#include "kernel/memlog_on.h"
+
+#include "kernel/common.h"
+#include "kernel/hashmap.h"
+#include "soundengine.h"
+
+#include "fmod.h"
+
+// -----------------------------------------------------------------------------
+// Forward Declarations
+// -----------------------------------------------------------------------------
+
+class BS_FMODExChannel;
+struct FMOD_SYSTEM;
+struct FMOD_CHANNEL;
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_FMODExSound : public BS_SoundEngine
+{
+public:
+ // -----------------------------------------------------------------------------
+ // Konstruktion / Destruktion
+ // -----------------------------------------------------------------------------
+
+ BS_FMODExSound(BS_Kernel* pKernel);
+ virtual ~BS_FMODExSound();
+
+ bool Init(unsigned int SampleRate, unsigned int Channels = 32);
+ void Update();
+ void SetVolume(float Volume, SOUND_TYPES Type);
+ float GetVolume(SOUND_TYPES Type);
+ void PauseAll();
+ void ResumeAll();
+ void PauseLayer(unsigned int Layer);
+ void ResumeLayer(unsigned int Layer);
+ bool PlaySound(const std::string& FileName, SOUND_TYPES Type, float Volume, float Pan, bool Loop, int LoopStart, int LoopEnd, unsigned int Layer);
+ unsigned int PlaySoundEx(const std::string& FileName, SOUND_TYPES Type, float Volume, float Pan, bool Loop, int LoopStart, int LoopEnd, unsigned int Layer);
+ unsigned int PlayDynamicSoundEx(DynamicSoundReadCallback ReadCallback, void * UserData, SOUND_TYPES Type, unsigned int SampleRate, unsigned int BitsPerSample, unsigned int Channels, float Volume = 1.0f, float Pan = 0.0f, unsigned int Layer = 0);
+
+ void SetSoundVolume(unsigned int Handle, float Volume);
+ void SetSoundPanning(unsigned int Handle, float Pan);
+ void PauseSound(unsigned int Handle);
+ void ResumeSound(unsigned int Handle);
+ void StopSound(unsigned int Handle);
+ bool IsSoundPaused(unsigned int Handle);
+ bool IsSoundPlaying(unsigned int Handle);
+ float GetSoundVolume(unsigned int Handle);
+ float GetSoundPanning(unsigned int Handle);
+ float GetSoundTime(unsigned int Handle);
+
+ BS_Resource * LoadResource(const std::string& FileName);
+ bool CanLoadResource(const std::string& FileName);
+
+ // -----------------------------------------------------------------------------
+ // Persistenz
+ // -----------------------------------------------------------------------------
+
+ bool Persist(BS_OutputPersistenceBlock & Writer);
+ bool Unpersist(BS_InputPersistenceBlock & Reader);
+
+private:
+ struct PlayingSoundData
+ {
+ PlayingSoundData() {};
+ PlayingSoundData(BS_Resource * ResourcePtr_, BS_FMODExChannel * ChannelPtr_, SOUND_TYPES Type_, unsigned int Layer_, float Volume_, DynamicSoundReadCallback ReadCallback_ = 0, void * UserData_ = 0) :
+ ResourcePtr(ResourcePtr_),
+ ChannelPtr(ChannelPtr_),
+ Type(Type_),
+ Layer(Layer_),
+ Volume(Volume_),
+ ReadCallback(ReadCallback_),
+ UserData(UserData_),
+ Paused(false),
+ PausedLayer(false),
+ PausedGlobal(false)
+ {}
+
+ BS_Resource * ResourcePtr;
+ BS_FMODExChannel * ChannelPtr;
+ SOUND_TYPES Type;
+ unsigned int Layer;
+ DynamicSoundReadCallback ReadCallback;
+ void * UserData;
+
+ float Volume;
+ bool Paused;
+ bool PausedLayer;
+ bool PausedGlobal;
+ };
+
+ typedef BS_Hashmap<unsigned int, PlayingSoundData> PSM;
+ typedef BS_Hashmap<unsigned int, PlayingSoundData>::iterator PSM_ITER;
+ typedef BS_Hashmap<unsigned int, PlayingSoundData>::const_iterator PSM_CONST_ITER;
+ PSM m_PlayingSoundsMap;
+
+ FMOD_SYSTEM * m_FMOD;
+ float m_Volumes[3];
+ unsigned int m_NextHandle;
+
+ void RemoveInactiveSounds();
+ PlayingSoundData * GetPlayingSoundDataByHandle(unsigned int Handle);
+ unsigned int PlaySoundInternal(const std::string& FileName, SOUND_TYPES Type, float Volume, float Pan, bool Loop, int LoopStart, int LoopEnd, unsigned int Layer, unsigned int Handle, unsigned int Position);
+ unsigned int CountPlayingDynamicSounds();
+
+ static FMOD_RESULT F_CALLBACK FMODExDynamicSoundSetPosCallback(FMOD_SOUND *sound, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
+ static FMOD_RESULT F_CALLBACK FMODExDynamicSoundReadCallback(FMOD_SOUND *sound, void *data, unsigned int datalen);
+ static FMOD_RESULT F_CALLBACK DSPReadCallback(FMOD_DSP_STATE * dsp_state, float * inbuffer, float * outbuffer, unsigned int length, int inchannels, int outchannels);
+};
+
+#endif
diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp
new file mode 100755
index 0000000000..d12c1fb604
--- /dev/null
+++ b/engines/sword25/sfx/soundengine.cpp
@@ -0,0 +1,36 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 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.
+//
+// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "SOUNDENGINE"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "soundengine.h"
+
+// -----------------------------------------------------------------------------
+
+BS_SoundEngine::BS_SoundEngine(BS_Kernel * pKernel) : BS_ResourceService(pKernel)
+{
+ if (!_RegisterScriptBindings())
+ BS_LOG_ERRORLN("Script bindings could not be registered.");
+ else
+ BS_LOGLN("Script bindings registered.");
+} \ No newline at end of file
diff --git a/engines/sword25/sfx/soundengine.h b/engines/sword25/sfx/soundengine.h
new file mode 100755
index 0000000000..16442c2481
--- /dev/null
+++ b/engines/sword25/sfx/soundengine.h
@@ -0,0 +1,253 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 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.
+//
+// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+/*
+ BS_SoundEngine
+ -------------
+ Dies ist das Soundengine Interface, dass alle Methoden enthält, die eine Soundengine
+ implementieren muss.
+ Implementationen der Soundengine müssen von dieser Klasse abgeleitet werden.
+ Es gilt zu beachten, dass eine Soundengine eine Liste mit ALLEN geladenen Samplen enthalten
+ muss, und dass diese Samples beim Aufruf des Destruktors freigegeben werden.
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef BS_SOUNDENGINE_H
+#define BS_SOUNDENGINE_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/resservice.h"
+#include "kernel/persistable.h"
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_SoundEngine : public BS_ResourceService, public BS_Persistable
+{
+public:
+ // -----------------------------------------------------------------------------
+ // Enums und Typen
+ // -----------------------------------------------------------------------------
+
+ enum SOUND_TYPES
+ {
+ MUSIC = 0,
+ SPEECH = 1,
+ SFX = 2
+ };
+
+ /**
+ @brief Die Callbackfunktion von PlayDynamicSoundEx
+ @param UserData Benutzerspezifizierter Pointer
+ @param Data Pointer auf den zu beschreibenden Puffer
+ @param DataLength Länge der zu schreibenden Daten in Byte
+ */
+ typedef void (*DynamicSoundReadCallback)(void * UserData, void * Data, unsigned int DataLength);
+
+ // -----------------------------------------------------------------------------
+ // Konstruktion / Destruktion
+ // -----------------------------------------------------------------------------
+
+ BS_SoundEngine(BS_Kernel* pKernel);
+ virtual ~BS_SoundEngine() {};
+
+ // --------------------------------------------------------------
+ // DIESE METHODEN MÜSSEN VON DER SOUNDENGINE IMPLEMENTIERT WERDEN
+ // --------------------------------------------------------------
+
+ /**
+ @brief Initialisiert die Sound-Engine
+ @param SampleRate Gibt die zu nutzende SampleRate an
+ @param Channels die maximale Anzahl der Kanäle.<br>
+ Der Standardwert ist 32.
+ @return Gibt bei Erfolg TRUE, ansonsten FALSE zurück
+ @remark Aufrufe an allen anderen Methoden dürfen erst erfolgen, wenn diese Methode erfolgreich aufgerufen wurde.
+ */
+ virtual bool Init(unsigned int SampleRate, unsigned int Channels = 32) = 0;
+
+ /**
+ @brief Führt einen "Tick" der Sound-Engine aus
+
+ Diese Methode sollte ein mal pro Frame aufgerufen werden. Sie dient dazu Implementationen der Sound-Engine zu ermöglichen,
+ die nicht in einem eigenen Thread laufen oder zusätzliche Verwaltungsaufgaben durchführen müssen.
+ */
+ virtual void Update() = 0;
+
+ /**
+ @brief Setzt die Standardlautstärke für die verschiedenen Soundtypen
+ @param Volume die Standardlautstärke (0 = aus, 1 = volle Lautstärke)
+ @param Type der Soundtyp dessen Lautstärke geändert werden soll
+ */
+ virtual void SetVolume(float Volume, SOUND_TYPES Type) = 0;
+
+ /**
+ @brief Gibt die Standardlautstärke der verschiedenen Soundtypen
+ @param Type der Soundtyp
+ @return Gibt die Standardlautstärke des übergebenen Soundtyps zurück (0 = aus, 1 = volle Laustärke)
+ */
+ virtual float GetVolume(SOUND_TYPES Type) = 0;
+
+ /**
+ @brief Pausiert alle Sounds die gerade spielen
+ */
+ virtual void PauseAll() = 0;
+
+ /**
+ @brief Setzt alle gestoppten Sounds fort
+ */
+ virtual void ResumeAll() = 0;
+
+ /**
+ @brief Pausiert alle Sounds eines bestimmten Sound-Layers
+ @param Layer ein Soundlayer
+ */
+ virtual void PauseLayer(unsigned int Layer) = 0;
+
+ /**
+ @brief Setzt alle Sounds eines Layers fort, die mit PauseLayer() zuvor gestoppt wurden
+ @param Layer ein Soundlayer
+ */
+ virtual void ResumeLayer(unsigned int Layer) = 0;
+
+
+ /**
+ @brief Spielt einen Sound ab
+ @param FileName der Dateiname des abzuspielenden Sounds
+ @param Type der Typ des Sounds
+ @param Volume die Lautstärke mit der der Soundabgespielt werden soll (0 = aus, 1 = volle Lautstärke)
+ @param Pan das Panning (-1 = ganz links, 1 = ganz rechts)
+ @param Loop gibt an ob der Sound geloopt werden soll
+ @param LoopStart gibt den Start-Looppoint an. Wenn ein Wert kleiner als 0 übergeben wird, wird der Start des Sounds benutzt.
+ @param LoopEnd gibt den End-Looppoint an. Wenn ein Wert kleiner als 0 übergeben wird, wird das Ende des Sounds benutzt.
+ @param Layer der Soundlayer
+ @return Gibt true zurück, wenn das Abspielen des Sounds eingeleitet werden konnte.
+ @remark Falls eine erweiterte Kontrolle über das Abspielen benötigt wird, z.B. das Ändern der Soundparameter
+ Volume und Panning während des Abspielvorgangens, sollte PlaySoundEx benutzt werden.
+ */
+ virtual bool PlaySound(const std::string& FileName, SOUND_TYPES Type, float Volume = 1.0f, float Pan = 0.0f, bool Loop = false, int LoopStart = -1, int LoopEnd = -1, unsigned int Layer = 0) = 0;
+
+ /**
+ @brief Spielt einen Sound ab
+ @param FileName der Dateiname des abzuspielenden Sounds
+ @param Type der Typ des Sounds
+ @param Volume die Lautstärke mit der der Soundabgespielt werden soll (0 = aus, 1 = volle Lautstärke)
+ @param Pan das Panning (-1 = ganz links, 1 = ganz rechts)
+ @param Loop gibt an ob der Sound geloopt werden soll
+ @param LoopStart gibt den Start-Looppoint an. Wenn ein Wert kleiner als 0 übergeben wird, wird der Start des Sounds benutzt.
+ @param LoopEnd gibt den End-Looppoint an. Wenn ein Wert kleiner als 0 übergeben wird, wird das Ende des Sounds benutzt.
+ @param Layer der Soundlayer
+ @return Gibt ein Handle auf den Sounds zurück. Mit diesem Handle kann der Sound während des Abspielens manipuliert werden.
+ @remark Falls eine erweiterte Kontrolle über das Abspielen benötigt wird, z.B. das Ändern der Soundparameter
+ Volume und Panning während des Abspielvorgangens, sollte PlaySoundEx benutzt werden.
+ */
+ virtual unsigned int PlaySoundEx(const std::string& FileName, SOUND_TYPES Type, float Volume = 1.0f, float Pan = 0.0f, bool Loop = false, int LoopStart = -1, int LoopEnd = -1, unsigned int Layer = 0) = 0;
+
+ /**
+ @brief Spielt einen zur Laufzeit generierten Sound ab
+ @param ReadCallback ein Pointer auf eine Callbackfunktion, die aufgerufen wird, wenn Sounddaten benötigt werden.<br>
+ Nähere Details zu dieser Funktion gibt es bei der Dokumentation von DynamicSoundReadCallback.
+ @param UserData ein Pointer auf benutzerdefinierte Daten. Diese werden der Callback-Funktion bei jedem Aufruf übergeben.<br>
+ Falls keine solche Daten benötigt werden, kann dieser Parameter auf 0 gesetzt werden.
+ @param Type der Typ des Sounds
+ @param SampleRate die Sample-Rate des Sounds
+ @param BitsPerSample die Größe eines Samples in Bits. Hiermit sind tatsächlich nur einzelne Sample gemeint, diese Angabe ist unabhängig von der Anzahl der Kanäle.<br>
+ Erlaubte Werte sind 8, 16, 24 und 32.
+ @param Channels die Anzahl der Kanäle.<br>
+ Erlaubte Werte sind 1 und 2.
+ @param Volume die Lautstärke mit der der Soundabgespielt werden soll (0 = aus, 1 = volle Lautstärke)
+ @param Pan das Panning (-1 = ganz links, 1 = ganz rechts)
+ @param Layer der Soundlayer
+ @return Gibt ein Handle auf den Sounds zurück. Mit diesem Handle kann der Sound während des Abspielens manipuliert werden.
+ @remark Dynamische Sounds können nicht persistiert werden.
+ */
+ virtual unsigned int PlayDynamicSoundEx(DynamicSoundReadCallback ReadCallback, void * UserData, SOUND_TYPES Type, unsigned int SampleRate, unsigned int BitsPerSample, unsigned int Channels, float Volume = 1.0f, float Pan = 0.0f, unsigned int Layer = 0) = 0;
+
+ /**
+ @brief Setzt die Lautstärke eines spielenden Sounds
+ @param Handle das Handle des Sounds
+ @param Volume die Lautstärke mit der der Soundabgespielt werden soll (0 = aus, 1 = volle Lautstärke)
+ */
+ virtual void SetSoundVolume(unsigned int Handle, float Volume) = 0;
+
+ /**
+ @brief Setzt das Panning eines spielenden Sounds
+ @param Handle das Handle des Sounds
+ @param Pan das Panning (-1 = ganz links, 1 = ganz rechts)
+ */
+ virtual void SetSoundPanning(unsigned int Handle, float Pan) = 0;
+
+ /**
+ @brief Pausiert einen Sound
+ @param Handle das Handle des Sounds
+ */
+ virtual void PauseSound(unsigned int Handle) = 0;
+
+ /**
+ @brief Setzt einen Sound fort
+ @param Handle das Handle des Sounds
+ */
+ virtual void ResumeSound(unsigned int Handle) = 0;
+
+ /**
+ @brief Stoppt einen Sound
+ @param Handle das Handle des Sounds
+ @remark Nach einem Aufruf dieser Methode ist das Handle ungültig und darf nicht mehr benutzt werden.
+ */
+ virtual void StopSound(unsigned int Handle) = 0;
+
+ /**
+ @brief Gibt zurück, ob ein Sound pausiert ist
+ @param Handle das Handle des Sounds
+ @return Gibt true zurück, wenn der Sound pausiert ist, ansonsten false.
+ */
+ virtual bool IsSoundPaused(unsigned int Handle) = 0;
+
+ /**
+ @brief Gibt zurück, ob ein Sound noch spielt
+ @param Handle das Handle des Sounds
+ @return Gibt true zurück, wenn der Sound noch spielt, ansonsten false.
+ */
+ virtual bool IsSoundPlaying(unsigned int Handle) = 0;
+
+ /**
+ @brief Gibt die Lautstärke eines spielenden Sounds zurück (0 = aus, 1 = volle Lautstärke)
+ */
+ virtual float GetSoundVolume(unsigned int Handle) = 0;
+
+ /**
+ @brief Gibt das Panning eines spielenden Sounds zurück (-1 = ganz links, 1 = ganz rechts)
+ */
+ virtual float GetSoundPanning(unsigned int Handle) = 0;
+
+ /**
+ @brief Gibt die Position innerhalb des abgespielten Sounds in Sekunden zurück
+ */
+ virtual float GetSoundTime(unsigned int Handle) = 0;
+
+private:
+ bool _RegisterScriptBindings();
+};
+
+#endif
diff --git a/engines/sword25/sfx/soundengine_script.cpp b/engines/sword25/sfx/soundengine_script.cpp
new file mode 100755
index 0000000000..9cc3fcb153
--- /dev/null
+++ b/engines/sword25/sfx/soundengine_script.cpp
@@ -0,0 +1,397 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 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.
+//
+// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/kernel.h"
+#include "script/script.h"
+#include "script/luabindhelper.h"
+
+#include "soundengine.h"
+
+// -----------------------------------------------------------------------------
+
+static int Init(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_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<unsigned int>(luaL_checknumber(L, 1)), 32));
+ else
+ lua_pushbooleancpp(L, pSfx->Init(static_cast<unsigned int>(luaL_checknumber(L, 1)), static_cast<unsigned int>(luaL_checknumber(L, 2))));
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int Update(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->Update();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetVolume(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->SetVolume(static_cast<float>(luaL_checknumber(L, 1)),
+ static_cast<BS_SoundEngine::SOUND_TYPES>(static_cast<unsigned int>(luaL_checknumber(L, 2))));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetVolume(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ lua_pushnumber(L, pSfx->GetVolume(static_cast<BS_SoundEngine::SOUND_TYPES>(static_cast<unsigned int>(luaL_checknumber(L, 1)))));
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int PauseAll(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->PauseAll();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int ResumeAll(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->ResumeAll();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int PauseLayer(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->PauseLayer(static_cast<int>(luaL_checknumber(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int ResumeLayer(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->ResumeLayer(static_cast<int>(luaL_checknumber(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static void ProcessPlayParams(lua_State * L, std::string & FileName, BS_SoundEngine::SOUND_TYPES & Type, float & Volume, float & Pan, bool & Loop, int & LoopStart, int & LoopEnd, unsigned int & Layer)
+{
+ FileName = luaL_checkstring(L, 1);
+
+ Type = static_cast<BS_SoundEngine::SOUND_TYPES>(static_cast<unsigned int>(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<unsigned int>(luaL_checknumber(L, 8));
+}
+
+static int PlaySound(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ std::string FileName;
+ BS_SoundEngine::SOUND_TYPES Type;
+ float Volume;
+ float Pan;
+ bool Loop;
+ int LoopStart;
+ int LoopEnd;
+ unsigned int 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)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ std::string FileName;
+ BS_SoundEngine::SOUND_TYPES Type;
+ float Volume;
+ float Pan;
+ bool Loop;
+ int LoopStart;
+ int LoopEnd;
+ unsigned int 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)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->SetSoundVolume(static_cast<unsigned int>(luaL_checknumber(L, 1)), static_cast<float>(luaL_checknumber(L, 2)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetSoundPanning(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->SetSoundPanning(static_cast<unsigned int>(luaL_checknumber(L, 1)), static_cast<float>(luaL_checknumber(L, 2)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int PauseSound(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->PauseSound(static_cast<unsigned int>(luaL_checknumber(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int ResumeSound(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->ResumeSound(static_cast<unsigned int>(luaL_checknumber(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int StopSound(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ pSfx->StopSound(static_cast<unsigned int>(luaL_checknumber(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int IsSoundPaused(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ lua_pushbooleancpp(L, pSfx->IsSoundPaused(static_cast<unsigned int>(luaL_checknumber(L, 1))));
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int IsSoundPlaying(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ lua_pushbooleancpp(L, pSfx->IsSoundPlaying(static_cast<unsigned int>(luaL_checknumber(L, 1))));
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetSoundVolume(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ lua_pushnumber(L, pSfx->GetSoundVolume(static_cast<unsigned int>(luaL_checknumber(L, 1))));
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetSoundPanning(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_SoundEngine * pSfx = static_cast<BS_SoundEngine *>(BS_Kernel::GetInstance()->GetService("sfx"));
+ BS_ASSERT(pSfx);
+
+ lua_pushnumber(L, pSfx->GetSoundPanning(static_cast<unsigned int>(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", BS_SoundEngine::MUSIC,
+ "SPEECH", BS_SoundEngine::SPEECH,
+ "SFX", BS_SoundEngine::SFX,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+bool BS_SoundEngine::_RegisterScriptBindings()
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ScriptEngine * pScript = static_cast<BS_ScriptEngine *>(pKernel->GetService("script"));
+ BS_ASSERT(pScript);
+ lua_State * L = static_cast<lua_State *>(pScript->GetScriptObject());
+ BS_ASSERT(L);
+
+ if (!BS_LuaBindhelper::AddFunctionsToLib(L, SFX_LIBRARY_NAME, SFX_FUNCTIONS)) return false;
+ if (!BS_LuaBindhelper::AddConstantsToLib(L, SFX_LIBRARY_NAME, SFX_CONSTANTS)) return false;
+
+ return true;
+}