1 /*
2  * Seven Kingdoms: Ancient Adversaries
3  *
4  * Copyright 1997,1998 Enlight Software Ltd.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 // Filename    : OSE.CPP
22 // Description : Sound Effect Controller
23 // Owner       : Gilbert
24 
25 #include <OSE.h>
26 #include <OAUDIO.h>
27 #include <OGAMESET.h>
28 #include <OMISC.h>
29 #include <OCONFIG.h>
30 
31 #define MIN_AUDIO_VOL 10
32 
33 // ------ Begin Function SERequest::add_request -------//
add_request(RelVolume relVolume)34 void SERequest::add_request(RelVolume relVolume)
35 {
36 	if( req_used < MAX_SE_STORE)
37 	{
38 		play_vol[req_used] = relVolume;
39 		req_used++;
40 	}
41 	else
42 	{
43 		// not enough space, remove the MIN volume one.
44 		RelVolume minVolume = relVolume;
45 		for( int i = 0; i < MAX_SE_STORE; ++i)
46 		{
47 			if( play_vol[i].rel_vol < minVolume.rel_vol)
48 			{
49 				RelVolume temp;
50 				// swap volume[i] and minVolume
51 				temp = play_vol[i];
52 				play_vol[i] = minVolume;
53 				minVolume = temp;
54 			}
55 		}
56 	}
57 }
58 // ------ End Function SERequest::add_request -------//
59 
60 
61 // ------ Begin Function SERequest::max_entry -------//
max_entry()62 int SERequest::max_entry()
63 {
64 	err_when( req_used <= 0);
65 
66 	int maxEntry = 0;
67 	RelVolume *maxVolume = &play_vol[maxEntry];
68 	for( int i = 1; i < req_used; ++i)
69 	{
70 		if( maxVolume->rel_vol < play_vol[i].rel_vol)
71 		{
72 			maxVolume = &play_vol[i];
73 			maxEntry = i;
74 		}
75 	}
76 
77 	return maxEntry;
78 }
79 // ------ End Function SERequest::max_entry -------//
80 
81 
82 // ------ Begin Function SERequest::remove_request -------//
remove_request(int slot)83 void SERequest::remove_request(int slot)
84 {
85 	if( slot >= req_used || slot < 0)
86 		return;
87 
88 	// ---- move element after slot -----/
89 	for( int i = slot+1; i < req_used; ++i)
90 	{
91 		play_vol[i-1] = play_vol[i];
92 	}
93 	req_used--;
94 }
95 // ------ End Function SERequest::remove_request -------//
96 
97 
98 // ------ Begin Function SERequest::clear_request -------//
clear_request()99 void SERequest::clear_request()
100 {
101 	req_used = 0;
102 }
103 // ------ End Function SERequest::clear_request -------//
104 
105 
106 // ------ Begin Function SECtrl::SECtrl -------//
SECtrl(Audio * audioPtr)107 SECtrl::SECtrl(Audio *audioPtr) : audio_ptr(audioPtr), res_supp(audioPtr->wav_res)
108 {
109 	init_flag = 0;
110 	audio_flag = 0;
111 	req_pool = NULL;
112 	last_cycle = NULL;
113 	max_sound_effect = 0;
114 	max_supp_effect = 0;
115 	total_effect = 0;
116 	biased_se = 0;
117 }
118 // ------ End Function SECtrl::SECtrl -------//
119 
120 
121 // ------ Begin Function SECtrl::~SECtrl ------//
~SECtrl()122 SECtrl::~SECtrl()
123 {
124 	deinit();
125 }
126 // ------ End Function SECtrl::~SECtrl ------//
127 
128 
129 // ------ Begin Function SECtrl::init -------//
init()130 void SECtrl::init()
131 {
132 	deinit();
133 
134 	audio_flag = audio_ptr->wav_init_flag;
135 	if( !audio_flag )
136 	{
137 		init_flag = 1;
138 		return;
139 	}
140 
141 	//----- open wave resource file -------//
142 
143 	String str;
144 
145 	str  = DIR_RES;
146 	str += "A_WAVE1.RES";
147 
148 	res_wave.init(str,1);  // 1-read all into buffer
149 
150 	//------- load database information --------//
151 
152 	load_info();
153 
154 	// ----- clear last_cycle array and wave_ptr --------//
155 	init_flag = 1;
156 	clear();
157 }
158 // ------ End Function SECtrl::init -------//
159 
160 
161 // ------ Begin Function SECtrl::deinit -------//
deinit()162 void SECtrl::deinit()
163 {
164 	if( init_flag )
165 	{
166 		init_flag = 0;
167 		if( audio_flag )
168 		{
169 			mem_del(req_pool);
170 			mem_del(last_cycle);
171 		}
172 	}
173 }
174 // ------ End Function SECtrl::deinit -------//
175 
176 
177 // ------ Begin Function SECtrl::load_info -------//
load_info()178 void SECtrl::load_info()
179 {
180 	int count = max_sound_effect = res_wave.rec_count;
181 	int suppCount = max_supp_effect = res_supp.rec_count;
182 	total_effect = max_sound_effect + max_supp_effect;
183 
184 	req_pool = (SERequest *)mem_add(total_effect * sizeof(SERequest) );
185 	last_cycle = (char *)mem_add(total_effect * sizeof(char));
186 
187 	short j;
188 	for(j=0; j < count; ++j)
189 	{
190 		req_pool[j].resx_id = j+1;
191 		req_pool[j].wave_ptr = res_wave.get_data(j+1);		// wave data pointer
192 		last_cycle[j] = 0;
193 	}
194 
195 	for(short k=0; k < suppCount; ++k, ++j)
196 	{
197 		req_pool[j].resx_id = k+1;
198 		req_pool[j].wave_ptr = NULL;
199 		last_cycle[j] = 0;
200 	}
201 }
202 // ------ End Function SECtrl::load_info -------//
203 
204 
205 // ------ Begin Function SECtrl::clear -------//
clear()206 void SECtrl::clear()
207 {
208 	for( int j = 0; j < total_effect; ++j)
209 	{
210 		req_pool[j].clear_request();
211 	}
212 }
213 // ------ End Function SECtrl::clear -------//
214 
215 
216 // ------ Begin Function SECtrl::request -------//
217 //
218 // Request to sound an effect
219 //
220 // <int> soundEffect        the id of the sound effect, return from SECtrl::search_effect_id
221 // <long> vol               volume (0 - 100 MAX loudness)
222 // <long> pan               pan (-10000 = full left; 10000 = full right)
223 // note the request is abolished if vol is 0 or soundEffect is 0
224 //
request(int soundEffect,RelVolume relVolume)225 void SECtrl::request(int soundEffect, RelVolume relVolume)
226 {
227 	if( !audio_flag || !config.sound_effect_flag)
228 		return;					// skip if audio cannot init wave device
229 	err_when( soundEffect < 0 || soundEffect > total_effect);
230 	if( relVolume.rel_vol >= MIN_AUDIO_VOL && soundEffect)
231 		req_pool[soundEffect-1].add_request(relVolume);
232 }
233 
234 
request(char * soundName,RelVolume relVolume)235 void SECtrl::request(char *soundName, RelVolume relVolume)
236 {
237 	if( !audio_flag || !config.sound_effect_flag)
238 		return;					// skip if audio cannot init wave device
239 	int soundEffect = search_effect_id(soundName);
240 	err_when( soundEffect < 0 || soundEffect > total_effect);
241 	if( relVolume.rel_vol >= MIN_AUDIO_VOL && soundEffect)
242 		req_pool[soundEffect-1].add_request(relVolume);
243 }
244 // ------ End Function SECtrl::request -------//
245 
246 // ------ Begin Function SECtrl::flush -------//
flush()247 void SECtrl::flush()
248 {
249 	err_when(!init_flag);
250 	// ##### begin Gilbert 11/11 ######//
251 	// err_when(!audio_ptr->init_flag);
252 	// ##### end Gilbert 11/11 ######//
253 	if( !audio_flag || !config.sound_effect_flag)
254 	{
255 		clear();
256 		return;					// skip if audio cannot init wave device
257 	}
258 	int chCount = audio_ptr->get_free_wav_ch();
259 	int reqCount = 0, reqSum = 0;
260 	int i,j,k;
261 	SERequest *seRequest;
262 
263 	k = 0;
264 	cached_size = 0;
265 	for( j = 0, seRequest=req_pool; j < total_effect ; ++j, ++seRequest)
266 	{
267 		if( seRequest->req_used > 0)
268 		{
269 			reqCount++;
270 			reqSum += seRequest->req_used;
271 		}
272 
273 		// cached sound effect
274 		if( (seRequest->req_used > 0 || last_cycle[j]) && cached_size < MAX_SE_CACHED )
275 		{
276 			cached_index[cached_size++] = j;
277 		}
278 	}
279 
280 	if( reqSum <= chCount )
281 	{
282 		// --------- enough for all requests --------//
283 		// for( j = 0, seRequest=req_pool; j < total_effect; ++j, ++seRequest)
284 		for( k = 0; k < cached_size; ++k)
285 		{
286 			j = cached_index[k]; seRequest = req_pool + j;
287 
288 			last_cycle[j] = 0;
289 			for( i = seRequest->req_used-1; i >= 0; --i)
290 			{
291 				if( seRequest->wave_ptr)
292 				{
293 					audio_ptr->play_resided_wav( seRequest->wave_ptr,
294 						seRequest->play_vol[i]);
295 				}
296 				else
297 				{
298 					audio_ptr->play_wav( seRequest->resx_id,
299 						seRequest->play_vol[i]);
300 				}
301 				last_cycle[j]++;
302 				chCount--;
303 			}
304 		}
305 		reqSum = 0;
306 		reqCount = 0;
307 	}
308 	else if( reqCount <= chCount )
309 	{
310 		// --------- one channel for one sound effect --------//
311 		for( k = 0; k < cached_size; ++k)
312 		{
313 			j = cached_index[k]; seRequest = req_pool + j;
314 			last_cycle[j] = 0;
315 			if( seRequest->req_used > 0)
316 			{
317 				i = seRequest->max_entry();
318 				if( seRequest->wave_ptr)
319 				{
320 					audio_ptr->play_resided_wav( seRequest->wave_ptr,
321 						seRequest->play_vol[i]);
322 				}
323 				else
324 				{
325 					audio_ptr->play_wav( seRequest->resx_id,
326 						seRequest->play_vol[i]);
327 				}
328 				last_cycle[j]++;
329 			}
330 		}
331 	}
332 	else
333 	{
334 		// -------- not enough for each sound effect ------//
335 
336 		// ------- one channel for one sound effect --------//
337 		for( k = 0; k < cached_size && biased_se > cached_index[k]; ++k);
338 		if( k >= cached_size)
339 			k = 0;
340 
341 		for( int c = 0; chCount > 0 && c < cached_size; ++c)
342 		{
343 			if( ++k >= cached_size)
344 				k = 0;
345 			j = cached_index[k]; seRequest = req_pool + j;
346 			if( seRequest->req_used > 0 && !last_cycle[j])
347 			{
348 				i = seRequest->max_entry();
349 				if( seRequest->wave_ptr )
350 				{
351 					audio_ptr->play_resided_wav( seRequest->wave_ptr,
352 						seRequest->play_vol[i]);
353 				}
354 				else
355 				{
356 					audio_ptr->play_wav( seRequest->resx_id,
357 						seRequest->play_vol[i]);
358 				}
359 				last_cycle[j]++;
360 				chCount--;
361 				biased_se = j;
362 			}
363 			else
364 			{
365 				last_cycle[j] = 0;
366 			}
367 		}
368 	}
369 
370 	clear();
371 }
372 // ------ End Function SECtrl::flush -------//
373 
374 
375 // ------ Begin Function SECtrl::get_effect_name -------//
376 //
377 // return the name of the sound effect
378 // int j           the id of the sound effect
379 //
get_effect_name(int j)380 char *SECtrl::get_effect_name(int j)
381 {
382 	err_when(!init_flag);
383 	err_when( j < 1 || j > total_effect );
384 	if( j > max_sound_effect )
385 		return res_supp.data_name(j - max_sound_effect);
386 	else
387 		return res_wave.data_name(j);
388 }
389 // ------ End Function SECtrl::get_effect_name -------//
390 
391 
392 // ------ Begin Function SECtrl::search_effect_id -------//
393 //
394 // find the sound effect id of an sound effect
395 //
396 // <char *> effectName      the name of the effect name
397 //
search_effect_id(const char * effectName)398 int SECtrl::search_effect_id(const char *effectName)
399 {
400 	err_when(!init_flag);
401 	if( !audio_flag )
402 		return 0;					// skip if audio cannot init wave device
403 
404 	int idx = res_wave.get_index(effectName);
405 	if( idx )
406 		return idx;
407 
408 	idx = res_supp.get_index(effectName);
409 	if( idx )
410 		return idx + max_sound_effect;
411 
412 	return 0;
413 }
414 // ------ End Function SECtrl::search_effect_id -------//
415 
416 
417 // ------ Begin Function SECtrl::search_effect_id -------//
418 //
419 // find the sound effect id of an sound effect
420 //
421 // <char *> effectName      the name of the effect name
422 // <int> len                the size of the effectName
423 //
search_effect_id(char * effectName,int len)424 int SECtrl::search_effect_id(char *effectName, int len)
425 {
426 	err_when(!init_flag);
427 	if( !audio_flag)
428 		return 0;					// skip if audio cannot init wave device
429 
430 	char tmpStr[16];
431 	err_when(len >= 16);
432 	memcpy(tmpStr, effectName, len);
433 	tmpStr[len] = '\0';
434 	misc.rtrim(tmpStr);
435 
436 	int idx = res_wave.get_index(tmpStr);
437 	if( idx )
438 		return idx;
439 
440 	idx = res_supp.get_index(tmpStr);
441 	if( idx )
442 		return idx + max_sound_effect;
443 
444 	return 0;
445 
446 }
447 // ------ End Function SECtrl::search_effect_id -------//
448 
449 /*
450 // ------ Begin Function SECtrl::sound_volume --------//
451 //
452 // calculate the volume from a location
453 //
454 // <short> locX, locY  - location x, y relative to the center of screen
455 // [short] limit       - volume is zero if dist > limit
456 // [short] drop        - volume is dropped (linearly) to zero when dist = drop
457 //                     drop > limit
458 //
459 
460 const default_vol_limit = 20;
461 const default_vol_drop = 100;
462 long SECtrl::sound_volume(short locX, short locY)
463 {
464 	short dist = MAX( locX >= 0? locX : -locX, locY >= 0? locY:-locY);
465 	err_when( default_vol_drop <= default_vol_limit);
466 
467 	if( dist > default_vol_limit)
468 		return 0;
469 	else
470 		return 90 - dist * 90 / default_vol_drop;
471 }
472 
473 
474 long SECtrl::sound_volume(short locX, short locY, short limit, short drop)
475 {
476 	short dist = MAX( locX >= 0? locX : -locX, locY >= 0? locY:-locY);
477 	err_when( drop <= limit);
478 
479 	if( dist > limit)
480 		return 0;
481 	else
482 		return 90 - dist * 90 / drop;
483 }
484 // ------ End Function SECtrl::sound_volume --------//
485 
486 
487 // ------ Begin Function SECtrl::sound_pan --------//
488 //
489 // calculate the pan setting of a location
490 //
491 // short locX, locY  - location x, y relative to the center of screen
492 // short drop        - panning is set to extreme value when abs(locX) >= drop
493 //
494 
495 const default_pan_drop = 100;
496 long SECtrl::sound_pan(short locX, short locY)
497 {
498 	if( locX >= default_pan_drop )
499 		return 10000;
500 	if( locX <= -default_pan_drop )
501 		return -10000;
502 	return 10000 / default_pan_drop * locX;
503 }
504 
505 
506 long SECtrl::sound_pan(short locX, short locY, short drop)
507 {
508 	if( locX >= drop )
509 		return 10000;
510 	if( locX <= -drop )
511 		return -10000;
512 	return 10000 * locX / drop;
513 }
514 // ------ End Function SECtrl::sound_pan --------//
515 */
516 
517 // ------- Begin Function SECtrl::immediate_sound ------------//
immediate_sound(const char * soundName,RelVolume relVolume)518 int SECtrl::immediate_sound(const char *soundName, RelVolume relVolume)
519 {
520 	if( !config.sound_effect_flag )
521 		return 0;
522 
523 	int effectId = search_effect_id(soundName);
524 	if( effectId )
525 	{
526 		SERequest *seRequest = req_pool + effectId-1;
527 		if( seRequest->wave_ptr )
528 			return audio_ptr->play_resided_wav( seRequest->wave_ptr, relVolume);
529 		else
530 			return audio_ptr->play_wav( seRequest->resx_id, relVolume);
531 	}
532 	return 0;
533 }
534 // ------- End Function SECtrl::immediate_sound ------------//
535