*******************************************************************************/
+#include <cstdio>
#include <string>
#include <queue>
#include <vector>
-#include <SDL/SDL.h>
-#include <SDL/SDL_sound.h>
#include <AL/al.h>
+#include <vorbis/codec.h>
+#include <vorbis/vorbisfile.h>
#include "Log.hh"
#include "Mippleton.hh"
#include "Sound.hh"
+#include "Timer.hh"
#define BUFFER_SIZE (64 * 1024)
//#define BUFFER_SIZE (5*2048)
struct Sound::Impl
{
- static ALenum getAudioFormat(const Sound_AudioInfo& audioInfo)
+ static ALenum getAudioFormat(const vorbis_info* audioInfo)
{
- if (audioInfo.format == AUDIO_U8 || audioInfo.format == AUDIO_S8)
- {
- if (audioInfo.channels == 1) return AL_FORMAT_MONO8;
- else return AL_FORMAT_STEREO8;
- }
- else
- {
- if (audioInfo.channels == 1) return AL_FORMAT_MONO16;
- else return AL_FORMAT_STEREO16;
- }
+ if (audioInfo->channels == 1) return AL_FORMAT_MONO16;
+ else return AL_FORMAT_STEREO16;
}
class Buffer;
class Buffer : public Mippleton<Buffer>
{
- Sound_Sample* sound;
+ OggVorbis_File oggStream;
+ ALenum audioFormat;
+ ALsizei audioFreq;
std::vector<ALuint> objects;
public:
Buffer(const std::string& name) :
- Mippleton<Buffer>(name),
- sound(0)
+ Mippleton<Buffer>(name)
{
+ oggStream.datasource = 0;
openFile();
}
objects.pop_back();
}
- if (sound) Sound_FreeSample(sound);
+ if (oggStream.datasource)
+ {
+ ov_clear(&oggStream);
+ }
}
void openFile()
{
- if (sound) Sound_FreeSample(sound);
+ if (oggStream.datasource)
+ {
+ ov_clear(&oggStream);
+ oggStream.datasource = 0;
+ }
- sound = Sound_NewSampleFromFile(Sound::getPath(getName()).c_str(),
- 0, BUFFER_SIZE);
+ std::string filePath = Sound::getPath(getName());
+ int result = ov_fopen((char*)filePath.c_str(), &oggStream);
- if (!sound)
+ if (result < 0)
{
- logWarning("error while loading sound %s: %s",
- getName().c_str(), Sound_GetError());
- throw Exception(Exception::FILE_NOT_FOUND);
+ logWarning("error while loading sound %s",
+ getName().c_str());
+ throw Exception(Exception::BAD_AUDIO_FORMAT);
}
- logDebug("buffer size: %d", sound->buffer_size);
- logDebug(" channels: %d", sound->actual.channels);
- logDebug(" format: %d", sound->actual.format);
- logDebug(" frequency: %d", sound->actual.rate);
+ vorbis_info* vorbisInfo = ov_info(&oggStream, -1);
+ audioFormat = getAudioFormat(vorbisInfo);
+ audioFreq = vorbisInfo->rate;
+
+ logDebug(" channels: %d", vorbisInfo->channels);
+ logDebug(" frequency: %d", vorbisInfo->rate);
}
void loadAll(ALuint source)
{
- if (!sound) openFile();
- if (!sound) return;
+ if (!oggStream.datasource) openFile();
+ if (!oggStream.datasource) return;
+
+ char data[BUFFER_SIZE];
+ int size = 0;
- unsigned decoded = Sound_DecodeAll(sound);
- if (decoded == 0)
+ for (;;)
+ {
+ int section;
+ int result = ov_read(&oggStream, data + size,
+ BUFFER_SIZE - size, 0, 2, 1, §ion);
+
+ if (result > 0)
+ {
+ size += result;
+ }
+ else
+ {
+ if (result < 0) logWarning("vorbis playback error");
+ break;
+ }
+ }
+ if (size == 0)
{
logWarning("decoded no bytes from %s", getName().c_str());
//throw Exception(Exception::FILE_NOT_FOUND);
ALuint obj;
alGenBuffers(1, &obj);
- alBufferData(obj, getAudioFormat(sound->actual), sound->buffer,
- sound->buffer_size, sound->actual.rate);
+ alBufferData(obj, audioFormat, data, size, audioFreq);
objects.push_back(obj);
alSourcei(source, AL_BUFFER, obj);
- // don't need t his anymore
- Sound_FreeSample(sound);
- sound = 0;
+ // don't need this anymore
+ ov_clear(&oggStream);
+ oggStream.datasource = 0;
}
- void beginStream(ALuint source, int nBuffers = 4)
+ void beginStream(ALuint source, int nBuffers = 8)
{
- if (!sound) openFile();
- if (!sound) return;
+ if (!oggStream.datasource) openFile();
+ if (!oggStream.datasource) return;
ALuint objs[nBuffers];
alGenBuffers(nBuffers, objs);
// that buffer doesn't belong to us
if (it == objects.end()) return STREAM_WRONG;
- unsigned bytes = Sound_Decode(sound);
+ char data[BUFFER_SIZE];
+ int size = 0;
+
+ while (size < BUFFER_SIZE)
+ {
+ int section;
+ int result = ov_read(&oggStream, data + size,
+ BUFFER_SIZE - size, 0, 2, 1, §ion);
+
+ if (result > 0)
+ {
+ size += result;
+ }
+ else
+ {
+ if (result < 0) logWarning("vorbis playback error");
+ break;
+ }
+ }
- if (bytes == 0) return STREAM_EOF;
+ if (size == 0) return STREAM_EOF;
- alBufferData(buffer, getAudioFormat(sound->actual), sound->buffer,
- bytes, sound->actual.rate);
+ alBufferData(buffer, audioFormat, data, size, audioFreq);
return STREAM_OK;
}
inline void rewind()
{
- if (!sound) openFile();
- else Sound_Rewind(sound);
+ if (!oggStream.datasource) openFile();
+ else ov_raw_seek(&oggStream, 0);
}
alSourcei(source_, AL_LOOPING, AL_FALSE);
alSourcePlay(source_);
playing_ = true;
+
+ streamTimer.init(boost::bind(&Impl::streamUpdate, this, _1, _2), 1.0,
+ Timer::REPEAT);
}
inline void update()
std::queue<BufferP> queue_;
std::vector<BufferP> expired_;
+
+ Timer streamTimer;
+
+ void streamUpdate(Timer& timer, Scalar t)
+ {
+ // don't let the music die!
+ update();
+ // TODO - might be nice to also allow using threads for streaming rather
+ // than a timer, probably as a compile-time option
+ }
};
Sound::Sound(const std::string& name) :
impl_->play();
}
-
void Sound::stream()
{
// pass through
impl_->stream();
}
-void Sound::update(Scalar t, Scalar dt)
-{
- // pass through
- impl_->update();
-}
-
void Sound::stop()
{
return impl_->isPlaying();
}
-void Sound::setPosition(Vector3 position)
+void Sound::setPosition(const Vector3& position)
{
float p[3] = {position[0], position[1], position[2]};
alSourcefv(impl_->source_, AL_POSITION, p);
}
-void Sound::setVelocity(Vector3 velocity)
+void Sound::setVelocity(const Vector3& velocity)
{
float v[3] = {velocity[0], velocity[1], velocity[2]};
alSourcefv(impl_->source_, AL_VELOCITY, v);
}
+void Sound::setListenerPosition(const Vector3& position)
+{
+ alListener3f(AL_POSITION, float(position[0]), float(position[1]),
+ float(position[2]));
+}
+
+void Sound::setListenerVelocity(const Vector3& velocity)
+{
+ alListener3f(AL_VELOCITY, float(velocity[0]), float(velocity[1]),
+ float(velocity[2]));
+}
+
+void Sound::setListenerOrientation(const Vector3& forward, const Vector3& up)
+{
+ float vec[6];
+ vec[0] = float(forward[0]);
+ vec[1] = float(forward[1]);
+ vec[2] = float(forward[2]);
+ vec[3] = float(up[0]);
+ vec[4] = float(up[1]);
+ vec[5] = float(up[2]);
+ alListenerfv(AL_ORIENTATION, vec);
+}
+
+
std::string Sound::getPath(const std::string& name)
{
std::string path = Resource::getPath("sounds/" + name + ".ogg");