get stereo audo working on linux
This commit is contained in:
parent
ae67c6adbc
commit
8e679f2da7
|
@ -203,6 +203,7 @@ SET(framework_SOURCES ${framework_SOURCES}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/sound/soundmanager.cpp
|
${CMAKE_CURRENT_LIST_DIR}/sound/soundmanager.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/sound/oggsoundfile.cpp
|
${CMAKE_CURRENT_LIST_DIR}/sound/oggsoundfile.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/sound/streamsoundsource.cpp
|
${CMAKE_CURRENT_LIST_DIR}/sound/streamsoundsource.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/sound/combinedsoundsource.cpp
|
||||||
|
|
||||||
# framework otml
|
# framework otml
|
||||||
${CMAKE_CURRENT_LIST_DIR}/otml/otmldocument.cpp
|
${CMAKE_CURRENT_LIST_DIR}/otml/otmldocument.cpp
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "combinedsoundsource.h"
|
||||||
|
|
||||||
|
CombinedSoundSource::CombinedSoundSource() : SoundSource(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::addSource(const SoundSourcePtr& source)
|
||||||
|
{
|
||||||
|
m_sources.push_back(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::play()
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources)
|
||||||
|
source->play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::stop()
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources)
|
||||||
|
source->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CombinedSoundSource::isPlaying()
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources) {
|
||||||
|
if(source->isPlaying())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::setLooping(bool looping)
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources)
|
||||||
|
source->setLooping(looping);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::setRelative(bool relative)
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources)
|
||||||
|
source->setRelative(relative);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::setReferenceDistance(float distance)
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources)
|
||||||
|
source->setReferenceDistance(distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::setGain(float gain)
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources)
|
||||||
|
source->setGain(gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::setPitch(float pitch)
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources)
|
||||||
|
source->setPitch(pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::setPosition(const Point& pos)
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources)
|
||||||
|
source->setPosition(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::setVelocity(const Point& velocity)
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources)
|
||||||
|
source->setVelocity(velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CombinedSoundSource::update()
|
||||||
|
{
|
||||||
|
for(const SoundSourcePtr& source : m_sources)
|
||||||
|
source->update();
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMBINEDSOUNDSOURCE_H
|
||||||
|
#define COMBINEDSOUNDSOURCE_H
|
||||||
|
|
||||||
|
#include "soundsource.h"
|
||||||
|
|
||||||
|
class CombinedSoundSource : public SoundSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CombinedSoundSource();
|
||||||
|
|
||||||
|
void addSource(const SoundSourcePtr& source);
|
||||||
|
std::vector<SoundSourcePtr> getSources() { return m_sources; }
|
||||||
|
|
||||||
|
void play();
|
||||||
|
void stop();
|
||||||
|
bool isPlaying();
|
||||||
|
|
||||||
|
void setLooping(bool looping);
|
||||||
|
void setRelative(bool relative);
|
||||||
|
void setReferenceDistance(float distance);
|
||||||
|
void setGain(float gain);
|
||||||
|
void setPitch(float pitch);
|
||||||
|
void setPosition(const Point& pos);
|
||||||
|
void setVelocity(const Point& velocity);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<SoundSourcePtr> m_sources;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -35,12 +35,14 @@ class SoundSource;
|
||||||
class SoundBuffer;
|
class SoundBuffer;
|
||||||
class SoundFile;
|
class SoundFile;
|
||||||
class StreamSoundSource;
|
class StreamSoundSource;
|
||||||
|
class CombinedSoundSource;
|
||||||
class OggSoundFile;
|
class OggSoundFile;
|
||||||
|
|
||||||
typedef std::shared_ptr<SoundSource> SoundSourcePtr;
|
typedef std::shared_ptr<SoundSource> SoundSourcePtr;
|
||||||
typedef std::shared_ptr<SoundFile> SoundFilePtr;
|
typedef std::shared_ptr<SoundFile> SoundFilePtr;
|
||||||
typedef std::shared_ptr<SoundBuffer> SoundBufferPtr;
|
typedef std::shared_ptr<SoundBuffer> SoundBufferPtr;
|
||||||
typedef std::shared_ptr<StreamSoundSource> StreamSoundSourcePtr;
|
typedef std::shared_ptr<StreamSoundSource> StreamSoundSourcePtr;
|
||||||
|
typedef std::shared_ptr<CombinedSoundSource> CombinedSoundSourcePtr;
|
||||||
typedef std::shared_ptr<OggSoundFile> OggSoundFilePtr;
|
typedef std::shared_ptr<OggSoundFile> OggSoundFilePtr;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,8 +23,6 @@
|
||||||
#include "soundbuffer.h"
|
#include "soundbuffer.h"
|
||||||
#include "soundfile.h"
|
#include "soundfile.h"
|
||||||
|
|
||||||
#include <framework/util/databuffer.h>
|
|
||||||
|
|
||||||
SoundBuffer::SoundBuffer()
|
SoundBuffer::SoundBuffer()
|
||||||
{
|
{
|
||||||
m_bufferId = 0;
|
m_bufferId = 0;
|
||||||
|
@ -38,7 +36,7 @@ SoundBuffer::~SoundBuffer()
|
||||||
assert(alGetError() == AL_NO_ERROR);
|
assert(alGetError() == AL_NO_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SoundBuffer::loadSoundFile(const SoundFilePtr& soundFile)
|
bool SoundBuffer::fillBuffer(const SoundFilePtr& soundFile)
|
||||||
{
|
{
|
||||||
ALenum format = soundFile->getSampleFormat();
|
ALenum format = soundFile->getSampleFormat();
|
||||||
if(format == AL_UNDETERMINED) {
|
if(format == AL_UNDETERMINED) {
|
||||||
|
@ -53,12 +51,16 @@ bool SoundBuffer::loadSoundFile(const SoundFilePtr& soundFile)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
alBufferData(m_bufferId, format, &samples[0], soundFile->getSize(), soundFile->getRate());
|
return fillBuffer(format, samples, samples.size(), soundFile->getRate());
|
||||||
ALenum err = alGetError();
|
|
||||||
if(err != AL_NO_ERROR) {
|
|
||||||
logError("unable to fill audio buffer data for '", soundFile->getName(), "': ", alGetString(err));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SoundBuffer::fillBuffer(ALenum sampleFormat, const DataBuffer<char>& data, int size, int rate)
|
||||||
|
{
|
||||||
|
alBufferData(m_bufferId, sampleFormat, &data[0], size, rate);
|
||||||
|
ALenum err = alGetError();
|
||||||
|
if(err != AL_NO_ERROR) {
|
||||||
|
logError("unable to fill audio buffer data: ", alGetString(err));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,15 +25,18 @@
|
||||||
|
|
||||||
#include "declarations.h"
|
#include "declarations.h"
|
||||||
|
|
||||||
|
#include <framework/util/databuffer.h>
|
||||||
|
|
||||||
class SoundBuffer
|
class SoundBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SoundBuffer();
|
SoundBuffer();
|
||||||
~SoundBuffer();
|
~SoundBuffer();
|
||||||
|
|
||||||
bool loadSoundFile(const SoundFilePtr& soundFile);
|
bool fillBuffer(const SoundFilePtr& soundFile);
|
||||||
|
bool fillBuffer(ALenum sampleFormat, const DataBuffer<char>& data, int size, int rate);
|
||||||
|
|
||||||
int getBufferId() { return m_bufferId; }
|
ALuint getBufferId() { return m_bufferId; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ALuint m_bufferId;
|
ALuint m_bufferId;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "soundbuffer.h"
|
#include "soundbuffer.h"
|
||||||
#include "soundfile.h"
|
#include "soundfile.h"
|
||||||
#include "streamsoundsource.h"
|
#include "streamsoundsource.h"
|
||||||
|
#include "combinedsoundsource.h"
|
||||||
|
|
||||||
#include <framework/core/clock.h>
|
#include <framework/core/clock.h>
|
||||||
#include <framework/core/eventdispatcher.h>
|
#include <framework/core/eventdispatcher.h>
|
||||||
|
@ -124,7 +125,7 @@ void SoundManager::preload(const std::string& filename)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SoundBufferPtr buffer = SoundBufferPtr(new SoundBuffer);
|
SoundBufferPtr buffer = SoundBufferPtr(new SoundBuffer);
|
||||||
if(buffer->loadSoundFile(soundFile))
|
if(buffer->fillBuffer(soundFile))
|
||||||
m_buffers[filename] = buffer;
|
m_buffers[filename] = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,30 +187,53 @@ void SoundManager::stopMusic(float fadetime)
|
||||||
|
|
||||||
SoundSourcePtr SoundManager::createSoundSource(const std::string& filename)
|
SoundSourcePtr SoundManager::createSoundSource(const std::string& filename)
|
||||||
{
|
{
|
||||||
SoundSourcePtr soundSource;
|
SoundSourcePtr source;
|
||||||
|
|
||||||
auto it = m_buffers.find(filename);
|
auto it = m_buffers.find(filename);
|
||||||
if(it != m_buffers.end()) {
|
if(it != m_buffers.end()) {
|
||||||
soundSource = SoundSourcePtr(new SoundSource);
|
source = SoundSourcePtr(new SoundSource);
|
||||||
soundSource->setBuffer(it->second);
|
source->setBuffer(it->second);
|
||||||
} else {
|
} else {
|
||||||
SoundFilePtr soundFile = SoundFile::loadSoundFile(filename);
|
SoundFilePtr soundFile = SoundFile::loadSoundFile(filename);
|
||||||
if(!soundFile)
|
if(!soundFile)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if(soundFile->getSize() <= MAX_CACHE_SIZE) {
|
if(soundFile->getSize() <= MAX_CACHE_SIZE) {
|
||||||
soundSource = SoundSourcePtr(new SoundSource);
|
source = SoundSourcePtr(new SoundSource);
|
||||||
SoundBufferPtr buffer = SoundBufferPtr(new SoundBuffer);
|
SoundBufferPtr buffer = SoundBufferPtr(new SoundBuffer);
|
||||||
buffer->loadSoundFile(soundFile);
|
buffer->fillBuffer(soundFile);
|
||||||
soundSource->setBuffer(buffer);
|
source->setBuffer(buffer);
|
||||||
m_buffers[filename] = buffer;
|
m_buffers[filename] = buffer;
|
||||||
logWarning("uncached sound '", filename, "' requested to be played");
|
logWarning("uncached sound '", filename, "' requested to be played");
|
||||||
} else {
|
} else {
|
||||||
StreamSoundSourcePtr streamSoundSource(new StreamSoundSource);
|
StreamSoundSourcePtr streamSource(new StreamSoundSource);
|
||||||
streamSoundSource->setSoundFile(soundFile);
|
streamSource->setSoundFile(soundFile);
|
||||||
soundSource = streamSoundSource;
|
source = streamSource;
|
||||||
|
|
||||||
|
#ifdef __linux
|
||||||
|
// due to OpenAL implementation bug stereo buffers are always downmixed to mono on linux systems
|
||||||
|
// this is hack to work around the issue
|
||||||
|
// solution taken from http://opensource.creative.com/pipermail/openal/2007-April/010355.html
|
||||||
|
if(soundFile->getSampleFormat() == AL_FORMAT_STEREO16) {
|
||||||
|
CombinedSoundSourcePtr combinedSource(new CombinedSoundSource);
|
||||||
|
|
||||||
|
streamSource->downMix(StreamSoundSource::DownMixLeft);
|
||||||
|
streamSource->setRelative(true);
|
||||||
|
streamSource->setPosition(Point(-128, 0));
|
||||||
|
combinedSource->addSource(streamSource);
|
||||||
|
|
||||||
|
streamSource = StreamSoundSourcePtr(new StreamSoundSource);
|
||||||
|
streamSource->setSoundFile(SoundFile::loadSoundFile(filename));
|
||||||
|
streamSource->downMix(StreamSoundSource::DownMixRight);
|
||||||
|
streamSource->setRelative(true);
|
||||||
|
streamSource->setPosition(Point(128,0));
|
||||||
|
combinedSource->addSource(streamSource);
|
||||||
|
|
||||||
|
source = combinedSource;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return soundSource;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,12 @@ SoundSource::SoundSource()
|
||||||
|
|
||||||
SoundSource::~SoundSource()
|
SoundSource::~SoundSource()
|
||||||
{
|
{
|
||||||
|
if(m_sourceId != 0) {
|
||||||
stop();
|
stop();
|
||||||
alDeleteSources(1, &m_sourceId);
|
alDeleteSources(1, &m_sourceId);
|
||||||
assert(alGetError() == AL_NO_ERROR);
|
assert(alGetError() == AL_NO_ERROR);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SoundSource::play()
|
void SoundSource::play()
|
||||||
{
|
{
|
||||||
|
@ -93,3 +95,13 @@ void SoundSource::setPitch(float pitch)
|
||||||
{
|
{
|
||||||
alSourcef(m_sourceId, AL_PITCH, pitch);
|
alSourcef(m_sourceId, AL_PITCH, pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoundSource::setPosition(const Point& pos)
|
||||||
|
{
|
||||||
|
alSource3f(m_sourceId, AL_POSITION, pos.x, pos.y, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundSource::setVelocity(const Point& velocity)
|
||||||
|
{
|
||||||
|
alSource3f(m_sourceId, AL_VELOCITY, velocity.x, velocity.y, 0);
|
||||||
|
}
|
||||||
|
|
|
@ -27,27 +27,31 @@
|
||||||
|
|
||||||
class SoundSource
|
class SoundSource
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
SoundSource(ALuint sourceId) : m_sourceId(sourceId) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SoundSource();
|
SoundSource();
|
||||||
virtual ~SoundSource();
|
virtual ~SoundSource();
|
||||||
|
|
||||||
void play();
|
virtual void play();
|
||||||
void stop();
|
virtual void stop();
|
||||||
|
virtual bool isPlaying();
|
||||||
|
|
||||||
bool isPlaying();
|
|
||||||
|
|
||||||
void setBuffer(const SoundBufferPtr& buffer);
|
|
||||||
virtual void setLooping(bool looping);
|
virtual void setLooping(bool looping);
|
||||||
void setRelative(bool relative);
|
virtual void setRelative(bool relative);
|
||||||
void setReferenceDistance(float distance);
|
virtual void setReferenceDistance(float distance);
|
||||||
void setGain(float gain);
|
virtual void setGain(float gain);
|
||||||
void setPitch(float pitch);
|
virtual void setPitch(float pitch);
|
||||||
|
virtual void setPosition(const Point& pos);
|
||||||
// TODO: velocity, position
|
virtual void setVelocity(const Point& velocity);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void setBuffer(const SoundBufferPtr& buffer);
|
||||||
|
|
||||||
virtual void update() { }
|
virtual void update() { }
|
||||||
friend class SoundManager;
|
friend class SoundManager;
|
||||||
|
friend class CombinedSoundSource;
|
||||||
|
|
||||||
ALuint m_sourceId;
|
ALuint m_sourceId;
|
||||||
SoundBufferPtr m_buffer;
|
SoundBufferPtr m_buffer;
|
||||||
|
|
|
@ -32,25 +32,39 @@ StreamSoundSource::StreamSoundSource()
|
||||||
for(auto& buffer : m_buffers)
|
for(auto& buffer : m_buffers)
|
||||||
buffer = SoundBufferPtr(new SoundBuffer);
|
buffer = SoundBufferPtr(new SoundBuffer);
|
||||||
m_fadeState = NoFading;
|
m_fadeState = NoFading;
|
||||||
|
m_downMix = NoDownMix;
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamSoundSource::~StreamSoundSource()
|
StreamSoundSource::~StreamSoundSource()
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
ALint queued;
|
|
||||||
alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queued);
|
|
||||||
for(int i = 0; i < queued; ++i) {
|
|
||||||
ALuint buffer;
|
|
||||||
alSourceUnqueueBuffers(m_sourceId, 1, &buffer);
|
|
||||||
}
|
|
||||||
m_buffers.fill(nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamSoundSource::setSoundFile(const SoundFilePtr& soundFile)
|
void StreamSoundSource::setSoundFile(const SoundFilePtr& soundFile)
|
||||||
{
|
{
|
||||||
m_soundFile = soundFile;
|
m_soundFile = soundFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamSoundSource::play()
|
||||||
|
{
|
||||||
|
if(!m_soundFile) {
|
||||||
|
logError("there is not sound file to play the stream");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
queueBuffers();
|
||||||
|
|
||||||
|
SoundSource::play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamSoundSource::stop()
|
||||||
|
{
|
||||||
|
SoundSource::stop();
|
||||||
|
unqueueBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamSoundSource::queueBuffers()
|
||||||
|
{
|
||||||
ALint queued;
|
ALint queued;
|
||||||
alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queued);
|
alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queued);
|
||||||
for(int i = 0; i < STREAM_FRAGMENTS - queued; ++i) {
|
for(int i = 0; i < STREAM_FRAGMENTS - queued; ++i) {
|
||||||
|
@ -59,6 +73,16 @@ void StreamSoundSource::setSoundFile(const SoundFilePtr& soundFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StreamSoundSource::unqueueBuffers()
|
||||||
|
{
|
||||||
|
ALint queued;
|
||||||
|
alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queued);
|
||||||
|
for(int i = 0; i < queued; ++i) {
|
||||||
|
ALuint buffer;
|
||||||
|
alSourceUnqueueBuffers(m_sourceId, 1, &buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void StreamSoundSource::update()
|
void StreamSoundSource::update()
|
||||||
{
|
{
|
||||||
ALint processed = 0;
|
ALint processed = 0;
|
||||||
|
@ -76,9 +100,8 @@ void StreamSoundSource::update()
|
||||||
if(processed == 0 || !m_looping)
|
if(processed == 0 || !m_looping)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// we might have to restart the source if we had a buffer underrun
|
logTraceError("restarting audio source because of buffer underrun");
|
||||||
//log_info << "Restarting audio source because of buffer underrun" << std::endl;
|
play();
|
||||||
//play();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float realTime = g_clock.asyncTime();
|
float realTime = g_clock.asyncTime();
|
||||||
|
@ -104,7 +127,8 @@ void StreamSoundSource::update()
|
||||||
bool StreamSoundSource::fillBufferAndQueue(ALuint buffer)
|
bool StreamSoundSource::fillBufferAndQueue(ALuint buffer)
|
||||||
{
|
{
|
||||||
// fill buffer
|
// fill buffer
|
||||||
DataBuffer<char> bufferData(STREAM_FRAGMENT_SIZE);
|
static DataBuffer<char> bufferData(STREAM_FRAGMENT_SIZE);
|
||||||
|
ALenum format = m_soundFile->getSampleFormat();
|
||||||
|
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
do {
|
do {
|
||||||
|
@ -119,8 +143,21 @@ bool StreamSoundSource::fillBufferAndQueue(ALuint buffer)
|
||||||
}
|
}
|
||||||
} while(bytesRead < STREAM_FRAGMENT_SIZE);
|
} while(bytesRead < STREAM_FRAGMENT_SIZE);
|
||||||
|
|
||||||
|
bool done = bytesRead >= STREAM_FRAGMENT_SIZE;
|
||||||
|
|
||||||
|
if(m_downMix != NoDownMix) {
|
||||||
|
if(format == AL_FORMAT_STEREO16) {
|
||||||
|
if(bytesRead > 0) {
|
||||||
|
uint16_t *data = (uint16_t*)bufferData.data();
|
||||||
|
bytesRead /= 2;
|
||||||
|
for(int i=0;i<bytesRead;i++)
|
||||||
|
data[i] = data[2*i + (m_downMix == DownMixLeft ? 0 : 1)];
|
||||||
|
}
|
||||||
|
format = AL_FORMAT_MONO16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(bytesRead > 0) {
|
if(bytesRead > 0) {
|
||||||
ALenum format = m_soundFile->getSampleFormat();
|
|
||||||
alBufferData(buffer, format, &bufferData[0], bytesRead, m_soundFile->getRate());
|
alBufferData(buffer, format, &bufferData[0], bytesRead, m_soundFile->getRate());
|
||||||
ALenum err = alGetError();
|
ALenum err = alGetError();
|
||||||
if(err != AL_NO_ERROR)
|
if(err != AL_NO_ERROR)
|
||||||
|
@ -133,7 +170,22 @@ bool StreamSoundSource::fillBufferAndQueue(ALuint buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// return false if there aren't more buffers to fill
|
// return false if there aren't more buffers to fill
|
||||||
return bytesRead >= STREAM_FRAGMENT_SIZE;
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamSoundSource::downMix(StreamSoundSource::DownMix downMix)
|
||||||
|
{
|
||||||
|
if(!m_soundFile) {
|
||||||
|
logError("down mix must be set after setting a sound file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_soundFile->getSampleFormat() != AL_FORMAT_STEREO16) {
|
||||||
|
logError("can only downmix 16 bit stereo audio files");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_downMix = downMix;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamSoundSource::setFading(FadeState state, float fadeTime)
|
void StreamSoundSource::setFading(FadeState state, float fadeTime)
|
||||||
|
|
|
@ -34,23 +34,31 @@ class StreamSoundSource : public SoundSource
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum DownMix { NoDownMix, DownMixLeft, DownMixRight };
|
||||||
enum FadeState { NoFading, FadingOn, FadingOff };
|
enum FadeState { NoFading, FadingOn, FadingOff };
|
||||||
|
|
||||||
StreamSoundSource();
|
StreamSoundSource();
|
||||||
virtual ~StreamSoundSource();
|
virtual ~StreamSoundSource();
|
||||||
|
|
||||||
|
void play();
|
||||||
|
void stop();
|
||||||
|
|
||||||
void setSoundFile(const SoundFilePtr& soundFile);
|
void setSoundFile(const SoundFilePtr& soundFile);
|
||||||
|
|
||||||
|
void downMix(DownMix downMix);
|
||||||
void setFading(FadeState state, float fadetime);
|
void setFading(FadeState state, float fadetime);
|
||||||
FadeState getFadeState() { return m_fadeState; }
|
FadeState getFadeState() { return m_fadeState; }
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void queueBuffers();
|
||||||
|
void unqueueBuffers();
|
||||||
bool fillBufferAndQueue(ALuint buffer);
|
bool fillBufferAndQueue(ALuint buffer);
|
||||||
|
|
||||||
SoundFilePtr m_soundFile;
|
SoundFilePtr m_soundFile;
|
||||||
std::array<SoundBufferPtr,STREAM_FRAGMENTS> m_buffers;
|
std::array<SoundBufferPtr,STREAM_FRAGMENTS> m_buffers;
|
||||||
|
DownMix m_downMix;
|
||||||
FadeState m_fadeState;
|
FadeState m_fadeState;
|
||||||
float m_fadeStartTime;
|
float m_fadeStartTime;
|
||||||
float m_fadeTime;
|
float m_fadeTime;
|
||||||
|
|
Loading…
Reference in New Issue