1 /*
2 * This code is released under the GNU General Public License. See COPYING for
3 * details. Copyright 2003 John Spray: spray_john@users.sourceforge.net
4 */
5
6 //SoundCore.c - The class that deals with audio. Note that one should already
7 //have done an SDL_Init(SDL_AUDIO) before calling SoundCore::Init
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <math.h>
12 #include <AL/al.h>
13 #include <AL/alut.h>
14 #include <string.h>
15 #include <physfs.h>
16 #include <string>
17
18 #include "SoundCore.h"
19 #include "Game.h"
20 #include "Config.h"
21
22 extern Config GLOB_conf;
23
24 //SoundCore::SoundCore - Simple Initialisation
SoundCore()25 SoundCore::SoundCore()
26 {
27 verbose=0;
28 paused=0;
29 reference_distance=50.0f;
30 volume=GLOB_conf.volume;
31 verbose=GLOB_conf.verbose;
32
33 //alutInit(0,NULL);
34 //fprintf(stderr,"SoundCore::SoundCore: OpenAL initialised\n");fflush(stderr);
35 alListenerf(AL_GAIN,volume);
36
37
38 alDopplerFactor(0.0f);
39 ALenum error;
40 if((error=alGetError())!=AL_NO_ERROR){
41 fprintf(stderr,"SoundCore::SoundCore: Error on alDopplerFactor\n");
42 PrintALError(error);
43 }
44
45 }
46
~SoundCore()47 SoundCore::~SoundCore()
48 {
49 LListItem<SampleType> *sampleitem;
50 LListItem<EffectType> *effectitem;
51 ALenum error;
52
53 alGetError();
54
55 for(effectitem=effectlist.head;effectitem;effectitem=effectitem->next){
56 alSourceStop(effectitem->data.alid);
57 alDeleteSources(1,&effectitem->data.alid);
58 if((error=alGetError())!=AL_NO_ERROR){
59 fprintf(stderr,"SoundCore::~SoundCore: Error on alDeleteSources(1,%d)\n",effectitem->data.alid);
60 PrintALError(error);
61 }
62
63 }
64
65 for(sampleitem=samplelist.head;sampleitem;sampleitem=sampleitem->next){
66 alDeleteBuffers(1,&sampleitem->data.alid);
67 if((error=alGetError())!=AL_NO_ERROR){
68 fprintf(stderr,"SoundCore::~SoundCore: Error on alDeleteBuffers(1,%d)\n",sampleitem->data.alid);
69 PrintALError(error);
70 }
71 }
72
73 //Looks like one isn't supposed to call alutExit unless
74 //one really does want to Exit
75 /*alutExit();
76 fprintf(stderr,"SoundCore::~SoundCore: OpenAL deinitialised\n");
77 fflush(stderr);*/
78
79 }
80
81
SetEar(Vector * newpos,Vector * newvel,Vector * newface,Vector * newup)82 void SoundCore::SetEar(Vector* newpos,Vector* newvel,Vector* newface,Vector* newup)
83 {
84
85 s=newpos;
86 alListener3f(AL_POSITION,s->x,s->y,s->z);
87
88 v=newvel;
89 alListener3f(AL_VELOCITY,v->x,v->y,v->z);
90
91 orientation_face=newface;
92 orientation_up=newup;
93 float orientv[]={orientation_face->x,orientation_face->y,
94 orientation_face->z,orientation_up->x,
95 orientation_up->y,orientation_up->z};
96
97 alListenerfv(AL_ORIENTATION,orientv);
98
99
100
101 }
102
103 //SoundCore::Update - if an effect has finished playing mark it
Update()104 void SoundCore::Update()
105 {
106 LListItem<EffectType> *effectitem,*temp;
107 ALenum sourcestate;
108 float orientv[]={orientation_face->x,orientation_face->y,orientation_face->z,orientation_up->x,orientation_up->y,orientation_up->z};
109
110 alListener3f(AL_VELOCITY,v->x,v->y,v->z);
111 alListener3f(AL_POSITION,s->x,s->y,s->z);
112 alListenerfv(AL_ORIENTATION,orientv);
113
114 for(effectitem=effectlist.head;effectitem;){
115 alGetSourcei(effectitem->data.alid,AL_SOURCE_STATE,&sourcestate);
116 if(sourcestate==AL_STOPPED){
117 effectitem->data.isplaying=0;
118 temp=effectitem->next;
119 alDeleteSources(1,&effectitem->data.alid);
120
121 effectlist.Del(effectitem);
122 effectitem=temp;
123 continue;
124 }
125 else{
126 if(effectitem->data.still){
127 alSource3f(effectitem->data.alid,AL_POSITION,
128 effectitem->data.s_static.x,
129 effectitem->data.s_static.y,
130 effectitem->data.s_static.z);
131 alSource3f(effectitem->data.alid,AL_VELOCITY,
132 effectitem->data.v_static.x,
133 effectitem->data.v_static.y,
134 effectitem->data.v_static.z);
135 }
136 else{
137 alSource3f(effectitem->data.alid,AL_POSITION,
138 effectitem->data.s->x,
139 effectitem->data.s->y,
140 effectitem->data.s->z);
141 alSource3f(effectitem->data.alid,AL_VELOCITY,
142 effectitem->data.v->x,
143 effectitem->data.v->y,
144 effectitem->data.v->z);
145 }
146 }
147 effectitem=effectitem->next;
148 }
149 }
150
SetVolume(float target_volume)151 void SoundCore::SetVolume(float target_volume)
152 {
153 // 0.001 coping with 0.0 apparently not being equal to -0.0
154 if(target_volume>=-0.001f&&target_volume<=1.001f)
155 volume=target_volume;
156 else
157 printf("SoundCore::SetVolume: Bad volume setting: %f\n",target_volume);
158
159 alListenerf(AL_GAIN,volume);
160 GLOB_conf.volume=volume;
161 }
162
GetVolume()163 float SoundCore::GetVolume()
164 {
165 return volume;
166 }
167
168 //SoundCore::Play - choose an available effect, select wave and position data, and
169 //set it playing.
Play(char * filename,int loopmode,Vector * sourcepos,Vector * sourcev)170 int SoundCore::Play(char* filename,int loopmode,Vector* sourcepos,Vector* sourcev)
171 {
172
173 SampleType *target_sample=NULL;
174 EffectType neweffect;
175 LListItem<SampleType> *sampleitem;
176
177 if(strlen(filename)>127||!filename){
178 printf("SoundCore::Play: malformed filename\n");
179 return -1;
180 }
181
182 for(sampleitem=samplelist.head;sampleitem;sampleitem=sampleitem->next){
183 if(!strcmp(filename,sampleitem->data.filename)){
184 target_sample=&sampleitem->data;
185 break;
186 }
187 }
188
189 if(target_sample==NULL){
190 printf("SoundCore::Play: file named %s is not loaded!\n",filename);
191 return -1;
192 }
193
194 if(verbose) printf("SoundCore::Play: playing %s\n",filename);
195
196
197 neweffect.s=sourcepos;
198 neweffect.v=sourcev;
199 neweffect.still=0;
200 alGenSources(1,&neweffect.alid);
201
202 alSourcei(neweffect.alid,AL_BUFFER,target_sample->alid);
203
204 if(loopmode==-1){
205 alSourcei(neweffect.alid,AL_LOOPING,AL_TRUE);
206 }
207 else{
208 alSourcei(neweffect.alid,AL_LOOPING,AL_FALSE);
209 }
210 alSourcePlay(neweffect.alid);
211
212 alSourcef(neweffect.alid,AL_REFERENCE_DISTANCE,reference_distance);
213
214 neweffect.isplaying=1;
215
216 effectlist.Add(&neweffect);
217
218 return neweffect.alid;
219 }
220
Play(char * filename,int loopmode,Vector sourcepos,Vector sourcev)221 int SoundCore::Play(char* filename,int loopmode,Vector sourcepos,Vector sourcev)
222 {
223 SampleType *target_sample=NULL;
224 EffectType neweffect;
225 LListItem<SampleType> *sampleitem;
226
227 if(strlen(filename)>127||!filename){
228 printf("SoundCore::Play: malformed filename\n");
229 return -1;
230 }
231
232 for(sampleitem=samplelist.head;sampleitem;sampleitem=sampleitem->next){
233 if(!strcmp(filename,sampleitem->data.filename)){
234 target_sample=&sampleitem->data;
235 break;
236 }
237 }
238
239 if(target_sample==NULL){
240 printf("SoundCore::Play: file named %s is not loaded!\n",filename);
241 return -1;
242 }
243
244 if(verbose) printf("SoundCore::Play: playing %s\n",filename);
245
246 neweffect.s_static=sourcepos;
247 neweffect.v_static=sourcev;
248 neweffect.v=NULL;
249 neweffect.s=NULL;
250 neweffect.still=1;
251 alGenSources(1,&neweffect.alid);
252 alSourcei(neweffect.alid,AL_BUFFER,target_sample->alid);
253 if(loopmode==-1)
254 alSourcei(neweffect.alid,AL_LOOPING,AL_TRUE);
255 else
256 alSourcei(neweffect.alid,AL_LOOPING,AL_FALSE);
257 alSourcePlay(neweffect.alid);
258
259 alSourcef(neweffect.alid,AL_REFERENCE_DISTANCE,reference_distance);
260
261 neweffect.isplaying=1;
262 effectlist.Add(&neweffect);
263 return neweffect.alid;
264 }
265
Play(char * filename)266 int SoundCore::Play(char* filename)
267 {
268 return Play(filename,0,s,v);
269 }
270
SetPaused(int target_paused)271 void SoundCore::SetPaused(int target_paused)
272 {
273 LListItem<EffectType> *effectitem;
274 ALenum error;
275
276 alGetError();
277
278 if(target_paused==0){
279 paused=0;
280 //Play all Effects
281 for(effectitem=effectlist.head;effectitem;effectitem=effectitem->next){
282 alSourcePlay(effectitem->data.alid);
283 if((error=alGetError())!=AL_NO_ERROR){
284 fprintf(stderr,"SoundCore::LoadSample: Error on alutUnloadWAV\n");
285 PrintALError(error);
286 }
287 }
288 }
289 else{
290 paused=1;
291 //Pause all Effects
292 for(effectitem=effectlist.head;effectitem;effectitem=effectitem->next){
293 alSourcePause(effectitem->data.alid);
294 }
295 }
296 }
297
HandleMixError()298 void SoundCore::HandleMixError()
299 {
300 fprintf(stderr,"HandleMixError got called in the OpenAL soundcore implementation!\n");
301 return;
302 }
303
StopEffect(ALint target_id)304 int SoundCore::StopEffect(ALint target_id)
305 {
306 LListItem<EffectType> *effectitem;
307 ALenum error,sourcestate;
308 if(verbose || target_id==-1)
309 printf("SoundCore::StopEffect: target_id=%d\n",target_id);
310
311 alGetError();
312
313 for(effectitem=effectlist.head;effectitem;effectitem=effectitem->next){
314 if((ALint)effectitem->data.alid==target_id){
315 alGetSourcei(effectitem->data.alid,AL_SOURCE_STATE,&sourcestate);
316 alSourceStop(effectitem->data.alid);
317 alDeleteSources(1,&effectitem->data.alid);
318 if( (error=alGetError()) != AL_NO_ERROR ){
319 fprintf(stderr,"SoundCore::StopEffect: Error on alDeleteSources\n");
320 PrintALError(error);
321 }
322 effectlist.Del(effectitem);
323 return 0;
324 }
325 }
326
327 printf("SoundCore::StopEffect: Invalid effect reference %d\n",target_id);
328 return -1;
329 }
330
LoadSample(char * filename)331 int SoundCore::LoadSample(char* filename)
332 {
333 PHYSFS_file* filehandle;
334 void* filedata;
335 long filesize=0;
336 SampleType newsample;
337
338 filehandle=PHYSFS_openRead(filename);
339
340 if(!filehandle) {printf("SoundCore::LoadSample: PHYSFS_openRead failed on %s with error %s!\n",filename,PHYSFS_getLastError()); return 1;}
341
342 filesize=PHYSFS_fileLength(filehandle);
343
344 filedata=malloc(filesize);
345 if(!filedata) {printf("SoundCore::LoadSample: malloc failed! Out of memory?\n"); return 1;}
346 if(PHYSFS_read(filehandle,filedata,1,filesize)!=filesize){
347 printf("SoundCore::LoadSample: PHYSFS_read and PHYSFS_fileLength disagree! Aborting.\n");
348 free(filedata);
349 PHYSFS_close(filehandle);
350 return 1;
351 }
352
353 PHYSFS_close(filehandle);
354
355 ALenum format;
356 ALvoid *data;
357 ALsizei size,freq;
358 ALboolean loop=AL_FALSE;
359 ALenum error;
360
361 alGetError();
362
363 alGenBuffers(1,&newsample.alid);
364 if((error=alGetError())!=AL_NO_ERROR){
365 fprintf(stderr,"SoundCore::LoadSample: Error on alGenBuffers\n");
366 PrintALError(error);
367 }
368 alutLoadWAVMemory((ALbyte*)filedata,&format,&data,&size,&freq,&loop);
369 if((error=alGetError())!=AL_NO_ERROR){
370 fprintf(stderr,"SoundCore::LoadSample: Error on alutLoadWAVMemory\n");
371 PrintALError(error);
372 }
373 alBufferData(newsample.alid,format,data,size,freq);
374 if((error=alGetError())!=AL_NO_ERROR){
375 fprintf(stderr,"SoundCore::LoadSample: Error on alBufferData\n");
376 PrintALError(error);
377 }
378 alutUnloadWAV(format,data,size,freq);
379 if((error=alGetError())!=AL_NO_ERROR){
380 fprintf(stderr,"SoundCore::LoadSample: Error on alutUnloadWAV\n");
381 PrintALError(error);
382 }
383
384 strcpy(newsample.filename,filename);
385 samplelist.Add(&newsample);
386
387
388 free(filedata);
389
390 return 0;
391 }
392
PrintALError(ALenum code)393 void SoundCore::PrintALError(ALenum code)
394 {
395 string description;
396
397 if(code==AL_INVALID_NAME)
398 description="Invalid Name";
399 else if(code==AL_INVALID_VALUE)
400 description="Invalid Value";
401 else if(code==AL_ILLEGAL_ENUM)
402 description="Illegal Enum";
403 else if(code==AL_ILLEGAL_COMMAND)
404 description="Illegal COmmand";
405 else if(code==AL_OUT_OF_MEMORY)
406 description="Out of Memory";
407 else if(code==AL_NO_ERROR)
408 description="No Error";
409 else
410 description="Unknown error code";
411
412 fprintf(stderr,"OpenAL error: %d: %s\n",code,description.c_str());
413 fflush(stderr);
414 }
415