+ if (snd_ctrl->format == AUDIO_FORMAT_U8)
+ for (i=0; i<sample_size; i++)
+ *buffer_ptr++ =
+ ((short)(((byte *)sample_ptr)[sample_pos + i] ^ 0x80)) << 8;
+ else /* AUDIO_FORMAT_S16 */
+ for (i=0; i<sample_size; i++)
+ *buffer_ptr++ =
+ ((short *)sample_ptr)[sample_pos + i];
+}
+
+#if defined(AUDIO_STREAMING_DSP)
+static void SoundServer_Mixer()
+{
+ static int stereo_volume[PSND_MAX_LEFT2RIGHT + 1];
+ static boolean stereo_volume_calculated = FALSE;
+ static short premix_first_buffer[SND_BLOCKSIZE];
+ static short premix_left_buffer[SND_BLOCKSIZE];
+ static short premix_right_buffer[SND_BLOCKSIZE];
+ static long premix_last_buffer[SND_BLOCKSIZE];
+ static byte playing_buffer[SND_BLOCKSIZE];
+ int max_sample_size;
+ int fragment_size = afmt.fragment_size;
+ int sample_bytes = (afmt.format & AUDIO_FORMAT_U8 ? 1 : 2);
+ boolean stereo = afmt.stereo;
+ int i, j;
+
+ if (!stereo_volume_calculated)
+ {
+ for(i=0; i<=PSND_MAX_LEFT2RIGHT; i++)
+ stereo_volume[i] =
+ (int)sqrt((float)(PSND_MAX_LEFT2RIGHT * PSND_MAX_LEFT2RIGHT - i * i));
+
+ stereo_volume_calculated = TRUE;
+ }
+
+ if (!playing_sounds)
+ return;
+
+ if (audio.device_fd < 0)
+ {
+ if ((audio.device_fd = OpenAudioDevice(audio.device_name)) < 0)
+ return;
+
+ InitAudioDevice(&afmt);
+ }
+
+ max_sample_size = fragment_size / ((stereo ? 2 : 1) * sample_bytes);
+
+ /* first clear the last premixing buffer */
+ memset(premix_last_buffer, 0,
+ max_sample_size * (stereo ? 2 : 1) * sizeof(long));
+
+ for(i=0; i<NUM_MIXER_CHANNELS; i++)
+ {
+ void *sample_ptr;
+ int sample_len;
+ int sample_pos;
+ int sample_size;
+
+ if (!playlist[i].active)
+ continue;
+
+ /* pointer, lenght and actual playing position of sound sample */
+ sample_ptr = playlist[i].data_ptr;
+ sample_len = playlist[i].data_len;
+ sample_pos = playlist[i].playingpos;
+ sample_size = MIN(max_sample_size, sample_len - sample_pos);
+ playlist[i].playingpos += sample_size;
+
+ /* copy original sample to first mixing buffer */
+ CopySampleToMixingBuffer(&playlist[i], sample_pos, sample_size,
+ premix_first_buffer);
+
+ /* are we about to restart a looping sound? */
+ if (IS_LOOP(playlist[i]) && sample_size < max_sample_size)
+ {
+ while (sample_size < max_sample_size)
+ {
+ int restarted_sample_size =
+ MIN(max_sample_size - sample_size, sample_len);
+
+ if (playlist[i].format == AUDIO_FORMAT_U8)
+ for (j=0; j<restarted_sample_size; j++)
+ premix_first_buffer[sample_size + j] =
+ ((short)(((byte *)sample_ptr)[j] ^ 0x80)) << 8;
+ else
+ for (j=0; j<restarted_sample_size; j++)
+ premix_first_buffer[sample_size + j] =
+ ((short *)sample_ptr)[j];
+
+ playlist[i].playingpos = restarted_sample_size;
+ sample_size += restarted_sample_size;
+ }
+ }
+
+ /* decrease volume if sound is fading out */
+ if (IS_FADING(playlist[i]) &&
+ playlist[i].volume >= SOUND_FADING_VOLUME_THRESHOLD)
+ playlist[i].volume -= SOUND_FADING_VOLUME_STEP;
+
+ /* adjust volume of actual sound sample */
+ if (playlist[i].volume != PSND_MAX_VOLUME)
+ for(j=0; j<sample_size; j++)
+ premix_first_buffer[j] =
+ (playlist[i].volume * (long)premix_first_buffer[j])
+ >> PSND_MAX_VOLUME_BITS;
+
+ /* fill the last mixing buffer with stereo or mono sound */
+ if (stereo)
+ {
+ int middle_pos = PSND_MAX_LEFT2RIGHT / 2;
+ int left_volume = stereo_volume[middle_pos + playlist[i].stereo];
+ int right_volume= stereo_volume[middle_pos - playlist[i].stereo];
+
+ for(j=0; j<sample_size; j++)
+ {
+ premix_left_buffer[j] =
+ (left_volume * premix_first_buffer[j])
+ >> PSND_MAX_LEFT2RIGHT_BITS;
+ premix_right_buffer[j] =
+ (right_volume * premix_first_buffer[j])
+ >> PSND_MAX_LEFT2RIGHT_BITS;
+
+ premix_last_buffer[2 * j + 0] += premix_left_buffer[j];
+ premix_last_buffer[2 * j + 1] += premix_right_buffer[j];
+ }
+ }
+ else
+ {
+ for(j=0; j<sample_size; j++)
+ premix_last_buffer[j] += premix_first_buffer[j];
+ }
+
+ /* delete completed sound entries from the playlist */
+ if (playlist[i].playingpos >= playlist[i].data_len)
+ {
+ if (IS_LOOP(playlist[i]))
+ playlist[i].playingpos = 0;
+ else
+ PlaylistRemoveSound(i);
+ }
+ else if (playlist[i].volume <= SOUND_FADING_VOLUME_THRESHOLD)
+ PlaylistRemoveSound(i);
+ }
+
+ /* prepare final playing buffer according to system audio format */
+ for(i=0; i<max_sample_size * (stereo ? 2 : 1); i++)
+ {
+ /* cut off at 17 bit value */
+ if (premix_last_buffer[i] < -65535)
+ premix_last_buffer[i] = -65535;
+ else if (premix_last_buffer[i] > 65535)
+ premix_last_buffer[i] = 65535;
+
+ /* shift to 16 bit value */
+ premix_last_buffer[i] >>= 1;
+
+ if (afmt.format & AUDIO_FORMAT_U8)
+ {
+ playing_buffer[i] = (premix_last_buffer[i] >> 8) ^ 0x80;
+ }
+ else if (afmt.format & AUDIO_FORMAT_LE) /* 16 bit */
+ {
+ playing_buffer[2 * i + 0] = premix_last_buffer[i] & 0xff;
+ playing_buffer[2 * i + 1] = premix_last_buffer[i] >> 8;
+ }
+ else /* big endian */
+ {
+ playing_buffer[2 * i + 0] = premix_last_buffer[i] >> 8;
+ playing_buffer[2 * i + 1] = premix_last_buffer[i] & 0xff;
+ }
+ }
+
+ /* finally play the sound fragment */
+ write(audio.device_fd, playing_buffer, fragment_size);
+
+ if (!playing_sounds)
+ CloseAudioDevice(&audio.device_fd);
+}
+
+#else /* !AUDIO_STREAMING_DSP */
+
+static int SoundServer_SimpleAudio(struct SoundControl snd_ctrl)
+{
+ static short premix_first_buffer[SND_BLOCKSIZE];
+ static byte playing_buffer[SND_BLOCKSIZE];
+ int max_sample_size = SND_BLOCKSIZE;
+ void *sample_ptr;
+ int sample_len;
+ int sample_pos;
+ int sample_size;
+ int i, j;
+
+ i = 1;
+
+ /* pointer, lenght and actual playing position of sound sample */
+ sample_ptr = playlist[i].data_ptr;
+ sample_len = playlist[i].data_len;
+ sample_pos = playlist[i].playingpos;
+ sample_size = MIN(max_sample_size, sample_len - sample_pos);
+ playlist[i].playingpos += sample_size;
+
+ /* copy original sample to first mixing buffer */
+ CopySampleToMixingBuffer(&playlist[i], sample_pos, sample_size,
+ premix_first_buffer);
+
+ /* adjust volume of actual sound sample */
+ if (playlist[i].volume != PSND_MAX_VOLUME)
+ for(j=0; j<sample_size; j++)
+ premix_first_buffer[j] =
+ (playlist[i].volume * (long)premix_first_buffer[j])
+ >> PSND_MAX_VOLUME_BITS;
+
+ /* might be needed for u-law /dev/audio */
+#if 0
+ for(j=0; j<sample_size; j++)
+ playing_buffer[j] =
+ linear_to_ulaw(premix_first_buffer[j]);
+#endif
+
+ /* delete completed sound entries from the playlist */
+ if (playlist[i].playingpos >= playlist[i].data_len)
+ PlaylistRemoveSound(i);
+
+ for(i=0; i<sample_size; i++)
+ playing_buffer[i] = (premix_first_buffer[i] >> 8) ^ 0x80;
+
+ /* finally play the sound fragment */
+ write(audio.device_fd, playing_buffer, sample_size);
+
+ return sample_size;
+}
+#endif /* !AUDIO_STREAMING_DSP */
+
+void SoundServer()
+{