1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
27 static SoundInfo **Sound = NULL;
28 static MusicInfo **Music = NULL;
29 static int num_sounds = 0, num_music = 0;
30 static char **sound_name;
33 /* ========================================================================= */
34 /* THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
36 static struct AudioFormatInfo afmt =
38 TRUE, 0, DEFAULT_AUDIO_SAMPLE_RATE, DEFAULT_AUDIO_FRAGMENT_SIZE
41 static int playing_sounds = 0;
42 static struct SoundControl playlist[MAX_SOUNDS_PLAYING];
43 static struct SoundControl emptySoundControl =
45 -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE, 0,0, 0,NULL
48 #if defined(PLATFORM_UNIX)
49 static int stereo_volume[PSND_MAX_LEFT2RIGHT + 1];
50 static short premix_first_buffer[SND_BLOCKSIZE];
51 #if defined(AUDIO_STREAMING_DSP)
52 static short premix_left_buffer[SND_BLOCKSIZE];
53 static short premix_right_buffer[SND_BLOCKSIZE];
54 static long premix_last_buffer[SND_BLOCKSIZE];
56 static byte playing_buffer[SND_BLOCKSIZE];
59 /* forward declaration of internal functions */
60 #if defined(AUDIO_STREAMING_DSP)
61 static void SoundServer_InsertNewSound(struct SoundControl);
62 static void InitAudioDevice_DSP(struct AudioFormatInfo *);
63 #elif defined(PLATFORM_HPUX)
64 static void InitAudioDevice_HPUX(struct AudioFormatInfo *);
65 #elif defined(PLATFORM_UNIX)
66 static unsigned char linear_to_ulaw(int);
67 static int ulaw_to_linear(unsigned char);
68 #elif defined(PLATFORM_MSDOS)
69 static void SoundServer_InsertNewSound(struct SoundControl);
70 static void SoundServer_StopSound(struct SoundControl);
71 static void SoundServer_StopAllSounds();
74 static void ReloadCustomSounds();
75 static void ReloadCustomMusic();
76 static void FreeSound(SoundInfo *);
78 #if defined(PLATFORM_UNIX)
79 static int OpenAudioDevice(char *audio_device_name)
83 /* check if desired audio device is accessible */
84 if (access(audio_device_name, W_OK) != 0)
87 /* try to open audio device in non-blocking mode */
88 if ((audio_fd = open(audio_device_name, O_WRONLY | O_NONBLOCK)) < 0)
91 /* re-open audio device in blocking mode */
93 audio_fd = open(audio_device_name, O_WRONLY);
98 static boolean TestAudioDevices(void)
100 static char *audio_device_name[] =
108 /* look for available audio devices, starting with preferred ones */
109 for (i=0; i<sizeof(audio_device_name)/sizeof(char *); i++)
110 if ((audio_fd = OpenAudioDevice(audio_device_name[i])) >= 0)
115 Error(ERR_WARN, "cannot open audio device -- no sound");
121 audio.device_name = audio_device_name[i];
126 #if !defined(TARGET_SDL)
127 static boolean ForkAudioProcess(void)
129 if (pipe(audio.soundserver_pipe) < 0)
131 Error(ERR_WARN, "cannot create pipe -- no sounds");
135 if ((audio.soundserver_pid = fork()) < 0)
137 Error(ERR_WARN, "cannot create sound server process -- no sounds");
141 if (audio.soundserver_pid == 0) /* we are child process */
148 else /* we are parent */
149 close(audio.soundserver_pipe[0]); /* no reading from pipe needed */
155 void UnixOpenAudio(void)
157 if (!TestAudioDevices())
160 audio.sound_available = TRUE;
161 audio.sound_enabled = TRUE;
163 #if defined(AUDIO_STREAMING_DSP)
164 audio.music_available = TRUE;
165 audio.loops_available = TRUE;
169 void UnixCloseAudio(void)
172 close(audio.device_fd);
174 if (audio.soundserver_pid > 0) /* we are parent process */
175 kill(audio.soundserver_pid, SIGTERM);
177 #endif /* PLATFORM_UNIX */
179 void InitPlaylist(void)
183 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
184 playlist[i] = emptySoundControl;
188 void StartSoundserver(void)
190 if (!audio.sound_available)
193 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
194 if (!ForkAudioProcess())
195 audio.sound_available = FALSE;
199 #if defined(PLATFORM_UNIX)
200 void SoundServer(void)
204 struct SoundControl snd_ctrl;
207 close(audio.soundserver_pipe[1]); /* no writing into pipe needed */
211 stereo_volume[PSND_MAX_LEFT2RIGHT] = 0;
212 for(i=0; i<PSND_MAX_LEFT2RIGHT; i++)
214 (int)sqrt((float)(PSND_MAX_LEFT2RIGHT * PSND_MAX_LEFT2RIGHT - i * i));
216 #if defined(PLATFORM_HPUX)
217 InitAudioDevice_HPUX(&afmt);
220 FD_ZERO(&sound_fdset);
221 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
223 while(1) /* wait for sound playing commands from client */
225 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
226 select(audio.soundserver_pipe[0] + 1, &sound_fdset, NULL, NULL, NULL);
227 if (!FD_ISSET(audio.soundserver_pipe[0], &sound_fdset))
229 if (read(audio.soundserver_pipe[0], &snd_ctrl, sizeof(snd_ctrl))
231 Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
233 if (snd_ctrl.reload_sounds || snd_ctrl.reload_music)
235 char *set_name = checked_malloc(snd_ctrl.data_len);
237 (snd_ctrl.reload_sounds ? &artwork.snd_current : &artwork.mus_current);
238 TreeInfo *ti = *ti_ptr;
239 unsigned long str_size1, str_size2, str_size3;
241 if (leveldir_current == NULL)
242 leveldir_current = checked_calloc(sizeof(TreeInfo));
244 ti = *ti_ptr = checked_calloc(sizeof(TreeInfo));
245 if (leveldir_current->fullpath != NULL)
246 free(leveldir_current->fullpath);
247 if (ti->basepath != NULL)
249 if (ti->fullpath != NULL)
252 if (read(audio.soundserver_pipe[0], set_name,
253 snd_ctrl.data_len) != snd_ctrl.data_len ||
254 read(audio.soundserver_pipe[0], leveldir_current,
255 sizeof(TreeInfo)) != sizeof(TreeInfo) ||
256 read(audio.soundserver_pipe[0], ti,
257 sizeof(TreeInfo)) != sizeof(TreeInfo) ||
258 read(audio.soundserver_pipe[0], &str_size1,
259 sizeof(unsigned long)) != sizeof(unsigned long) ||
260 read(audio.soundserver_pipe[0], &str_size2,
261 sizeof(unsigned long)) != sizeof(unsigned long) ||
262 read(audio.soundserver_pipe[0], &str_size3,
263 sizeof(unsigned long)) != sizeof(unsigned long))
264 Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
266 leveldir_current->fullpath = checked_calloc(str_size1);
267 ti->basepath = checked_calloc(str_size2);
268 ti->fullpath = checked_calloc(str_size3);
270 if (read(audio.soundserver_pipe[0], leveldir_current->fullpath,
271 str_size1) != str_size1 ||
272 read(audio.soundserver_pipe[0], ti->basepath,
273 str_size2) != str_size2 ||
274 read(audio.soundserver_pipe[0], ti->fullpath,
275 str_size3) != str_size3)
276 Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
280 close(audio.device_fd);
282 if (snd_ctrl.reload_sounds)
284 artwork.sounds_set_current = set_name;
285 ReloadCustomSounds();
287 audio.func_reload_sounds();
292 artwork.music_set_current = set_name;
295 audio.func_reload_music();
304 #if defined(AUDIO_STREAMING_DSP)
306 if (snd_ctrl.fade_sound)
312 playlist[audio.music_channel].fade_sound = TRUE;
314 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
315 if (snd_ctrl.stop_all_sounds ||
316 (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr))
317 playlist[i].fade_sound = TRUE;
319 else if (snd_ctrl.stop_all_sounds)
324 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
325 playlist[i] = emptySoundControl;
328 close(audio.device_fd);
330 else if (snd_ctrl.stop_sound)
337 playlist[audio.music_channel] = emptySoundControl;
341 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
343 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr)
345 playlist[i] = emptySoundControl;
351 close(audio.device_fd);
354 if (playing_sounds || snd_ctrl.active)
356 if (playing_sounds ||
357 (audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
359 struct timeval delay = { 0, 0 };
361 if (!playing_sounds) /* we just opened the audio device */
362 InitAudioDevice_DSP(&afmt);
364 if (snd_ctrl.active) /* new sound has arrived */
365 SoundServer_InsertNewSound(snd_ctrl);
367 while (playing_sounds &&
368 select(audio.soundserver_pipe[0] + 1,
369 &sound_fdset, NULL, NULL, &delay) < 1)
372 int fragment_size = afmt.fragment_size;
373 int sample_bytes = (afmt.format & AUDIO_FORMAT_U8 ? 1 : 2);
374 boolean stereo = afmt.stereo;
376 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
378 max_sample_size = fragment_size / ((stereo ? 2 : 1) * sample_bytes);
380 /* first clear the last premixing buffer */
381 memset(premix_last_buffer, 0,
382 max_sample_size * (stereo ? 2 : 1) * sizeof(long));
384 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
392 if (!playlist[i].active)
395 /* pointer, lenght and actual playing position of sound sample */
396 sample_ptr = playlist[i].data_ptr;
397 sample_len = playlist[i].data_len;
398 sample_pos = playlist[i].playingpos;
399 sample_size = MIN(max_sample_size, sample_len - sample_pos);
400 playlist[i].playingpos += sample_size;
402 /* copy original sample to first mixing buffer */
403 if (playlist[i].format == AUDIO_FORMAT_U8)
404 for (j=0; j<sample_size; j++)
405 premix_first_buffer[j] =
406 ((short)(((byte *)sample_ptr)[sample_pos + j] ^ 0x80)) << 8;
407 else /* AUDIO_FORMAT_S16 */
408 for (j=0; j<sample_size; j++)
409 premix_first_buffer[j] =
410 ((short *)sample_ptr)[sample_pos + j];
412 /* are we about to restart a looping sound? */
413 if (playlist[i].loop && sample_size < max_sample_size)
415 while (sample_size < max_sample_size)
417 int restarted_sample_size =
418 MIN(max_sample_size - sample_size, sample_len);
420 if (playlist[i].format == AUDIO_FORMAT_U8)
421 for (j=0; j<restarted_sample_size; j++)
422 premix_first_buffer[sample_size + j] =
423 ((short)(((byte *)sample_ptr)[j] ^ 0x80)) << 8;
425 for (j=0; j<restarted_sample_size; j++)
426 premix_first_buffer[sample_size + j] =
427 ((short *)sample_ptr)[j];
429 playlist[i].playingpos = restarted_sample_size;
430 sample_size += restarted_sample_size;
434 /* decrease volume if sound is fading out */
435 if (playlist[i].fade_sound &&
436 playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
437 playlist[i].volume -= SOUND_FADING_VOLUME_STEP;
439 /* adjust volume of actual sound sample */
440 if (playlist[i].volume != PSND_MAX_VOLUME)
441 for(j=0; j<sample_size; j++)
442 premix_first_buffer[j] =
443 (playlist[i].volume * (long)premix_first_buffer[j])
444 >> PSND_MAX_VOLUME_BITS;
446 /* fill the last mixing buffer with stereo or mono sound */
449 int middle_pos = PSND_MAX_LEFT2RIGHT / 2;
450 int left_volume = stereo_volume[middle_pos + playlist[i].stereo];
451 int right_volume= stereo_volume[middle_pos - playlist[i].stereo];
453 for(j=0; j<sample_size; j++)
455 premix_left_buffer[j] =
456 (left_volume * premix_first_buffer[j])
457 >> PSND_MAX_LEFT2RIGHT_BITS;
458 premix_right_buffer[j] =
459 (right_volume * premix_first_buffer[j])
460 >> PSND_MAX_LEFT2RIGHT_BITS;
462 premix_last_buffer[2 * j + 0] += premix_left_buffer[j];
463 premix_last_buffer[2 * j + 1] += premix_right_buffer[j];
468 for(j=0; j<sample_size; j++)
469 premix_last_buffer[j] += premix_first_buffer[j];
472 /* delete completed sound entries from the playlist */
473 if (playlist[i].playingpos >= playlist[i].data_len)
475 if (playlist[i].loop)
476 playlist[i].playingpos = 0;
479 playlist[i] = emptySoundControl;
483 else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD)
485 playlist[i] = emptySoundControl;
490 /* prepare final playing buffer according to system audio format */
491 for(i=0; i<max_sample_size * (stereo ? 2 : 1); i++)
493 /* cut off at 17 bit value */
494 if (premix_last_buffer[i] < -65535)
495 premix_last_buffer[i] = -65535;
496 else if (premix_last_buffer[i] > 65535)
497 premix_last_buffer[i] = 65535;
499 /* shift to 16 bit value */
500 premix_last_buffer[i] >>= 1;
502 if (afmt.format & AUDIO_FORMAT_U8)
504 playing_buffer[i] = (premix_last_buffer[i] >> 8) ^ 0x80;
506 else if (afmt.format & AUDIO_FORMAT_LE) /* 16 bit */
508 playing_buffer[2 * i + 0] = premix_last_buffer[i] & 0xff;
509 playing_buffer[2 * i + 1] = premix_last_buffer[i] >> 8;
511 else /* big endian */
513 playing_buffer[2 * i + 0] = premix_last_buffer[i] >> 8;
514 playing_buffer[2 * i + 1] = premix_last_buffer[i] & 0xff;
518 /* finally play the sound fragment */
519 write(audio.device_fd, playing_buffer, fragment_size);
522 /* if no sounds playing, free device for other sound programs */
524 close(audio.device_fd);
528 #else /* !AUDIO_STREAMING_DSP */
530 if (snd_ctrl.active && !snd_ctrl.loop)
532 struct timeval delay = { 0, 0 };
534 long sample_size, max_sample_size = SND_BLOCKSIZE;
535 long sample_rate = 8000; /* standard "/dev/audio" sampling rate */
536 int wait_percent = 90; /* wait 90% of the real playing time */
539 if ((audio.device_fd = OpenAudioDevice(audio.device_name)) >= 0)
543 while (playing_sounds &&
544 select(audio.soundserver_pipe[0] + 1,
545 &sound_fdset, NULL, NULL, &delay) < 1)
547 FD_SET(audio.soundserver_pipe[0], &sound_fdset);
549 /* get pointer and size of the actual sound sample */
550 sample_ptr = snd_ctrl.data_ptr + snd_ctrl.playingpos;
552 MIN(max_sample_size, snd_ctrl.data_len - snd_ctrl.playingpos);
553 snd_ctrl.playingpos += sample_size;
555 /* fill the first mixing buffer with original sample */
556 memcpy(premix_first_buffer,sample_ptr,sample_size);
558 /* adjust volume of actual sound sample */
559 if (snd_ctrl.volume != PSND_MAX_VOLUME)
560 for(i=0;i<sample_size;i++)
561 premix_first_buffer[i] =
562 (snd_ctrl.volume * (int)premix_first_buffer[i])
563 >> PSND_MAX_VOLUME_BITS;
565 for(i=0;i<sample_size;i++)
567 linear_to_ulaw(((int)premix_first_buffer[i]) << 8);
569 if (snd_ctrl.playingpos >= snd_ctrl.data_len)
572 /* finally play the sound fragment */
573 write(audio.device_fd,playing_buffer,sample_size);
576 delay.tv_usec = ((sample_size*10*wait_percent)/(sample_rate))*1000;
578 close(audio.device_fd);
581 #endif /* !AUDIO_STREAMING_DSP */
584 #endif /* PLATFORM_UNIX */
586 #if defined(PLATFORM_MSDOS)
587 static void sound_handler(struct SoundControl snd_ctrl)
591 if (snd_ctrl.fade_sound)
596 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
597 if ((snd_ctrl.stop_all_sounds ||
598 (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr) ||
599 (i == audio.music_channel && snd_ctrl.music)) &&
600 !playlist[i].fade_sound)
602 playlist[i].fade_sound = TRUE;
603 if (voice_check(playlist[i].voice))
604 voice_ramp_volume(playlist[i].voice, 1000, 0);
605 playlist[i].loop = PSND_NO_LOOP;
608 else if (snd_ctrl.stop_all_sounds)
612 SoundServer_StopAllSounds();
614 else if (snd_ctrl.stop_sound)
618 SoundServer_StopSound(snd_ctrl);
621 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
623 if (!playlist[i].active || playlist[i].loop)
626 playlist[i].playingpos = voice_get_position(playlist[i].voice);
627 playlist[i].volume = voice_get_volume(playlist[i].voice);
628 if (playlist[i].playingpos == -1 || !playlist[i].volume)
630 deallocate_voice(playlist[i].voice);
631 playlist[i] = emptySoundControl;
637 SoundServer_InsertNewSound(snd_ctrl);
639 #endif /* PLATFORM_MSDOS */
641 #if !defined(PLATFORM_WIN32)
642 static void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
647 snd_ctrl.nr = snd_ctrl.nr % num_music;
649 /* if playlist is full, remove oldest sound */
650 if (playing_sounds == MAX_SOUNDS_PLAYING)
652 int longest = 0, longest_nr = 0;
654 for (i=0; i<MAX_SOUNDS_PLAYING; i++)
656 #if !defined(PLATFORM_MSDOS)
657 int actual = 100 * playlist[i].playingpos / playlist[i].data_len;
659 int actual = playlist[i].playingpos;
662 if (i != audio.music_channel && !playlist[i].loop && actual > longest)
668 #if defined(PLATFORM_MSDOS)
669 voice_set_volume(playlist[longest_nr].voice, 0);
670 deallocate_voice(playlist[longest_nr].voice);
672 playlist[longest_nr] = emptySoundControl;
676 /* check if sound is already being played (and how often) */
677 for (k=0,i=0; i<MAX_SOUNDS_PLAYING; i++)
678 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr)
681 /* restart loop sounds only if they are just fading out */
682 if (k >= 1 && snd_ctrl.loop)
684 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
686 if (i != audio.music_channel && playlist[i].nr == snd_ctrl.nr &&
687 playlist[i].fade_sound)
689 playlist[i].fade_sound = FALSE;
690 playlist[i].volume = PSND_MAX_VOLUME;
691 #if defined(PLATFORM_MSDOS)
692 playlist[i].loop = PSND_LOOP;
693 voice_stop_volumeramp(playlist[i].voice);
694 voice_ramp_volume(playlist[i].voice, playlist[i].volume, 1000);
702 /* don't play sound more than n times simultaneously (with n == 2 for now) */
705 int longest = 0, longest_nr = 0;
707 /* look for oldest equal sound */
708 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
712 if (!playlist[i].active ||
713 i == audio.music_channel ||
714 playlist[i].nr != snd_ctrl.nr)
717 #if !defined(PLATFORM_MSDOS)
718 actual = 100 * playlist[i].playingpos / playlist[i].data_len;
720 actual = playlist[i].playingpos;
722 if (actual >= longest)
729 #if defined(PLATFORM_MSDOS)
730 voice_set_volume(playlist[longest_nr].voice, 0);
731 deallocate_voice(playlist[longest_nr].voice);
733 playlist[longest_nr] = emptySoundControl;
737 /* add new sound to playlist */
738 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
740 if (!playlist[i].active ||
741 (snd_ctrl.music && i == audio.music_channel))
743 SoundInfo *snd_info =
744 (snd_ctrl.music ? Music[snd_ctrl.nr] : Sound[snd_ctrl.nr]);
746 snd_ctrl.data_ptr = snd_info->data_ptr;
747 snd_ctrl.data_len = snd_info->data_len;
748 snd_ctrl.format = snd_info->format;
750 playlist[i] = snd_ctrl;
753 #if defined(PLATFORM_MSDOS)
754 playlist[i].voice = allocate_voice((SAMPLE *)playlist[i].data_ptr);
757 voice_set_playmode(playlist[i].voice, PLAYMODE_LOOP);
759 voice_set_volume(playlist[i].voice, snd_ctrl.volume);
760 voice_set_pan(playlist[i].voice, snd_ctrl.stereo);
761 voice_start(playlist[i].voice);
767 #endif /* !PLATFORM_WIN32 */
770 void SoundServer_FadeSound(int nr)
777 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
778 if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
779 playlist[i].fade_sound = TRUE;
783 #if !defined(PLATFORM_WIN32)
784 #if defined(PLATFORM_MSDOS)
785 static void SoundServer_StopSound(struct SoundControl snd_ctrl)
787 int nr = snd_ctrl.nr;
793 for(i=0; i<MAX_SOUNDS_PLAYING; i++)
795 if ((i == audio.music_channel && snd_ctrl.music) ||
796 (i != audio.music_channel && playlist[i].nr == nr))
798 #if defined(PLATFORM_MSDOS)
799 voice_set_volume(playlist[i].voice, 0);
800 deallocate_voice(playlist[i].voice);
802 playlist[i] = emptySoundControl;
807 #if !defined(PLATFORM_MSDOS)
809 close(audio.device_fd);
813 static void SoundServer_StopAllSounds()
817 for(i=0;i<MAX_SOUNDS_PLAYING;i++)
819 #if defined(PLATFORM_MSDOS)
820 voice_set_volume(playlist[i].voice, 0);
821 deallocate_voice(playlist[i].voice);
823 playlist[i]=emptySoundControl;
827 #if !defined(PLATFORM_MSDOS)
828 close(audio.device_fd);
831 #endif /* PLATFORM_MSDOS */
832 #endif /* !PLATFORM_WIN32 */
835 /* ------------------------------------------------------------------------- */
836 /* platform dependant audio initialization code */
837 /* ------------------------------------------------------------------------- */
839 #if defined(AUDIO_LINUX_IOCTL)
840 static void InitAudioDevice_Linux(struct AudioFormatInfo *afmt)
842 /* "ioctl()" expects pointer to 'int' value for stereo flag
843 (boolean is defined as 'char', which will not work here) */
844 unsigned int fragment_spec = 0;
845 int fragment_size_query;
854 /* supported audio format in preferred order */
855 { AFMT_S16_LE, AUDIO_FORMAT_S16 | AUDIO_FORMAT_LE },
856 { AFMT_S16_BE, AUDIO_FORMAT_S16 | AUDIO_FORMAT_BE },
857 { AFMT_U8, AUDIO_FORMAT_U8 },
862 /* determine logarithm (log2) of the fragment size */
863 while ((1 << fragment_spec) < afmt->fragment_size)
866 /* use two fragments (play one fragment, prepare the other);
867 one fragment would result in interrupted audio output, more
868 than two fragments would raise audio output latency to much */
869 fragment_spec |= 0x00020000;
871 /* Example for fragment specification:
872 - 2 buffers / 512 bytes (giving 1/16 second resolution for 8 kHz)
873 - (with stereo the effective buffer size will shrink to 256)
874 => fragment_size = 0x00020009 */
876 if (ioctl(audio.device_fd, SNDCTL_DSP_SETFRAGMENT, &fragment_spec) < 0)
877 Error(ERR_EXIT_SOUND_SERVER,
878 "cannot set fragment size of /dev/dsp -- no sounds");
882 while (formats[i].format_result != -1)
884 unsigned int audio_format = formats[i].format_ioctl;
885 if (ioctl(audio.device_fd, SNDCTL_DSP_SETFMT, &audio_format) == 0)
887 afmt->format = formats[i].format_result;
892 if (afmt->format == 0) /* no supported audio format found */
893 Error(ERR_EXIT_SOUND_SERVER,
894 "cannot set audio format of /dev/dsp -- no sounds");
896 /* try if we can use stereo sound */
898 if (ioctl(audio.device_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
899 afmt->stereo = FALSE;
901 if (ioctl(audio.device_fd, SNDCTL_DSP_SPEED, &afmt->sample_rate) < 0)
902 Error(ERR_EXIT_SOUND_SERVER,
903 "cannot set sample rate of /dev/dsp -- no sounds");
905 /* get the real fragmentation size; this should return 512 */
906 if (ioctl(audio.device_fd, SNDCTL_DSP_GETBLKSIZE, &fragment_size_query) < 0)
907 Error(ERR_EXIT_SOUND_SERVER,
908 "cannot get fragment size of /dev/dsp -- no sounds");
909 if (fragment_size_query != afmt->fragment_size)
910 Error(ERR_EXIT_SOUND_SERVER,
911 "cannot set fragment size of /dev/dsp -- no sounds");
913 #endif /* AUDIO_LINUX_IOCTL */
915 #if defined(PLATFORM_NETBSD)
916 static void InitAudioDevice_NetBSD(struct AudioFormatInfo *afmt)
919 boolean stereo = TRUE;
921 AUDIO_INITINFO(&a_info);
922 a_info.play.encoding = AUDIO_ENCODING_LINEAR8;
923 a_info.play.precision = 8;
924 a_info.play.channels = 2;
925 a_info.play.sample_rate = sample_rate;
926 a_info.blocksize = fragment_size;
928 afmt->format = AUDIO_FORMAT_U8;
931 if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
933 /* try to disable stereo */
934 a_info.play.channels = 1;
936 afmt->stereo = FALSE;
938 if (ioctl(audio.device_fd, AUDIO_SETINFO, &a_info) < 0)
939 Error(ERR_EXIT_SOUND_SERVER,
940 "cannot set sample rate of /dev/audio -- no sounds");
943 #endif /* PLATFORM_NETBSD */
945 #if defined(PLATFORM_HPUX)
946 static void InitAudioDevice_HPUX(struct AudioFormatInfo *afmt)
948 struct audio_describe ainfo;
951 audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
953 Error(ERR_EXIT_SOUND_SERVER, "cannot open /dev/audioCtl -- no sounds");
955 if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
956 Error(ERR_EXIT_SOUND_SERVER, "no audio info -- no sounds");
958 if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
959 Error(ERR_EXIT_SOUND_SERVER, "ulaw audio not available -- no sounds");
961 ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
962 ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
964 afmt->format = AUDIO_FORMAT_U8;
965 afmt->stereo = FALSE;
966 afmt->sample_rate = 8000;
970 #endif /* PLATFORM_HPUX */
972 #if defined(PLATFORM_UNIX)
973 static void InitAudioDevice_DSP(struct AudioFormatInfo *afmt)
975 #if defined(AUDIO_LINUX_IOCTL)
976 InitAudioDevice_Linux(afmt);
977 #elif defined(PLATFORM_NETBSD)
978 InitAudioDevice_NetBSD(afmt);
979 #elif defined(PLATFORM_HPUX)
980 InitAudioDevice_HPUX(afmt);
983 #endif /* PLATFORM_UNIX */
985 #if defined(PLATFORM_UNIX) && !defined(AUDIO_STREAMING_DSP)
987 /* these two are stolen from "sox"... :) */
990 ** This routine converts from linear to ulaw.
992 ** Craig Reese: IDA/Supercomputing Research Center
993 ** Joe Campbell: Department of Defense
997 ** 1) CCITT Recommendation G.711 (very difficult to follow)
998 ** 2) "A New Digital Technique for Implementation of Any
999 ** Continuous PCM Companding Law," Villeret, Michel,
1000 ** et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
1001 ** 1973, pg. 11.12-11.17
1002 ** 3) MIL-STD-188-113,"Interoperability and Performance Standards
1003 ** for Analog-to_Digital Conversion Techniques,"
1006 ** Input: Signed 16 bit linear sample
1007 ** Output: 8 bit ulaw sample
1010 #define ZEROTRAP /* turn on the trap as per the MIL-STD */
1011 #define BIAS 0x84 /* define the add-in bias for 16 bit samples */
1014 static unsigned char linear_to_ulaw(int sample)
1016 static int exp_lut[256] =
1018 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
1019 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
1020 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
1021 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
1022 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1023 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1024 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1025 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1026 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1027 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1028 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1029 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1030 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1031 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1032 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1033 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
1036 int sign, exponent, mantissa;
1037 unsigned char ulawbyte;
1039 /* Get the sample into sign-magnitude. */
1040 sign = (sample >> 8) & 0x80; /* set aside the sign */
1042 sample = -sample; /* get magnitude */
1044 sample = CLIP; /* clip the magnitude */
1046 /* Convert from 16 bit linear to ulaw. */
1047 sample = sample + BIAS;
1048 exponent = exp_lut[( sample >> 7 ) & 0xFF];
1049 mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
1050 ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
1053 ulawbyte = 0x02; /* optional CCITT trap */
1060 ** This routine converts from ulaw to 16 bit linear.
1062 ** Craig Reese: IDA/Supercomputing Research Center
1063 ** 29 September 1989
1066 ** 1) CCITT Recommendation G.711 (very difficult to follow)
1067 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
1068 ** for Analog-to_Digital Conversion Techniques,"
1071 ** Input: 8 bit ulaw sample
1072 ** Output: signed 16 bit linear sample
1075 static int ulaw_to_linear(unsigned char ulawbyte)
1077 static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
1078 int sign, exponent, mantissa, sample;
1080 ulawbyte = ~ ulawbyte;
1081 sign = ( ulawbyte & 0x80 );
1082 exponent = ( ulawbyte >> 4 ) & 0x07;
1083 mantissa = ulawbyte & 0x0F;
1084 sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
1090 #endif /* PLATFORM_UNIX && !AUDIO_STREAMING_DSP */
1093 /* THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS */
1094 /* ========================================================================= */
1095 /* THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS */
1097 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
1098 #define WAV_HEADER_SIZE 16 /* size of WAV file header */
1100 static SoundInfo *Load_WAV(char *filename)
1102 SoundInfo *snd_info;
1103 #if !defined(TARGET_SDL) && !defined(PLATFORM_MSDOS)
1104 byte sound_header_buffer[WAV_HEADER_SIZE];
1105 char chunk_name[CHUNK_ID_LEN + 1];
1111 if (!audio.sound_available)
1115 printf("loading WAV file '%s'\n", filename);
1118 snd_info = checked_calloc(sizeof(SoundInfo));
1120 #if defined(TARGET_SDL)
1122 if ((snd_info->data_ptr = Mix_LoadWAV(filename)) == NULL)
1124 Error(ERR_WARN, "cannot read sound file '%s'", filename);
1129 #elif defined(TARGET_ALLEGRO)
1131 if ((snd_info->data_ptr = load_sample(filename)) == NULL)
1133 Error(ERR_WARN, "cannot read sound file '%s'", filename);
1138 #else /* PLATFORM_UNIX */
1140 if ((file = fopen(filename, MODE_READ)) == NULL)
1142 Error(ERR_WARN, "cannot open sound file '%s'", filename);
1147 /* read chunk id "RIFF" */
1148 getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN);
1149 if (strcmp(chunk_name, "RIFF") != 0)
1151 Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
1157 /* read "RIFF" type id "WAVE" */
1158 getFileChunk(file, chunk_name, NULL, BYTE_ORDER_LITTLE_ENDIAN);
1159 if (strcmp(chunk_name, "WAVE") != 0)
1161 Error(ERR_WARN, "missing 'WAVE' type ID of sound file '%s'", filename);
1167 while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_LITTLE_ENDIAN))
1169 if (strcmp(chunk_name, "fmt ") == 0)
1171 /* read header information */
1172 for (i=0; i < MIN(chunk_size, WAV_HEADER_SIZE); i++)
1173 sound_header_buffer[i] = fgetc(file);
1175 if (chunk_size > WAV_HEADER_SIZE)
1176 ReadUnusedBytesFromFile(file, chunk_size - WAV_HEADER_SIZE);
1178 else if (strcmp(chunk_name, "data") == 0)
1180 snd_info->data_len = chunk_size;
1181 snd_info->data_ptr = checked_malloc(snd_info->data_len);
1183 /* read sound data */
1184 if (fread(snd_info->data_ptr, 1, snd_info->data_len, file) !=
1187 Error(ERR_WARN,"cannot read 'data' chunk of sound file '%s'",filename);
1189 free(snd_info->data_ptr);
1194 /* check for odd number of sample bytes (data chunk is word aligned) */
1195 if ((chunk_size % 2) == 1)
1196 ReadUnusedBytesFromFile(file, 1);
1198 else /* unknown chunk -- ignore */
1199 ReadUnusedBytesFromFile(file, chunk_size);
1204 if (snd_info->data_ptr == NULL)
1206 Error(ERR_WARN, "missing 'data' chunk of sound file '%s'", filename);
1211 snd_info->format = AUDIO_FORMAT_U8;
1213 #endif /* PLATFORM_UNIX */
1215 snd_info->type = SND_TYPE_WAV;
1216 snd_info->source_filename = getStringCopy(filename);
1221 static void LoadCustomSound(SoundInfo **snd_info, char *basename)
1223 char *filename = getCustomSoundFilename(basename);
1225 if (filename == NULL) /* (should never happen) */
1227 Error(ERR_WARN, "cannot find sound file '%s'", basename);
1231 if (*snd_info && strcmp(filename, (*snd_info)->source_filename) == 0)
1233 /* The old and new sound are the same (have the same filename and path).
1234 This usually means that this sound does not exist in this sound set
1235 and a fallback to the existing sound is done. */
1241 FreeSound(*snd_info);
1243 *snd_info = Load_WAV(filename);
1246 void InitSoundList(char *sound_name_list[], int num_list_entries)
1249 Sound = checked_calloc(num_list_entries * sizeof(SoundInfo *));
1251 sound_name = sound_name_list;
1252 num_sounds = num_list_entries;
1255 void LoadSoundToList(char *basename, int list_pos)
1257 if (Sound == NULL || list_pos >= num_sounds)
1260 LoadCustomSound(&Sound[list_pos], basename);
1263 static MusicInfo *Load_MOD(char *filename)
1265 #if defined(TARGET_SDL)
1266 MusicInfo *mod_info;
1268 if (!audio.sound_available)
1271 mod_info = checked_calloc(sizeof(MusicInfo));
1273 if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL)
1275 Error(ERR_WARN, "cannot read music file '%s'", filename);
1280 mod_info->type = MUS_TYPE_MOD;
1281 mod_info->source_filename = getStringCopy(filename);
1289 void LoadCustomMusic(void)
1291 char *music_directory = getCustomMusicDirectory();
1293 struct dirent *dir_entry;
1295 if (!audio.sound_available)
1298 if ((dir = opendir(music_directory)) == NULL)
1300 Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
1301 audio.music_available = FALSE;
1305 while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
1307 char *basename = dir_entry->d_name;
1308 char *filename = getPath2(music_directory, basename);
1309 MusicInfo *mus_info = NULL;
1311 if (FileIsSound(basename))
1312 mus_info = Load_WAV(filename);
1313 else if (FileIsMusic(basename))
1314 mus_info = Load_MOD(filename);
1321 Music = checked_realloc(Music, num_music * sizeof(MusicInfo *));
1322 Music[num_music -1] = mus_info;
1329 Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
1333 void PlayMusic(int nr)
1335 if (!audio.music_available)
1338 #if defined(TARGET_SDL)
1340 nr = nr % num_music;
1342 if (Music[nr]->type == MUS_TYPE_MOD)
1344 Mix_PlayMusic(Music[nr]->data_ptr, -1);
1345 Mix_VolumeMusic(SOUND_MAX_VOLUME); /* must be _after_ Mix_PlayMusic()! */
1347 else /* play WAV music loop */
1349 Mix_Volume(audio.music_channel, SOUND_MAX_VOLUME);
1350 Mix_PlayChannel(audio.music_channel, Music[nr]->data_ptr, -1);
1360 void PlaySound(int nr)
1362 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
1365 void PlaySoundStereo(int nr, int stereo)
1367 PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
1370 void PlaySoundLoop(int nr)
1372 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
1375 void PlaySoundMusic(int nr)
1377 PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_MUSIC);
1380 void PlaySoundExt(int nr, int volume, int stereo, boolean loop_type)
1382 struct SoundControl snd_ctrl = emptySoundControl;
1384 if (!audio.sound_available ||
1385 !audio.sound_enabled ||
1386 audio.sound_deactivated)
1389 if (volume < PSND_MIN_VOLUME)
1390 volume = PSND_MIN_VOLUME;
1391 else if (volume > PSND_MAX_VOLUME)
1392 volume = PSND_MAX_VOLUME;
1394 if (stereo < PSND_MAX_LEFT)
1395 stereo = PSND_MAX_LEFT;
1396 else if (stereo > PSND_MAX_RIGHT)
1397 stereo = PSND_MAX_RIGHT;
1400 snd_ctrl.volume = volume;
1401 snd_ctrl.stereo = stereo;
1402 snd_ctrl.loop = (loop_type != PSND_NO_LOOP);
1403 snd_ctrl.music = (loop_type == PSND_MUSIC);
1404 snd_ctrl.active = TRUE;
1407 /* now only used internally in sound server child process */
1408 snd_ctrl.data_ptr = Sound[nr].data_ptr;
1409 snd_ctrl.data_len = Sound[nr].data_len;
1412 #if defined(TARGET_SDL)
1413 Mix_Volume(-1, SOUND_MAX_VOLUME);
1414 Mix_PlayChannel(-1, Sound[nr]->data_ptr, (loop_type ? -1 : 0));
1415 #elif defined(PLATFORM_UNIX)
1416 if (audio.soundserver_pid == 0) /* we are child process */
1419 if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1421 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1422 audio.sound_available = audio.sound_enabled = FALSE;
1425 #elif defined(PLATFORM_MSDOS)
1426 sound_handler(snd_ctrl);
1430 void FadeMusic(void)
1432 if (!audio.sound_available)
1435 #if defined(TARGET_SDL)
1436 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1437 Mix_FadeOutChannel(audio.music_channel, SOUND_FADING_INTERVAL);
1439 StopSoundExt(-1, SSND_FADE_MUSIC);
1443 void FadeSound(int nr)
1445 StopSoundExt(nr, SSND_FADE_SOUND);
1451 StopSoundExt(-1, SSND_FADE_ALL);
1454 void StopMusic(void)
1456 #if defined(TARGET_SDL)
1457 if (!audio.sound_available)
1461 Mix_HaltChannel(audio.music_channel);
1463 StopSoundExt(-1, SSND_STOP_MUSIC);
1467 void StopSound(int nr)
1469 StopSoundExt(nr, SSND_STOP_SOUND);
1474 StopSoundExt(-1, SSND_STOP_ALL);
1477 void StopSoundExt(int nr, int method)
1479 struct SoundControl snd_ctrl = emptySoundControl;
1481 if (!audio.sound_available)
1484 if (method & SSND_FADING)
1485 snd_ctrl.fade_sound = TRUE;
1487 if (method & SSND_ALL)
1488 snd_ctrl.stop_all_sounds = TRUE;
1491 snd_ctrl.stop_sound = TRUE;
1495 if (method & SSND_MUSIC)
1496 snd_ctrl.music = TRUE;
1498 #if defined(TARGET_SDL)
1500 if (method & SSND_FADING)
1504 for (i=0; i<audio.channels; i++)
1505 if (i != audio.music_channel || snd_ctrl.music)
1506 Mix_FadeOutChannel(i, SOUND_FADING_INTERVAL);
1508 Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
1514 for (i=0; i<audio.channels; i++)
1515 if (i != audio.music_channel || snd_ctrl.music)
1521 #elif !defined(PLATFORM_MSDOS)
1523 if (audio.soundserver_pid == 0) /* we are child process */
1526 if (write(audio.soundserver_pipe[1], &snd_ctrl, sizeof(snd_ctrl)) < 0)
1528 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1529 audio.sound_available = audio.sound_enabled = FALSE;
1533 sound_handler(snd_ctrl);
1537 static void ReloadCustomSounds()
1542 printf("DEBUG: reloading sounds '%s' ...\n", artwork.sounds_set_current);
1547 for(i=0; i<num_sounds; i++)
1548 LoadSoundToList(sound_name[i], i);
1551 static void ReloadCustomMusic()
1554 printf("DEBUG: reloading music '%s' ...\n", artwork.music_set_current);
1562 static void InitReloadSoundsOrMusic(char *set_name, int type)
1564 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
1565 struct SoundControl snd_ctrl = emptySoundControl;
1567 (type == SND_RELOAD_SOUNDS ? artwork.snd_current : artwork.mus_current);
1568 unsigned long str_size1 = strlen(leveldir_current->fullpath) + 1;
1569 unsigned long str_size2 = strlen(ti->basepath) + 1;
1570 unsigned long str_size3 = strlen(ti->fullpath) + 1;
1573 if (!audio.sound_available)
1576 #if defined(TARGET_SDL) || defined(TARGET_ALLEGRO)
1577 if (type == SND_RELOAD_SOUNDS)
1578 audio.func_reload_sounds();
1580 audio.func_reload_music();
1581 #elif defined(PLATFORM_UNIX)
1582 if (audio.soundserver_pid == 0) /* we are child process */
1585 if (leveldir_current == NULL) /* should never happen */
1586 Error(ERR_EXIT, "leveldir_current == NULL");
1588 snd_ctrl.reload_sounds = (type == SND_RELOAD_SOUNDS);
1589 snd_ctrl.reload_music = (type == SND_RELOAD_MUSIC);
1590 snd_ctrl.data_len = strlen(set_name) + 1;
1592 if (write(audio.soundserver_pipe[1], &snd_ctrl,
1593 sizeof(snd_ctrl)) < 0 ||
1594 write(audio.soundserver_pipe[1], set_name,
1595 snd_ctrl.data_len) < 0 ||
1596 write(audio.soundserver_pipe[1], leveldir_current,
1597 sizeof(TreeInfo)) < 0 ||
1598 write(audio.soundserver_pipe[1], ti,
1599 sizeof(TreeInfo)) < 0 ||
1600 write(audio.soundserver_pipe[1], &str_size1,
1601 sizeof(unsigned long)) < 0 ||
1602 write(audio.soundserver_pipe[1], &str_size2,
1603 sizeof(unsigned long)) < 0 ||
1604 write(audio.soundserver_pipe[1], &str_size3,
1605 sizeof(unsigned long)) < 0 ||
1606 write(audio.soundserver_pipe[1], leveldir_current->fullpath,
1608 write(audio.soundserver_pipe[1], ti->basepath,
1610 write(audio.soundserver_pipe[1], ti->fullpath,
1613 Error(ERR_WARN, "cannot pipe to child process -- no sounds");
1614 audio.sound_available = audio.sound_enabled = FALSE;
1620 void InitReloadSounds(char *set_name)
1622 InitReloadSoundsOrMusic(set_name, SND_RELOAD_SOUNDS);
1625 void InitReloadMusic(char *set_name)
1627 InitReloadSoundsOrMusic(set_name, SND_RELOAD_MUSIC);
1630 void FreeSound(SoundInfo *sound)
1635 if (sound->data_ptr)
1637 #if defined(TARGET_SDL)
1638 Mix_FreeChunk(sound->data_ptr);
1639 #elif defined(TARGET_ALLEGRO)
1640 destroy_sample(sound->data_ptr);
1641 #else /* PLATFORM_UNIX */
1642 free(sound->data_ptr);
1649 void FreeMusic(MusicInfo *music)
1654 if (music->data_ptr)
1656 #if defined(TARGET_SDL)
1657 if (music->type == MUS_TYPE_MOD)
1658 Mix_FreeMusic(music->data_ptr);
1660 Mix_FreeChunk(music->data_ptr);
1661 #elif defined(TARGET_ALLEGRO)
1662 destroy_sample(music->data_ptr);
1663 #else /* PLATFORM_UNIX */
1664 free(music->data_ptr);
1671 void FreeAllSounds()
1678 for(i=0; i<num_sounds; i++)
1679 FreeSound(Sound[i]);
1694 for(i=0; i<num_music; i++)
1695 FreeMusic(Music[i]);
1703 /* THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS */
1704 /* ========================================================================= */