1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 
6 #ifdef HAVE_Y2
7 # include <Y2/Y.h>	/* We get Y_H defined by #including this. */
8 # include <Y2/Ylib.h>
9 # include <Y2/Ymixercodes.h>
10 #endif	/* HAVE_Y2 */
11 
12 #include "../include/string.h"
13 #include "../include/disk.h"
14 
15 #include "sound.h"
16 #include "sar.h"
17 
18 
19 #ifdef Y_H
20 /* Default values for Y. */
21 # ifndef DEF_Y_CONNECT_ARG
22 #  define DEF_Y_CONNECT_ARG		"127.0.0.1:9433"
23 # endif
24 # ifndef DEF_Y_AUDIO_MODE_NAME
25 #  define DEF_Y_AUDIO_MODE_NAME		"Default"
26 # endif
27 #endif	/* Y_H */
28 
29 
30 
31 snd_recorder_struct *SoundInit(
32 	void *core,
33 	int type,
34 	const char *connect_arg,
35 	const char *start_arg,
36 	void *window
37 );
38 int SoundManageEvents(snd_recorder_struct *recorder);
39 void SoundShutdown(snd_recorder_struct *recorder);
40 
41 int SoundChangeMode(
42 	snd_recorder_struct *recorder, const char *mode_name
43 );
44 
45 snd_play_struct *SoundStartPlay(
46 	snd_recorder_struct *recorder,
47 	const char *object,
48 	float volume_left, float volume_right,
49 	int sample_rate,
50 	snd_flags_t options
51 );
52 void SoundStartPlayVoid(
53 	snd_recorder_struct *recorder,
54 	const char *object,
55 	float volume_left, float volume_right,
56 	int sample_rate,
57 	snd_flags_t options
58 );
59 
60 void SoundPlayMute(
61 	snd_recorder_struct *recorder,
62 	snd_play_struct *snd_play,
63 	int mute
64 );
65 void SoundChangePlayVolume(
66 	snd_recorder_struct *recorder,
67 	snd_play_struct *snd_play,
68 	float volume_left, float volume_right
69 );
70 void SoundChangePlaySampleRate(
71 	snd_recorder_struct *recorder,
72 	snd_play_struct *snd_play,
73 	int sample_rate
74 );
75 
76 void SoundStopPlay(
77 	snd_recorder_struct *recorder,
78 	snd_play_struct *snd_play
79 );
80 
81 
82 int SoundMusicStartPlay(
83 	snd_recorder_struct *recorder,
84 	const char *object,     /* Full path to object. */
85 	int repeats             /* Number of repeats, -1 for infinate. */
86 );
87 int SoundMusicIsPlaying(snd_recorder_struct *recorder);
88 void SoundMusicStopPlay(snd_recorder_struct *recorder);
89 
90 #ifdef Y_H
91 static int SoundGetYMixerCode(const char *channel_name);
92 #endif
93 void SoundMixerGet(
94 	snd_recorder_struct *recorder, const char *channel_name,
95 	float *left, float *right	/* 0.0 to 1.0 */
96 );
97 void SoundMixerSet(
98 	snd_recorder_struct *recorder, const char *channel_name,
99 	float left, float right		/* 0.0 to 1.0 */
100 );
101 
102 
103 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
104 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
105 #define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
106 
107 
108 /*
109  *	Initializes sound server and returns a newly allocated
110  *	recorder structure.
111  */
SoundInit(void * core,int type,const char * connect_arg,const char * start_arg,void * window)112 snd_recorder_struct *SoundInit(
113 	void *core,
114 	int type,
115 	const char *connect_arg,
116 	const char *start_arg,
117 	void *window
118 )
119 {
120 	snd_recorder_struct *recorder;
121 	const sar_option_struct *opt;
122         int my_type = type;
123 
124         #ifdef SDL_H
125         int audio_rate = 22050;
126         Uint16 audio_format = AUDIO_S16SYS;
127         int audio_channels = 2;
128         int audio_buffers = 4096;
129         if (type == SOUND_DEFAULT)
130             my_type = SNDSERV_TYPE_SDL;
131         #endif
132         #ifdef Y_H
133         if (type == SOUND_DEFAULT)
134            my_type = SNDSERV_TYPE_Y;
135         #endif
136 
137 	sar_core_struct *core_ptr = SAR_CORE(core);
138 	if(core_ptr == NULL)
139 	    return(NULL);
140 
141 	opt = &core_ptr->option;
142 
143 	recorder = (snd_recorder_struct *)calloc(
144 	    1, sizeof(snd_recorder_struct)
145 	);
146 	if(recorder == NULL)
147 	    return(NULL);
148 
149 	recorder->type = my_type;
150 	recorder->con = NULL;
151 	recorder->sample_rate = 0;
152 	recorder->sample_size = 0;
153 	recorder->channels = 0;
154 	recorder->bytes_per_cycle = 0;
155 	recorder->background_music_sndobj = NULL;
156 
157 	/* Initialize by sound server type. */
158 	switch(my_type)
159 	{
160 	  case SNDSERV_TYPE_Y:
161 #ifdef Y_H
162 	    if(connect_arg == NULL)
163 		connect_arg = (const char *)getenv("RECORDER");
164 	    if(connect_arg == NULL)
165 		connect_arg = DEF_Y_CONNECT_ARG;
166 
167 	    /* Connect to sound server. */
168 #ifdef __MSW__
169 	    recorder->con = (void *)YOpenConnectionWin32(
170 		start_arg, connect_arg, opt->sound_priority, window
171 	    );
172 #else
173 	    recorder->con = (void *)YOpenConnection(
174 		start_arg, connect_arg
175 	    );
176 #endif
177 	    /* Failed to connect? */
178 	    if(recorder->con == NULL)
179 	    {
180 		free(recorder);
181 		return(NULL);
182 	    }
183 
184 	    /* Record sound server type. */
185 	    recorder->type = type;
186 
187 	    if(opt->runtime_debug)
188 		printf(
189 "SoundInit(): Initialized sound server at \"%s\".\n",
190 		    connect_arg
191 		);
192 #endif	/* Y_H */
193 	    if(recorder->con == NULL)
194 	    {
195 		fprintf(
196 		    stderr,
197 		    "SoundInit(): No sound support.\n"
198 		);
199 		free(recorder);
200 		return(NULL);
201 	    }
202 	    break;
203 
204          case SNDSERV_TYPE_SDL:
205          #ifdef SDL_H
206               if (SDL_Init(SDL_INIT_AUDIO) != 0)
207               {
208                   printf("Unable to Initialize SDL sound.\n");
209                   return NULL;
210               }
211 
212               if ( Mix_OpenAudio(audio_rate, audio_format,
213                                  audio_channels, audio_buffers) != 0)
214               {
215 	           printf("Unable to initialize audio: %s\n", Mix_GetError());
216                    return NULL;
217               }
218           #endif
219             break;
220 
221 	  default:
222 	    fprintf(
223 		stderr,
224 		"SoundInit(): Unsupported sound server type `%i'.\n",
225 		my_type
226 	    );
227 	    free(recorder);
228 	    return(NULL);
229 	    break;
230 	}
231 
232 	return(recorder);
233 }
234 
235 
236 /*
237  *	Manages sound server events.
238  *
239  *	Returns the number of events recieved or -1 on error.
240  *
241  *	If -1 is returned then recorder has become invalid and should
242  *	not be referenced again. This usually means the sound server
243  *	has shut down, the connection to the sound server was broken, or
244  *	some other fatal error occured.
245  */
SoundManageEvents(snd_recorder_struct * recorder)246 int SoundManageEvents(snd_recorder_struct *recorder)
247 {
248 	int events_handled = 0;
249 
250 
251 	if(recorder == NULL)
252 	    return(-1);
253 
254 	switch(recorder->type)
255 	{
256 	  case SNDSERV_TYPE_Y:
257 #ifdef Y_H
258 
259 /* Macro to return the YID of a given pointer to a snd_play_struct. */
260 #define GET_SND_PLAY_YID(p)		\
261  (((p) != NULL) ? (YID)((snd_play_struct *)(p)->data) : YIDNULL)
262 
263 /* Macro to set the given snd_play_struct pointer's member data to
264  * YIDNULL.
265  */
266 #define SET_SND_PLAY_YID_NULL(p)	\
267  { if((p) != NULL) (p)->data = (void *)YIDNULL; }
268 
269 	    if(recorder->con != NULL)
270 	    {
271 		YConnection *con = (YConnection *)recorder->con;
272 		YEvent event;
273 		YEventSoundKill *kill;
274 		YEventMixer *mixer;
275 
276 		/* Begin queued Y events. */
277 		while(YGetNextEvent(
278 		    con,
279 		    &event,
280 		    False		/* Do not block. */
281 		) > 0)
282 		{
283 		    events_handled++;
284 
285 		    switch(event.type)
286 		    {
287 		      case YDisconnect: case YShutdown:
288 			/* Y server has disconnected or shutdown, the
289 			 * connection structure needs to be closed,
290 			 * deallocated, and set to NULL.
291 			 */
292 			YCloseConnection(con, False);
293 			recorder->con = con = NULL;
294 
295 if(event.type == YShutdown)
296  fprintf(
297   stderr,
298   "Lost connection to Y server: Y server has shut down.\n"
299  );
300 else
301  fprintf(
302   stderr,
303   "Lost connection to Y server: Y server has disconnected us.\n"
304  );
305 
306 			/* Deallocate recorder structure and return
307 			 * indicating that the recorder should not be
308 			 * referenced again.
309 			 */
310 			free(recorder);
311 			return(-1);
312 			break;
313 
314 		      /* Sound object has stopped playing. */
315 		      case YSoundObjectKill:
316 			kill = &event.kill;
317 			if(kill->yid != YIDNULL)
318 			{
319 			    YID yid = kill->yid;
320 
321 			    /* Begin checking which sound object this is. */
322 			    /* Background music? */
323 			    if(yid == GET_SND_PLAY_YID(recorder->background_music_sndobj))
324 			    {
325 				SET_SND_PLAY_YID_NULL(recorder->background_music_sndobj);
326 				SoundStopPlay(
327 				    recorder,
328 				    recorder->background_music_sndobj
329 				);
330 				recorder->background_music_sndobj = NULL;
331 			    }
332 			}
333 			break;
334 
335 		      case YMixerChannel:
336 			mixer = &event.mixer;
337 			switch(mixer->code)
338 			{
339 			  case YMixerCodeVolume:
340 			    break;
341 			  case YMixerCodeSynth:
342 			    break;
343 			  case YMixerCodePCM:
344 			    break;
345 			}
346 			break;
347 		    }
348 		}	/* Handle queued Y events. */
349 	    }
350 #undef SET_SND_PLAY_YID_NULL
351 #undef GET_SND_PLAY_YID
352 #endif  /* Y_H */
353 	    break;
354 
355           case SNDSERV_TYPE_SDL:
356             /* not sure if we need something here....
357               will simply return with OK value */
358             return 0;
359             break;
360 	  default:
361 	    free(recorder);
362 	    return(-1);
363 	    break;
364 	}
365 
366 	return(events_handled);
367 }
368 
369 /*
370  *      Shuts down the sound server, all resources on the given recorder
371  *	structure will be deallocated and the recorder structure itself
372  *	will be deallocated. The recorder should not be referenced again
373  *	after this call.
374  */
SoundShutdown(snd_recorder_struct * recorder)375 void SoundShutdown(
376 	snd_recorder_struct *recorder
377 )
378 {
379 	if(recorder == NULL)
380 	    return;
381 
382 	/* Stop related resources first. */
383 	SoundMusicStopPlay(recorder);
384 
385 	/* Shut down sound server by type. */
386 	switch(recorder->type)
387 	{
388 	  case SNDSERV_TYPE_Y:
389 #ifdef Y_H
390 	    if(recorder->con != NULL)
391 	    {
392 		YConnection *con = (YConnection *)recorder->con;
393 
394 		/* Close connection to server. */
395 		YCloseConnection(con, False);
396 		recorder->con = con = NULL;
397 	    }
398 #endif  /* Y_H */
399 	    break;
400            case SNDSERV_TYPE_SDL:
401            #ifdef SDL_H
402            Mix_CloseAudio();
403            SDL_QuitSubSystem(SDL_INIT_AUDIO);
404            #endif
405            break;
406 
407 	}
408 
409 	/* Deallocate recorder structure. */
410 	free(recorder);
411 }
412 
413 
414 
415 /*
416  *	Changes audio mode to the one specified by mode_name.
417  *
418  *	Returns 0 on success or -1 on error.
419  */
SoundChangeMode(snd_recorder_struct * recorder,const char * mode_name)420 int SoundChangeMode(
421 	snd_recorder_struct *recorder, const char *mode_name
422 )
423 {
424 	if(recorder == NULL)
425 	    return(-1);
426 
427 	switch(recorder->type)
428 	{
429 	  case SNDSERV_TYPE_Y:
430 #ifdef Y_H
431 	    if(recorder->con != NULL)
432 	    {
433 		YConnection *con = (YConnection *)recorder->con;
434 		YAudioModeValuesStruct **ptr, *yaudio_mode;
435 		int i, total_yaudio_modes;
436 
437 		int sample_rate = 0;
438 		int sample_size = 0;
439 		int channels = 0;
440 		int fragment_size_bytes = 0;
441 
442 
443 		if(mode_name == NULL)
444 		    mode_name = DEF_Y_AUDIO_MODE_NAME;
445 
446 		/* Get listing of available Audio mode. */
447 		ptr = YGetAudioModes(con, &total_yaudio_modes);
448 
449 		/* Check if specified Audio mode is in list. */
450 		for(i = 0; i < total_yaudio_modes; i++)
451 		{
452 		    yaudio_mode = ptr[i];
453 		    if(yaudio_mode == NULL)
454 			continue;
455 
456 		    if(yaudio_mode->name == NULL)
457 			continue;
458 
459 		    /* Audio mode names match? */
460 		    if(!strcasecmp(yaudio_mode->name, mode_name))
461 		    {
462 			sample_rate = yaudio_mode->sample_rate;
463 			sample_size = yaudio_mode->sample_size;
464 			channels = yaudio_mode->sample_rate;
465 			fragment_size_bytes = yaudio_mode->fragment_size_bytes;
466 			break;
467 		    }
468 		}
469 		/* Free Audio modes listing. */
470 		YFreeAudioModesList(ptr, total_yaudio_modes);
471 
472 	        /* Audio mode name in list? */
473 	        if(i >= total_yaudio_modes)
474 		{
475 		    /* Could not match audio mode name from server's list
476 		     * of audio mode names. So we need to return -1 here.
477 		     */
478 		    return(-1);
479 		}
480 
481 	        /* Change Audio mode. */
482 		if(YChangeAudioModePreset(con, mode_name))
483 		    return(-1);
484 
485 		/* Record new Audio values on our recorder structure. */
486 		recorder->sample_rate = sample_rate;
487 		recorder->sample_size = sample_size;
488 		recorder->channels = channels;
489 		recorder->bytes_per_cycle = fragment_size_bytes;
490 	    }
491 #endif	/* Y_H */
492 	    break;
493 
494 	}
495 
496 	return(0);
497 }
498 
499 
500 /*
501  *	Plays a sound object by given object path. Returns a dynamically
502  *	allocated structure containing the play information or NULL on failure.
503  */
SoundStartPlay(snd_recorder_struct * recorder,const char * object,float volume_left,float volume_right,int sample_rate,snd_flags_t options)504 snd_play_struct *SoundStartPlay(
505 	snd_recorder_struct *recorder,
506 	const char *object,	/* Full path to sound object. */
507 	float volume_left,     /* Volume, from 0.0 to 1.0. */
508 	float volume_right,
509 	int sample_rate,        /* Applied sample rate, can be 0. */
510 	snd_flags_t options     /* Any of SND_PLAY_OPTION_*. */
511 )
512 {
513         int repeat = 0;
514 	snd_play_struct *snd_play = NULL;
515         #ifdef SDL_H
516         Mix_Chunk *sound = NULL;
517         #endif
518 
519 	if((recorder == NULL) || (object == NULL))
520 	    return(snd_play);
521 
522 	switch(recorder->type)
523 	{
524 	  case SNDSERV_TYPE_Y:
525 #ifdef Y_H
526 	    if(recorder->con != NULL)
527 	    {
528 		YConnection *con = (YConnection *)recorder->con;
529 		YID yid;
530 		YEventSoundPlay value;
531 
532 		/* Set up sound play values. */
533 		value.flags = YPlayValuesFlagPosition |
534 			      YPlayValuesFlagTotalRepeats |
535 			      YPlayValuesFlagVolume |
536 			      YPlayValuesFlagSampleRate;
537 		value.position = 0;
538 		value.total_repeats = ((options & SND_PLAY_OPTION_REPEATING) ?
539 		    -1 : 1
540 		);
541 		value.left_volume = CLIP(
542 		    (options & SND_PLAY_OPTION_MUTE) ? 0.0 : volume_left,
543 		    0.0, 1.0
544 		);
545 		value.right_volume = CLIP(
546 		    (options & SND_PLAY_OPTION_MUTE) ? 0.0 : volume_right,
547 		    0.0, 1.0
548 		);
549 		value.sample_rate = sample_rate;
550 
551 		/* Start playing sound object. */
552 		yid = YStartPlaySoundObject(
553 		    con,
554 		    object,
555 		    &value
556 		);
557 		if(yid == YIDNULL)
558 		    return(NULL);
559 
560 		/* Allocate sound play structure. */
561 		snd_play = (snd_play_struct *)calloc(
562 		    1, sizeof(snd_play_struct)
563 		);
564 		if(snd_play == NULL)
565 		    return(NULL);
566 
567 		/* Record values. */
568 		snd_play->data = (void *)yid;
569 		snd_play->volume_left = (float)value.left_volume;
570 		snd_play->volume_right = (float)value.right_volume;
571 		snd_play->sample_rate = sample_rate;
572 		snd_play->options = options;
573 	    }
574 #endif	/* Y_H */
575 	    break;
576             case SNDSERV_TYPE_SDL:
577             #ifdef SDL_H
578             sound = Mix_LoadWAV(object);
579                if (! sound)
580                   return NULL;
581             snd_play = (snd_play_struct *) calloc(1, sizeof(snd_play_struct));
582             if (! snd_play)
583                 return NULL;
584             if (options & SND_PLAY_OPTION_MUTE)
585             {
586                volume_left = 0.0;
587                volume_right = 0.0;
588             }
589             else
590             {
591                volume_left = 1.0;
592                volume_right = 1.0;
593             }
594             if (options & SND_PLAY_OPTION_REPEATING)
595                 repeat = -1;
596             else
597                 repeat = 0;
598             snd_play->volume_left = volume_left;
599             snd_play->volume_right = volume_right;
600             snd_play->sample_rate = sample_rate;
601             snd_play->options = options;
602             snd_play->data = (void *)Mix_PlayChannel(-1, sound, repeat);
603             snd_play->chunk = sound;
604             #endif
605             break;
606 
607 	}
608 
609 	return(snd_play);
610 }
611 
612 /*
613  *	Same as SoundStartPlay() except no reference is returned and there
614  *	is no way to control the sound object being played after it has
615  *	started playing (except for calling SoundShutdown()).
616  */
SoundStartPlayVoid(snd_recorder_struct * recorder,const char * object,float volume_left,float volume_right,int sample_rate,snd_flags_t options)617 void SoundStartPlayVoid(
618 	snd_recorder_struct *recorder,
619 	const char *object,	/* Full path to sound object. */
620 	float volume_left,	/* Volume, from 0.0 to 1.0. */
621 	float volume_right,
622 	int sample_rate,        /* Applied sample rate, can be 0. */
623 	snd_flags_t options     /* Any of SND_PLAY_OPTION_*. */
624 )
625 {
626         #ifdef SDL_H
627         Mix_Chunk *sound = NULL;
628         #endif
629 
630 	if((recorder == NULL) || (object == NULL))
631 	    return;
632 
633 	switch(recorder->type)
634 	{
635 	  case SNDSERV_TYPE_Y:
636 #ifdef Y_H
637 	    if(recorder->con != NULL)
638 	    {
639 		YConnection *con = (YConnection *)recorder->con;
640 		YID yid;
641 		YEventSoundPlay value;
642 
643 		/* Set up sound play values. */
644 		value.flags = YPlayValuesFlagPosition |
645 			      YPlayValuesFlagTotalRepeats |
646 			      YPlayValuesFlagVolume |
647 			      YPlayValuesFlagSampleRate;
648 		value.position = 0;
649 		value.total_repeats = ((options & SND_PLAY_OPTION_REPEATING) ?
650 		    -1 : 1
651 		);
652 		value.left_volume = CLIP(
653 		    (options & SND_PLAY_OPTION_MUTE) ? 0.0 : volume_left,
654 		    0.0, 1.0
655 		);
656 		value.right_volume = CLIP(
657 		    (options & SND_PLAY_OPTION_MUTE) ? 0.0 : volume_right,
658 		    0.0, 1.0
659 		);
660 		value.sample_rate = sample_rate;
661 
662 		/* Start playing sound object. */
663 		yid = YStartPlaySoundObject(con, object, &value);
664 		if(yid == YIDNULL)
665 		    return;
666 	    }
667 #endif  /* Y_H */
668 	    break;
669             case SNDSERV_TYPE_SDL:
670             #ifdef SDL_H
671             sound = Mix_LoadWAV(object);
672             if (sound)
673                 Mix_PlayChannel(-1, sound, 0);
674             #endif
675             break;
676 
677 	}
678 }
679 
680 /*
681  *	Mutes or unmutes a sound object already playing.
682  */
SoundPlayMute(snd_recorder_struct * recorder,snd_play_struct * snd_play,int mute)683 void SoundPlayMute(
684 	snd_recorder_struct *recorder, snd_play_struct *snd_play,
685 	int mute
686 )
687 {
688 	if((recorder == NULL) || (snd_play == NULL))
689 	    return;
690 
691 	if(mute)
692 	    snd_play->options |= SND_PLAY_OPTION_MUTE;
693 	else
694 	    snd_play->options &= ~SND_PLAY_OPTION_MUTE;
695 
696 	SoundChangePlayVolume(
697 	    recorder, snd_play,
698 	    snd_play->volume_left, snd_play->volume_right
699 	);
700 }
701 
702 /*
703  *	Changes the volume of the sound object already playing.
704  */
SoundChangePlayVolume(snd_recorder_struct * recorder,snd_play_struct * snd_play,float volume_left,float volume_right)705 void SoundChangePlayVolume(
706 	snd_recorder_struct *recorder, snd_play_struct *snd_play,
707 	float volume_left,     /* Volume, from 0.0 to 1.0. */
708 	float volume_right
709 )
710 {
711 	if((recorder == NULL) || (snd_play == NULL))
712 	    return;
713 
714 	/* Change in volume? */
715 	if((volume_left == snd_play->volume_left) &&
716 	   (volume_right == snd_play->volume_right)
717 	)
718 	    return;
719 
720 	switch(recorder->type)
721 	{
722 	  case SNDSERV_TYPE_Y:
723 #ifdef Y_H
724 	    if((recorder->con != NULL) &&
725 	       (snd_play->data != NULL)
726 	    )
727 	    {
728 		YConnection *con = (YConnection *)recorder->con;
729 		YID yid = (YID)snd_play->data;
730 		YEventSoundPlay value;
731 
732 
733 		/* Set up sound play values. */
734 		value.flags = YPlayValuesFlagVolume;
735 		value.left_volume = CLIP(
736 		    (snd_play->options & SND_PLAY_OPTION_MUTE) ? 0.0 : volume_left,
737 		    0.0, 1.0
738 		);
739 		value.right_volume = CLIP(
740 		    (snd_play->options & SND_PLAY_OPTION_MUTE) ? 0.0 : volume_right,
741 		    0.0, 1.0
742 		);
743 
744 		/* Change play sound object values. */
745 		YSetPlaySoundObjectValues(con, yid, &value);
746 
747 		/* Record values. */
748 		snd_play->volume_left = (float)value.left_volume;
749 		snd_play->volume_right = (float)value.right_volume;
750 	    }
751 #endif  /* Y_H */
752 	    break;
753             case SNDSERV_TYPE_SDL:
754             #ifdef SDL_H
755                 snd_play->volume_left = volume_left;
756                 snd_play->volume_right = volume_right;
757                 if (snd_play->data)
758                 {
759                    int my_volume;
760                    my_volume = (int) (volume_left * MIX_MAX_VOLUME);
761                    Mix_Volume((int) snd_play->data, my_volume);
762                 }
763             #endif
764             break;
765 
766 	}
767 }
768 
769 /*
770  *      Changes the sample rate of the sound object already playing.
771  */
SoundChangePlaySampleRate(snd_recorder_struct * recorder,snd_play_struct * snd_play,int sample_rate)772 void SoundChangePlaySampleRate(
773 	snd_recorder_struct *recorder,
774 	snd_play_struct *snd_play,
775 	int sample_rate         /* Applied sample rate, can be 0. */
776 )
777 {
778 	if((recorder == NULL) || (snd_play == NULL))
779 	    return;
780 
781 	/* Change in applied sample rate? */
782 	if(sample_rate == snd_play->sample_rate)
783 	    return;
784 
785 	switch(recorder->type)
786 	{
787 	  case SNDSERV_TYPE_Y:
788 #ifdef Y_H
789 	    if((recorder->con != NULL) &&
790 	       (snd_play->data != NULL)
791 	    )
792 	    {
793 		YConnection *con = (YConnection *)recorder->con;
794 		YID yid = (YID)snd_play->data;
795 		YEventSoundPlay value;
796 
797 
798 		if(sample_rate < 0)
799 		    sample_rate = 0;
800 
801 		/* Set up sound play values. */
802 		value.flags = YPlayValuesFlagSampleRate;
803 		value.sample_rate = sample_rate;
804 
805 		/* Change play sound object values. */
806 		YSetPlaySoundObjectValues(con, yid, &value);
807 
808 		/* Record values. */
809 		snd_play->sample_rate = sample_rate;
810 	    }
811 #endif  /* Y_H */
812 	    break;
813 
814 	}
815 }
816 
817 /*
818  *	Stops a sound object already playing and deallocates the given
819  *	snd_play structure. The snd_play structure should not be
820  *	referenced again after this call. The snd_play structure will be
821  *	deallocated even if recorder is NULL. However recorder should
822  *	always be given if available.
823  */
SoundStopPlay(snd_recorder_struct * recorder,snd_play_struct * snd_play)824 void SoundStopPlay(
825 	snd_recorder_struct *recorder, snd_play_struct *snd_play
826 )
827 {
828 #define DO_FREE_PLAY_STRUCT	\
829 { if(snd_play != NULL) { free(snd_play); snd_play = NULL; } }
830 
831 	if(recorder == NULL)
832 	{
833 	    DO_FREE_PLAY_STRUCT
834 	    return;
835 	}
836 
837 	if(snd_play == NULL)
838 	    return;
839 
840 	switch(recorder->type)
841 	{
842 	  case SNDSERV_TYPE_Y:
843 #ifdef Y_H
844 	    if((recorder->con != NULL) &&
845 	       ((YID)snd_play->data != YIDNULL)
846 	    )
847 	    {
848 		YConnection *con = (YConnection *)recorder->con;
849 		YID yid = (YID)snd_play->data;
850 
851 		YDestroyPlaySoundObject(con, yid);
852 		snd_play->data = (void *)YIDNULL;
853 	    }
854 #endif	/* Y_H */
855 	    break;
856             case SNDSERV_TYPE_SDL:
857             #ifdef SDL_H
858                  Mix_HaltChannel((int) snd_play->data);
859                  Mix_FreeChunk(snd_play->chunk);
860             #endif
861             break;
862 	}
863 
864 	DO_FREE_PLAY_STRUCT
865 #undef DO_FREE_PLAY_STRUCT
866 }
867 
868 
869 
870 /*
871  *	Starts playing the given background music sound object specified
872  *	by object. If an existing background music sound object is being
873  *	played then it will be stopped first.
874  *
875  *	The given repeats can be -1 for infinate repeating (only stopped
876  *	when another background music sound object begins to play or when
877  *	the sound server shuts down).
878  *
879  *	Returns non-zero on error.
880  */
SoundMusicStartPlay(snd_recorder_struct * recorder,const char * object,int repeats)881 int SoundMusicStartPlay(
882 	snd_recorder_struct *recorder,
883 	const char *object,     /* Full path to object. */
884 	int repeats             /* Number of repeats, -1 for infinate. */
885 )
886 {
887 	snd_play_struct *snd_play = NULL;
888 
889         #ifdef SDL_H
890         Mix_Chunk *sound;
891         #endif
892 
893 	if((recorder == NULL) || (object == NULL))
894 	    return(-1);
895 
896 	/* Stop currently playing background music if any. */
897 	SoundMusicStopPlay(recorder);
898 
899 	/* Unable to destroy background music sound object? */
900 	if(recorder->background_music_sndobj != NULL)
901 	    return(-1);
902 
903 
904 	switch(recorder->type)
905 	{
906 	  case SNDSERV_TYPE_Y:
907 #ifdef Y_H
908 	    if(recorder->con != NULL)
909 	    {
910 		YConnection *con = (YConnection *)recorder->con;
911 		YID yid;
912 		YEventSoundPlay value;
913 
914 
915 		/* Set up sound play values. */
916 		value.flags = YPlayValuesFlagPosition |
917 			      YPlayValuesFlagTotalRepeats |
918 			      YPlayValuesFlagVolume |
919 			      YPlayValuesFlagSampleRate;
920 		value.position = 0;
921 		value.total_repeats = repeats;
922 		value.left_volume = 1.0;
923 		value.right_volume = 1.0;
924 		value.sample_rate = recorder->sample_rate;
925 
926 		/* Start playing sound object. */
927 		yid = YStartPlaySoundObject(con, object, &value);
928 		if(yid == YIDNULL)
929 		    return(-1);
930 
931 		/* Allocate background music sound play structure. */
932 		recorder->background_music_sndobj = snd_play = (snd_play_struct *)calloc(
933 		    1, sizeof(snd_play_struct)
934 		);
935 		if(snd_play == NULL)
936 		    return(-1);
937 
938 		/* Record values. */
939 		snd_play->data = (void *)yid;
940 		snd_play->volume_left = (float)value.left_volume;
941 		snd_play->volume_right = (float)value.right_volume;
942 		snd_play->sample_rate = value.sample_rate;
943 		snd_play->options = 0;
944 	    }
945 #endif  /* Y_H */
946 	    break;
947             case SNDSERV_TYPE_SDL:
948             #ifdef SDL_H
949                 snd_play = (snd_play_struct *) calloc(1, sizeof(snd_play_struct));
950                 if (! snd_play)
951                   return -1;
952                 sound = Mix_LoadWAV(object);
953                 if (! sound)
954                 {
955                     free(snd_play);
956                     return -1;
957                 }
958                 snd_play->data = (void *) Mix_PlayChannel(-1, sound, 0);
959                 recorder->background_music_sndobj = snd_play;
960             #endif
961             break;
962 
963 	}
964 
965 	return(0);
966 }
967 
968 /*
969  *	Returns true if there is a background music sound object playing
970  *	on the specified recorder.
971  */
SoundMusicIsPlaying(snd_recorder_struct * recorder)972 int SoundMusicIsPlaying(snd_recorder_struct *recorder)
973 {
974 	return((recorder != NULL) ?
975 	    (recorder->background_music_sndobj != NULL) : 0
976 	);
977 }
978 
979 /*
980  *	Stops playing the background music sound object (if any).
981  */
SoundMusicStopPlay(snd_recorder_struct * recorder)982 void SoundMusicStopPlay(snd_recorder_struct *recorder)
983 {
984 	if(recorder == NULL)
985 	    return;
986 
987 	if(recorder->background_music_sndobj != NULL)
988 	{
989 	    SoundStopPlay(
990 		recorder,
991 		recorder->background_music_sndobj
992 	    );
993 	    recorder->background_music_sndobj = NULL;
994 	}
995 /* printf("SoundMusicStopPlay()\n"); */
996 }
997 
998 
999 #ifdef Y_H
1000 /*
1001  *	Returns one of YMixerCode* based on channel_name or -1 on
1002  *	error.
1003  */
SoundGetYMixerCode(const char * channel_name)1004 static int SoundGetYMixerCode(const char *channel_name)
1005 {
1006 	if(channel_name == NULL)
1007 	    return(-1);
1008 
1009 	if(!strcasecmp(channel_name, "volume"))
1010 	    return(YMixerCodeVolume);
1011 	else if(!strcasecmp(channel_name, "midi"))
1012 	    return(YMixerCodeSynth);
1013 	else if(!strcasecmp(channel_name, "wav"))
1014 	    return(YMixerCodePCM);
1015 	else
1016 	    return(-1);
1017 }
1018 #endif
1019 
1020 /*
1021  *	Obtains the mixer channel's values.
1022  */
SoundMixerGet(snd_recorder_struct * recorder,const char * channel_name,float * left,float * right)1023 void SoundMixerGet(
1024 	snd_recorder_struct *recorder, const char *channel_name,
1025 	float *left, float *right       /* 0.0 to 1.0 */
1026 )
1027 {
1028 	if(left != NULL)
1029 	    *left = 0.0f;
1030 	if(right != NULL)
1031 	    *right = 0.0f;
1032 
1033 	if(recorder == NULL)
1034 	    return;
1035 
1036 	switch(recorder->type)
1037 	{
1038 	  case SNDSERV_TYPE_Y:
1039 #ifdef Y_H
1040 	    if(recorder->con != NULL)
1041 	    {
1042 		YConnection *con = (YConnection *)recorder->con;
1043 		int mixer_channel_code = SoundGetYMixerCode(channel_name);
1044 		Coefficient v[2];
1045 
1046 		if(mixer_channel_code > -1)
1047 		{
1048 		    YGetMixerChannel(
1049 			con, mixer_channel_code,
1050 			&v[0], &v[1]
1051 		    );
1052 		    if(left != NULL)
1053 			*left = (float)v[0];
1054 		    if(right != NULL)
1055 			*right = (float)v[1];
1056 		}
1057 	    }
1058 #endif	/* Y_H */
1059 	    break;
1060 	}
1061 }
1062 
1063 /*
1064  *	Sets the mixer channel value.
1065  */
SoundMixerSet(snd_recorder_struct * recorder,const char * channel_name,float left,float right)1066 void SoundMixerSet(
1067 	snd_recorder_struct *recorder, const char *channel_name,
1068 	float left, float right         /* 0.0 to 1.0 */
1069 )
1070 {
1071 	if(recorder == NULL)
1072 	    return;
1073 
1074 	switch(recorder->type)
1075 	{
1076 	  case SNDSERV_TYPE_Y:
1077 #ifdef Y_H
1078 	    if(recorder->con != NULL)
1079 	    {
1080 		YConnection *con = (YConnection *)recorder->con;
1081 		int mixer_channel_code = SoundGetYMixerCode(channel_name);
1082 		Coefficient v[2];
1083 
1084 		if(mixer_channel_code > -1)
1085 		{
1086 		    v[0] = left;
1087 		    v[1] = right;
1088 		    YSetMixerChannel(
1089 			con, mixer_channel_code,
1090 			v[0], v[1]
1091 		    );
1092 /*printf("Set %i: %.2f %.2f\n", mixer_channel_code, v[0], v[1]);*/
1093 		}
1094 	    }
1095 #endif  /* Y_H */
1096 	    break;
1097 	}
1098 }
1099