]>
Dogcows Code - chaz/yoink/blob - src/Moof/Sound.cc
110dc4ba0416e03c268147097bd8e4c7f44821ee
2 /*******************************************************************************
4 Copyright (c) 2009, Charles McGarvey
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *******************************************************************************/
34 #include <SDL/SDL_sound.h>
38 #include "Mippleton.hh"
41 #define BUFFER_SIZE (64 * 1024)
42 //#define BUFFER_SIZE (5*2048)
50 static ALenum
getAudioFormat(const Sound_AudioInfo
& audioInfo
)
52 if (audioInfo
.format
== AUDIO_U8
|| audioInfo
.format
== AUDIO_S8
)
54 if (audioInfo
.channels
== 1) return AL_FORMAT_MONO8
;
55 else return AL_FORMAT_STEREO8
;
59 if (audioInfo
.channels
== 1) return AL_FORMAT_MONO16
;
60 else return AL_FORMAT_STEREO16
;
65 typedef boost::shared_ptr
<Buffer
> BufferP
;
67 class Buffer
: public Mippleton
<Buffer
>
70 std::vector
<ALuint
> objects
;
74 Buffer(const std::string
& name
) :
75 Mippleton
<Buffer
>(name
),
83 while (!objects
.empty())
85 alDeleteBuffers(1, &objects
.back());
89 if (sound
) Sound_FreeSample(sound
);
95 if (sound
) Sound_FreeSample(sound
);
97 sound
= Sound_NewSampleFromFile(Sound::getPath(getName()).c_str(),
102 logWarning("error while loading sound %s: %s",
103 getName().c_str(), Sound_GetError());
104 throw Exception(Exception::FILE_NOT_FOUND
);
107 logDebug("buffer size: %d", sound
->buffer_size
);
108 logDebug(" channels: %d", sound
->actual
.channels
);
109 logDebug(" format: %d", sound
->actual
.format
);
110 logDebug(" frequency: %d", sound
->actual
.rate
);
114 void loadAll(ALuint source
)
116 if (!sound
) openFile();
119 unsigned decoded
= Sound_DecodeAll(sound
);
122 logWarning("decoded no bytes from %s", getName().c_str());
123 //throw Exception(Exception::FILE_NOT_FOUND);
128 alGenBuffers(1, &obj
);
130 alBufferData(obj
, getAudioFormat(sound
->actual
), sound
->buffer
,
131 sound
->buffer_size
, sound
->actual
.rate
);
133 objects
.push_back(obj
);
135 alSourcei(source
, AL_BUFFER
, obj
);
137 // don't need t his anymore
138 Sound_FreeSample(sound
);
143 void beginStream(ALuint source
, int nBuffers
= 4)
145 if (!sound
) openFile();
148 ALuint objs
[nBuffers
];
149 alGenBuffers(nBuffers
, objs
);
151 for (int i
= 0; i
< nBuffers
; ++i
)
153 objects
.push_back(objs
[i
]);
157 alSourceQueueBuffers(source
, nBuffers
, objs
);
167 StreamStatus
stream(ALuint buffer
)
169 std::vector
<ALuint
>::iterator it
=
170 std::find(objects
.begin(), objects
.end(), buffer
);
172 // that buffer doesn't belong to us
173 if (it
== objects
.end()) return STREAM_WRONG
;
175 unsigned bytes
= Sound_Decode(sound
);
177 if (bytes
== 0) return STREAM_EOF
;
179 alBufferData(buffer
, getAudioFormat(sound
->actual
), sound
->buffer
,
180 bytes
, sound
->actual
.rate
);
187 if (!sound
) openFile();
188 else Sound_Rewind(sound
);
192 // delete unused buffers, return true if all buffers deleted
195 // clear any openal errors
198 while (!objects
.empty())
200 ALuint buffer
= objects
.back();
201 alDeleteBuffers(1, &buffer
);
203 // if an error occured, the buffer was not deleted because it's
204 // still in use by some source
205 if (alGetError() != AL_NO_ERROR
) return false;
215 Impl(const std::string
& name
) :
216 buffer_(Buffer::getInstance(name
)),
220 ALfloat zero
[] = {0.0f
, 0.0f
, 0.0f
};
222 alGenSources(1, &source_
);
224 alSourcef(source_
, AL_PITCH
, 1.0f
);
225 alSourcef(source_
, AL_GAIN
, 1.0f
);
226 alSourcefv(source_
, AL_POSITION
, zero
);
227 alSourcefv(source_
, AL_VELOCITY
, zero
);
232 alDeleteSources(1, &source_
);
239 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
241 if (type
!= AL_STATIC
)
243 buffer_
->loadAll(source_
);
246 alSourcei(source_
, AL_LOOPING
, looping_
);
247 alSourcePlay(source_
);
255 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
257 alSourcei(source_
, AL_BUFFER
, AL_NONE
);
259 buffer_
->beginStream(source_
);
261 alSourcei(source_
, AL_LOOPING
, AL_FALSE
);
262 alSourcePlay(source_
);
270 alGetSourcei(source_
, AL_BUFFERS_PROCESSED
, &finished
);
272 while (finished
-- > 0)
276 alSourceUnqueueBuffers(source_
, 1, &buffer
);
278 Buffer::StreamStatus status
= buffer_
->stream(buffer
);
280 if (status
== Buffer::STREAM_OK
)
282 alSourceQueueBuffers(source_
, 1, &buffer
);
284 else if (status
== Buffer::STREAM_EOF
)
288 // begin the next buffer in the queue
289 expired_
.push_back(buffer_
);
290 buffer_
= queue_
.front();
292 buffer_
->beginStream(source_
, 1);
296 // restart from the beginning
298 buffer_
->stream(buffer
);
299 alSourceQueueBuffers(source_
, 1, &buffer
);
302 else if (status
== Buffer::STREAM_WRONG
)
305 buffer_
->beginStream(source_
, 1);
310 alGetSourcei(source_
, AL_SOURCE_STATE
, &state
);
312 // restart playing if we're stopped but supposed to be playing... this
313 // means we didn't queue enough and the audio skipped
314 if (playing_
&& state
!= AL_PLAYING
)
316 alSourcePlay(source_
);
322 // try to remove expired buffers
323 std::vector
<BufferP
>::iterator it
;
324 for (it
= expired_
.end() - 1; it
>= expired_
.begin(); --it
)
326 if ((*it
)->clear()) expired_
.erase(it
);
333 alSourceStop(source_
);
339 alSourcePause(source_
);
345 alSourcePlay(source_
);
350 inline void setSample(const std::string
& name
)
352 bool playing
= isPlaying();
354 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
358 //alSourcei(source_, AL_BUFFER, AL_NONE);
359 buffer_
= Buffer::getInstance(name
);
361 if (type
== AL_STREAMING
)
363 if (playing
) stream();
371 inline void enqueue(const std::string
& name
)
373 BufferP buffer
= Buffer::getInstance(name
);
378 inline bool isPlaying() const
380 if (playing_
) return true;
383 alGetSourcei(source_
, AL_SOURCE_STATE
, &state
);
385 return state
== AL_PLAYING
;
389 inline void setLooping(bool looping
)
394 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
396 if (type
!= AL_STREAMING
)
398 alSourcei(source_
, AL_LOOPING
, looping_
);
409 std::queue
<BufferP
> queue_
;
410 std::vector
<BufferP
> expired_
;
413 Sound::Sound(const std::string
& name
) :
415 impl_(new Sound::Impl(name
)) {}
431 void Sound::update(Scalar t
, Scalar dt
)
458 if (impl_
->playing_
) pause();
463 void Sound::setSample(const std::string
& name
)
466 impl_
->setSample(name
);
469 void Sound::enqueue(const std::string
& name
)
472 impl_
->enqueue(name
);
476 bool Sound::isPlaying() const
479 return impl_
->isPlaying();
482 void Sound::setPosition(Vector3 position
)
484 float p
[3] = {position
[0], position
[1], position
[2]};
485 alSourcefv(impl_
->source_
, AL_POSITION
, p
);
488 void Sound::setVelocity(Vector3 velocity
)
490 float v
[3] = {velocity
[0], velocity
[1], velocity
[2]};
491 alSourcefv(impl_
->source_
, AL_VELOCITY
, v
);
494 void Sound::setGain(Scalar gain
)
496 alSourcef(impl_
->source_
, AL_GAIN
, float(gain
));
499 void Sound::setPitch(Scalar pitch
)
501 alSourcef(impl_
->source_
, AL_PITCH
, float(pitch
));
504 void Sound::setLooping(bool looping
)
507 impl_
->setLooping(looping
);
511 std::string
Sound::getPath(const std::string
& name
)
513 std::string path
= Resource::getPath("sounds/" + name
+ ".ogg");
520 /** vim: set ts=4 sw=4 tw=80: *************************************************/
This page took 0.059697 seconds and 4 git commands to generate.