Implemented libsndfile loader in PhysFS

dev-mp
Krzysztof Dermont 2014-06-21 02:58:41 +02:00
parent 2260f6bf4f
commit 1630cf0ed2
8 changed files with 248 additions and 56 deletions

View File

@ -77,6 +77,7 @@ common/stringutils.cpp
common/resources/resourcemanager.cpp
common/resources/resourcestreambuffer.cpp
common/resources/inputstream.cpp
common/resources/sndfile.cpp
graphics/core/color.cpp
graphics/engine/camera.cpp
graphics/engine/cloud.cpp

View File

@ -124,7 +124,13 @@ SDL_RWops* CResourceManager::GetSDLFileHandler(const std::string &filename)
}
int CResourceManager::SDLClose(SDL_RWops* context)
CSNDFile* CResourceManager::GetSNDFileHandler(const std::string &filename)
{
return new CSNDFile(filename);
}
int CResourceManager::SDLClose(SDL_RWops *context)
{
if (CheckSDLContext(context))
{
@ -138,7 +144,7 @@ int CResourceManager::SDLClose(SDL_RWops* context)
}
int CResourceManager::SDLRead(SDL_RWops* context, void* ptr, int size, int maxnum)
int CResourceManager::SDLRead(SDL_RWops *context, void *ptr, int size, int maxnum)
{
if (CheckSDLContext(context))
{
@ -152,13 +158,13 @@ int CResourceManager::SDLRead(SDL_RWops* context, void* ptr, int size, int maxnu
}
int CResourceManager::SDLWrite(SDL_RWops* context, const void* ptr, int size, int num)
int CResourceManager::SDLWrite(SDL_RWops *context, const void *ptr, int size, int num)
{
return 0;
}
int CResourceManager::SDLSeek(SDL_RWops* context, int offset, int whence)
int CResourceManager::SDLSeek(SDL_RWops *context, int offset, int whence)
{
if (CheckSDLContext(context))
{
@ -188,7 +194,7 @@ int CResourceManager::SDLSeek(SDL_RWops* context, int offset, int whence)
}
bool CResourceManager::CheckSDLContext(SDL_RWops* context)
bool CResourceManager::CheckSDLContext(SDL_RWops *context)
{
if (context->type != 0xc010b04f)
{

View File

@ -19,6 +19,8 @@
#include <string>
#include <SDL.h>
#include "common/resources/sndfile.h"
class CResourceManager
{
public:
@ -30,6 +32,7 @@ public:
static bool SetSaveLocation(const std::string &location);
static std::string GetLanguageLocation();
static SDL_RWops* GetSDLFileHandler(const std::string &filename);
static CSNDFile* GetSNDFileHandler(const std::string &filename);
private:
static int SDLSeek(SDL_RWops *context, int offset, int whence);

View File

@ -0,0 +1,130 @@
// * This file is part of the COLOBOT source code
// * Copyright (C) 2014 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/.
#include "common/resources/sndfile.h"
#include <cstring>
CSNDFile::CSNDFile(const std::string& filename)
{
memset(&m_file_info, 0, sizeof(SF_INFO));
if (PHYSFS_isInit())
{
m_file = PHYSFS_openRead(filename.c_str());
}
else
{
m_last_error = "Resource system not started!";
}
if (m_file)
{
m_snd_file = sf_open_virtual(&snd_callbacks, SFM_READ, &m_file_info, m_file);
if (!m_snd_file)
{
m_last_error = "Could not load file";
}
}
else
{
m_last_error = std::string(PHYSFS_getLastError());
}
}
CSNDFile::~CSNDFile()
{
if (m_file)
{
PHYSFS_close(m_file);
}
if (m_snd_file)
{
sf_close(m_snd_file);
}
}
bool CSNDFile::IsOpen()
{
return m_snd_file;
}
SF_INFO &CSNDFile::GetFileInfo()
{
return m_file_info;
}
std::string& CSNDFile::GetLastError()
{
return m_last_error;
}
sf_count_t CSNDFile::Read(short int *ptr, sf_count_t items)
{
return sf_read_short(m_snd_file, ptr, items);
}
sf_count_t CSNDFile::SNDLength(void *data)
{
return PHYSFS_fileLength(static_cast<PHYSFS_File *>(data));
}
sf_count_t CSNDFile::SNDRead(void *ptr, sf_count_t count, void *data)
{
return PHYSFS_read(static_cast<PHYSFS_File *>(data), ptr, 1, count);
}
sf_count_t CSNDFile::SNDSeek(sf_count_t offset, int whence, void *data)
{
PHYSFS_File *file = static_cast<PHYSFS_File *>(data);
switch(whence)
{
case SEEK_CUR:
PHYSFS_seek(file, PHYSFS_tell(file) + offset);
break;
case SEEK_SET:
PHYSFS_seek(file, offset);
break;
case SEEK_END:
PHYSFS_seek(file, PHYSFS_fileLength(file) + offset);
break;
}
return PHYSFS_tell(file);
}
sf_count_t CSNDFile::SNDTell(void *data)
{
return PHYSFS_tell(static_cast<PHYSFS_File *>(data));
}
sf_count_t CSNDFile::SNDWrite(const void *ptr, sf_count_t count, void *data)
{
return PHYSFS_write(static_cast<PHYSFS_File *>(data), ptr, 1, count);
}

View File

@ -0,0 +1,54 @@
// * This file is part of the COLOBOT source code
// * Copyright (C) 2014 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/.
#pragma once
#include <string>
#include <physfs.h>
#include <sndfile.h>
class CSNDFile
{
public:
CSNDFile(const std::string &filename);
virtual ~CSNDFile();
SF_INFO &GetFileInfo();
bool IsOpen();
std::string &GetLastError();
sf_count_t Read(short int *ptr, sf_count_t items);
private:
static sf_count_t SNDLength(void *data);
static sf_count_t SNDSeek(sf_count_t offset, int whence, void *data);
static sf_count_t SNDRead(void *ptr, sf_count_t count, void *data);
static sf_count_t SNDWrite(const void *ptr, sf_count_t count, void *data);
static sf_count_t SNDTell(void *data);
SF_INFO m_file_info;
SNDFILE *m_snd_file;
PHYSFS_File *m_file;
std::string m_last_error;
SF_VIRTUAL_IO snd_callbacks = {
SNDLength,
SNDSeek,
SNDRead,
SNDWrite,
SNDTell
};
};

View File

@ -48,45 +48,44 @@ public:
ALSound();
~ALSound();
bool Create();
bool Cache(Sound, const std::string &);
bool CacheMusic(const std::string &);
bool Create() override;
bool Cache(Sound, const std::string &) override;
bool CacheMusic(const std::string &) override;
bool GetEnable();
bool GetEnable() override;
void SetAudioVolume(int volume);
int GetAudioVolume();
void SetMusicVolume(int volume);
int GetMusicVolume();
void SetAudioVolume(int volume) override;
int GetAudioVolume() override;
void SetMusicVolume(int volume) override;
int GetMusicVolume() override;
void SetListener(const Math::Vector &eye, const Math::Vector &lookat);
void FrameMove(float rTime);
void SetListener(const Math::Vector &eye, const Math::Vector &lookat) override;
void FrameMove(float rTime) override;
int Play(Sound sound, float amplitude=1.0f, float frequency=1.0f, bool bLoop = false);
int Play(Sound sound, const 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, const Math::Vector &pos);
bool Frequency(int channel, float frequency);
bool Stop(int channel);
bool StopAll();
bool MuteAll(bool bMute);
int Play(Sound sound, float amplitude=1.0f, float frequency=1.0f, bool bLoop = false) override;
int Play(Sound sound, const Math::Vector &pos, float amplitude=1.0f, float frequency=1.0f, bool bLoop = false) override;
bool FlushEnvelope(int channel) override;
bool AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper) override;
bool Position(int channel, const Math::Vector &pos) override;
bool Frequency(int channel, float frequency) override;
bool Stop(int channel) override;
bool StopAll() override;
bool MuteAll(bool bMute) override;
bool PlayMusic(int rank, bool bRepeat, float fadeTime=2.0f);
bool PlayMusic(const std::string &filename, bool bRepeat, float fadeTime=2.0f);
bool RestartMusic();
void SuspendMusic();
void StopMusic(float fadeTime=2.0f);
bool IsPlayingMusic();
bool PlayPauseMusic(const std::string &filename, bool repeat);
void StopPauseMusic();
bool CheckChannel(int &channel);
bool PlayMusic(int rank, bool bRepeat, float fadeTime=2.0f) override;
bool PlayMusic(const std::string &filename, bool bRepeat, float fadeTime=2.0f) override;
bool RestartMusic() override;
void SuspendMusic() override;
void StopMusic(float fadeTime=2.0f) override;
bool IsPlayingMusic() override;
bool PlayPauseMusic(const std::string &filename, bool repeat) override;
void StopPauseMusic() override;
private:
void CleanUp();
int GetPriority(Sound);
bool SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded);
bool CheckChannel(int &channel);
bool m_enabled;
float m_audioVolume;

View File

@ -17,7 +17,10 @@
#include "sound/oalsound/buffer.h"
#include <cstring>
#include <memory>
#include "common/resources/resourcemanager.h"
Buffer::Buffer()
{
@ -42,19 +45,17 @@ bool Buffer::LoadFromFile(std::string filename, Sound sound)
m_sound = sound;
GetLogger()->Debug("Loading audio file: %s\n", filename.c_str());
SF_INFO fileInfo;
memset(&fileInfo, 0, sizeof(SF_INFO));
SNDFILE *file = sf_open(filename.c_str(), SFM_READ, &fileInfo);
std::unique_ptr<CSNDFile> file = std::unique_ptr<CSNDFile>(CResourceManager::GetSNDFileHandler(filename));
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);
GetLogger()->Trace(" channels %d\n", file->GetFileInfo().channels);
GetLogger()->Trace(" format %d\n", file->GetFileInfo().format);
GetLogger()->Trace(" frames %d\n", file->GetFileInfo().frames);
GetLogger()->Trace(" samplerate %d\n", file->GetFileInfo().samplerate);
GetLogger()->Trace(" sections %d\n", file->GetFileInfo().sections);
if (!file)
if (!file->IsOpen())
{
GetLogger()->Warn("Could not load file. Reason: %s\n", sf_strerror(file));
GetLogger()->Warn("Could not load file. Reason: %s\n", file->GetLastError().c_str());
m_loaded = false;
return false;
}
@ -64,23 +65,21 @@ bool Buffer::LoadFromFile(std::string filename, Sound sound)
{
GetLogger()->Warn("Could not create audio buffer\n");
m_loaded = false;
sf_close(file);
return false;
}
// read chunks of 4096 samples
std::vector<uint16_t> data;
std::array<int16_t, 4096> buffer;
data.reserve(fileInfo.frames);
data.reserve(file->GetFileInfo().frames);
size_t read = 0;
while ((read = sf_read_short(file, buffer.data(), buffer.size())) != 0)
while ((read = file->Read(buffer.data(), buffer.size())) != 0)
{
data.insert(data.end(), buffer.begin(), buffer.begin() + read);
}
sf_close(file);
alBufferData(m_buffer, fileInfo.channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, &data.front(), data.size() * sizeof(uint16_t), fileInfo.samplerate);
m_duration = static_cast<float>(fileInfo.frames) / fileInfo.samplerate;
alBufferData(m_buffer, file->GetFileInfo().channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, &data.front(), data.size() * sizeof(uint16_t), file->GetFileInfo().samplerate);
m_duration = static_cast<float>(file->GetFileInfo().frames) / file->GetFileInfo().samplerate;
m_loaded = true;
return true;
}

View File

@ -46,7 +46,7 @@ void CSoundInterface::CacheAll()
for ( int i = 1; i < SOUND_MAX; i++ )
{
std::stringstream filename;
filename << "sound" << std::setfill('0') << std::setw(3) << i << ".wav";
filename << "sounds/sound" << std::setfill('0') << std::setw(3) << i << ".wav";
if ( !Cache(static_cast<Sound>(i), filename.str()) )
GetLogger()->Warn("Unable to load audio: %s\n", filename.str().c_str());
}
@ -54,10 +54,10 @@ void CSoundInterface::CacheAll()
void CSoundInterface::AddMusicFiles()
{
CacheMusic("Intro1.ogg");
CacheMusic("Intro2.ogg");
CacheMusic("music010.ogg");
CacheMusic("music011.ogg");
CacheMusic("music/Intro1.ogg");
CacheMusic("music/Intro2.ogg");
CacheMusic("music/music010.ogg");
CacheMusic("music/music011.ogg");
}
bool CSoundInterface::Cache(Sound bSound, const std::string &bFile)