+#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;
+ }
+
+ for(i=audio.first_sound_channel; i<audio.num_channels; i++)
+ if (SAME_SOUND_NR(mixer[i], snd_ctrl) || ALL_SOUNDS(snd_ctrl))
+ Mixer_StopChannel(i);
+
+#if defined(AUDIO_UNIX_NATIVE)
+ if (!mixer_active_channels)
+ CloseAudioDevice(&audio.device_fd);
+#endif
+ }
+ else if (snd_ctrl.active) /* add new sound to mixer */
+ {
+ Mixer_InsertSound(snd_ctrl);
+ }
+}
+
+void StartMixer(void)
+{
+ int i;
+
+#if 0
+ SDL_version compile_version;
+ const SDL_version *link_version;
+ MIX_VERSION(&compile_version);
+ printf("compiled with SDL_mixer version: %d.%d.%d\n",
+ compile_version.major,
+ compile_version.minor,
+ compile_version.patch);
+ link_version = Mix_Linked_Version();
+ printf("running with SDL_mixer version: %d.%d.%d\n",
+ link_version->major,
+ link_version->minor,
+ link_version->patch);
+#endif
+
+ if (!audio.sound_available)
+ return;
+
+ /* initialize stereo position conversion information */
+ for(i=0; i<=SOUND_MAX_LEFT2RIGHT; i++)
+ stereo_volume[i] =
+ (int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i));
+
+#if defined(AUDIO_UNIX_NATIVE)
+ if (!ForkAudioProcess())
+ audio.sound_available = FALSE;
+#endif
+}
+
+#if defined(AUDIO_UNIX_NATIVE)
+
+static void CopySampleToMixingBuffer(SoundControl *snd_ctrl,
+ int sample_pos, int sample_size,
+ short *buffer_base_ptr, int buffer_pos,
+ int num_output_channels)
+{
+ short *buffer_ptr = buffer_base_ptr + num_output_channels * buffer_pos;
+ int num_channels = snd_ctrl->num_channels;
+ int stepsize = num_channels;
+ int output_stepsize = num_output_channels;
+ int i, j;
+
+ if (snd_ctrl->format == AUDIO_FORMAT_U8)
+ {
+ byte *sample_ptr = (byte *)snd_ctrl->data_ptr + num_channels * sample_pos;
+
+ for (i=0; i<num_output_channels; i++)
+ {
+ int offset = (snd_ctrl->num_channels == 1 ? 0 : i);
+
+ for (j=0; j<sample_size; j++)
+ buffer_ptr[output_stepsize * j + i] =
+ ((short)(sample_ptr[stepsize * j + offset] ^ 0x80)) << 8;
+ }
+ }
+ else /* AUDIO_FORMAT_S16 */
+ {
+ short *sample_ptr= (short *)snd_ctrl->data_ptr + num_channels * sample_pos;
+
+ for (i=0; i<num_output_channels; i++)
+ {
+ int offset = (snd_ctrl->num_channels == 1 ? 0 : i);
+
+ for (j=0; j<sample_size; j++)
+ buffer_ptr[output_stepsize * j + i] =
+ sample_ptr[stepsize * j + offset];
+ }
+ }
+}
+
+#if defined(AUDIO_STREAMING_DSP)
+static void Mixer_Main_DSP()
+{
+ static short premix_first_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE];
+ static long premix_last_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE];
+ static byte playing_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE];
+ boolean stereo;
+ int fragment_size;
+ int sample_bytes;
+ int max_sample_size;
+ int num_output_channels;
+ int i, j;
+
+ if (!mixer_active_channels)
+ return;
+
+ if (audio.device_fd < 0)
+ {
+ if ((audio.device_fd = OpenAudioDevice(audio.device_name)) < 0)
+ return;
+
+ InitAudioDevice(&afmt);
+ }
+
+ stereo = afmt.stereo;
+ fragment_size = afmt.fragment_size;
+ sample_bytes = (afmt.format & AUDIO_FORMAT_U8 ? 1 : 2);
+ num_output_channels = (stereo ? 2 : 1);
+ max_sample_size = fragment_size / (num_output_channels * sample_bytes);
+
+ /* first clear the last premixing buffer */
+ memset(premix_last_buffer, 0,
+ max_sample_size * num_output_channels * sizeof(long));
+
+ for(i=0; i<audio.num_channels; i++)
+ {
+ void *sample_ptr;
+ int sample_len;
+ int sample_pos;
+ int sample_size;
+
+ if (!mixer[i].active)
+ continue;
+
+ if (Mixer_ChannelExpired(i))
+ {
+ Mixer_StopChannel(i);
+ continue;
+ }
+
+ /* pointer, lenght and actual playing position of sound sample */
+ sample_ptr = mixer[i].data_ptr;
+ sample_len = mixer[i].data_len;
+ sample_pos = mixer[i].playing_pos;
+ sample_size = MIN(max_sample_size, sample_len - sample_pos);
+ mixer[i].playing_pos += sample_size;
+
+ /* copy original sample to first mixing buffer */
+ CopySampleToMixingBuffer(&mixer[i], sample_pos, sample_size,
+ premix_first_buffer, 0, num_output_channels);
+
+ /* are we about to restart a looping sound? */
+ if (IS_LOOP(mixer[i]) && sample_size < max_sample_size)
+ {
+ while (sample_size < max_sample_size)
+ {
+ int restarted_sample_size =
+ MIN(max_sample_size - sample_size, sample_len);
+
+ CopySampleToMixingBuffer(&mixer[i], 0, restarted_sample_size,
+ premix_first_buffer, sample_size,
+ num_output_channels);
+
+ mixer[i].playing_pos = restarted_sample_size;
+ sample_size += restarted_sample_size;
+ }
+ }
+
+ /* decrease volume if sound is fading out */
+ if (IS_FADING(mixer[i]) &&
+ mixer[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
+ mixer[i].volume -= SOUND_FADING_VOLUME_STEP;
+
+ /* adjust volume of actual sound sample */
+ if (mixer[i].volume != SOUND_MAX_VOLUME)
+ for(j=0; j<sample_size * num_output_channels; j++)
+ premix_first_buffer[j] =
+ mixer[i].volume * (long)premix_first_buffer[j] / SOUND_MAX_VOLUME;