From ecab9761d46754cd8d7a513a8ac16a8b88499d55 Mon Sep 17 00:00:00 2001 From: erihel Date: Wed, 4 Jul 2012 19:38:18 +0200 Subject: * Added OpenAL sound plugin Plugin needs some more work and tests. It doesn't support playing music yet as sound interface is propably going to change a bit. --- src/plugins/sound/oalsound/CMakeLists.txt | 25 ++ src/plugins/sound/oalsound/alsound.cpp | 534 ++++++++++++++++++++++++++++++ src/plugins/sound/oalsound/alsound.h | 94 ++++++ src/plugins/sound/oalsound/buffer.cpp | 80 +++++ src/plugins/sound/oalsound/buffer.h | 48 +++ src/plugins/sound/oalsound/channel.cpp | 304 +++++++++++++++++ src/plugins/sound/oalsound/channel.h | 99 ++++++ src/plugins/sound/oalsound/check.h | 39 +++ 8 files changed, 1223 insertions(+) create mode 100644 src/plugins/sound/oalsound/CMakeLists.txt create mode 100644 src/plugins/sound/oalsound/alsound.cpp create mode 100644 src/plugins/sound/oalsound/alsound.h create mode 100644 src/plugins/sound/oalsound/buffer.cpp create mode 100644 src/plugins/sound/oalsound/buffer.h create mode 100644 src/plugins/sound/oalsound/channel.cpp create mode 100644 src/plugins/sound/oalsound/channel.h create mode 100644 src/plugins/sound/oalsound/check.h (limited to 'src') diff --git a/src/plugins/sound/oalsound/CMakeLists.txt b/src/plugins/sound/oalsound/CMakeLists.txt new file mode 100644 index 0000000..6056590 --- /dev/null +++ b/src/plugins/sound/oalsound/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 2.8) + +set(SOURCES + alsound.cpp + buffer.cpp + channel.cpp + ../../../common/logger.cpp +) + +SET (CMAKE_CXX_FLAGS "-Wall -g -std=c++0x") + +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..87baabd --- /dev/null +++ b/src/plugins/sound/oalsound/alsound.cpp @@ -0,0 +1,534 @@ +// * 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, CSoundInterface) + + +char* ALSound::pluginName() +{ + return const_cast("Sound plugin using OpenAL library to play sounds."); +} + + +int ALSound::pluginVersion() +{ + return 1; +} + + +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"); + mEnabled = false; + + for (auto item : mSounds) + delete item.second; + + 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..d41f6bf --- /dev/null +++ b/src/plugins/sound/oalsound/alsound.h @@ -0,0 +1,94 @@ +// * 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 +#include + +#include + +#include +#include +#include + +#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 pluginInit(); + + 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 mSounds; + std::map 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 + +#include + +#include +#include + +#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 +#include +#include + +#include +#include + +#include + +#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 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 +#include + +#include + +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; +} -- cgit v1.2.3-1-g7c22