diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/plugin.cpp | 97 | ||||
-rw-r--r-- | src/plugins/plugin.h | 25 | ||||
-rw-r--r-- | src/plugins/plugininterface.h | 37 | ||||
-rw-r--r-- | src/plugins/sound/oalsound/CMakeLists.txt | 24 | ||||
-rw-r--r-- | src/plugins/sound/oalsound/alsound.cpp | 548 | ||||
-rw-r--r-- | src/plugins/sound/oalsound/alsound.h | 95 | ||||
-rw-r--r-- | src/plugins/sound/oalsound/buffer.cpp | 80 | ||||
-rw-r--r-- | src/plugins/sound/oalsound/buffer.h | 48 | ||||
-rw-r--r-- | src/plugins/sound/oalsound/channel.cpp | 304 | ||||
-rw-r--r-- | src/plugins/sound/oalsound/channel.h | 99 | ||||
-rw-r--r-- | src/plugins/sound/oalsound/check.h | 39 | ||||
-rw-r--r-- | src/plugins/test/CMakeLists.txt | 11 | ||||
-rw-r--r-- | src/plugins/test/plugin_test.cpp | 40 |
13 files changed, 1441 insertions, 6 deletions
diff --git a/src/plugins/plugin.cpp b/src/plugins/plugin.cpp new file mode 100644 index 0000000..ca0fe0e --- /dev/null +++ b/src/plugins/plugin.cpp @@ -0,0 +1,97 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012 Polish Portal of Colobot (PPC) +// * +// * 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/. + +// plugin.cpp + + +#include "plugin.h" + + +CPlugin::CPlugin(std::string filename) +{ + mInterface = nullptr; + mFilename = filename; + mLoaded = false; +} + + +char* CPlugin::GetName() +{ + if (mLoaded) + return mInterface->PluginName(); + return nullptr; +} + + +int CPlugin::GetVersion() +{ + if (mLoaded) + return mInterface->PluginVersion(); + return 0; +} + + +bool CPlugin::IsLoaded() +{ + return mLoaded; +} + + +bool CPlugin::UnloadPlugin() +{ + if (!mLoaded) { + GetLogger()->Warn("Plugin %s is not loaded.\n"); + return true; + } + + void (*uninstall)() = (void (*)()) lt_dlsym(mHandle, "UninstallPluginEntry"); + if (!uninstall) { + GetLogger()->Error("Error getting UninstallPluginEntry for plugin %s: %s\n", mFilename.c_str(), lt_dlerror()); + return false; + } + + lt_dlclose(mHandle); + mLoaded = false; + return true; +} + + +bool CPlugin::LoadPlugin() +{ + mHandle = lt_dlopenext(mFilename.c_str()); + if (!mHandle) { + GetLogger()->Error("Error loading plugin %s: %s\n", mFilename.c_str(), lt_dlerror()); + return false; + } + + void (*install)() = (void (*)()) lt_dlsym(mHandle, "InstallPluginEntry"); + if (!install) { + GetLogger()->Error("Error getting InstallPluginEntry for plugin %s: %s\n", mFilename.c_str(), lt_dlerror()); + return false; + } + + CPluginInterface* (*getInterface)() = (CPluginInterface* (*)()) lt_dlsym(mHandle, "GetPluginInterfaceEntry"); + + if (!getInterface) { + GetLogger()->Error("Error getting GetPluginInterfaceEntry for plugin %s: %s\n", mFilename.c_str(), lt_dlerror()); + return false; + } + + install(); + mInterface = getInterface(); + mLoaded = true; + return true; +} diff --git a/src/plugins/plugin.h b/src/plugins/plugin.h index f238122..e7d4b12 100644 --- a/src/plugins/plugin.h +++ b/src/plugins/plugin.h @@ -19,15 +19,28 @@ #pragma once +#include <ltdl.h> +#include <string> -#define PLUGIN_INTERFACE(class_type, interface_type) \ - extern "C" interface_type* installPlugin() { return (interface_type *)new class_type(); } \ - extern "C" void uninstallPlugin(class_type *_class) { delete _class; } +#include <common/logger.h> + +#include "plugininterface.h" class CPlugin { public: - virtual char* PluginName() = 0; - virtual int PluginVersion() = 0; + CPlugin(std::string filename); + + char* GetName(); + int GetVersion(); + bool UnloadPlugin(); + bool LoadPlugin(); + bool IsLoaded(); + + + private: + CPluginInterface* mInterface; + std::string mFilename; + lt_dlhandle mHandle; + bool mLoaded; }; - diff --git a/src/plugins/plugininterface.h b/src/plugins/plugininterface.h new file mode 100644 index 0000000..bf4e040 --- /dev/null +++ b/src/plugins/plugininterface.h @@ -0,0 +1,37 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * 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/. + +// plugininterface.h + + +#pragma once + + +#define PLUGIN_INTERFACE(class_type) \ + static class_type* Plugin##class_type; \ + extern "C" void InstallPluginEntry() { Plugin##class_type = new class_type(); Plugin##class_type->InstallPlugin(); } \ + extern "C" void UninstallPluginEntry() { Plugin##class_type->UninstallPlugin(); delete Plugin##class_type; } \ + extern "C" CPluginInterface* GetPluginInterfaceEntry() { return static_cast<CPluginInterface*>(Plugin##class_type); } + + +class CPluginInterface { + public: + virtual char* PluginName() = 0; + virtual int PluginVersion() = 0; + virtual void InstallPlugin() = 0; + virtual void UninstallPlugin() = 0; +}; + diff --git a/src/plugins/sound/oalsound/CMakeLists.txt b/src/plugins/sound/oalsound/CMakeLists.txt new file mode 100644 index 0000000..e36f3ac --- /dev/null +++ b/src/plugins/sound/oalsound/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 2.8) + +set(SOURCES + alsound.cpp + buffer.cpp + channel.cpp +) + +SET (CMAKE_CXX_FLAGS "-Wall -g -std=c++0x -fPIC") + +include(FindPkgConfig) +include(FindOpenAL) +pkg_check_modules(OPENAL_LIB REQUIRED openal) + +set(OPENAL_LIBRARIES + openal + alut +) + + +include_directories(../../..) +include_directories(.) +add_library(openalsound SHARED ${SOURCES}) +target_link_libraries(openalsound ${OPENAL_LIBRARIES}) diff --git a/src/plugins/sound/oalsound/alsound.cpp b/src/plugins/sound/oalsound/alsound.cpp new file mode 100644 index 0000000..19da66a --- /dev/null +++ b/src/plugins/sound/oalsound/alsound.cpp @@ -0,0 +1,548 @@ +// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012 Polish Portal of Colobot (PPC)
+// *
+// * 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/.
+
+// alsound.cpp
+
+
+#include "alsound.h"
+
+
+#define MIN(a, b) (a > b ? b : a)
+
+
+PLUGIN_INTERFACE(ALSound)
+
+
+char* ALSound::PluginName()
+{
+ return const_cast<char *>("Sound plugin using OpenAL library to play sounds.");
+}
+
+
+int ALSound::PluginVersion()
+{
+ return 1;
+}
+
+
+void ALSound::InstallPlugin()
+{
+ CInstanceManager::GetInstancePointer()->AddInstance(CLASS_SOUND, this);
+}
+
+
+void ALSound::UninstallPlugin()
+{
+ CInstanceManager::GetInstancePointer()->DeleteInstance(CLASS_SOUND, this);
+ CleanUp();
+}
+
+
+ALSound::ALSound()
+{
+ mEnabled = false;
+ m3D = false;
+ mAudioVolume = MAXVOLUME;
+ mMute = false;
+}
+
+
+ALSound::~ALSound()
+{
+ CleanUp();
+}
+
+
+void ALSound::CleanUp()
+{
+ if (mEnabled) {
+ GetLogger()->Info("Unloading files and closing device...\n");
+ StopAll();
+
+ for (auto item : mSounds)
+ delete item.second;
+
+ mEnabled = false;
+ alutExit();
+ }
+}
+
+
+bool ALSound::Create(bool b3D)
+{
+ CleanUp();
+
+ if (mEnabled)
+ return true;
+
+ GetLogger()->Info("Opening audio device...\n");
+ if (!alutInit(NULL, NULL)) {
+ ALenum error = alutGetError();
+ GetLogger()->Error("Could not open audio device! Reason: %s\n", alutGetErrorString(error));
+ return false;
+ }
+ GetLogger()->Info("Done.\n");
+
+ mEnabled = true;
+ return true;
+}
+
+
+void ALSound::SetSound3D(bool bMode)
+{
+ // TODO stub! need to be implemented
+ m3D = bMode;
+}
+
+
+bool ALSound::RetSound3D()
+{
+ // TODO stub! need to be implemented
+ return true;
+}
+
+
+bool ALSound::RetSound3DCap()
+{
+ // TODO stub! need to be implemented
+ return true;
+}
+
+
+bool ALSound::RetEnable()
+{
+ return mEnabled;
+}
+
+
+void ALSound::SetAudioVolume(int volume)
+{
+ alListenerf(AL_GAIN, MIN(volume, MAXVOLUME) * 0.01f);
+ mAudioVolume = MIN(volume, MAXVOLUME);
+}
+
+
+int ALSound::RetAudioVolume()
+{
+ float volume;
+ if ( !mEnabled )
+ return 0;
+
+ alGetListenerf(AL_GAIN, &volume);
+ return volume * MAXVOLUME;
+}
+
+
+void ALSound::SetMusicVolume(int volume)
+{
+ // TODO stub! Add music support
+}
+
+
+int ALSound::RetMusicVolume()
+{
+ // TODO stub! Add music support
+ if ( !mEnabled )
+ return 0;
+
+ return 0;
+}
+
+
+bool ALSound::Cache(Sound sound, std::string filename)
+{
+ Buffer *buffer = new Buffer();
+ if (buffer->LoadFromFile(filename, sound)) {
+ mSounds[sound] = buffer;
+ return true;
+ }
+ return false;
+}
+
+
+void ALSound::CacheAll()
+{
+ char filename[100];
+ for ( int i = 1; i < 69; i++ )
+ {
+ sprintf(filename, "high/sound%.3d.wav", i);
+ if ( !Cache((Sound) i, std::string(filename)) )
+ {
+ fprintf(stderr, "Unable to load audio: %s\n", filename);
+ }
+ }
+}
+
+
+int ALSound::RetPriority(Sound sound)
+{
+ if ( sound == SOUND_FLYh ||
+ sound == SOUND_FLY ||
+ sound == SOUND_MOTORw ||
+ sound == SOUND_MOTORt ||
+ sound == SOUND_MOTORr ||
+ sound == SOUND_MOTORs ||
+ sound == SOUND_SLIDE ||
+ sound == SOUND_ERROR )
+ {
+ return 30;
+ }
+
+ if ( sound == SOUND_CONVERT ||
+ sound == SOUND_ENERGY ||
+ sound == SOUND_DERRICK ||
+ sound == SOUND_STATION ||
+ sound == SOUND_REPAIR ||
+ sound == SOUND_RESEARCH ||
+ sound == SOUND_BURN ||
+ sound == SOUND_BUILD ||
+ sound == SOUND_TREMBLE ||
+ sound == SOUND_NUCLEAR ||
+ sound == SOUND_EXPLO ||
+ sound == SOUND_EXPLOl ||
+ sound == SOUND_EXPLOlp ||
+ sound == SOUND_EXPLOp ||
+ sound == SOUND_EXPLOi )
+ {
+ return 20;
+ }
+
+ if ( sound == SOUND_BLUP ||
+ sound == SOUND_INSECTs ||
+ sound == SOUND_INSECTa ||
+ sound == SOUND_INSECTb ||
+ sound == SOUND_INSECTw ||
+ sound == SOUND_INSECTm ||
+ sound == SOUND_PSHHH ||
+ sound == SOUND_EGG )
+ {
+ return 0;
+ }
+
+ return 10;
+}
+
+
+bool ALSound::SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded)
+{
+ int priority = RetPriority(sound);
+
+ // Seeks a channel used which sound is stopped.
+ for (auto it : mChannels) {
+ if (it.second->IsPlaying())
+ continue;
+ if (it.second->GetSoundType() != sound)
+ continue;
+
+ it.second->SetPriority(priority);
+ channel = it.first;
+ bAlreadyLoaded = true;
+ return true;
+ }
+
+ // just add a new channel if we dont have any
+ if (mChannels.size() == 0) {
+ Channel *chn = new Channel();
+ // check if we channel ready to play music, if not report error
+ if (chn->IsReady()) {
+ chn->SetPriority(priority);
+ mChannels[1] = chn;
+ channel = 1;
+ bAlreadyLoaded = false;
+ return true;
+ }
+ delete chn;
+ GetLogger()->Error("Could not open channel to play sound!");
+ return false;
+ }
+
+ // Seeks a channel completely free.
+ auto it = mChannels.end();
+ it--;
+ int i = (*it).first;
+ while (++i)
+ {
+ if (mChannels.find(i) == mChannels.end()) {
+ Channel *chn = new Channel();
+ // check if we channel ready to play music, if not destroy it and seek free one
+ if (chn->IsReady()) {
+ chn->SetPriority(priority);
+ mChannels[1] = chn;
+ channel = 1;
+ bAlreadyLoaded = false;
+ return true;
+ }
+ delete chn;
+ GetLogger()->Warn("Could not open additional channel to play sound!");
+ }
+ }
+
+ int lowerOrEqual = -1;
+ for (auto it : mChannels) {
+ if (it.second->GetPriority() < priority) {
+ GetLogger()->Info("Sound channel with lower priority will be reused.");
+ channel = it.first;
+ return true;
+ }
+ if (it.second->GetPriority() <= priority)
+ lowerOrEqual = it.first;
+ }
+
+ if (lowerOrEqual != -1) {
+ channel = lowerOrEqual;
+ GetLogger()->Info("Sound channel with lower or equal priority will be reused.");
+ return true;
+ }
+
+ GetLogger()->Warn("Could not find free buffer to use.\n");
+ return false;
+}
+
+
+int ALSound::Play(Sound sound, float amplitude, float frequency, bool bLoop)
+{
+ return Play(sound, Math::Vector(), amplitude, frequency, bLoop);
+}
+
+
+int ALSound::Play(Sound sound, Math::Vector pos, float amplitude, float frequency, bool bLoop)
+{
+ if (!mEnabled)
+ return -1;
+
+ if (mAudioVolume <= 0.0f)
+ return -1;
+
+ if (mSounds.find(sound) == mSounds.end()) {
+ GetLogger()->Warn("Sound %d was not loaded!\n", sound);
+ return -1;
+ }
+
+ int channel;
+ bool bAlreadyLoaded;
+ if (!SearchFreeBuffer(sound, channel, bAlreadyLoaded))
+ return -1;
+ if ( !bAlreadyLoaded ) {
+ mChannels[channel]->SetBuffer(mSounds[sound]);
+ }
+
+ Position(channel, pos);
+
+ // setting initial values
+ mChannels[channel]->SetStartAmplitude(amplitude);
+ mChannels[channel]->SetStartFrequency(frequency);
+ mChannels[channel]->SetChangeFrequency(1.0f);
+ mChannels[channel]->ResetOper();
+ mChannels[channel]->AdjustFrequency(frequency);
+ mChannels[channel]->AdjustVolume(mAudioVolume);
+ mChannels[channel]->Play();
+ return channel;
+}
+
+
+bool ALSound::FlushEnvelope(int channel)
+{
+ if (mChannels.find(channel) == mChannels.end()) {
+ return false;
+ }
+
+ mChannels[channel]->ResetOper();
+ return true;
+}
+
+
+bool ALSound::AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper)
+{
+ if (!mEnabled)
+ return false;
+
+ if (mChannels.find(channel) == mChannels.end()) {
+ return false;
+ }
+
+ SoundOper op;
+ op.finalAmplitude = amplitude;
+ op.finalFrequency = frequency;
+ op.totalTime = time;
+ op.nextOper = oper;
+ mChannels[channel]->AddOper(op);
+
+ return false;
+}
+
+
+bool ALSound::Position(int channel, Math::Vector pos)
+{
+ if (!mEnabled)
+ return false;
+
+ if (mChannels.find(channel) == mChannels.end()) {
+ return false;
+ }
+
+ mChannels[channel]->SetPosition(pos);
+ return true;
+}
+
+
+bool ALSound::Frequency(int channel, float frequency)
+{
+ if (!mEnabled)
+ return false;
+
+ if (mChannels.find(channel) == mChannels.end()) {
+ return false;
+ }
+
+ mChannels[channel]->SetFrequency(frequency);
+ return true;
+}
+
+bool ALSound::Stop(int channel)
+{
+ if (!mEnabled)
+ return false;
+
+ if (mChannels.find(channel) == mChannels.end()) {
+ return false;
+ }
+
+ mChannels[channel]->Stop();
+ mChannels[channel]->ResetOper();
+
+ return true;
+}
+
+
+bool ALSound::StopAll()
+{
+ if (!mEnabled)
+ return false;
+
+ for (auto channel : mChannels) {
+ channel.second->Stop();
+ channel.second->ResetOper();
+ }
+
+ return true;
+}
+
+
+bool ALSound::MuteAll(bool bMute)
+{
+ if (!mEnabled)
+ return false;
+
+ float volume;
+ mMute = bMute;
+ if (mMute)
+ volume = 0;
+ else
+ volume = mAudioVolume;
+
+ for (auto channel : mChannels) {
+ channel.second->SetVolume(volume);
+ }
+
+ return true;
+}
+
+
+void ALSound::FrameMove(float delta)
+{
+ if (!mEnabled)
+ return;
+
+ float progress;
+ float volume, frequency;
+ for (auto it : mChannels) {
+ if (!it.second->IsPlaying())
+ continue;
+
+ if (!it.second->HasEnvelope())
+ continue;
+
+ //it.second->GetEnvelope().currentTime += delta;
+ SoundOper oper = it.second->GetEnvelope();
+ progress = it.second->GetCurrentTime() / oper.totalTime;
+ progress = MIN(progress, 1.0f);
+
+ // setting volume
+ volume = progress * abs(oper.finalAmplitude - it.second->GetStartAmplitude());
+ it.second->AdjustVolume(volume * mAudioVolume);
+
+ // setting frequency
+ frequency = progress * (oper.finalFrequency - it.second->GetStartFrequency()) * it.second->GetStartFrequency() * it.second->GetChangeFrequency();
+ it.second->AdjustFrequency(frequency);
+
+ if (it.second->GetEnvelope().totalTime <= it.second->GetCurrentTime()) {
+
+ if (oper.nextOper == SOPER_LOOP) {
+ GetLogger()->Info("Replay.\n");
+ it.second->SetCurrentTime(0.0f);
+ it.second->Play();
+ } else {
+ GetLogger()->Info("Next.\n");
+ it.second->SetStartAmplitude(oper.finalAmplitude);
+ it.second->SetStartFrequency(oper.finalFrequency);
+ it.second->PopEnvelope();
+ }
+ }
+ }
+}
+
+
+void ALSound::SetListener(Math::Vector eye, Math::Vector lookat)
+{
+ GetLogger()->Info("Setting listener position.\n");
+ float orientation[] = {lookat.x, lookat.y, lookat.z, 0.f, 1.f, 0.f};
+ alListener3f(AL_POSITION, eye.x, eye.y, eye.z);
+ alListenerfv(AL_ORIENTATION, orientation);
+}
+
+
+bool ALSound::PlayMusic(int rank, bool bRepeat)
+{
+ // TODO stub! Add music support
+ return true;
+}
+
+
+bool ALSound::RestartMusic()
+{
+ // TODO stub! Add music support
+ return true;
+}
+
+void ALSound::StopMusic()
+{
+ // TODO stub! Add music support
+ SuspendMusic();
+}
+
+
+bool ALSound::IsPlayingMusic()
+{
+ // TODO stub! Add music support
+ return true;
+}
+
+
+void ALSound::SuspendMusic()
+{
+ // TODO stub! Add music support
+}
diff --git a/src/plugins/sound/oalsound/alsound.h b/src/plugins/sound/oalsound/alsound.h new file mode 100644 index 0000000..6d4e5b6 --- /dev/null +++ b/src/plugins/sound/oalsound/alsound.h @@ -0,0 +1,95 @@ +// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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/.
+
+// alsound.h
+
+#pragma once
+
+#include <map>
+#include <string>
+
+#include <AL/alut.h>
+
+#include <common/iman.h>
+#include <common/logger.h>
+#include <sound/sound.h>
+
+#include "buffer.h"
+#include "channel.h"
+#include "check.h"
+
+
+class ALSound : public CSoundInterface
+{
+ public:
+ ALSound();
+ ~ALSound();
+
+ bool Create(bool b3D);
+ void CacheAll();
+ bool Cache(Sound, std::string);
+
+ bool RetEnable();
+
+ void SetSound3D(bool bMode);
+ bool RetSound3D();
+ bool RetSound3DCap();
+
+ void SetAudioVolume(int volume);
+ int RetAudioVolume();
+ void SetMusicVolume(int volume);
+ int RetMusicVolume();
+
+ void SetListener(Math::Vector eye, Math::Vector lookat);
+ void FrameMove(float rTime);
+
+ int Play(Sound sound, float amplitude=1.0f, float frequency=1.0f, bool bLoop = false);
+ int Play(Sound sound, Math::Vector pos, float amplitude=1.0f, float frequency=1.0f, bool bLoop = false);
+ bool FlushEnvelope(int channel);
+ bool AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper);
+ bool Position(int channel, Math::Vector pos);
+ bool Frequency(int channel, float frequency);
+ bool Stop(int channel);
+ bool StopAll();
+ bool MuteAll(bool bMute);
+
+ bool PlayMusic(int rank, bool bRepeat);
+ bool RestartMusic();
+ void SuspendMusic();
+ void StopMusic();
+ bool IsPlayingMusic();
+
+ // plugin interface
+ char* PluginName();
+ int PluginVersion();
+ void InstallPlugin();
+ void UninstallPlugin();
+
+ private:
+ void CleanUp();
+ int RetPriority(Sound);
+ bool SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded);
+
+ bool mEnabled;
+ bool m3D;
+ bool mMute;
+ int mAudioVolume;
+ ALCdevice* audioDevice;
+ ALCcontext* audioContext;
+ std::map<Sound, Buffer*> mSounds;
+ std::map<int, Channel*> mChannels;
+};
diff --git a/src/plugins/sound/oalsound/buffer.cpp b/src/plugins/sound/oalsound/buffer.cpp new file mode 100644 index 0000000..37211e9 --- /dev/null +++ b/src/plugins/sound/oalsound/buffer.cpp @@ -0,0 +1,80 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * 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/. + +// buffer.cpp + +#include "buffer.h" + +Buffer::Buffer() { + mLoaded = false; + mDuration = 0; +} + + +Buffer::~Buffer() { + if (mLoaded) { + alDeleteBuffers(1, &mBuffer); + if (alCheck()) + GetLogger()->Warn("Failed to unload buffer. Code %d\n", alGetCode()); + } +} + + +bool Buffer::LoadFromFile(std::string filename, Sound sound) { + mSound = sound; + + GetLogger()->Info("Loading audio file: %s\n", filename.c_str()); + mBuffer = alutCreateBufferFromFile(filename.c_str()); + + ALenum error = alutGetError(); + if (error) { + GetLogger()->Warn("Failed to load file. Reason: %s\n", alutGetErrorString(error)); + mLoaded = false; + return false; + } + + ALint size, bits, channels, freq; + + alGetBufferi(mBuffer, AL_SIZE, &size); + alGetBufferi(mBuffer, AL_BITS, &bits); + alGetBufferi(mBuffer, AL_CHANNELS, &channels); + alGetBufferi(mBuffer, AL_FREQUENCY, &freq); + + mDuration = (ALfloat)size / channels / bits / 8 / (ALfloat)freq; + + mLoaded = true; + return true; +} + + +Sound Buffer::GetSoundType() { + return mSound; +} + + +ALuint Buffer::GetBuffer() { + return mBuffer; +} + + +bool Buffer::IsLoaded() { + return mLoaded; +} + + +float Buffer::GetDuration() { + return mDuration; +} diff --git a/src/plugins/sound/oalsound/buffer.h b/src/plugins/sound/oalsound/buffer.h new file mode 100644 index 0000000..6eefe72 --- /dev/null +++ b/src/plugins/sound/oalsound/buffer.h @@ -0,0 +1,48 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * 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/. + +// buffer.h + +#pragma once + +#include <string> + +#include <AL/alut.h> + +#include <sound/sound.h> +#include <common/logger.h> + +#include "check.h" + +class Buffer +{ + public: + Buffer(); + ~Buffer(); + + bool LoadFromFile(std::string, Sound); + bool IsLoaded(); + + Sound GetSoundType(); + ALuint GetBuffer(); + float GetDuration(); + + private: + ALuint mBuffer; + Sound mSound; + bool mLoaded; + float mDuration; +}; diff --git a/src/plugins/sound/oalsound/channel.cpp b/src/plugins/sound/oalsound/channel.cpp new file mode 100644 index 0000000..4476dee --- /dev/null +++ b/src/plugins/sound/oalsound/channel.cpp @@ -0,0 +1,304 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * 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/. + +// channel.cpp + +#include "channel.h" + + +Channel::Channel() { + alGenSources(1, &mSource); + + if (alCheck()) { + GetLogger()->Warn("Failed to create sound source. Code: %d\n", alGetCode()); + mReady = false; + } else { + mReady = true; + } + + mPriority = 0; + mBuffer = nullptr; +} + + +Channel::~Channel() { + if (mReady) { + alSourcei(mSource, AL_BUFFER, 0); + alDeleteSources(1, &mSource); + if (alCheck()) + GetLogger()->Warn("Failed to delete sound source. Code: %s\n", alGetCode()); + } +} + + +bool Channel::Play() { + if (!mReady) + return false; + + alSourcePlay(mSource); + if (alCheck()) + GetLogger()->Warn("Could not play audio sound source. Code: %s\n", alGetCode()); + return true; +} + + +bool Channel::SetPosition(Math::Vector pos) { + if (!mReady) + return false; + + alSource3f(mSource, AL_POSITION, pos.x, pos.y, pos.z); + if (alCheck()) { + GetLogger()->Warn("Could not set sound position. Code: %s\n", alGetCode()); + return false; + } + return true; +} + + +bool Channel::SetFrequency(float freq) +{ + if (!mReady) + return false; + + alSourcef(mSource, AL_PITCH, freq); + if (alCheck()) { + GetLogger()->Warn("Could not set sound pitch. Code: %s\n", alGetCode()); + return false; + } + return true; +} + + +float Channel::GetFrequency() +{ + ALfloat freq; + if (!mReady) + return 0; + + alGetSourcef(mSource, AL_PITCH, &freq); + if (alCheck()) { + GetLogger()->Warn("Could not get sound pitch. Code: %s\n", alGetCode()); + return 0; + } + + return freq; +} + + +bool Channel::SetVolume(float vol) +{ + if (!mReady || vol < 0) + return false; + + alSourcef(mSource, AL_GAIN, vol / MAXVOLUME); + if (alCheck()) { + GetLogger()->Warn("Could not set sound volume. Code: %s\n", alGetCode()); + return false; + } + return true; +} + + +float Channel::GetVolume() +{ + ALfloat vol; + if (!mReady) + return 0; + + alGetSourcef(mSource, AL_GAIN, &vol); + if (alCheck()) { + GetLogger()->Warn("Could not get sound volume. Code: %s\n", alGetCode()); + return 0; + } + + return vol * MAXVOLUME; +} + + +int Channel::GetPriority() +{ + return mPriority; +} + + +void Channel::SetPriority(int pri) +{ + mPriority = pri; +} + + +void Channel::SetStartAmplitude(float gain) +{ + mStartAmplitude = gain; +} + + +void Channel::SetStartFrequency(float freq) +{ + mStartFrequency = freq; +} + + +void Channel::SetChangeFrequency(float freq) +{ + mChangeFrequency = freq; +} + + +void Channel::SetInitFrequency(float freq) +{ + mInitFrequency = freq; +} + + +float Channel::GetStartAmplitude() +{ + return mStartAmplitude; +} + + +float Channel::GetStartFrequency() +{ + return mStartFrequency; +} + + +float Channel::GetChangeFrequency() +{ + return mChangeFrequency; +} + + +float Channel::GetInitFrequency() +{ + return mInitFrequency; +} + + +void Channel::AddOper(SoundOper oper) +{ + mOper.push_back(oper); +} + + +void Channel::ResetOper() +{ + mOper.clear(); +} + + +Sound Channel::GetSoundType() { + return mBuffer->GetSoundType(); +} + + +bool Channel::SetBuffer(Buffer *buffer) { + if (!mReady) + return false; + + assert(buffer); + mBuffer = buffer; + alSourcei(mSource, AL_BUFFER, buffer->GetBuffer()); + if (alCheck()) { + GetLogger()->Warn("Could not set sound buffer. Code: %s\n", alGetCode()); + return false; + } + mInitFrequency = GetFrequency(); + return true; +} + + +void Channel::AdjustFrequency(float freq) { + SetFrequency(freq * mInitFrequency); +} + + +void Channel::AdjustVolume(float volume) { + SetVolume(mStartAmplitude * (float) volume); +} + + +bool Channel::IsPlaying() { + ALint status; + if (!mReady) return false; + + alGetSourcei(mSource, AL_SOURCE_STATE, &status); + if (alCheck()) { + GetLogger()->Warn("Could not get sound status. Code: %s\n", alGetCode()); + return false; + } + + return status == AL_PLAYING; +} + + +bool Channel::IsReady() { + return mReady; +} + + +bool Channel::Stop() { + alSourceStop(mSource); + if (alCheck()) { + GetLogger()->Warn("Could not stop sound. Code: %s\n", alGetCode()); + return false; + } + return true; +} + + +float Channel::GetCurrentTime() +{ + ALfloat current; + alGetSourcef(mSource, AL_SEC_OFFSET, ¤t); + if (alCheck()) { + GetLogger()->Warn("Could not get source current play time. Code: %s\n", alGetCode()); + return 0.0f; + } + return current; +} + + +void Channel::SetCurrentTime(float current) +{ + alSourcef(mSource, AL_SEC_OFFSET, current); + if (alCheck()) + GetLogger()->Warn("Could not get source current play time. Code: %s\n", alGetCode()); +} + + +float Channel::GetDuration() +{ + return mBuffer->GetDuration(); +} + + +bool Channel::HasEnvelope() +{ + return mOper.size() > 0; +} + + +SoundOper& Channel::GetEnvelope() +{ + return mOper.front(); +} + + +void Channel::PopEnvelope() +{ + mOper.pop_front(); +} diff --git a/src/plugins/sound/oalsound/channel.h b/src/plugins/sound/oalsound/channel.h new file mode 100644 index 0000000..3099931 --- /dev/null +++ b/src/plugins/sound/oalsound/channel.h @@ -0,0 +1,99 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * 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/. + +// channel.h + +#pragma once + +#include <string> +#include <deque> +#include <cassert> + +#include <AL/al.h> +#include <AL/alc.h> + +#include <sound/sound.h> + +#include "buffer.h" +#include "check.h" + +struct SoundOper +{ + float finalAmplitude; + float finalFrequency; + float totalTime; + SoundNext nextOper; +}; + + +class Channel +{ + public: + Channel(); + ~Channel(); + + bool Play(); + bool Stop(); + bool SetPosition(Math::Vector); + + bool SetFrequency(float); + float GetFrequency(); + + float GetCurrentTime(); + void SetCurrentTime(float); + float GetDuration(); + + bool SetVolume(float); + float GetVolume(); + bool IsPlaying(); + bool IsReady(); + + bool SetBuffer(Buffer *); + bool HasEnvelope(); + SoundOper& GetEnvelope(); + void PopEnvelope(); + + int GetPriority(); + void SetPriority(int); + + void SetStartAmplitude(float); + void SetStartFrequency(float); + void SetChangeFrequency(float); + void SetInitFrequency(float); + + float GetStartAmplitude(); + float GetStartFrequency(); + float GetChangeFrequency(); + float GetInitFrequency(); + + void AddOper(SoundOper); + void ResetOper(); + Sound GetSoundType(); + void AdjustFrequency(float); + void AdjustVolume(float); + + private: + Buffer *mBuffer; + ALuint mSource; + + int mPriority; + float mStartAmplitude; + float mStartFrequency; + float mChangeFrequency; + float mInitFrequency; + std::deque<SoundOper> mOper; + bool mReady; +}; diff --git a/src/plugins/sound/oalsound/check.h b/src/plugins/sound/oalsound/check.h new file mode 100644 index 0000000..cb6b4a1 --- /dev/null +++ b/src/plugins/sound/oalsound/check.h @@ -0,0 +1,39 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * 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/. + +// check.h + +#pragma once + +#include <AL/al.h> +#include <AL/alc.h> + +#include <common/logger.h> + +static ALenum CODE = AL_NO_ERROR; + +inline bool alCheck() +{ + CODE = alGetError(); + return CODE != AL_NO_ERROR; +} + +inline ALenum alGetCode() +{ + ALenum ret = CODE; + CODE = AL_NO_ERROR; + return ret; +} diff --git a/src/plugins/test/CMakeLists.txt b/src/plugins/test/CMakeLists.txt new file mode 100644 index 0000000..551daeb --- /dev/null +++ b/src/plugins/test/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.8) + +set(CMAKE_BUILD_TYPE debug) +set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0 -std=c++11 -rdynamic") + +add_executable(plugin_test plugin_test.cpp ../../common/iman.cpp ../../common/logger.cpp ../plugin.cpp) + +# Change to DirectX SDK directory +include_directories("../../") + +target_link_libraries(plugin_test ltdl)
\ No newline at end of file diff --git a/src/plugins/test/plugin_test.cpp b/src/plugins/test/plugin_test.cpp new file mode 100644 index 0000000..7175773 --- /dev/null +++ b/src/plugins/test/plugin_test.cpp @@ -0,0 +1,40 @@ +#include <string> +#include <cstdio> +#include <unistd.h> + +#include <common/logger.h> +#include <common/iman.h> +#include <sound/sound.h> +#include <plugins/plugin.h> + + +int main() { + new CLogger(); + new CInstanceManager(); + + lt_dlinit(); + + CPlugin *plugin = new CPlugin("libopenalsound"); + if (plugin->LoadPlugin()) { + CSoundInterface *sound = static_cast<CSoundInterface*>(CInstanceManager::GetInstancePointer()->SearchInstance(CLASS_SOUND)); + + sound->Create(true); + sound->CacheAll(); + sound->Play((Sound)8); + sound->Play((Sound)18); + + sleep(10); + /* + while (1) + { + // just a test, very slow + plugin->FrameMove(0); + //if ('n' == getchar()) + // break; + }*/ + plugin->UnloadPlugin(); + } + + lt_dlexit(); + return 0; +} |