]> Dogcows Code - chaz/yoink/blob - src/Moof/Sound.cc
better logging (maybe) and exception handling
[chaz/yoink] / src / Moof / Sound.cc
1
2 /*******************************************************************************
3
4 Copyright (c) 2009, Charles McGarvey
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
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.
15
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.
26
27 *******************************************************************************/
28
29 #include <string>
30
31 #include <SDL/SDL.h>
32 #include <SDL/SDL_sound.h>
33 #include <AL/al.h>
34
35 #include "Log.hh"
36 #include "Mippleton.hh"
37 #include "Sound.hh"
38
39 #define BUFFER_SIZE (8 * 4096)
40
41 namespace Mf {
42
43
44 struct Sound::Impl
45 {
46
47 static ALenum getAudioFormat(const Sound_AudioInfo& audioInfo)
48 {
49 if (audioInfo.format == AUDIO_U8 || audioInfo.format == AUDIO_S8)
50 {
51 if (audioInfo.channels == 1) return AL_FORMAT_MONO8;
52 else return AL_FORMAT_STEREO8;
53 }
54 else
55 {
56 if (audioInfo.channels == 1) return AL_FORMAT_MONO16;
57 else return AL_FORMAT_STEREO16;
58 }
59 }
60
61 struct Buffer : public Mippleton<Buffer>
62 {
63 Buffer(const std::string& name) :
64 Mippleton<Buffer>(name)
65 {
66 objects[0] = 0;
67 objects[1] = 0;
68 }
69
70 ~Buffer()
71 {
72 alDeleteBuffers(2, objects);
73
74 if (sound) Sound_FreeSample(sound);
75 }
76
77
78 void loadFromFile(const std::string& filePath, bool stream)
79 {
80 if (objects[0] != 0) return;
81
82 sound = Sound_NewSampleFromFile(filePath.c_str(),
83 NULL, BUFFER_SIZE);
84
85 if (!sound)
86 {
87 logWarning("audio not found: %s", getName().c_str());
88 throw Exception(Exception::FILE_NOT_FOUND);
89 }
90
91 if (!stream)
92 {
93 unsigned decoded = Sound_DecodeAll(sound);
94 if (decoded == 0)
95 {
96 logWarning("decoded not bytes from %s", getName().c_str());
97 throw Exception(Exception::FILE_NOT_FOUND);
98 }
99
100 alGenBuffers(2, objects);
101 alBufferData(objects[0], getAudioFormat(sound->actual), sound->buffer,
102 sound->buffer_size, sound->actual.rate);
103 logDebug("buffer size: %d", sound->buffer_size);
104 logDebug(" channels: %d", sound->actual.channels);
105 logDebug(" format: %d", sound->actual.format);
106 logDebug(" frequency: %d", sound->actual.rate);
107
108 Sound_FreeSample(sound);
109 sound = 0;
110 }
111 else
112 {
113 logDebug("buffer size: %d", sound->buffer_size);
114 logDebug(" channels: %d", sound->actual.channels);
115 logDebug(" format: %d", sound->actual.format);
116 logDebug(" frequency: %d", sound->actual.rate);
117 alGenBuffers(2, objects);
118 }
119 }
120
121 bool stream(ALuint buffer)
122 {
123 int bytes = Sound_Decode(sound);
124
125 if (bytes < BUFFER_SIZE) return false;
126
127 alBufferData(buffer, getAudioFormat(sound->actual), sound->buffer,
128 sound->buffer_size, sound->actual.rate);
129 return false;
130 }
131
132 Sound_Sample* sound;
133 ALuint objects[2];
134
135 //ALfloat location[] = {0.0f, 0.0f, 0.0f};
136 //ALfloat location2[] = {0.0f, 0.0f, 0.0f};
137 //ALfloat orient[] = {0.0f, 0.0f, -1.0f, 0.0, 1.0, 0.0};
138
139
140 //alListenerfv(AL_POSITION, location);
141 //alListenerfv(AL_VELOCITY, location);
142 //alListenerfv(AL_VELOCITY, orient);
143 };
144
145 Impl(const std::string& name, bool stream = false) :
146 buffer_(Buffer::getInstance(name))
147 {
148 if (!stream) buffer_->loadFromFile(Sound::getPath(name), stream);
149 else buffer_->loadFromFile(SoundStream::getPath(name), stream);
150
151 ALfloat location[] = {0.0f, 0.0f, 0.0f};
152
153 alGenSources(1, &source_);
154
155 alSourcef(source_, AL_PITCH, 1.0f);
156 alSourcef(source_, AL_GAIN, 1.0f);
157 alSourcefv(source_, AL_POSITION, location);
158 alSourcefv(source_, AL_VELOCITY, location);
159 alSourcei(source_, AL_LOOPING, AL_FALSE);
160
161 if (!stream)
162 {
163 alSourcei(source_, AL_BUFFER, buffer_->objects[0]);
164 }
165 else
166 {
167 buffer_->stream(buffer_->objects[0]);
168 buffer_->stream(buffer_->objects[1]);
169
170 alSourceQueueBuffers(source_, 2, buffer_->objects);
171 }
172 }
173
174 ~Impl()
175 {
176 alDeleteSources(1, &source_);
177 }
178
179
180 void update()
181 {
182 int finished = 0;
183
184 alGetSourcei(source_, AL_BUFFERS_PROCESSED, &finished);
185
186 while (finished-- > 0)
187 {
188 ALuint buffer;
189
190 alSourceUnqueueBuffers(source_, 1, &buffer);
191 buffer_->stream(buffer);
192 alSourceQueueBuffers(source_, 1, &buffer);
193 }
194 }
195
196
197 boost::shared_ptr<Buffer> buffer_;
198 ALuint source_;
199 bool playing;
200 };
201
202
203 Sound::Sound(const std::string& name) :
204 // pass through
205 impl_(new Sound::Impl(name)) {}
206
207
208 void Sound::play()
209 {
210 //alSourceRewind(impl_->source_);
211 alSourcePlay(impl_->source_);
212 impl_->playing = true;
213 }
214
215 void Sound::pause()
216 {
217 alSourcePause(impl_->source_);
218 impl_->playing = false;
219 }
220
221 void Sound::togglePlayPause()
222 {
223 if (impl_->playing) pause();
224 else play();
225 }
226
227 void Sound::setGain(Scalar gain)
228 {
229 alSourcef(impl_->source_, AL_GAIN, gain);
230 }
231
232
233 std::string Sound::getPath(const std::string& name)
234 {
235 std::string path = Resource::getPath("sounds/" + name + ".ogg");
236 return path;
237 }
238
239
240 //##############################################################################
241
242
243 SoundStream::SoundStream(const std::string& name)
244 // pass through
245 //impl_(name, true) {}
246 {
247 impl_ = boost::shared_ptr<Sound::Impl>(new Sound::Impl(name, true));
248 }
249
250
251 void SoundStream::update(Scalar t, Scalar dt)
252 {
253 // pass through
254 impl_->update();
255 }
256
257
258 std::string SoundStream::getPath(const std::string& name)
259 {
260 std::string path = Resource::getPath("sounds/" + name + ".xm");
261 return path;
262 }
263
264
265 } // namespace Mf
266
267 /** vim: set ts=4 sw=4 tw=80: *************************************************/
268
This page took 0.046637 seconds and 5 git commands to generate.