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