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