]>
Dogcows Code - chaz/yoink/blob - src/Moof/Sound.cc
f912b318d153c2dfa13ecf1b991169f4e87751ee
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 *******************************************************************************/
35 #include <vorbis/codec.h>
36 #include <vorbis/vorbisfile.h>
39 #include "Mippleton.hh"
42 #define BUFFER_SIZE (64 * 1024)
43 //#define BUFFER_SIZE (5*2048)
51 static ALenum
getAudioFormat(const vorbis_info
* audioInfo
)
53 if (audioInfo
->channels
== 1) return AL_FORMAT_MONO16
;
54 else return AL_FORMAT_STEREO16
;
58 typedef boost::shared_ptr
<Buffer
> BufferP
;
60 class Buffer
: public Mippleton
<Buffer
>
62 OggVorbis_File oggStream
;
65 std::vector
<ALuint
> objects
;
69 Buffer(const std::string
& name
) :
70 Mippleton
<Buffer
>(name
)
72 oggStream
.datasource
= 0;
78 while (!objects
.empty())
80 alDeleteBuffers(1, &objects
.back());
84 if (oggStream
.datasource
)
93 if (oggStream
.datasource
)
96 oggStream
.datasource
= 0;
99 std::string filePath
= Sound::getPath(getName());
100 int result
= ov_fopen((char*)filePath
.c_str(), &oggStream
);
104 logWarning("error while loading sound %s",
106 throw Exception(Exception::BAD_AUDIO_FORMAT
);
109 vorbis_info
* vorbisInfo
= ov_info(&oggStream
, -1);
110 audioFormat
= getAudioFormat(vorbisInfo
);
111 audioFreq
= vorbisInfo
->rate
;
113 logDebug(" channels: %d", vorbisInfo
->channels
);
114 logDebug(" frequency: %d", vorbisInfo
->rate
);
118 void loadAll(ALuint source
)
120 if (!oggStream
.datasource
) openFile();
121 if (!oggStream
.datasource
) return;
123 char data
[BUFFER_SIZE
];
129 int result
= ov_read(&oggStream
, data
+ size
,
130 BUFFER_SIZE
- size
, 0, 2, 1, §ion
);
138 if (result
< 0) logWarning("vorbis playback error");
144 logWarning("decoded no bytes from %s", getName().c_str());
145 //throw Exception(Exception::FILE_NOT_FOUND);
150 alGenBuffers(1, &obj
);
152 alBufferData(obj
, audioFormat
, data
, size
, audioFreq
);
154 objects
.push_back(obj
);
156 alSourcei(source
, AL_BUFFER
, obj
);
158 // don't need this anymore
159 ov_clear(&oggStream
);
160 oggStream
.datasource
= 0;
164 void beginStream(ALuint source
, int nBuffers
= 4)
166 if (!oggStream
.datasource
) openFile();
167 if (!oggStream
.datasource
) return;
169 ALuint objs
[nBuffers
];
170 alGenBuffers(nBuffers
, objs
);
172 for (int i
= 0; i
< nBuffers
; ++i
)
174 objects
.push_back(objs
[i
]);
178 alSourceQueueBuffers(source
, nBuffers
, objs
);
188 StreamStatus
stream(ALuint buffer
)
190 std::vector
<ALuint
>::iterator it
=
191 std::find(objects
.begin(), objects
.end(), buffer
);
193 // that buffer doesn't belong to us
194 if (it
== objects
.end()) return STREAM_WRONG
;
196 char data
[BUFFER_SIZE
];
199 while (size
< BUFFER_SIZE
)
202 int result
= ov_read(&oggStream
, data
+ size
,
203 BUFFER_SIZE
- size
, 0, 2, 1, §ion
);
211 if (result
< 0) logWarning("vorbis playback error");
216 if (size
== 0) return STREAM_EOF
;
218 alBufferData(buffer
, audioFormat
, data
, size
, audioFreq
);
225 if (!oggStream
.datasource
) openFile();
226 else ov_raw_seek(&oggStream
, 0);
230 // delete unused buffers, return true if all buffers deleted
233 // clear any openal errors
236 while (!objects
.empty())
238 ALuint buffer
= objects
.back();
239 alDeleteBuffers(1, &buffer
);
241 // if an error occured, the buffer was not deleted because it's
242 // still in use by some source
243 if (alGetError() != AL_NO_ERROR
) return false;
253 Impl(const std::string
& name
) :
254 buffer_(Buffer::getInstance(name
)),
258 ALfloat zero
[] = {0.0f
, 0.0f
, 0.0f
};
260 alGenSources(1, &source_
);
262 alSourcef(source_
, AL_PITCH
, 1.0f
);
263 alSourcef(source_
, AL_GAIN
, 1.0f
);
264 alSourcefv(source_
, AL_POSITION
, zero
);
265 alSourcefv(source_
, AL_VELOCITY
, zero
);
270 alDeleteSources(1, &source_
);
277 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
279 if (type
!= AL_STATIC
)
281 buffer_
->loadAll(source_
);
284 alSourcei(source_
, AL_LOOPING
, looping_
);
285 alSourcePlay(source_
);
293 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
295 alSourcei(source_
, AL_BUFFER
, AL_NONE
);
297 buffer_
->beginStream(source_
);
299 alSourcei(source_
, AL_LOOPING
, AL_FALSE
);
300 alSourcePlay(source_
);
308 alGetSourcei(source_
, AL_BUFFERS_PROCESSED
, &finished
);
310 while (finished
-- > 0)
314 alSourceUnqueueBuffers(source_
, 1, &buffer
);
316 Buffer::StreamStatus status
= buffer_
->stream(buffer
);
318 if (status
== Buffer::STREAM_OK
)
320 alSourceQueueBuffers(source_
, 1, &buffer
);
322 else if (status
== Buffer::STREAM_EOF
)
326 // begin the next buffer in the queue
327 expired_
.push_back(buffer_
);
328 buffer_
= queue_
.front();
330 buffer_
->beginStream(source_
, 1);
334 // restart from the beginning
336 buffer_
->stream(buffer
);
337 alSourceQueueBuffers(source_
, 1, &buffer
);
340 else if (status
== Buffer::STREAM_WRONG
)
343 buffer_
->beginStream(source_
, 1);
348 alGetSourcei(source_
, AL_SOURCE_STATE
, &state
);
350 // restart playing if we're stopped but supposed to be playing... this
351 // means we didn't queue enough and the audio skipped
352 if (playing_
&& state
!= AL_PLAYING
)
354 alSourcePlay(source_
);
360 // try to remove expired buffers
361 std::vector
<BufferP
>::iterator it
;
362 for (it
= expired_
.end() - 1; it
>= expired_
.begin(); --it
)
364 if ((*it
)->clear()) expired_
.erase(it
);
371 alSourceStop(source_
);
377 alSourcePause(source_
);
383 alSourcePlay(source_
);
388 inline void setSample(const std::string
& name
)
390 bool playing
= isPlaying();
392 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
396 //alSourcei(source_, AL_BUFFER, AL_NONE);
397 buffer_
= Buffer::getInstance(name
);
399 if (type
== AL_STREAMING
)
401 if (playing
) stream();
409 inline void enqueue(const std::string
& name
)
411 BufferP buffer
= Buffer::getInstance(name
);
416 inline bool isPlaying() const
418 if (playing_
) return true;
421 alGetSourcei(source_
, AL_SOURCE_STATE
, &state
);
423 return state
== AL_PLAYING
;
427 inline void setLooping(bool looping
)
432 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
434 if (type
!= AL_STREAMING
)
436 alSourcei(source_
, AL_LOOPING
, looping_
);
447 std::queue
<BufferP
> queue_
;
448 std::vector
<BufferP
> expired_
;
451 Sound::Sound(const std::string
& name
) :
453 impl_(new Sound::Impl(name
)) {}
469 void Sound::update(Scalar t
, Scalar dt
)
496 if (impl_
->playing_
) pause();
501 void Sound::setSample(const std::string
& name
)
504 impl_
->setSample(name
);
507 void Sound::enqueue(const std::string
& name
)
510 impl_
->enqueue(name
);
514 bool Sound::isPlaying() const
517 return impl_
->isPlaying();
520 void Sound::setPosition(Vector3 position
)
522 float p
[3] = {position
[0], position
[1], position
[2]};
523 alSourcefv(impl_
->source_
, AL_POSITION
, p
);
526 void Sound::setVelocity(Vector3 velocity
)
528 float v
[3] = {velocity
[0], velocity
[1], velocity
[2]};
529 alSourcefv(impl_
->source_
, AL_VELOCITY
, v
);
532 void Sound::setGain(Scalar gain
)
534 alSourcef(impl_
->source_
, AL_GAIN
, float(gain
));
537 void Sound::setPitch(Scalar pitch
)
539 alSourcef(impl_
->source_
, AL_PITCH
, float(pitch
));
542 void Sound::setLooping(bool looping
)
545 impl_
->setLooping(looping
);
549 std::string
Sound::getPath(const std::string
& name
)
551 std::string path
= Resource::getPath("sounds/" + name
+ ".ogg");
558 /** vim: set ts=4 sw=4 tw=80: *************************************************/
This page took 0.059065 seconds and 4 git commands to generate.