28 #include <boost/scope_exit.hpp> 68 const TypeList::iterator &ti,
AudioStream *s,
bool d) :
69 id(i), index(idx), state(AL_PAUSED), stream(s, d), source(0),
70 type(t), typeIt(ti), finishedBuffers(0), gain(1.0f) {
95 _dev = alcOpenDevice(0);
103 alcMakeContextCurrent(
_ctx);
105 ALenum
error = alGetError();
106 if (
error != AL_NO_ERROR)
110 _format51 = alGetEnumValue(
"AL_FORMAT_51CHN16");
133 alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
146 alcMakeContextCurrent(0);
147 alcDestroyContext(
_ctx);
148 alcCloseDevice(
_dev);
197 ALenum
error = AL_NO_ERROR;
200 alGetSourcei(
_channels[channel]->source, AL_SOURCE_STATE, &val);
201 if ((
error = alGetError()) != AL_NO_ERROR)
205 if (val != AL_PLAYING) {
208 alGetSourcei(
_channels[channel]->source, AL_BUFFERS_QUEUED, &buffersQueued);
209 if ((
error = alGetError()) != AL_NO_ERROR)
213 ALint buffersProcessed;
214 alGetSourcei(
_channels[channel]->source, AL_BUFFERS_PROCESSED, &buffersProcessed);
215 if ((
error = alGetError()) != AL_NO_ERROR)
216 throw Common::Exception(
"OpenAL error while getting processed buffers in %s: 0x%X",
219 if (buffersQueued == buffersProcessed)
223 if (
_channels[channel]->state != AL_PLAYING)
226 alSourcePlay(
_channels[channel]->source);
248 if (tag == 0xfff360c4) {
252 }
else if (tag ==
MKTAG(
'R',
'I',
'F',
'F')) {
256 if (tag !=
MKTAG(
'f',
'm',
't',
' '))
263 while ((tag ==
MKTAG(
'f',
'a',
'c',
't')) || (tag ==
MKTAG(
'P',
'A',
'D',
' ')) ||
264 (tag ==
MKTAG(
'c',
'u',
'e',
' ')) || (tag ==
MKTAG(
'L',
'I',
'S',
'T')) ||
265 (tag ==
MKTAG(
's',
'm',
'p',
'l'))) {
271 if (tag !=
MKTAG(
'd',
'a',
't',
'a'))
282 }
else if ((tag ==
MKTAG(
'B',
'M',
'U',
' ')) &&
289 }
else if (tag ==
MKTAG(
'O',
'g',
'g',
'S')) {
295 throw Common::Exception(
"Vorbis decoding disabled when building without libvorbis");
298 }
else if (tag == 0x3026B275) {
304 }
else if (((tag & 0xFFFFFF00) | 0x20) ==
MKTAG(
'I',
'D',
'3',
' ')) {
310 }
else if ((tag & 0xFFFA0000) == 0xFFFA0000) {
342 bool success =
false;
343 BOOST_SCOPE_EXIT ( (&success) (&handle) (this_) ) {
345 this_->freeChannel(handle);
346 } BOOST_SCOPE_EXIT_END
348 const TypeList::iterator typeEndIt =
_types[type].
list.end();
356 ALenum
error = AL_NO_ERROR;
360 alGenSources(1, &channel.
source);
361 if ((
error = alGetError()) != AL_NO_ERROR)
368 alGenBuffers(1, &buffer);
369 if ((
error = alGetError()) != AL_NO_ERROR)
375 alSourceQueueBuffers(channel.
source, 1, &buffer);
376 if ((
error = alGetError()) != AL_NO_ERROR)
383 channel.
buffers.push_back(buffer);
389 alSourcei(channel.
source, AL_SOURCE_RELATIVE, AL_TRUE);
416 warning(
"SoundManager::playSoundFile(): The input stream cannot be rewound, this will not loop.");
454 if (!channel || !channel->
stream)
457 channel->
state = AL_PLAYING;
468 if (!channel || !channel->
stream)
478 if (!channel || !channel->
stream)
516 alListenerf(AL_GAIN, gain);
524 alListener3f(AL_POSITION, x, y, z);
532 float orientation[] = {dirX, dirY, dirZ, upX, upY, upZ};
533 alListenerfv(AL_ORIENTATION, orientation);
540 if (!channel || !channel->
stream)
543 if (channel->
stream->getChannels() > 1)
548 alSource3f(channel->
source, AL_POSITION, x, y, z);
555 if (!channel || !channel->
stream)
558 if (channel->
stream->getChannels() > 1)
563 alGetSource3f(channel->
source, AL_POSITION, &x, &y, &z);
570 if (!channel || !channel->
stream)
573 channel->
gain = gain;
583 if (!channel || !channel->
stream)
587 alSourcef(channel->
source, AL_PITCH, pitch);
594 if (!channel || !channel->
stream)
598 alSourcei(channel->
source, AL_SOURCE_RELATIVE, relative ? AL_TRUE : AL_FALSE);
605 if (!channel || !channel->
stream)
609 alSourcef(channel->
source, AL_REFERENCE_DISTANCE, minDistance);
610 alSourcef(channel->
source, AL_MAX_DISTANCE, maxDistance);
618 if (!channel || !channel->
stream)
625 ALint currentPosition;
626 alGetSourcei(channel->
source, AL_BYTE_OFFSET, ¤tPosition);
632 return byteCount / channel->
stream->getChannels() / 2;
639 if (!channel || !channel->
stream)
654 for (TypeList::iterator t =
_types[type].list.begin(); t !=
_types[type].
list.end(); ++t) {
658 alSourcef((*t)->source, AL_GAIN, (*t)->gain * gain);
663 AudioStream *stream, ALsizei &bufferedSize)
const {
679 if (channelCount == 1) {
680 format = AL_FORMAT_MONO16;
681 }
else if (channelCount == 2) {
682 format = AL_FORMAT_STEREO16;
683 }
else if (channelCount == 6) {
685 warning(
"SoundManager::fillBuffer(): TODO: !_hasMultiChannel in %s",
693 warning(
"SoundManager::fillBuffer(): Unsupported channel count in %s: %d",
704 numSamples = stream->
readBuffer(reinterpret_cast<int16 *>(buffer.
get()), numSamples);
706 warning(
"Failed reading from stream while filling buffer in %s",
formatChannel(&channel).c_str());
710 bufferedSize = numSamples * 2;
711 alBufferData(alBuffer, format, buffer.
get(), bufferedSize, stream->
getRate());
713 ALenum
error = alGetError();
714 if (
error != AL_NO_ERROR) {
736 ALenum
error = AL_NO_ERROR;
739 ALint buffersProcessed = -1;
740 alGetSourcei(channel.
source, AL_BUFFERS_PROCESSED, &buffersProcessed);
741 if ((
error = alGetError()) != AL_NO_ERROR)
742 throw Common::Exception(
"OpenAL error while getting processed buffers in %s: 0x%X",
745 assert(buffersProcessed >= 0);
748 throw Common::Exception(
"Got more processed buffers than total source buffers in %s?!?",
753 alSourceUnqueueBuffers(channel.
source, buffersProcessed, freeBuffers);
754 if ((
error = alGetError()) != AL_NO_ERROR)
759 for (
size_t i = 0; i < (size_t)buffersProcessed; i++) {
766 std::list<ALuint>::iterator buffer = channel.
freeBuffers.begin();
771 alSourceQueueBuffers(channel.
source, 1, &*buffer);
772 if ((
error = alGetError()) != AL_NO_ERROR)
788 size_t channelCount = 0;
831 if (!channel || channel->
id == 0)
834 ALenum
error = AL_NO_ERROR;
837 alSourcePause(channel->
source);
838 if ((
error = alGetError()) != AL_NO_ERROR)
839 warning(
"OpenAL error while attempting to pause channel %s: 0x%X",
843 channel->
state = AL_PAUSED;
845 channel->
state = AL_PLAYING;
854 if (channel->
state == AL_PAUSED)
856 else if (channel->
state == AL_PLAYING)
886 alDeleteSources(1, &c->
source);
889 for (std::list<ALuint>::iterator buffer = c->
buffers.begin(); buffer != c->
buffers.end(); ++buffer)
890 alDeleteBuffers(1, &*buffer);
902 while (!
_killThread.load(boost::memory_order_relaxed)) {
TypeList::iterator typeIt
Iterator into the type list.
bool _ready
Was the sound subsystem successfully initialized?
void getChannelPosition(const ChannelHandle &handle, float &x, float &y, float &z)
Get the position of the channel.
#define MKTAG(a0, a1, a2, a3)
A wrapper macro used around four character constants, like 'DATA', to ensure portability.
static AudioStream * makeAudioStream(Common::SeekableReadStream *stream)
Create an audio stream from this data stream.
void setTypeGain(SoundType type, float gain)
Set the gain/volume of all channels of a specific type.
"GSound", global, non-engine sound.
float gain
The sound type's current gain.
void deinit()
Deinitialize the sound subsystem.
uint32 readUint32LE()
Read an unsigned 32-bit word stored in little endian (LSB first) order from the stream and return it...
void debugC(Common::DebugChannel channel, uint32 level, const char *s,...)
A class holding an UTF-8 string.
void init()
Initialize the sound subsystem.
virtual size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)=0
Sets the stream position indicator for the stream.
void setChannelRelative(const ChannelHandle &handle, bool relative)
Set if the channel is relative.
ALint state
The sound's state.
Utility functions for debug output.
The global config manager.
TypeList list
The list of channels for that type.
Decoding RIFF WAVE (Resource Interchange File Format Waveform).
UString composeString(T value)
Convert any POD integer, float/double or bool type into a string.
virtual int getChannels() const =0
Return the number channels in this stream.
bool isValidChannel(const ChannelHandle &handle) const
Does this channel handle point to an existing channel?
virtual int getRate() const =0
Sample rate of the stream.
boost::atomic< bool > _killThread
Common::ScopedPtr< Channel > _channels[kChannelCount]
The sound channels.
void startChannel(ChannelHandle &handle)
Start the channel.
void stopAll()
Stop all channels.
static const size_t kOpenALBufferCount
Control how many buffers per sound OpenAL will create.
void setChannelPitch(const ChannelHandle &handle, float pitch)
Set the pitch of the channel.
void setListenerOrientation(float dirX, float dirY, float dirZ, float upX, float upY, float upZ)
Set the orientation of the listener.
RewindableAudioStream * makeASFStream(Common::SeekableReadStream *stream, bool disposeAfterUse)
Try to load a ASF from the given seekable stream and create a RewindableAudioStream from that data...
Utility templates and functions for working with strings and streams.
Exception that provides a stack of explanations.
static const size_t kOpenALBufferSize
Number of bytes per OpenAL buffer.
void exceptionDispatcherWarning(const char *s,...)
Exception dispatcher that prints the exception as a warning, and adds another reason on top...
std::list< ALuint > buffers
List of buffers for that channel.
bool wait(uint32 timeout=0)
Basic exceptions to throw.
A rewindable audio stream.
const char * c_str() const
Return the (utf8 encoded) string data.
bool createThread(const UString &name="")
float gain
The channel's gain.
bool isPaused(const ChannelHandle &handle)
Is that channel currently paused?
#define ConfigMan
Shortcut for accessing the config manager.
Utility templates and functions.
ALuint source
OpenAL source for this channel.
RewindableAudioStream * makeWAVStream(Common::SeekableReadStream *stream, bool disposeAfterUse)
Try to load a WAVE from the given seekable stream and create an AudioStream from that data...
virtual size_t readBuffer(int16 *buffer, const size_t numSamples)=0
Fill the given buffer with up to numSamples samples.
uint64 getChannelDurationPlayed(const ChannelHandle &handle)
Return the time this channel has already played in milliseconds.
static const size_t kSizeInvalid
#define DECLARE_SINGLETON(T)
Note that you need to use this macro from the global namespace.
Common::Condition _needUpdate
Condition to signal that an update is needed.
void checkReady()
Check that the SoundManager was properly initialized.
void bufferData(Channel &channel)
Buffer more sound from the channel to the OpenAL buffers.
The global events manager.
Common::UString formatChannel(const ChannelHandle &handle) const
Return a string representing the channel referenced by this handle.
void setChannelGain(const ChannelHandle &handle, float gain)
Set the gain/volume of the channel.
virtual size_t skip(ptrdiff_t offset)
Skip the specified number of bytes, adding that offset to the current position in the stream...
void update()
Update the sound information.
The global sound manager, handling all sound output.
RewindableAudioStream * makeVorbisStream(Common::SeekableReadStream *stream, bool disposeAfterUse)
Create a new RewindableAudioStream from the Ogg Vorbis data in the given stream.
void setChannelPosition(const ChannelHandle &handle, float x, float y, float z)
Set the position the channel is being played.
void setListenerGain(float gain)
Set the gain of the listener (= the global master volume).
SoundType type
The channel's sound type.
void warning(const char *s,...)
virtual size_t size() const =0
Obtains the total size of the stream, measured in bytes.
std::list< ALuint > freeBuffers
List of free buffers not filled with data.
Basic reading stream interfaces.
virtual size_t pos() const =0
Obtains the current value of the stream position indicator of the stream.
Convenience class that locks a mutex on creation and unlocks it on destruction.
static const size_t kChannelCount
Maximal number of channels.
Type _types[kSoundTypeMAX]
The sound types.
std::map< ALuint, ALsizei > bufferSize
Size of a buffer in bytes.
uint32 _curID
The ID the next sound will get.
uint32 readUint32BE()
Read an unsigned 32-bit word stored in big endian (MSB first) order from the stream and return it...
bool _hasSound
Do we have working sound output?
const Channel * getChannel(const ChannelHandle &handle) const
Return the channel the handle refers to.
void stopChannel(ChannelHandle &handle)
Stop and free the channel.
Generic audio input stream.
void setChannelDistance(const ChannelHandle &handle, float minDistance, float maxDistance)
Set the min and max distance for the channel.
ChannelHandle playAudioStream(AudioStream *audStream, SoundType type, bool disposeAfterUse=true)
Play an audio stream.
PointerType get() const
Returns the plain pointer value.
uint32 id
The channel's ID.
bool _hasMultiChannel
Do we have the multi-channel extension?
A handle to a sound channel.
SoundType
The type of a sound.
UString debugTag(uint32 tag, bool trim)
Create an elaborate string from an integer tag, for debugging purposes.
void pauseChannel(ChannelHandle &handle, bool pause)
Pause the channel.
void setListenerPosition(float x, float y, float z)
Set the position of the listener.
void pauseAll(bool pause)
Pause all channels.
size_t index
The channel's index.
static const size_t kChannelInvalid
Common::DisposablePtr< AudioStream > stream
The actual audio stream.
AudioStream * makeLoopingAudioStream(RewindableAudioStream *stream, size_t loops)
Wrapper functionality to efficiently create a stream, which might be looped.
void triggerUpdate()
Signal that one of streams currently being played has changed and should be updated immediately...
bool fillBuffer(const Channel &channel, ALuint alBuffer, AudioStream *stream, ALsizei &bufferedSize) const
Fill the buffer with data from the audio stream.
bool ready() const
Was the sound subsystem successfully initialized?
Decoding Microsoft's Advanced Streaming Format.
SeekableSubReadStream provides access to a SeekableReadStream restricted to the range [begin...
Decoding MP3 (MPEG-1 Audio Layer 3).
RewindableAudioStream * makeMP3Stream(Common::SeekableReadStream *stream, bool disposeAfterUse)
Create a new SeekableAudioStream from the MP3 data in the given stream.
uint64 finishedBuffers
Number of bytes in all buffers that finished playing and were unqueued.
ChannelHandle playSoundFile(Common::SeekableReadStream *wavStream, SoundType type, bool loop=false)
Play a sound file.
void NORETURN_PRE error(const char *s,...)
uint64 getChannelSamplesPlayed(const ChannelHandle &handle)
Return the number of samples this channel has already played.
void freeChannel(ChannelHandle &handle)
Stop and free a channel.
bool isPlaying(const ChannelHandle &handle)
Is that channel currently playing a sound?
Interface for a seekable & readable data stream.
ALenum _format51
The value for the 5.1 multi-channel format.
virtual bool endOfData() const =0
End of data reached? If this returns true, it means that at this time there is no data available in t...
ChannelHandle newChannel()
Look for a free place in the channel vector.