* Removed alut

* Using libsndfile to load sounds and music
* Added support for playing music files
dev-ui
erihel 2013-01-14 22:55:16 +01:00
parent 35faf628cf
commit 58f35e44ae
13 changed files with 216 additions and 74 deletions

5
.gitignore vendored
View File

@ -14,3 +14,8 @@ Makefile
/Testing /Testing
/CTestTestfile.cmake /CTestTestfile.cmake
/src/CBot/tests/CBot_console/bin/ /src/CBot/tests/CBot_console/bin/
.kdev4
*.kdev4
*.flv
*.mp4

View File

@ -113,6 +113,8 @@ option(GLEW_STATIC "Link statically with GLEW" OFF)
find_package(GLEW REQUIRED) find_package(GLEW REQUIRED)
include("${colobot_SOURCE_DIR}/cmake/FindLibSndFile.cmake")
## ##
# Additional settings to use when cross-compiling with MXE (http://mxe.cc/) # Additional settings to use when cross-compiling with MXE (http://mxe.cc/)

View File

@ -0,0 +1,23 @@
# Base Io build system
# Written by Jeremy Tregunna <jeremy.tregunna@me.com>
#
# Find libsndfile.
FIND_PATH(LIBSNDFILE_INCLUDE_DIR sndfile.h)
SET(LIBSNDFILE_NAMES ${LIBSNDFILE_NAMES} sndfile libsndfile)
FIND_LIBRARY(LIBSNDFILE_LIBRARY NAMES ${LIBSNDFILE_NAMES} PATH)
IF(LIBSNDFILE_INCLUDE_DIR AND LIBSNDFILE_LIBRARY)
SET(LIBSNDFILE_FOUND TRUE)
ENDIF(LIBSNDFILE_INCLUDE_DIR AND LIBSNDFILE_LIBRARY)
IF(LIBSNDFILE_FOUND)
IF(NOT LibSndFile_FIND_QUIETLY)
MESSAGE(STATUS "Found LibSndFile: ${LIBSNDFILE_LIBRARY}")
ENDIF (NOT LibSndFile_FIND_QUIETLY)
ELSE(LIBSNDFILE_FOUND)
IF(LibSndFile_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find sndfile")
ENDIF(LibSndFile_FIND_REQUIRED)
ENDIF (LIBSNDFILE_FOUND)

View File

@ -30,12 +30,14 @@ if (${OPENAL_SOUND})
if (${MXE}) if (${MXE})
set(OPTIONAL_LIBS set(OPTIONAL_LIBS
${CMAKE_FIND_ROOT_PATH}/lib/libOpenAL32.a ${CMAKE_FIND_ROOT_PATH}/lib/libOpenAL32.a
${CMAKE_FIND_ROOT_PATH}/lib/libalut.a )
elseif (${PLATFORM_WINDOWS})
set(OPTIONAL_LIBS
OpenAL32
) )
else() else()
set(OPTIONAL_LIBS set(OPTIONAL_LIBS
openal openal
alut
) )
endif() endif()
endif() endif()
@ -200,6 +202,7 @@ ${GLEW_LIBRARY}
${Boost_LIBRARIES} ${Boost_LIBRARIES}
${OPTIONAL_LIBS} ${OPTIONAL_LIBS}
${PLATFORM_LIBS} ${PLATFORM_LIBS}
${LIBSNDFILE_LIBRARY}
) )
# Local # Local
@ -207,6 +210,7 @@ include_directories(
. .
.. ..
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
${LIBSNDFILE_INCLUDE_DIR}
) )
# System # System

View File

@ -321,10 +321,17 @@ bool CApplication::Create()
#endif #endif
m_sound->Create(true); m_sound->Create(true);
if (GetProfile().GetLocalProfileString("Resources", "Sound", path)) if (GetProfile().GetLocalProfileString("Resources", "Sound", path)) {
m_sound->CacheAll(path); m_sound->CacheAll(path);
else } else {
m_sound->CacheAll(GetDataSubdirPath(DIR_SOUND)); m_sound->CacheAll(GetDataSubdirPath(DIR_SOUND));
}
if (GetProfile().GetLocalProfileString("Resources", "Music", path)) {
m_sound->AddMusicFiles(path);
} else {
m_sound->AddMusicFiles(GetDataSubdirPath(DIR_MUSIC));
}
} }
std::string standardInfoMessage = std::string standardInfoMessage =

View File

@ -27,7 +27,9 @@ ALSound::ALSound()
mEnabled = false; mEnabled = false;
m3D = false; m3D = false;
mAudioVolume = 1.0f; mAudioVolume = 1.0f;
mMusicVolume = 1.0f;
mMute = false; mMute = false;
mCurrentMusic = new Channel();
auto pointer = CInstanceManager::GetInstancePointer(); auto pointer = CInstanceManager::GetInstancePointer();
if (pointer != nullptr) if (pointer != nullptr)
CInstanceManager::GetInstancePointer()->AddInstance(CLASS_SOUND, this); CInstanceManager::GetInstancePointer()->AddInstance(CLASS_SOUND, this);
@ -48,17 +50,21 @@ void ALSound::CleanUp()
if (mEnabled) { if (mEnabled) {
GetLogger()->Info("Unloading files and closing device...\n"); GetLogger()->Info("Unloading files and closing device...\n");
StopAll(); StopAll();
for (auto channel : mChannels) { for (auto channel : mChannels) {
delete channel.second; delete channel.second;
} }
for (auto item : mSounds) { for (auto item : mSounds) {
delete item.second; delete item.second;
} }
mEnabled = false; mEnabled = false;
alutExit();
mCurrentMusic->FreeBuffer();
delete mCurrentMusic;
alcDestroyContext(mContext);
alcCloseDevice(mDevice);
} }
} }
@ -71,13 +77,20 @@ bool ALSound::Create(bool b3D)
return true; return true;
GetLogger()->Info("Opening audio device...\n"); GetLogger()->Info("Opening audio device...\n");
if (!alutInit(NULL, NULL)) { mDevice = alcOpenDevice(NULL);
ALenum error = alutGetError(); if (!mDevice) {
GetLogger()->Error("Could not open audio device! Reason: %s\n", alutGetErrorString(error)); GetLogger()->Error("Could not open audio device!\n");
return false; return false;
} }
GetLogger()->Info("Done.\n");
mContext = alcCreateContext(mDevice, NULL);
if (!mContext) {
GetLogger()->Error("Could not create audio context!\n");
return false;
}
alcMakeContextCurrent(mContext);
GetLogger()->Info("Done.\n");
mEnabled = true; mEnabled = true;
return true; return true;
} }
@ -119,28 +132,26 @@ void ALSound::SetAudioVolume(int volume)
int ALSound::GetAudioVolume() int ALSound::GetAudioVolume()
{ {
float volume;
if ( !mEnabled ) if ( !mEnabled )
return 0; return 0;
alGetListenerf(AL_GAIN, &volume); return mAudioVolume * MAXVOLUME;
return volume * MAXVOLUME;
} }
void ALSound::SetMusicVolume(int volume) void ALSound::SetMusicVolume(int volume)
{ {
// TODO stub! Add music support alListenerf(AL_GAIN, MIN(static_cast<float>(volume) / MAXVOLUME, 1.0f));
mMusicVolume = MIN(static_cast<float>(volume) / MAXVOLUME, 1.0f);
} }
int ALSound::GetMusicVolume() int ALSound::GetMusicVolume()
{ {
// TODO stub! Add music support
if ( !mEnabled ) if ( !mEnabled )
return 0; return 0.0f;
return 0; return mMusicVolume * MAXVOLUME;
} }
@ -242,8 +253,7 @@ bool ALSound::SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded)
auto it = mChannels.end(); auto it = mChannels.end();
it--; it--;
int i = (*it).first; int i = (*it).first;
while (++i) while (++i) {
{
if (mChannels.find(i) == mChannels.end()) { if (mChannels.find(i) == mChannels.end()) {
Channel *chn = new Channel(); Channel *chn = new Channel();
// check if channel is ready to play music, if not destroy it and seek free one // check if channel is ready to play music, if not destroy it and seek free one
@ -307,9 +317,9 @@ int ALSound::Play(Sound sound, Math::Vector pos, float amplitude, float frequenc
bAlreadyLoaded = false; bAlreadyLoaded = false;
if (!bAlreadyLoaded) { if (!bAlreadyLoaded) {
if (!mChannels[channel]->SetBuffer(mSounds[sound])) { if (!mChannels[channel]->SetBuffer(mSounds[sound])) {
mChannels[channel]->SetBuffer(nullptr); mChannels[channel]->SetBuffer(nullptr);
return -1; return -1;
} }
} }
Position(channel, pos); Position(channel, pos);
@ -445,36 +455,36 @@ void ALSound::FrameMove(float delta)
for (auto it : mChannels) { for (auto it : mChannels) {
if (!it.second->IsPlaying()) { if (!it.second->IsPlaying()) {
continue; continue;
} }
if (!it.second->HasEnvelope()) if (!it.second->HasEnvelope())
continue; continue;
SoundOper &oper = it.second->GetEnvelope(); SoundOper &oper = it.second->GetEnvelope();
oper.currentTime += delta; oper.currentTime += delta;
progress = oper.currentTime / oper.totalTime; progress = oper.currentTime / oper.totalTime;
progress = MIN(progress, 1.0f); progress = MIN(progress, 1.0f);
// setting volume // setting volume
volume = progress * (oper.finalAmplitude - it.second->GetStartAmplitude()); volume = progress * (oper.finalAmplitude - it.second->GetStartAmplitude());
it.second->SetVolume(volume + it.second->GetStartAmplitude()); it.second->SetVolume(volume + it.second->GetStartAmplitude());
// setting frequency // setting frequency
frequency = progress * (oper.finalFrequency - it.second->GetStartFrequency()) * it.second->GetStartFrequency() * it.second->GetChangeFrequency() * it.second->GetInitFrequency(); frequency = progress * (oper.finalFrequency - it.second->GetStartFrequency()) * it.second->GetStartFrequency() * it.second->GetChangeFrequency() * it.second->GetInitFrequency();
it.second->AdjustFrequency(frequency); it.second->AdjustFrequency(frequency);
if (oper.totalTime <= oper.currentTime) { if (oper.totalTime <= oper.currentTime) {
if (oper.nextOper == SOPER_LOOP) { if (oper.nextOper == SOPER_LOOP) {
oper.currentTime = 0.0f; oper.currentTime = 0.0f;
it.second->Play(); it.second->Play();
} else { } else {
it.second->SetStartAmplitude(oper.finalAmplitude); it.second->SetStartAmplitude(oper.finalAmplitude);
it.second->SetStartFrequency(oper.finalFrequency); it.second->SetStartFrequency(oper.finalFrequency);
if (oper.nextOper == SOPER_STOP) { if (oper.nextOper == SOPER_STOP) {
it.second->Stop(); it.second->Stop();
} }
it.second->PopEnvelope(); it.second->PopEnvelope();
} }
} }
} }
@ -491,32 +501,67 @@ void ALSound::SetListener(Math::Vector eye, Math::Vector lookat)
bool ALSound::PlayMusic(int rank, bool bRepeat) bool ALSound::PlayMusic(int rank, bool bRepeat)
{ {
// TODO stub! Add music support if (!mEnabled) {
return false;
}
if (static_cast<int>(mCurrentMusic->GetSoundType()) != rank) {
mCurrentMusic->FreeBuffer();
if (mMusic.find(rank) == mMusic.end()) {
GetLogger()->Info("Requested music %d was not found.\n", rank);
return false;
}
Buffer *buffer = new Buffer();
buffer->LoadFromFile(mMusic.at(rank), static_cast<Sound>(rank));
mCurrentMusic->SetBuffer(buffer);
}
mCurrentMusic->SetVolume(mMusicVolume);
mCurrentMusic->SetLoop(bRepeat);
mCurrentMusic->Play();
return true; return true;
} }
bool ALSound::RestartMusic() bool ALSound::RestartMusic()
{ {
// TODO stub! Add music support if (!mEnabled || !mCurrentMusic) {
return false;
}
mCurrentMusic->Stop();
mCurrentMusic->Play();
return true; return true;
} }
void ALSound::StopMusic() void ALSound::StopMusic()
{ {
// TODO stub! Add music support if (!mEnabled || !mCurrentMusic) {
return;
}
SuspendMusic(); SuspendMusic();
} }
bool ALSound::IsPlayingMusic() bool ALSound::IsPlayingMusic()
{ {
// TODO stub! Add music support if (!mEnabled || !mCurrentMusic) {
return true; return false;
}
return mCurrentMusic->IsPlaying();
} }
void ALSound::SuspendMusic() void ALSound::SuspendMusic()
{ {
// TODO stub! Add music support if (!mEnabled || !mCurrentMusic) {
return;
}
mCurrentMusic->Stop();
} }

View File

@ -22,7 +22,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include <AL/alut.h> #include <AL/al.h>
#include "common/iman.h" #include "common/iman.h"
#include "common/logger.h" #include "common/logger.h"
@ -87,8 +87,10 @@ class ALSound : public CSoundInterface
bool m3D; bool m3D;
bool mMute; bool mMute;
float mAudioVolume; float mAudioVolume;
ALCdevice* audioDevice; float mMusicVolume;
ALCcontext* audioContext; ALCdevice* mDevice;
ALCcontext* mContext;
std::map<Sound, Buffer*> mSounds; std::map<Sound, Buffer*> mSounds;
std::map<int, Channel*> mChannels; std::map<int, Channel*> mChannels;
Channel *mCurrentMusic;
}; };

View File

@ -35,26 +35,43 @@ Buffer::~Buffer() {
bool Buffer::LoadFromFile(std::string filename, Sound sound) { bool Buffer::LoadFromFile(std::string filename, Sound sound) {
mSound = sound; mSound = sound;
GetLogger()->Debug("Loading audio file: %s\n", filename.c_str()); GetLogger()->Debug("Loading audio file: %s\n", filename.c_str());
mBuffer = alutCreateBufferFromFile(filename.c_str());
ALenum error = alutGetError(); SF_INFO fileInfo;
if (error) { SNDFILE *file = sf_open(filename.c_str(), SFM_READ, &fileInfo);
GetLogger()->Warn("Failed to load file. Reason: %s\n", alutGetErrorString(error));
GetLogger()->Trace(" channels %d\n", fileInfo.channels);
GetLogger()->Trace(" format %d\n", fileInfo.format);
GetLogger()->Trace(" frames %d\n", fileInfo.frames);
GetLogger()->Trace(" samplerate %d\n", fileInfo.samplerate);
GetLogger()->Trace(" sections %d\n", fileInfo.sections);
if (!file) {
GetLogger()->Warn("Could not load file. Reason: %s\n", sf_strerror(file));
mLoaded = false; mLoaded = false;
return false; return false;
} }
ALint size, bits, channels, freq; alGenBuffers(1, &mBuffer);
if (!mBuffer) {
GetLogger()->Warn("Could not create audio buffer\n");
mLoaded = false;
sf_close(file);
return false;
}
alGetBufferi(mBuffer, AL_SIZE, &size); // read chunks of 4096 samples
alGetBufferi(mBuffer, AL_BITS, &bits); std::vector<uint16_t> data;
alGetBufferi(mBuffer, AL_CHANNELS, &channels); std::array<int16_t, 4096> buffer;
alGetBufferi(mBuffer, AL_FREQUENCY, &freq); data.reserve(fileInfo.frames);
size_t read = 0;
mDuration = static_cast<ALfloat>(size) * 8 / channels / bits / static_cast<ALfloat>(freq); while ((read = sf_read_short(file, buffer.data(), buffer.size())) != 0) {
data.insert(data.end(), buffer.begin(), buffer.begin() + read);
}
sf_close(file);
alBufferData(mBuffer, fileInfo.channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, &data.front(), data.size() * sizeof(uint16_t), fileInfo.samplerate);
mDuration = static_cast<float>(fileInfo.frames) / fileInfo.samplerate;
mLoaded = true; mLoaded = true;
return true; return true;
} }

View File

@ -19,8 +19,11 @@
#pragma once #pragma once
#include <string> #include <string>
#include <vector>
#include <array>
#include <AL/alut.h> #include <AL/al.h>
#include <sndfile.h>
#include "sound/sound.h" #include "sound/sound.h"
#include "common/logger.h" #include "common/logger.h"

View File

@ -34,12 +34,15 @@ Channel::Channel() {
mBuffer = nullptr; mBuffer = nullptr;
mLoop = false; mLoop = false;
mInitFrequency = 0.0f; mInitFrequency = 0.0f;
mStartAmplitude = 0.0f;
mStartFrequency = 0.0f;
mChangeFrequency = 0.0f;
} }
Channel::~Channel() { Channel::~Channel() {
if (mReady) { if (mReady) {
alSourceStop(mSource); alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0); alSourcei(mSource, AL_BUFFER, 0);
alDeleteSources(1, &mSource); alDeleteSources(1, &mSource);
if (alCheck()) if (alCheck())
@ -223,8 +226,8 @@ bool Channel::SetBuffer(Buffer *buffer) {
mBuffer = buffer; mBuffer = buffer;
if (buffer == nullptr) { if (buffer == nullptr) {
alSourcei(mSource, AL_BUFFER, 0); alSourcei(mSource, AL_BUFFER, 0);
return true; return true;
} }
alSourcei(mSource, AL_BUFFER, buffer->GetBuffer()); alSourcei(mSource, AL_BUFFER, buffer->GetBuffer());
@ -237,10 +240,26 @@ bool Channel::SetBuffer(Buffer *buffer) {
} }
bool Channel::FreeBuffer() {
if (!mReady)
return false;
if (!mBuffer) {
return false;
}
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
delete mBuffer;
mBuffer = nullptr;
return true;
}
bool Channel::IsPlaying() { bool Channel::IsPlaying() {
ALint status; ALint status;
if (!mReady || mBuffer == nullptr) if (!mReady || mBuffer == nullptr)
return false; return false;
alGetSourcei(mSource, AL_SOURCE_STATE, &status); alGetSourcei(mSource, AL_SOURCE_STATE, &status);
if (alCheck()) { if (alCheck()) {
@ -263,7 +282,7 @@ bool Channel::IsLoaded() {
bool Channel::Stop() { bool Channel::Stop() {
if (!mReady || mBuffer == nullptr) if (!mReady || mBuffer == nullptr)
return false; return false;
alSourceStop(mSource); alSourceStop(mSource);
if (alCheck()) { if (alCheck()) {
@ -277,7 +296,7 @@ bool Channel::Stop() {
float Channel::GetCurrentTime() float Channel::GetCurrentTime()
{ {
if (!mReady || mBuffer == nullptr) if (!mReady || mBuffer == nullptr)
return 0.0f; return 0.0f;
ALfloat current; ALfloat current;
alGetSourcef(mSource, AL_SEC_OFFSET, &current); alGetSourcef(mSource, AL_SEC_OFFSET, &current);
@ -292,7 +311,7 @@ float Channel::GetCurrentTime()
void Channel::SetCurrentTime(float current) void Channel::SetCurrentTime(float current)
{ {
if (!mReady || mBuffer == nullptr) if (!mReady || mBuffer == nullptr)
return; return;
alSourcef(mSource, AL_SEC_OFFSET, current); alSourcef(mSource, AL_SEC_OFFSET, current);
if (alCheck()) if (alCheck())
@ -303,7 +322,7 @@ void Channel::SetCurrentTime(float current)
float Channel::GetDuration() float Channel::GetDuration()
{ {
if (!mReady || mBuffer == nullptr) if (!mReady || mBuffer == nullptr)
return 0.0f; return 0.0f;
return mBuffer->GetDuration(); return mBuffer->GetDuration();
} }

View File

@ -52,7 +52,7 @@ class Channel
bool SetFrequency(float); bool SetFrequency(float);
float GetFrequency(); float GetFrequency();
bool AdjustFrequency(float); bool AdjustFrequency(float);
float GetCurrentTime(); float GetCurrentTime();
void SetCurrentTime(float); void SetCurrentTime(float);
@ -62,9 +62,11 @@ class Channel
float GetVolume(); float GetVolume();
bool IsPlaying(); bool IsPlaying();
bool IsReady(); bool IsReady();
bool IsLoaded(); bool IsLoaded();
bool SetBuffer(Buffer *); bool SetBuffer(Buffer *);
bool FreeBuffer();
bool HasEnvelope(); bool HasEnvelope();
SoundOper& GetEnvelope(); SoundOper& GetEnvelope();
void PopEnvelope(); void PopEnvelope();
@ -84,7 +86,7 @@ class Channel
void AddOper(SoundOper); void AddOper(SoundOper);
void ResetOper(); void ResetOper();
Sound GetSoundType(); Sound GetSoundType();
void SetLoop(bool); void SetLoop(bool);
private: private:
Buffer *mBuffer; Buffer *mBuffer;
@ -97,5 +99,5 @@ class Channel
float mInitFrequency; float mInitFrequency;
std::deque<SoundOper> mOper; std::deque<SoundOper> mOper;
bool mReady; bool mReady;
bool mLoop; bool mLoop;
}; };

View File

@ -22,6 +22,7 @@
#pragma once #pragma once
#include <boost/filesystem.hpp>
#include "math/vector.h" #include "math/vector.h"
@ -32,6 +33,7 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <map>
/*! /*!
@ -177,6 +179,16 @@ class CSoundInterface
} }
}; };
/** Function called to add all music files to list */
inline void AddMusicFiles(std::string path) {
for ( int i = 1; i <= 12; i++ ) {
std::stringstream filename;
filename << path << "/music" << std::setfill('0') << std::setw(3) << i << ".ogg";
if (boost::filesystem::exists(filename.str()))
mMusic[i] = filename.str();
}
};
/** Function called to cache sound effect file. /** Function called to cache sound effect file.
* This function is called by plugin interface for each file. * This function is called by plugin interface for each file.
* \param bSound - id of a file, will be used to identify sound files * \param bSound - id of a file, will be used to identify sound files
@ -328,5 +340,8 @@ class CSoundInterface
* \return return true if music is playing * \return return true if music is playing
*/ */
inline virtual bool IsPlayingMusic() {return true;}; inline virtual bool IsPlayingMusic() {return true;};
protected:
std::map<int, std::string> mMusic;
}; };

View File

@ -5458,10 +5458,8 @@ void CMainDialog::ChangeSetupButtons()
ps = static_cast<CSlider*>(pw->SearchControl(EVENT_INTERFACE_VOLMUSIC)); ps = static_cast<CSlider*>(pw->SearchControl(EVENT_INTERFACE_VOLMUSIC));
if ( ps != 0 ) if ( ps != 0 )
{ {
/*
TODO: midi volume
value = ps->GetVisibleValue(); value = ps->GetVisibleValue();
m_sound->SetMidiVolume((int)value);*/ m_sound->SetMusicVolume(static_cast<int>(value));
} }
} }