]>
Dogcows Code - chaz/yoink/blob - src/Moof/Sound.cc
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
>
63 OggVorbis_File oggStream
;
66 std::vector
<ALuint
> objects
;
70 Buffer(const std::string
& name
) :
71 Mippleton
<Buffer
>(name
),
79 while (!objects
.empty())
81 alDeleteBuffers(1, &objects
.back());
100 //soundFile = Sound_NewSampleFromFile(soundFile::getPath(getName()).c_str(),
102 soundFile
= fopen(Sound::getPath(getName()).c_str(), "rb");
106 logWarning("error while loading sound %s", getName().c_str());
107 throw Exception(Exception::FILE_NOT_FOUND
);
110 int result
= ov_open(soundFile
, &oggStream
, NULL
, 0);
117 logWarning("error while loading oggvorbis stream %s",
119 throw Exception(Exception::BAD_AUDIO_FORMAT
);
122 vorbis_info
* vorbisInfo
= ov_info(&oggStream
, -1);
123 audioFormat
= getAudioFormat(vorbisInfo
);
124 audioFreq
= vorbisInfo
->rate
;
126 logDebug(" version: %d", vorbisInfo
->version
);
127 logDebug(" channels: %d", vorbisInfo
->channels
);
128 logDebug(" frequency: %d", vorbisInfo
->rate
);
132 void loadAll(ALuint source
)
134 if (!soundFile
) openFile();
135 if (!soundFile
) return;
137 char data
[BUFFER_SIZE
];
140 //unsigned decoded = Sound_DecodeAll(soundFile);
144 int result
= ov_read(&oggStream
, data
+ size
,
145 BUFFER_SIZE
- size
, 0, 2, 1, §ion
);
153 if (result
< 0) logWarning("vorbis playback error");
159 logWarning("decoded no bytes from %s", getName().c_str());
160 //throw Exception(Exception::FILE_NOT_FOUND);
165 alGenBuffers(1, &obj
);
167 alBufferData(obj
, audioFormat
, data
, size
, audioFreq
);
169 objects
.push_back(obj
);
171 alSourcei(source
, AL_BUFFER
, obj
);
173 // don't need this anymore
174 ov_clear(&oggStream
);
179 void beginStream(ALuint source
, int nBuffers
= 4)
181 if (!soundFile
) openFile();
182 if (!soundFile
) return;
184 ALuint objs
[nBuffers
];
185 alGenBuffers(nBuffers
, objs
);
187 for (int i
= 0; i
< nBuffers
; ++i
)
189 objects
.push_back(objs
[i
]);
193 alSourceQueueBuffers(source
, nBuffers
, objs
);
203 StreamStatus
stream(ALuint buffer
)
205 std::vector
<ALuint
>::iterator it
=
206 std::find(objects
.begin(), objects
.end(), buffer
);
208 // that buffer doesn't belong to us
209 if (it
== objects
.end()) return STREAM_WRONG
;
211 char data
[BUFFER_SIZE
];
214 //unsigned bytes = Sound_Decode(soundFile);
215 while (size
< BUFFER_SIZE
)
218 int result
= ov_read(&oggStream
, data
+ size
,
219 BUFFER_SIZE
- size
, 0, 2, 1, §ion
);
227 if (result
< 0) logWarning("vorbis playback error");
232 if (size
== 0) return STREAM_EOF
;
234 alBufferData(buffer
, audioFormat
, data
, size
, audioFreq
);
241 if (!soundFile
) openFile();
242 else ov_raw_seek(&oggStream
, 0);
246 // delete unused buffers, return true if all buffers deleted
249 // clear any openal errors
252 while (!objects
.empty())
254 ALuint buffer
= objects
.back();
255 alDeleteBuffers(1, &buffer
);
257 // if an error occured, the buffer was not deleted because it's
258 // still in use by some source
259 if (alGetError() != AL_NO_ERROR
) return false;
269 Impl(const std::string
& name
) :
270 buffer_(Buffer::getInstance(name
)),
274 ALfloat zero
[] = {0.0f
, 0.0f
, 0.0f
};
276 alGenSources(1, &source_
);
278 alSourcef(source_
, AL_PITCH
, 1.0f
);
279 alSourcef(source_
, AL_GAIN
, 1.0f
);
280 alSourcefv(source_
, AL_POSITION
, zero
);
281 alSourcefv(source_
, AL_VELOCITY
, zero
);
286 alDeleteSources(1, &source_
);
293 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
295 if (type
!= AL_STATIC
)
297 buffer_
->loadAll(source_
);
300 alSourcei(source_
, AL_LOOPING
, looping_
);
301 alSourcePlay(source_
);
309 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
311 alSourcei(source_
, AL_BUFFER
, AL_NONE
);
313 buffer_
->beginStream(source_
);
315 alSourcei(source_
, AL_LOOPING
, AL_FALSE
);
316 alSourcePlay(source_
);
324 alGetSourcei(source_
, AL_BUFFERS_PROCESSED
, &finished
);
326 while (finished
-- > 0)
330 alSourceUnqueueBuffers(source_
, 1, &buffer
);
332 Buffer::StreamStatus status
= buffer_
->stream(buffer
);
334 if (status
== Buffer::STREAM_OK
)
336 alSourceQueueBuffers(source_
, 1, &buffer
);
338 else if (status
== Buffer::STREAM_EOF
)
342 // begin the next buffer in the queue
343 expired_
.push_back(buffer_
);
344 buffer_
= queue_
.front();
346 buffer_
->beginStream(source_
, 1);
350 // restart from the beginning
352 buffer_
->stream(buffer
);
353 alSourceQueueBuffers(source_
, 1, &buffer
);
356 else if (status
== Buffer::STREAM_WRONG
)
359 buffer_
->beginStream(source_
, 1);
364 alGetSourcei(source_
, AL_SOURCE_STATE
, &state
);
366 // restart playing if we're stopped but supposed to be playing... this
367 // means we didn't queue enough and the audio skipped
368 if (playing_
&& state
!= AL_PLAYING
)
370 alSourcePlay(source_
);
376 // try to remove expired buffers
377 std::vector
<BufferP
>::iterator it
;
378 for (it
= expired_
.end() - 1; it
>= expired_
.begin(); --it
)
380 if ((*it
)->clear()) expired_
.erase(it
);
387 alSourceStop(source_
);
393 alSourcePause(source_
);
399 alSourcePlay(source_
);
404 inline void setSample(const std::string
& name
)
406 bool playing
= isPlaying();
408 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
412 //alSourcei(source_, AL_BUFFER, AL_NONE);
413 buffer_
= Buffer::getInstance(name
);
415 if (type
== AL_STREAMING
)
417 if (playing
) stream();
425 inline void enqueue(const std::string
& name
)
427 BufferP buffer
= Buffer::getInstance(name
);
432 inline bool isPlaying() const
434 if (playing_
) return true;
437 alGetSourcei(source_
, AL_SOURCE_STATE
, &state
);
439 return state
== AL_PLAYING
;
443 inline void setLooping(bool looping
)
448 alGetSourcei(source_
, AL_SOURCE_TYPE
, &type
);
450 if (type
!= AL_STREAMING
)
452 alSourcei(source_
, AL_LOOPING
, looping_
);
463 std::queue
<BufferP
> queue_
;
464 std::vector
<BufferP
> expired_
;
467 Sound::Sound(const std::string
& name
) :
469 impl_(new Sound::Impl(name
)) {}
485 void Sound::update(Scalar t
, Scalar dt
)
512 if (impl_
->playing_
) pause();
517 void Sound::setSample(const std::string
& name
)
520 impl_
->setSample(name
);
523 void Sound::enqueue(const std::string
& name
)
526 impl_
->enqueue(name
);
530 bool Sound::isPlaying() const
533 return impl_
->isPlaying();
536 void Sound::setPosition(Vector3 position
)
538 float p
[3] = {position
[0], position
[1], position
[2]};
539 alSourcefv(impl_
->source_
, AL_POSITION
, p
);
542 void Sound::setVelocity(Vector3 velocity
)
544 float v
[3] = {velocity
[0], velocity
[1], velocity
[2]};
545 alSourcefv(impl_
->source_
, AL_VELOCITY
, v
);
548 void Sound::setGain(Scalar gain
)
550 alSourcef(impl_
->source_
, AL_GAIN
, float(gain
));
553 void Sound::setPitch(Scalar pitch
)
555 alSourcef(impl_
->source_
, AL_PITCH
, float(pitch
));
558 void Sound::setLooping(bool looping
)
561 impl_
->setLooping(looping
);
565 std::string
Sound::getPath(const std::string
& name
)
567 std::string path
= Resource::getPath("sounds/" + name
+ ".ogg");
574 /** vim: set ts=4 sw=4 tw=80: *************************************************/
This page took 0.060861 seconds and 4 git commands to generate.