+static void ReadReloadInfoFromPipe(SoundControl *snd_ctrl)
+{
+ TreeInfo **ti_ptr = ((snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS) ?
+ &artwork.snd_current : &artwork.mus_current);
+ TreeInfo *ti = *ti_ptr;
+ unsigned long str_size1, str_size2, str_size3, str_size4, str_size5;
+ static char *set_identifier = NULL;
+ boolean *override_level_artwork = (snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS ?
+ &setup.override_level_sounds :
+ &setup.override_level_music);
+
+ if (set_identifier)
+ free(set_identifier);
+
+ set_identifier = checked_malloc(snd_ctrl->data_len);
+
+ if (leveldir_current == NULL)
+ leveldir_current = checked_calloc(sizeof(TreeInfo));
+
+ if (ti == NULL)
+ ti = *ti_ptr = checked_calloc(sizeof(TreeInfo));
+ if (leveldir_current->fullpath != NULL)
+ free(leveldir_current->fullpath);
+ if (leveldir_current->sounds_path != NULL)
+ free(leveldir_current->sounds_path);
+ if (leveldir_current->music_path != NULL)
+ free(leveldir_current->music_path);
+ if (ti->basepath != NULL)
+ free(ti->basepath);
+ if (ti->fullpath != NULL)
+ free(ti->fullpath);
+
+ if (read(audio.mixer_pipe[0], set_identifier,
+ snd_ctrl->data_len) != snd_ctrl->data_len ||
+ read(audio.mixer_pipe[0], override_level_artwork,
+ sizeof(boolean)) != sizeof(boolean) ||
+ read(audio.mixer_pipe[0], leveldir_current,
+ sizeof(TreeInfo)) != sizeof(TreeInfo) ||
+ read(audio.mixer_pipe[0], ti,
+ sizeof(TreeInfo)) != sizeof(TreeInfo) ||
+ read(audio.mixer_pipe[0], &str_size1,
+ sizeof(unsigned long)) != sizeof(unsigned long) ||
+ read(audio.mixer_pipe[0], &str_size2,
+ sizeof(unsigned long)) != sizeof(unsigned long) ||
+ read(audio.mixer_pipe[0], &str_size3,
+ sizeof(unsigned long)) != sizeof(unsigned long) ||
+ read(audio.mixer_pipe[0], &str_size4,
+ sizeof(unsigned long)) != sizeof(unsigned long) ||
+ read(audio.mixer_pipe[0], &str_size5,
+ sizeof(unsigned long)) != sizeof(unsigned long))
+ Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
+
+ leveldir_current->fullpath = checked_calloc(str_size1);
+ leveldir_current->sounds_path = checked_calloc(str_size2);
+ leveldir_current->music_path = checked_calloc(str_size3);
+ ti->basepath = checked_calloc(str_size4);
+ ti->fullpath = checked_calloc(str_size5);
+
+ if (read(audio.mixer_pipe[0], leveldir_current->fullpath,
+ str_size1) != str_size1 ||
+ read(audio.mixer_pipe[0], leveldir_current->sounds_path,
+ str_size2) != str_size2 ||
+ read(audio.mixer_pipe[0], leveldir_current->music_path,
+ str_size3) != str_size3 ||
+ read(audio.mixer_pipe[0], ti->basepath,
+ str_size4) != str_size4 ||
+ read(audio.mixer_pipe[0], ti->fullpath,
+ str_size5) != str_size5)
+ Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
+
+ if (snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS)
+ artwork.snd_current_identifier = set_identifier;
+ else
+ artwork.mus_current_identifier = set_identifier;
+}
+
+#endif /* AUDIO_UNIX_NATIVE */
+
+
+/* ------------------------------------------------------------------------- */
+/* mixer functions */
+/* ------------------------------------------------------------------------- */
+
+void Mixer_InitChannels()
+{
+ int i;
+
+ for(i=0; i<audio.num_channels; i++)
+ mixer[i].active = FALSE;
+ mixer_active_channels = 0;
+}
+
+static void Mixer_ResetChannelExpiration(int channel)
+{
+ mixer[channel].playing_starttime = Counter();
+
+#if defined(TARGET_SDL)
+ if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]))
+ Mix_ExpireChannel(channel, SOUND_LOOP_EXPIRATION_TIME);
+#endif
+}
+
+static boolean Mixer_ChannelExpired(int channel)
+{
+ if (!mixer[channel].active)
+ return TRUE;
+
+ if (IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) &&
+ DelayReached(&mixer[channel].playing_starttime,
+ SOUND_LOOP_EXPIRATION_TIME))
+ return TRUE;
+
+#if defined(TARGET_SDL)
+
+ if (!Mix_Playing(channel))
+ return TRUE;
+
+#elif defined(TARGET_ALLEGRO)
+
+ mixer[channel].playing_pos = voice_get_position(mixer[channel].voice);
+ mixer[channel].volume = voice_get_volume(mixer[channel].voice);
+
+ /* sound sample has completed playing or was completely faded out */
+ if (mixer[channel].playing_pos == -1 || mixer[channel].volume == 0)
+ return TRUE;
+
+#endif /* TARGET_ALLEGRO */
+
+ return FALSE;
+}
+
+static boolean Mixer_AllocateChannel(int channel)
+{
+#if defined(TARGET_ALLEGRO)
+ mixer[channel].voice = allocate_voice((SAMPLE *)mixer[channel].data_ptr);
+ if (mixer[channel].voice < 0)
+ return FALSE;
+#endif
+
+ return TRUE;
+}
+
+static void Mixer_SetChannelProperties(int channel)
+{
+#if defined(TARGET_SDL)
+ Mix_Volume(channel, mixer[channel].volume);
+ Mix_SetPanning(channel,
+ SOUND_VOLUME_LEFT(mixer[channel].stereo_position),
+ SOUND_VOLUME_RIGHT(mixer[channel].stereo_position));
+#elif defined(TARGET_ALLEGRO)
+ voice_set_volume(mixer[channel].voice, mixer[channel].volume);
+ voice_set_pan(mixer[channel].voice, mixer[channel].stereo_position);
+#endif
+}
+
+static void Mixer_StartChannel(int channel)
+{
+#if defined(TARGET_SDL)
+ Mix_PlayChannel(channel, mixer[channel].data_ptr,
+ IS_LOOP(mixer[channel]) ? -1 : 0);
+#elif defined(TARGET_ALLEGRO)
+ if (IS_LOOP(mixer[channel]))
+ voice_set_playmode(mixer[channel].voice, PLAYMODE_LOOP);
+
+ voice_start(mixer[channel].voice);
+#endif
+}
+
+static void Mixer_PlayChannel(int channel)
+{
+ /* start with inactive channel in case something goes wrong */
+ mixer[channel].active = FALSE;
+
+ if (mixer[channel].type != MUS_TYPE_WAV)
+ return;
+
+ if (!Mixer_AllocateChannel(channel))
+ return;
+
+ Mixer_SetChannelProperties(channel);
+ Mixer_StartChannel(channel);
+
+ Mixer_ResetChannelExpiration(channel);
+
+ mixer[channel].playing_pos = 0;
+ mixer[channel].active = TRUE;
+ mixer_active_channels++;
+}
+
+static void Mixer_PlayMusicChannel()
+{
+ Mixer_PlayChannel(audio.music_channel);
+
+#if defined(TARGET_SDL)
+ if (mixer[audio.music_channel].type != MUS_TYPE_WAV)
+ {
+ /* Mix_VolumeMusic() must be called _after_ Mix_PlayMusic() --
+ this looks like a bug in the SDL_mixer library */
+ Mix_PlayMusic(mixer[audio.music_channel].data_ptr, -1);
+ Mix_VolumeMusic(SOUND_MAX_VOLUME);
+ }
+#endif
+}
+
+static void Mixer_StopChannel(int channel)
+{
+ if (!mixer[channel].active)
+ return;
+
+#if defined(TARGET_SDL)
+ Mix_HaltChannel(channel);
+#elif defined(TARGET_ALLEGRO)
+ voice_set_volume(mixer[channel].voice, 0);
+ deallocate_voice(mixer[channel].voice);
+#endif
+
+ mixer[channel].active = FALSE;
+ mixer_active_channels--;
+}
+
+static void Mixer_StopMusicChannel()
+{
+ Mixer_StopChannel(audio.music_channel);
+
+#if defined(TARGET_SDL)
+ Mix_HaltMusic();
+#endif
+}
+
+static void Mixer_FadeChannel(int channel)
+{
+ if (!mixer[channel].active)
+ return;
+
+ mixer[channel].state |= SND_CTRL_FADE;
+
+#if defined(TARGET_SDL)
+ Mix_FadeOutChannel(channel, SOUND_FADING_INTERVAL);
+#elif defined(TARGET_ALLEGRO)
+ if (voice_check(mixer[channel].voice))
+ voice_ramp_volume(mixer[channel].voice, SOUND_FADING_INTERVAL, 0);
+#endif
+}
+
+static void Mixer_FadeMusicChannel()
+{
+ Mixer_FadeChannel(audio.music_channel);
+
+#if defined(TARGET_SDL)
+ Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
+#endif
+}
+
+static void Mixer_UnFadeChannel(int channel)
+{
+ if (!mixer[channel].active || !IS_FADING(mixer[channel]))
+ return;
+
+ mixer[channel].state &= ~SND_CTRL_FADE;
+ mixer[channel].volume = SOUND_MAX_VOLUME;
+
+#if defined(TARGET_SDL)
+ Mix_ExpireChannel(channel, -1);
+ Mix_Volume(channel, mixer[channel].volume);
+#elif defined(TARGET_ALLEGRO)
+ voice_stop_volumeramp(mixer[channel].voice);
+ voice_ramp_volume(mixer[channel].voice, SOUND_FADING_INTERVAL,
+ mixer[channel].volume);
+#endif
+}
+
+static void Mixer_InsertSound(SoundControl snd_ctrl)
+{
+ SoundInfo *snd_info;
+ int i, k;
+ int num_sounds = getSoundListSize();
+
+#if 0
+ printf("NEW SOUND %d ARRIVED [%d] [%d ACTIVE CHANNELS]\n",
+ snd_ctrl.nr, num_sounds, mixer_active_channels);
+#endif
+
+ if (IS_MUSIC(snd_ctrl))
+ {
+ if (num_music == 0)
+ return;
+
+ snd_ctrl.nr = snd_ctrl.nr % num_music;
+ }
+ else if (snd_ctrl.nr >= num_sounds)
+ return;
+
+#if 0
+ snd_info = (IS_MUSIC(snd_ctrl) ? Music[snd_ctrl.nr] : Sound[snd_ctrl.nr]);
+#else
+ snd_info = (IS_MUSIC(snd_ctrl) ? Music[snd_ctrl.nr] :
+ getSoundInfoEntryFromSoundID(snd_ctrl.nr));
+#endif
+
+ if (snd_info == NULL)
+ return;
+
+ /* copy sound sample and format information */
+ snd_ctrl.type = snd_info->type;
+ snd_ctrl.format = snd_info->format;
+ snd_ctrl.data_ptr = snd_info->data_ptr;
+ snd_ctrl.data_len = snd_info->data_len;
+ snd_ctrl.num_channels = snd_info->num_channels;
+
+ /* play music samples on a dedicated music channel */
+ if (IS_MUSIC(snd_ctrl))
+ {
+ Mixer_StopMusicChannel();
+
+ mixer[audio.music_channel] = snd_ctrl;
+ Mixer_PlayMusicChannel();
+
+ return;
+ }
+
+ /* check if (and how often) this sound sample is already playing */
+ for (k=0, i=audio.first_sound_channel; i<audio.num_channels; i++)
+ if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
+ k++;
+
+#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++)