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