1 /*
2 * ALURE OpenAL utility library
3 * Copyright (c) 2009 by Chris Robinson.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 /* Title: File Loading */
25
26 #include "config.h"
27
28 #include "main.h"
29
30 #include <string.h>
31
32 #include <vector>
33 #include <memory>
34
35
load_stream(alureStream * _stream,ALuint buffer)36 static bool load_stream(alureStream *_stream, ALuint buffer)
37 {
38 if(!_stream)
39 return false;
40
41 std::auto_ptr<std::istream> fstream(_stream->fstream);
42 std::auto_ptr<alureStream> stream(_stream);
43
44 ALenum format;
45 ALuint freq, blockAlign;
46
47 if(!stream->GetFormat(&format, &freq, &blockAlign))
48 {
49 SetError("Could not get sample format");
50 return false;
51 }
52
53 if(format == AL_NONE)
54 {
55 SetError("No valid format");
56 return false;
57 }
58 if(blockAlign == 0)
59 {
60 SetError("Invalid block size");
61 return false;
62 }
63 if(freq == 0)
64 {
65 SetError("Invalid sample rate");
66 return false;
67 }
68
69 ALuint writePos = 0, got;
70 std::vector<ALubyte> data(freq*blockAlign);
71 while((got=stream->GetData(&data[writePos], data.size()-writePos)) > 0)
72 {
73 writePos += got;
74 data.resize(writePos + freq*blockAlign);
75 }
76 data.resize(writePos - (writePos%blockAlign));
77 stream.reset(NULL);
78
79 alBufferData(buffer, format, &data[0], data.size(), freq);
80 if(alGetError() != AL_NO_ERROR)
81 {
82 SetError("Buffer load failed");
83 return false;
84 }
85
86 return true;
87 }
88
89 extern "C" {
90
91 /* Function: alureCreateBufferFromFile
92 *
93 * Loads the given file into a new OpenAL buffer object. The formats supported
94 * depend on the options the library was compiled with, what libraries are
95 * available at runtime, and the installed decode callbacks. Requires an active
96 * context.
97 *
98 * Returns:
99 * A new buffer ID with the loaded sound, or AL_NONE on error.
100 *
101 * See Also:
102 * <alureBufferDataFromFile>
103 */
alureCreateBufferFromFile(const ALchar * fname)104 ALURE_API ALuint ALURE_APIENTRY alureCreateBufferFromFile(const ALchar *fname)
105 {
106 if(alGetError() != AL_NO_ERROR)
107 {
108 SetError("Existing OpenAL error");
109 return AL_NONE;
110 }
111
112 ALuint buf;
113 alGenBuffers(1, &buf);
114 if(alGetError() != AL_NO_ERROR)
115 {
116 SetError("Buffer creation failed");
117 return AL_NONE;
118 }
119
120 if(alureBufferDataFromFile(fname, buf) == AL_FALSE)
121 {
122 alDeleteBuffers(1, &buf);
123 alGetError();
124 buf = AL_NONE;
125 }
126
127 return buf;
128 }
129
130 /* Function: alureCreateBufferFromMemory
131 *
132 * Loads a file image from memory into a new OpenAL buffer object, similar to
133 * alureCreateBufferFromFile. Requires an active context.
134 *
135 * Returns:
136 * A new buffer ID with the loaded sound, or AL_NONE on error.
137 *
138 * See Also:
139 * <alureBufferDataFromMemory>
140 */
alureCreateBufferFromMemory(const ALubyte * fdata,ALsizei length)141 ALURE_API ALuint ALURE_APIENTRY alureCreateBufferFromMemory(const ALubyte *fdata, ALsizei length)
142 {
143 if(alGetError() != AL_NO_ERROR)
144 {
145 SetError("Existing OpenAL error");
146 return AL_NONE;
147 }
148
149 ALuint buf;
150 alGenBuffers(1, &buf);
151 if(alGetError() != AL_NO_ERROR)
152 {
153 SetError("Buffer creation failed");
154 return AL_NONE;
155 }
156
157 if(alureBufferDataFromMemory(fdata, length, buf) == AL_FALSE)
158 {
159 alDeleteBuffers(1, &buf);
160 alGetError();
161 buf = AL_NONE;
162 }
163
164 return buf;
165 }
166
167 /* Function: alureBufferDataFromFile
168 *
169 * Loads the given file into an existing OpenAL buffer object. The previous
170 * contents of the buffer are replaced. Requires an active context.
171 *
172 * Returns:
173 * AL_FALSE on error.
174 *
175 * See Also:
176 * <alureCreateBufferFromFile>
177 */
alureBufferDataFromFile(const ALchar * fname,ALuint buffer)178 ALURE_API ALboolean ALURE_APIENTRY alureBufferDataFromFile(const ALchar *fname, ALuint buffer)
179 {
180 if(alGetError() != AL_NO_ERROR)
181 {
182 SetError("Existing OpenAL error");
183 return AL_FALSE;
184 }
185
186 if(!buffer || !alIsBuffer(buffer))
187 {
188 SetError("Invalid buffer ID");
189 return false;
190 }
191
192 if(load_stream(create_stream(fname), buffer) == false)
193 return AL_FALSE;
194 return AL_TRUE;
195 }
196
197 /* Function: alureBufferDataFromMemory
198 *
199 * Loads a file image from memory into an existing OpenAL buffer object,
200 * similar to alureBufferDataFromFile. Requires an active context.
201 *
202 * Returns:
203 * AL_FALSE on error.
204 *
205 * See Also:
206 * <alureCreateBufferFromMemory>
207 */
alureBufferDataFromMemory(const ALubyte * fdata,ALsizei length,ALuint buffer)208 ALURE_API ALboolean ALURE_APIENTRY alureBufferDataFromMemory(const ALubyte *fdata, ALsizei length, ALuint buffer)
209 {
210 if(alGetError() != AL_NO_ERROR)
211 {
212 SetError("Existing OpenAL error");
213 return AL_FALSE;
214 }
215
216 if(!buffer || !alIsBuffer(buffer))
217 {
218 SetError("Invalid buffer ID");
219 return false;
220 }
221
222 if(length < 0)
223 {
224 SetError("Invalid data length");
225 return AL_FALSE;
226 }
227
228 MemDataInfo memData;
229 memData.Data = fdata;
230 memData.Length = length;
231 memData.Pos = 0;
232
233 if(load_stream(create_stream(memData), buffer) == false)
234 return AL_FALSE;
235 return AL_TRUE;
236 }
237
238 } // extern "C"
239