+#if 0
+ printf("SOUND %d [CURRENTLY PLAYING %d TIMES]\n", snd_ctrl.nr, k);
+#endif
+
+ /* reset expiration delay for already playing loop sounds */
+ if (k > 0 && IS_LOOP(snd_ctrl))
+ {
+ for (i = audio.first_sound_channel; i < audio.num_channels; i++)
+ {
+ if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
+ {
+#if 0
+ printf("RESETTING EXPIRATION FOR SOUND %d\n", snd_ctrl.nr);
+#endif
+
+ if (IS_FADING(mixer[i]))
+ Mixer_UnFadeChannel(i);
+
+ /* restore settings like volume and stereo position */
+ mixer[i].volume = snd_ctrl.volume;
+ mixer[i].stereo_position = snd_ctrl.stereo_position;
+
+ Mixer_SetChannelProperties(i);
+ Mixer_ResetChannelExpiration(i);
+
+#if 0
+ printf("RESETTING VOLUME/STEREO FOR SOUND %d TO %d/%d\n",
+ snd_ctrl.nr, snd_ctrl.volume, snd_ctrl.stereo_position);
+#endif
+ }
+ }
+
+ return;
+ }
+
+#if 0
+ printf("PLAYING NEW SOUND %d\n", snd_ctrl.nr);
+#endif
+
+ /* don't play sound more than n times simultaneously (with n == 2 for now) */
+ if (k >= 2)
+ {
+ unsigned long playing_current = Counter();
+ int longest = 0, longest_nr = audio.first_sound_channel;
+
+ /* look for oldest equal sound */
+ for (i = audio.first_sound_channel; i < audio.num_channels; i++)
+ {
+ int playing_time = playing_current - mixer[i].playing_starttime;
+ int actual;
+
+ if (!mixer[i].active || !SAME_SOUND_NR(mixer[i], snd_ctrl))
+ continue;
+
+ actual = 1000 * playing_time / mixer[i].data_len;
+
+ if (actual >= longest)
+ {
+ longest = actual;
+ longest_nr = i;
+ }
+ }
+
+ Mixer_StopChannel(longest_nr);
+ }
+
+ /* If all (non-music) channels are active, stop the channel that has
+ played its sound sample most completely (in percent of the sample
+ length). As we cannot currently get the actual playing position
+ of the channel's sound sample when compiling with the SDL mixer
+ library, we use the current playing time (in milliseconds) instead. */
+
+#if DEBUG
+ /* channel allocation sanity check -- should not be needed */
+ if (mixer_active_channels ==
+ audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
+ {
+ for (i = audio.first_sound_channel; i < audio.num_channels; i++)
+ {
+ if (!mixer[i].active)
+ {
+ Error(ERR_RETURN, "Mixer_InsertSound: Channel %d inactive", i);
+ Error(ERR_RETURN, "Mixer_InsertSound: This should never happen!");
+
+ mixer_active_channels--;
+ }
+ }
+ }
+#endif
+
+ if (mixer_active_channels ==
+ audio.num_channels - (mixer[audio.music_channel].active ? 0 : 1))
+ {
+ unsigned long playing_current = Counter();
+ int longest = 0, longest_nr = audio.first_sound_channel;
+
+#if 0
+#if DEBUG
+ /* print some debugging information about audio channel usage */
+ for (i = audio.first_sound_channel; i < audio.num_channels; i++)
+ {
+ Error(ERR_RETURN, "Mixer_InsertSound: %d [%d]: %ld (%ld)",
+ i, mixer[i].active, mixer[i].data_len, (long)mixer[i].data_ptr);
+ }
+#endif
+#endif
+
+ for (i = audio.first_sound_channel; i < audio.num_channels; i++)
+ {
+ int playing_time = playing_current - mixer[i].playing_starttime;
+ int actual = 1000 * playing_time / mixer[i].data_len;
+
+ if (!IS_LOOP(mixer[i]) && actual > longest)
+ {
+ longest = actual;
+ longest_nr = i;
+ }
+ }
+
+ Mixer_StopChannel(longest_nr);
+ }
+
+ /* add the new sound to the mixer */
+ for (i = audio.first_sound_channel; i < audio.num_channels; i++)
+ {
+#if 0
+ printf("CHECKING CHANNEL %d FOR SOUND %d ...\n", i, snd_ctrl.nr);
+#endif
+
+ if (!mixer[i].active)
+ {
+#if 0
+ printf("ADDING NEW SOUND %d TO MIXER\n", snd_ctrl.nr);
+#endif
+
+#if defined(AUDIO_UNIX_NATIVE)
+ if (snd_info->data_len == 0)
+ {
+ printf("THIS SHOULD NEVER HAPPEN! [snd_info->data_len == 0]\n");
+ }
+#endif
+
+ mixer[i] = snd_ctrl;
+ Mixer_PlayChannel(i);
+
+ break;
+ }
+ }
+}
+
+static void HandleSoundRequest(SoundControl snd_ctrl)
+{
+ int i;
+
+#if defined(AUDIO_UNIX_NATIVE)
+ if (IS_PARENT_PROCESS())
+ {
+ SendSoundControlToMixerProcess(&snd_ctrl);
+ return;
+ }
+#endif
+
+ /* deactivate channels that have expired since the last request */
+ for (i = 0; i < audio.num_channels; i++)
+ if (mixer[i].active && Mixer_ChannelExpired(i))
+ Mixer_StopChannel(i);
+
+ if (IS_RELOADING(snd_ctrl)) /* load new sound or music files */
+ {
+ Mixer_StopMusicChannel();
+ for (i = audio.first_sound_channel; i < audio.num_channels; i++)
+ Mixer_StopChannel(i);
+
+#if defined(AUDIO_UNIX_NATIVE)
+ CloseAudioDevice(&audio.device_fd);
+ ReadReloadInfoFromPipe(&snd_ctrl);
+#endif
+
+ if (snd_ctrl.state & SND_CTRL_RELOAD_SOUNDS)
+ ReloadCustomSounds();
+ else
+ ReloadCustomMusic();
+ }
+ else if (IS_FADING(snd_ctrl)) /* fade out existing sound or music */
+ {
+ if (IS_MUSIC(snd_ctrl))
+ {
+ Mixer_FadeMusicChannel();
+ return;
+ }
+
+ for (i = audio.first_sound_channel; i < audio.num_channels; i++)
+ if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
+ Mixer_FadeChannel(i);
+ }
+ else if (IS_STOPPING(snd_ctrl)) /* stop existing sound or music */
+ {
+ if (IS_MUSIC(snd_ctrl))
+ {
+ Mixer_StopMusicChannel();
+ return;
+ }