]>
Dogcows Code - chaz/yoink/blob - src/Moof/Sound.cc
460f7bb24a1054d2a18e0e579f08e8386320e06c
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"
43 #define BUFFER_SIZE (64 * 1024)
44 //#define BUFFER_SIZE (5*2048)
52 static ALenum
getAudioFormat(const vorbis_info
* audioInfo
)
54 if (audioInfo
->channels
== 1) return AL_FORMAT_MONO16
;
55 else return AL_FORMAT_STEREO16
;
59 typedef boost::shared_ptr
<Buffer
> BufferP
;
61 class Buffer
: public Mippleton
<Buffer
>
63 OggVorbis_File oggStream
;
66 std::vector
<ALuint
> objects
;
70 Buffer(const std::string
& name
) :
71 Mippleton
<Buffer
>(name
)
73 oggStream
.datasource
= 0;
79 while (!objects
.empty())
81 alDeleteBuffers(1, &objects
.back());
85 if (oggStream
.datasource
)
94 if (oggStream
.datasource
)
97 oggStream
.datasource
= 0;
100 std::string filePath
= Sound::getPath(getName());
101 int result
= ov_fopen((char*)filePath
.c_str(), &oggStream
);
105 logWarning("error while loading sound %s",
107 throw Exception(Exception::BAD_AUDIO_FORMAT
);
110 vorbis_info
* vorbisInfo
= ov_info(&oggStream
, -1);
111 audioFormat
= getAudioFormat(vorbisInfo
);
112 audioFreq
= vorbisInfo
->rate
;
114 logDebug(" channels: %d", vorbisInfo
->channels
);
115 logDebug(" frequency: %d", vorbisInfo
->rate
);
119 void loadAll(ALuint source
)
121 if (!oggStream
.datasource
) openFile();
122 if (!oggStream
.datasource
) return;
124 char data
[BUFFER_SIZE
];
130 int result
= ov_read(&oggStream
, data
+ size
,
131 BUFFER_SIZE
- size
, 0, 2, 1, §ion
);
139 if (result
< 0) logWarning("vorbis playback error");
145 logWarning("decoded no bytes from %s", getName().c_str());
146 //throw Exception(Exception::FILE_NOT_FOUND);
151 alGenBuffers(1, &obj
);
153 alBufferData(obj
, audioFormat
, data
, size
, audioFreq
);
155 objects
.push_back(obj
);
157 alSourcei(source
, AL_BUFFER
, obj
);
159 // don't need this anymore
160 ov_clear(&oggStream
);
161 oggStream
.datasource
= 0;
165 void beginStream(ALuint source
, int nBuffers
= 8)
167 if (!oggStream
.datasource
) openFile();
168 if (!oggStream
.datasource
) return;
170 ALuint objs
[nBuffers
];
171 alGenBuffers(nBuffers
, objs
);
173 for (int i
= 0; i
< nBuffers
; ++i
)
175 objects
.push_back(objs
[i
]);
179 alSourceQueueBuffers(source
, nBuffers
, objs
);
189 StreamStatus
stream(ALuint buffer
)
191 std::vector
<ALuint
>::iterator it
=
192 std::find(objects
.begin(), objects
.end(), buffer
);
194 // that buffer doesn't belong to us
195 if (it
== objects
.end()) return STREAM_WRONG
;
197 char data
[BUFFER_SIZE
];
200 while (size
< BUFFER_SIZE
)
203 int result
= ov_read(&oggStream
, data
+ size
,
204 BUFFER_SIZE
- size
, 0, 2, 1, §ion
);
212 if (result
< 0) logWarning("vorbis playback error");
217 if (size
== 0) return STREAM_EOF
;
219 alBufferData(buffer
, audioFormat
, data
, size
, audioFreq
);
226 if (!oggStream
.datasource
) openFile();
227 else ov_raw_seek(&oggStream
, 0);
231 // delete unused buffers, return true if all buffers deleted
234 // clear any openal errors
237 while (!objects
.empty())
239 ALuint buffer
= objects
.back();
240 alDeleteBuffers(1, &buffer
);
242 // if an error occured, the buffer was not deleted because it's
243 // still in use by some source
244 if (alGetError() != AL_NO_ERROR
) return false;
254 Impl(const std::string
& name
) :
255 buffer_(Buffer::getInstance(name
)),
259 ALfloat zero
[] = {0.0f
, 0.0f
, 0.0f
};
261 alGenSources(1, &source_
);
263 alSourcef(source_
, AL_PITCH
, 1.0f
);
264 alSourcef(source_
, AL_GAIN
, 1.0f
);
265 alSourcefv(source_
, AL_POSITION
, zero
);
266 alSourcefv(source_
, AL_VELOCITY
, zero
);
271 alDeleteSources(1, &source_
);
278 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
280 if (type
!= AL_STATIC
)
282 buffer_
->loadAll(source_
);
285 alSourcei(source_
, AL_LOOPING
, looping_
);
286 alSourcePlay(source_
);
294 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
296 alSourcei(source_
, AL_BUFFER
, AL_NONE
);
298 buffer_
->beginStream(source_
);
300 alSourcei(source_
, AL_LOOPING
, AL_FALSE
);
301 alSourcePlay(source_
);
304 streamTimer
.init(boost::bind(&Impl::streamUpdate
, this, _1
, _2
), 1.0,
312 alGetSourcei(source_
, AL_BUFFERS_PROCESSED
, &finished
);
314 while (finished
-- > 0)
318 alSourceUnqueueBuffers(source_
, 1, &buffer
);
320 Buffer::StreamStatus status
= buffer_
->stream(buffer
);
322 if (status
== Buffer::STREAM_OK
)
324 alSourceQueueBuffers(source_
, 1, &buffer
);
326 else if (status
== Buffer::STREAM_EOF
)
330 // begin the next buffer in the queue
331 expired_
.push_back(buffer_
);
332 buffer_
= queue_
.front();
334 buffer_
->beginStream(source_
, 1);
338 // restart from the beginning
340 buffer_
->stream(buffer
);
341 alSourceQueueBuffers(source_
, 1, &buffer
);
344 else if (status
== Buffer::STREAM_WRONG
)
347 buffer_
->beginStream(source_
, 1);
352 alGetSourcei(source_
, AL_SOURCE_STATE
, &state
);
354 // restart playing if we're stopped but supposed to be playing... this
355 // means we didn't queue enough and the audio skipped
356 if (playing_
&& state
!= AL_PLAYING
)
358 alSourcePlay(source_
);
364 // try to remove expired buffers
365 std::vector
<BufferP
>::iterator it
;
366 for (it
= expired_
.end() - 1; it
>= expired_
.begin(); --it
)
368 if ((*it
)->clear()) expired_
.erase(it
);
375 alSourceStop(source_
);
381 alSourcePause(source_
);
387 alSourcePlay(source_
);
392 inline void setSample(const std::string
& name
)
394 bool playing
= isPlaying();
396 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
400 //alSourcei(source_, AL_BUFFER, AL_NONE);
401 buffer_
= Buffer::getInstance(name
);
403 if (type
== AL_STREAMING
)
405 if (playing
) stream();
413 inline void enqueue(const std::string
& name
)
415 BufferP buffer
= Buffer::getInstance(name
);
420 inline bool isPlaying() const
422 if (playing_
) return true;
425 alGetSourcei(source_
, AL_SOURCE_STATE
, &state
);
427 return state
== AL_PLAYING
;
431 inline void setLooping(bool looping
)
436 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
438 if (type
!= AL_STREAMING
)
440 alSourcei(source_
, AL_LOOPING
, looping_
);
451 std::queue
<BufferP
> queue_
;
452 std::vector
<BufferP
> expired_
;
456 void streamUpdate(Timer
& timer
, Scalar t
)
458 // don't let the music die!
463 Sound::Sound(const std::string
& name
) :
465 impl_(new Sound::Impl(name
)) {}
501 if (impl_
->playing_
) pause();
506 void Sound::setSample(const std::string
& name
)
509 impl_
->setSample(name
);
512 void Sound::enqueue(const std::string
& name
)
515 impl_
->enqueue(name
);
519 bool Sound::isPlaying() const
522 return impl_
->isPlaying();
525 void Sound::setPosition(Vector3 position
)
527 float p
[3] = {position
[0], position
[1], position
[2]};
528 alSourcefv(impl_
->source_
, AL_POSITION
, p
);
531 void Sound::setVelocity(Vector3 velocity
)
533 float v
[3] = {velocity
[0], velocity
[1], velocity
[2]};
534 alSourcefv(impl_
->source_
, AL_VELOCITY
, v
);
537 void Sound::setGain(Scalar gain
)
539 alSourcef(impl_
->source_
, AL_GAIN
, float(gain
));
542 void Sound::setPitch(Scalar pitch
)
544 alSourcef(impl_
->source_
, AL_PITCH
, float(pitch
));
547 void Sound::setLooping(bool looping
)
550 impl_
->setLooping(looping
);
554 std::string
Sound::getPath(const std::string
& name
)
556 std::string path
= Resource::getPath("sounds/" + name
+ ".ogg");
563 /** vim: set ts=4 sw=4 tw=80: *************************************************/
This page took 0.054263 seconds and 3 git commands to generate.