Re: [AD] Allegro's mixer, update

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


For benchmarking, I could recommend the following:

- Create a NULL sound driver. This will basically just eat up all commands sent its way.
- Give the mixer the ability to run entirely polled; nothing runs on timers.

Then, benchmarking would be as simple as just running some loop that polls the mixer. It would also be much more accurate.



Chris wrote:
I've continued work on Allegro's mixer (despite having no access to my comp for two week due to moving). The mixer itself is about as done as I'm gonna do, probably. Though I would ask if the low quality mixer is still required. It doesn't seem likely that there's a noticeable speed gain, and it would be nice to remove 4 functions that look almost identical to the 4 right after them. Unfortunately I can't test the mixer speeds myself as the profile version of Allegro seems to crash (it seems to be associate with calling _mix_some_samples too quickly). The debug and optimized builds are fine though, so I don't know what's up with it. I've added these self-explanitory functions:
int get_mixer_buffer_length(void); <-- Returns # of samples per channel
int get_mixer_voices(void);
int get_mixer_bits(void);
int get_mixer_channels(void);
int get_mixer_frequency(void);

I've also added new functionality that I would hope could be part of the exposed API, though generally used through audio streams, which can sit on top of this. I've added mixer streams that allow you to pass formatted audio data right into Allegro's mixer. They don't rely on looping voices, ala audio streams, and don't count towards the total voice count. They're sort of like a mix between audio streams and regular voices, though I'd like to think they could take the place of both. The only thing they can't do automatically, like voices, is automatic looping. Proper manipulation of data can emulate looping though. Mixer streams are designed to run on a poll-like system, though a seperate timer should be able to automate them just fine. Here's some of the self-explanitories:
void set_mixer_stream_freq(MIXER_STREAM *mixer, int freq);
void set_mixer_stream_volume(MIXER_STREAM *mixer, int freq);
void set_mixer_stream_pan(MIXER_STREAM *mixer, int freq);
// Those set_* functions have get_* counterparts.
int get_mixer_stream_position(MIXER_STREAM *mixer);

MIXER_STREAM *create_mixer_stream(int bits, int channels, int freq, int vol, int pan);
void destroy_mixer_stream(MIXER_STREAM *mixer);

// These two should probably be renamed, but I can't think of names.
int poke_mixer_stream(MIXER_STREAM *mixer); Tells if the stream is ready for more data int write_to_mixer_stream(MIXER_STREAM *mixer, void *buf, int len); stores the buf pointer to copy into Allegro's mixer; len is # of samples per chan

As you can see, it deals with pointers instead of indices. Since there can theoretically an be unlimited number of streams allocated (if not in use), I felt restricting the number via an array unnecesary. It does mean though that they can't be allocated in time-sensitive areas like voices (deletion is fine since that's done in the mixer thread).

Anyway, here's the diff. Apply it to the original 4.1.13 mixer.c.


------------------------------------------------------------------------

--- mixer.c.orig	2004-03-21 02:08:54.000000000 -0800
+++ mixer.c	2004-04-12 02:14:12.000000000 -0700
@@ -20,6 +20,10 @@
  *
  *      Synchronization added by Sam Hocevar.
  *
+ *      Chris Robinson included functions to report the mixer's settings,
+ *      switched to signed 24-bit mixing, cleaned up some of the mess the
+ *      code had gathered, and added the mixer stream functionality.
+ *
  *      See readme.txt for copyright information.
  */
@@ -35,8 +39,10 @@
 {
    int playing;               /* are we active? */
    int stereo;                /* mono or stereo input data? */
-   unsigned char *data8;      /* data for 8 bit samples */
-   unsigned short *data16;    /* data for 16 bit samples */
+   union {
+      unsigned char *u8;      /* data for 8 bit samples */
+      unsigned short *u16;    /* data for 16 bit samples */
+   } data;
    long pos;                  /* fixed point position in sample */
    long diff;                 /* fixed point speed of play */
    long len;                  /* fixed point sample length */
@@ -44,10 +50,45 @@
    long loop_end;             /* fixed point loop end position */
    int lvol;                  /* left channel volume */
    int rvol;                  /* right channel volume */
+   AL_METHOD(void, mix_samples, (struct MIXER_VOICE *, PHYS_VOICE *, signed int *, int));
 } MIXER_VOICE;
-#define MIX_VOLUME_LEVELS 32
+typedef struct MIXER_STREAM
+{
+	/* These make it easier to update in real time */
+	int freq, dfreq;
+	int pan, dpan;
+	int vol, dvol;
+
+	/* Stuff used by the mixer */
+	int bits;
+	int channels;
+	int lvol, rvol;
+	int step;
+
+	union {
+		unsigned char *u8;
+		unsigned short *u16;
+		void *buffer;
+	} data;
+	unsigned int pos;
+	unsigned int end_pos;
+
+	struct {
+		void *buffer;
+		unsigned int buffer_len;
+	} ext;
+
+	/* Flag to tell if we want to kill the stream ASAP (1) or wait until
+	 * it's finished playing before killing it (-1) */
+	int kill;
+
+	/* This is actually a linked list, but don't tell anyone */
+	void *extra;
+} MIXER_STREAM;
+MIXER_STREAM *mixer_stream_list;
+
 #define MIX_FIX_SHIFT         8
 #define MIX_FIX_SCALE         (1<<MIX_FIX_SHIFT)
@@ -59,41 +100,22 @@
 static MIXER_VOICE mixer_voice[MIXER_MAX_SFX];
/* temporary sample mixing buffer */ -static unsigned short *mix_buffer = NULL; +static signed int *mix_buffer = NULL; /* lookup table for converting sample volumes */
-typedef signed short MIXER_VOL_TABLE[256];
+#define MIX_VOLUME_LEVELS     32
+typedef signed int MIXER_VOL_TABLE[256];
 static MIXER_VOL_TABLE *mix_vol_table = NULL;
-/* lookup table for amplifying and clipping samples */
-static unsigned short *mix_clip_table = NULL;
-
-#define MIX_RES_16            14
-#define MIX_RES_8             10
-
-/* alternative table system for high-quality sample mixing */
-#define BITS_PAN 7 -#define BITS_VOL 7 -#define BITS_MIXER_CORE 32
-#define BITS_SAMPLES          16
-
-typedef unsigned short VOLUME_T;
-
-#define BITS_TOT (BITS_PAN+BITS_VOL) -#define ENTRIES_VOL_TABLE (1<<BITS_TOT)
-#define SIZE_VOLUME_TABLE (sizeof(VOLUME_T)*ENTRIES_VOL_TABLE)
-
-static VOLUME_T *volume_table = NULL;
-
 /* flags for the mixing code */
 static int mix_voices;
 static int mix_size;
 static int mix_freq;
-static int mix_stereo;
-static int mix_16bit;
+static int mix_channels;
+static int mix_bits;
/* shift factor for volume per voice */
-static int voice_volume_scale = -1;
+static int voice_volume_scale = 1;
static void mixer_lock_mem(void); @@ -104,6 +126,178 @@ +/* get_mixer_*:
+ *  Returns various info about the mixer.
+ */
+int get_mixer_frequency(void)
+{
+	return mix_freq;
+}
+END_OF_FUNCTION(get_mixer_frequency);
+
+int get_mixer_bits(void)
+{
+	return mix_bits;
+}
+END_OF_FUNCTION(get_mixer_bits);
+
+int get_mixer_channels(void)
+{
+	return mix_channels;
+}
+END_OF_FUNCTION(get_mixer_channels);
+
+int get_mixer_voices(void)
+{
+	return mix_voices;
+}
+END_OF_FUNCTION(get_mixer_voices);
+
+int get_mixer_buffer_length(void)
+{
+	return mix_size / mix_channels;
+}
+END_OF_FUNCTION(get_mixer_buffer_length);
+
+
+MIXER_STREAM *create_mixer_stream(int bits, int channels, int freq, int vol, int pan)
+{
+	MIXER_STREAM *mixer;
+	int i;
+
+	if(((bits != 8) && (bits != 16)) || ((channels != 1) && (channels != 2)) ||
+	   (freq <= 0))
+		return NULL;
+
+	mixer = calloc(1, sizeof(MIXER_STREAM));
+	if(!mixer)
+		return NULL;
+	LOCK_DATA(mixer, sizeof(MIXER_STREAM));
+
+	mixer->bits = bits;
+	mixer->channels = channels;
+
+	mixer->dfreq = freq;
+	mixer->dpan = pan;
+	mixer->dvol = vol;
+
+	mixer->extra = (void*)mixer_stream_list;
+	mixer_stream_list = mixer;
+
+	return mixer;
+}
+END_OF_FUNCTION(create_mixer_stream);
+
+void destroy_mixer_stream(MIXER_STREAM *mixer)
+{
+	if(mixer && !mixer->kill)
+		mixer->kill = 1;
+}
+END_OF_FUNCTION(destroy_mixer_stream);
+
+void release_mixer_stream(MIXER_STREAM *mixer)
+{
+	if(mixer && !mixer->kill)
+		mixer->kill = -1;
+}
+END_OF_FUNCTION(release_mixer_stream);
+
+int get_mixer_stream_position(MIXER_STREAM *mixer)
+{
+	ASSERT(mixer);
+
+	if(!mixer->data.buffer)
+		return -1;
+
+	return mixer->pos >> MIX_FIX_SHIFT;
+}
+END_OF_FUNCTION(get_mixer_stream_position);
+
+int get_mixer_stream_freq(MIXER_STREAM *mixer)
+{
+	ASSERT(mixer);
+	return mixer->freq;
+}
+END_OF_FUNCTION(get_mixer_stream_freq);
+
+int get_mixer_stream_volume(MIXER_STREAM *mixer)
+{
+	ASSERT(mixer);
+	return mixer->vol;
+}
+END_OF_FUNCTION(get_mixer_stream_volume);
+
+int get_mixer_stream_pan(MIXER_STREAM *mixer, int pan)
+{
+	ASSERT(mixer);
+	return mixer->pan;
+}
+END_OF_FUNCTION(get_mixer_stream_pan);
+
+void set_mixer_stream_freq(MIXER_STREAM *mixer, int freq)
+{
+	ASSERT(mixer);
+	ASSERT(freq > 0);
+
+	mixer->dfreq += freq - mixer->freq;
+}
+END_OF_FUNCTION(set_mixer_stream_freq);
+
+void set_mixer_stream_volume(MIXER_STREAM *mixer, int vol)
+{
+	ASSERT(mixer);
+
+	if(vol < 0) vol = 0;
+	if(vol > 255) vol = 255;
+
+	mixer->dvol += vol - mixer->vol;
+}
+END_OF_FUNCTION(set_mixer_stream_volume);
+
+void set_mixer_stream_pan(MIXER_STREAM *mixer, int pan)
+{
+	ASSERT(mixer);
+
+	if(pan < 0) pan = 0;
+	if(pan > 255) pan = 255;
+
+	mixer->dpan += pan - mixer->pan;
+}
+END_OF_FUNCTION(set_mixer_stream_pan);
+
+int poke_mixer_stream(MIXER_STREAM *mixer)
+{
+	if(mixer->ext.buffer)
+		return FALSE;
+
+	return TRUE;
+}
+
+int write_to_mixer_stream(MIXER_STREAM *mixer, void *buf, int len)
+{
+	ASSERT(mixer);
+	ASSERT(buf);
+	ASSERT(len > 0);
+
+	if(!mixer->data.buffer)
+	{
+		mixer->data.buffer = buf;
+		mixer->end_pos = len * MIX_FIX_SCALE;
+		mixer->pos = 0;
+
+		return TRUE;
+	}
+
+	if(mixer->ext.buffer)
+		return FALSE;
+
+	mixer->ext.buffer_len = len * MIX_FIX_SCALE;
+	mixer->ext.buffer = buf;
+
+	return TRUE;
+}
+
+
 /* set_volume_per_voice:
  *  Enables the programmer (not the end-user) to alter the maximum volume of
  *  each voice:
@@ -114,41 +308,36 @@
  *  - pass 1 if you want to pan a full-volume sample to one side without
  *    distortion,
  *  - each time the scale parameter increases by 1, the volume halves.
- *
- *  This must be called _before_ install_sound().
  */
+static void update_mixer_volume(MIXER_VOICE *mv, PHYS_VOICE *pv);
 void set_volume_per_voice(int scale)
 {
-   voice_volume_scale = scale;
-}
-
-
-/* create_volume_table:
- *  Builds a volume table for the high quality 16 bit mixing mode.
- */
-static int create_volume_table(int vol_scale)
-{
-   double step;
-   double acum = 0;
-   int i;
-
-   if (!volume_table) {
-      volume_table = (VOLUME_T *)malloc(SIZE_VOLUME_TABLE);
-      if (!volume_table)
-	 return 1;
-      LOCK_DATA(volume_table, SIZE_VOLUME_TABLE);
-   }
-
-   step = (double)(32768 >> vol_scale) / ENTRIES_VOL_TABLE;
-
-   for (i=0; i<ENTRIES_VOL_TABLE; i++, acum+=step)
-      volume_table[i] = acum;
+	int i;
- return 0;
+	if(scale < 0)
+	{
+		/* Work out the # of voices and the needed scale */
+		scale = 1;
+		for(i = 1;i < mix_voices;i <<= 1)
+			scale++;
+
+		/* Backwards compatiblity with 3.12 */
+		if(scale < 2)
+			scale = 2;
+	}
+
+	/* Scale 0 could overflow the lq volume table */
+	if((!_sound_hq) && (scale < 1))
+		scale = 1;
+
+	voice_volume_scale = scale;
+
+	/* Update the mixer voices' volumes */
+	for(i = 0;i < MIXER_MAX_SFX;++i)
+		update_mixer_volume(mixer_voice+i, _phys_voice+i);
 }
-
 /* _mixer_init:
  *  Initialises the sample mixing code, returning 0 on success. You should
  *  pass it the number of samples you want it to mix each time the refill
@@ -162,105 +351,49 @@
 int _mixer_init(int bufsize, int freq, int stereo, int is16bit, int *voices)
 {
    int i, j;
-   int clip_size;
-   int clip_scale;
-   int clip_max;
-   int mix_vol_scale;
-
-   mix_voices = 1;
-   mix_vol_scale = -1;
-
-   while ((mix_voices < MIXER_MAX_SFX) && (mix_voices < *voices)) {
-      mix_voices <<= 1;
-      mix_vol_scale++;
-   }
-
-   if (voice_volume_scale >= 0)
-      mix_vol_scale = voice_volume_scale;
-   else {
-      /* backward compatibility with 3.12 version */
-      if (mix_vol_scale < 2)
-         mix_vol_scale = 2;
-   }
- *voices = mix_voices;
+   mix_voices = *voices;
+   if(mix_voices > MIXER_MAX_SFX)
+      *voices = mix_voices = MIXER_MAX_SFX;
mix_size = bufsize;
    mix_freq = freq;
-   mix_stereo = stereo;
-   mix_16bit = is16bit;
+   mix_channels = (stereo ? 2 : 1);
+   mix_bits = (is16bit ? 16 : 8);
for (i=0; i<MIXER_MAX_SFX; i++) {
       mixer_voice[i].playing = FALSE;
-      mixer_voice[i].data8 = NULL;
-      mixer_voice[i].data16 = NULL;
+      mixer_voice[i].data.u8 = NULL;
+      mixer_voice[i].data.u16 = NULL;
    }
/* temporary buffer for sample mixing */
-   mix_buffer = malloc(mix_size*sizeof(short));
+   mix_buffer = malloc(mix_size * sizeof(*mix_buffer));
    if (!mix_buffer)
       return -1;
- LOCK_DATA(mix_buffer, mix_size*sizeof(short));
-
-   /* volume table for mixing samples into the temporary buffer */
-   mix_vol_table = malloc(sizeof(MIXER_VOL_TABLE) * MIX_VOLUME_LEVELS);
-   if (!mix_vol_table) {
-      free(mix_buffer);
-      mix_buffer = NULL;
-      return -1;
-   }
-
-   LOCK_DATA(mix_vol_table, sizeof(MIXER_VOL_TABLE) * MIX_VOLUME_LEVELS);
+   LOCK_DATA(mix_buffer, mix_size * sizeof(*mix_buffer));
- for (j=0; j<MIX_VOLUME_LEVELS; j++)
-      for (i=0; i<256; i++)
-         mix_vol_table[j][i] = ((i-128) * j * 128 / MIX_VOLUME_LEVELS) >> mix_vol_scale;
-
-   if ((_sound_hq) && (mix_stereo) && (mix_16bit)) {
-      /* make high quality table if requested and output is 16 bit stereo */
-      if (create_volume_table(mix_vol_scale) != 0)
-	 return -1;
-   }
-   else
+   /* 16 bit output isn't required for the high quality mixers */
+   if ((!_sound_hq) || (mix_channels == 1)) {
+	  /* no high quality mixer available */
       _sound_hq = 0;
- /* lookup table for amplifying and clipping sample buffers */
-   if (mix_16bit) {
-      clip_size = 1 << MIX_RES_16;
-      clip_scale = 18 - MIX_RES_16;
-      clip_max = 0xFFFF;
-   }
-   else {
-      clip_size = 1 << MIX_RES_8;
-      clip_scale = 10 - MIX_RES_8;
-      clip_max = 0xFF;
-   }
-
-   /* We now always use a clip table, owing to the new set_volume_per_voice()
-    * functionality. It is not a big loss in performance.
-    */
-   mix_clip_table = malloc(sizeof(short) * clip_size);
-   if (!mix_clip_table) {
-      free(mix_buffer);
-      mix_buffer = NULL;
-      free(mix_vol_table);
-      mix_vol_table = NULL;
-      free(volume_table);
-      volume_table = NULL;
-      return -1;
-   }
+      /* volume table for mixing samples into the temporary buffer */
+      mix_vol_table = malloc(sizeof(MIXER_VOL_TABLE) * MIX_VOLUME_LEVELS);
+      if (!mix_vol_table) {
+         free(mix_buffer);
+         mix_buffer = NULL;
+         return -1;
+      }
- LOCK_DATA(mix_clip_table, sizeof(short) * clip_size);
+      LOCK_DATA(mix_vol_table, sizeof(MIXER_VOL_TABLE) * MIX_VOLUME_LEVELS);
- /* clip extremes of the sample range */
-   for (i=0; i<clip_size*3/8; i++) {
-      mix_clip_table[i] = 0;
-      mix_clip_table[clip_size-1-i] = clip_max;
+      for (j=0; j<MIX_VOLUME_LEVELS; j++)
+         for (i=0; i<256; i++)
+            mix_vol_table[j][i] = ((i-128) * 256 * j / MIX_VOLUME_LEVELS) << 8;
    }
-
-   for (i=0; i<clip_size/4; i++)
-      mix_clip_table[clip_size*3/8 + i] = i<<clip_scale;
+   /* We no longer need to use prebuilt stuff for the high quality mixers */
mixer_lock_mem(); @@ -285,29 +418,21 @@
    mixer_mutex = NULL;
 #endif
- if (mix_buffer) {
+   if (mix_buffer)
       free(mix_buffer);
-      mix_buffer = NULL;
-   }
+   mix_buffer = NULL;
- if (mix_vol_table) {
+   if (mix_vol_table)
       free(mix_vol_table);
-      mix_vol_table = NULL;
-   }
-
-   if (mix_clip_table) {
-      free(mix_clip_table);
-      mix_clip_table = NULL;
-   }
+   mix_vol_table = NULL;
- if (volume_table) {
-      free(volume_table);
-      volume_table = NULL;
-   }
+   mix_size = 0;
+   mix_freq = 0;
+   mix_channels = 0;
+   mix_bits = 0;
 }
-
 /* update_mixer_volume:
* Called whenever the voice volume or pan changes, to update the mixer * amplification table indexes.
@@ -317,37 +442,41 @@
    int vol, pan, lvol, rvol;
if (_sound_hq) {
-      vol = pv->vol>>13;
-      pan = pv->pan>>13;
+	  /* now use full 16 bit volume ranges */
+      vol = pv->vol>>12;
+      pan = pv->pan>>12;
- /* no need to check for mix_stereo if we're using hq */
-      lvol = vol*(127-pan);
+      /* no need to check for mix_channels if we're using hq */
+      lvol = vol*(255-pan);
       rvol = vol*pan;
- /* adjust for 127*127<128*128-1 */
-      lvol += lvol>>6;
-      rvol += rvol>>6;
-
-      mv->lvol = MID(0, lvol, ENTRIES_VOL_TABLE-1);
-      mv->rvol = MID(0, rvol, ENTRIES_VOL_TABLE-1);
+      /* Adjust for 255*255 < 256*256-1 */
+      lvol += lvol >> 7;
+      rvol += rvol >> 7;
+
+	  /* Multiply 2 to emulate the old behavior of voice_scale=0 being
+	   * 1 step louder than regular volume
+	   */
+      mv->lvol = (MID(0, lvol, 65535) << 1) >> voice_volume_scale;
+      mv->rvol = (MID(0, rvol, 65535) << 1) >> voice_volume_scale;
    }
    else {
       vol = pv->vol >> 12;
       pan = pv->pan >> 12;
- if (mix_stereo) {
-	 lvol = vol * (256-pan) * MIX_VOLUME_LEVELS / 65536;
+      if (mix_channels == 2) {
+	 lvol = vol * (255-pan) * MIX_VOLUME_LEVELS / 65536;
 	 rvol = vol * pan * MIX_VOLUME_LEVELS / 65536;
       }
       else if (mv->stereo) {
-	 lvol = vol * (256-pan) * MIX_VOLUME_LEVELS / 131072;
+	 lvol = vol * (255-pan) * MIX_VOLUME_LEVELS / 131072;
 	 rvol = vol * pan * MIX_VOLUME_LEVELS / 131072;
       }
       else
 	 lvol = rvol = vol * MIX_VOLUME_LEVELS / 512;
- mv->lvol = MID(0, lvol, MIX_VOLUME_LEVELS-1);
-      mv->rvol = MID(0, rvol, MIX_VOLUME_LEVELS-1);
+      mv->lvol = (MID(0, lvol, MIX_VOLUME_LEVELS-1) << 1) >> voice_volume_scale;
+      mv->rvol = (MID(0, rvol, MIX_VOLUME_LEVELS-1) << 1) >> voice_volume_scale;
    }
 }
@@ -466,9 +595,9 @@
 	    if (spl->pos < spl->loop_start) {                                \
 	       if (voice->playmode & PLAYMODE_BIDIR) {                       \
 		  spl->diff = -spl->diff;                                    \
-                  /* however far the sample has overshot, move it the same */\
-                  /* distance from the loop point, within the loop section */\
-                  spl->pos = (spl->loop_start << 1) - spl->pos;              \
+		  /* however far the sample has overshot, move it the same */\
+		  /* distance from the loop point, within the loop section */\
+		  spl->pos = (spl->loop_start << 1) - spl->pos;              \
 		  voice->playmode ^= PLAYMODE_BACKWARD;                      \
 	       }                                                             \
 	       else                                                          \
@@ -601,12 +730,12 @@
* Mixes from an eight bit sample into a mono buffer, until either len * samples have been mixed or until the end of the sample is reached.
  */
-static void mix_mono_8x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_mono_8x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   signed short *vol = (short *)(mix_vol_table + spl->lvol);
+   signed int *vol = (int *)(mix_vol_table + spl->lvol);
#define MIX() \
-      *(buf++) += vol[spl->data8[spl->pos>>MIX_FIX_SHIFT]];
+      *(buf++) += vol[spl->data.u8[spl->pos>>MIX_FIX_SHIFT]];
MIXER(); @@ -621,14 +750,14 @@ * Mixes from an eight bit stereo sample into a mono buffer, until either * len samples have been mixed or until the end of the sample is reached.
  */
-static void mix_mono_8x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_mono_8x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   signed short *lvol = (short *)(mix_vol_table + spl->lvol);
-   signed short *rvol = (short *)(mix_vol_table + spl->rvol);
+   signed int *lvol = (int *)(mix_vol_table + spl->lvol);
+   signed int *rvol = (int *)(mix_vol_table + spl->rvol);
#define MIX() \
-      *(buf)   += lvol[spl->data8[(spl->pos>>MIX_FIX_SHIFT)*2]];             \
-      *(buf++) += rvol[spl->data8[(spl->pos>>MIX_FIX_SHIFT)*2+1]];
+      *(buf)   += lvol[spl->data.u8[(spl->pos>>MIX_FIX_SHIFT)*2]];             \
+      *(buf++) += rvol[spl->data.u8[(spl->pos>>MIX_FIX_SHIFT)*2+1]];
MIXER(); @@ -643,12 +772,12 @@ * Mixes from a 16 bit sample into a mono buffer, until either len samples * have been mixed or until the end of the sample is reached.
  */
-static void mix_mono_16x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_mono_16x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   signed short *vol = (short *)(mix_vol_table + spl->lvol);
+   signed int *vol = (int *)(mix_vol_table + spl->lvol);
#define MIX() \
-      *(buf++) += vol[(spl->data16[spl->pos>>MIX_FIX_SHIFT])>>8];
+      *(buf++) += vol[(spl->data.u16[spl->pos>>MIX_FIX_SHIFT])>>8];
MIXER(); @@ -663,14 +792,14 @@ * Mixes from a 16 bit stereo sample into a mono buffer, until either len * samples have been mixed or until the end of the sample is reached.
  */
-static void mix_mono_16x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_mono_16x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   signed short *lvol = (short *)(mix_vol_table + spl->lvol);
-   signed short *rvol = (short *)(mix_vol_table + spl->rvol);
+   signed int *lvol = (int *)(mix_vol_table + spl->lvol);
+   signed int *rvol = (int *)(mix_vol_table + spl->rvol);
#define MIX() \
-      *(buf)   += lvol[(spl->data16[(spl->pos>>MIX_FIX_SHIFT)*2])>>8];       \
-      *(buf++) += rvol[(spl->data16[(spl->pos>>MIX_FIX_SHIFT)*2+1])>>8];
+      *(buf)   += lvol[(spl->data.u16[(spl->pos>>MIX_FIX_SHIFT)*2])>>8];       \
+      *(buf++) += rvol[(spl->data.u16[(spl->pos>>MIX_FIX_SHIFT)*2+1])>>8];
MIXER(); @@ -685,16 +814,16 @@ * Mixes from an eight bit sample into a stereo buffer, until either len * samples have been mixed or until the end of the sample is reached.
  */
-static void mix_stereo_8x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_stereo_8x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   signed short *lvol = (short *)(mix_vol_table + spl->lvol);
-   signed short *rvol = (short *)(mix_vol_table + spl->rvol);
+   signed int *lvol = (int *)(mix_vol_table + spl->lvol);
+   signed int *rvol = (int *)(mix_vol_table + spl->rvol);
len >>= 1; #define MIX() \
-      *(buf++) += lvol[spl->data8[spl->pos>>MIX_FIX_SHIFT]];                 \
-      *(buf++) += rvol[spl->data8[spl->pos>>MIX_FIX_SHIFT]];
+      *(buf++) += lvol[spl->data.u8[spl->pos>>MIX_FIX_SHIFT]];                 \
+      *(buf++) += rvol[spl->data.u8[spl->pos>>MIX_FIX_SHIFT]];
MIXER(); @@ -709,16 +838,16 @@ * Mixes from an eight bit stereo sample into a stereo buffer, until either * len samples have been mixed or until the end of the sample is reached.
  */
-static void mix_stereo_8x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_stereo_8x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   signed short *lvol = (short *)(mix_vol_table + spl->lvol);
-   signed short *rvol = (short *)(mix_vol_table + spl->rvol);
+   signed int *lvol = (int *)(mix_vol_table + spl->lvol);
+   signed int *rvol = (int *)(mix_vol_table + spl->rvol);
len >>= 1; #define MIX() \
-      *(buf++) += lvol[spl->data8[(spl->pos>>MIX_FIX_SHIFT)*2]];             \
-      *(buf++) += rvol[spl->data8[(spl->pos>>MIX_FIX_SHIFT)*2+1]];
+      *(buf++) += lvol[spl->data.u8[(spl->pos>>MIX_FIX_SHIFT)*2]];             \
+      *(buf++) += rvol[spl->data.u8[(spl->pos>>MIX_FIX_SHIFT)*2+1]];
MIXER(); @@ -733,16 +862,16 @@ * Mixes from a 16 bit sample into a stereo buffer, until either len samples * have been mixed or until the end of the sample is reached.
  */
-static void mix_stereo_16x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_stereo_16x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   signed short *lvol = (short *)(mix_vol_table + spl->lvol);
-   signed short *rvol = (short *)(mix_vol_table + spl->rvol);
+   signed int *lvol = (int *)(mix_vol_table + spl->lvol);
+   signed int *rvol = (int *)(mix_vol_table + spl->rvol);
len >>= 1; #define MIX() \
-      *(buf++) += lvol[(spl->data16[spl->pos>>MIX_FIX_SHIFT])>>8];           \
-      *(buf++) += rvol[(spl->data16[spl->pos>>MIX_FIX_SHIFT])>>8];
+      *(buf++) += lvol[(spl->data.u16[spl->pos>>MIX_FIX_SHIFT])>>8];           \
+      *(buf++) += rvol[(spl->data.u16[spl->pos>>MIX_FIX_SHIFT])>>8];
MIXER(); @@ -757,16 +886,16 @@ * Mixes from a 16 bit stereo sample into a stereo buffer, until either len * samples have been mixed or until the end of the sample is reached.
  */
-static void mix_stereo_16x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_stereo_16x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   signed short *lvol = (short *)(mix_vol_table + spl->lvol);
-   signed short *rvol = (short *)(mix_vol_table + spl->rvol);
+   signed int *lvol = (int *)(mix_vol_table + spl->lvol);
+   signed int *rvol = (int *)(mix_vol_table + spl->rvol);
len >>= 1; #define MIX() \
-      *(buf++) += lvol[(spl->data16[(spl->pos>>MIX_FIX_SHIFT)*2])>>8];       \
-      *(buf++) += rvol[(spl->data16[(spl->pos>>MIX_FIX_SHIFT)*2+1])>>8];
+      *(buf++) += lvol[(spl->data.u16[(spl->pos>>MIX_FIX_SHIFT)*2])>>8];       \
+      *(buf++) += rvol[(spl->data.u16[(spl->pos>>MIX_FIX_SHIFT)*2+1])>>8];
MIXER(); @@ -775,23 +904,21 @@ END_OF_STATIC_FUNCTION(mix_stereo_16x2_samples); -
-
 /* mix_hq1_8x1_samples:
* Mixes from a mono 8 bit sample into a high quality stereo buffer, * until either len samples have been mixed or until the end of the * sample is reached.
  */
-static void mix_hq1_8x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_hq1_8x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   int lvol = volume_table[spl->lvol];
-   int rvol = volume_table[spl->rvol];
+   int lvol = spl->lvol;
+   int rvol = spl->rvol;
len >>= 1; #define MIX() \
-      *(buf++) += ((spl->data8[spl->pos>>MIX_FIX_SHIFT]-0x80)*lvol)>>8;      \
-      *(buf++) += ((spl->data8[spl->pos>>MIX_FIX_SHIFT]-0x80)*rvol)>>8;
+	  *(buf++) += ((spl->data.u8[spl->pos>>MIX_FIX_SHIFT]-0x80)*lvol);	\
+	  *(buf++) += ((spl->data.u8[spl->pos>>MIX_FIX_SHIFT]-0x80)*rvol);
MIXER(); @@ -807,16 +934,16 @@ * until either len samples have been mixed or until the end of the * sample is reached.
  */
-static void mix_hq1_8x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_hq1_8x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   int lvol = volume_table[spl->lvol];
-   int rvol = volume_table[spl->rvol];
+   int lvol = spl->lvol;
+   int rvol = spl->rvol;
len >>= 1; #define MIX() \
-      *(buf++) += ((spl->data8[(spl->pos>>MIX_FIX_SHIFT)*2]-0x80)*lvol)>>8;  \
-      *(buf++) += ((spl->data8[(spl->pos>>MIX_FIX_SHIFT)*2+1]-0x80)*rvol)>>8;
+	  *(buf++) += ((spl->data.u8[(spl->pos>>MIX_FIX_SHIFT)*2]-0x80)*lvol);  \
+	  *(buf++) += ((spl->data.u8[(spl->pos>>MIX_FIX_SHIFT)*2+1]-0x80)*rvol);
MIXER(); @@ -832,16 +959,16 @@ * until either len samples have been mixed or until the end of the sample * is reached.
  */
-static void mix_hq1_16x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_hq1_16x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   int lvol = volume_table[spl->lvol];
-   int rvol = volume_table[spl->rvol];
+   int lvol = spl->lvol;
+   int rvol = spl->rvol;
len >>= 1; #define MIX() \
-      *(buf++) += ((spl->data16[spl->pos>>MIX_FIX_SHIFT]-0x8000)*lvol)>>16;  \
-      *(buf++) += ((spl->data16[spl->pos>>MIX_FIX_SHIFT]-0x8000)*rvol)>>16;
+	  *(buf++) += ((spl->data.u16[spl->pos>>MIX_FIX_SHIFT]-0x8000)*lvol)>>8;  \
+	  *(buf++) += ((spl->data.u16[spl->pos>>MIX_FIX_SHIFT]-0x8000)*rvol)>>8;
MIXER(); @@ -857,16 +984,16 @@ * until either len samples have been mixed or until the end of the sample * is reached.
  */
-static void mix_hq1_16x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_hq1_16x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   int lvol = volume_table[spl->lvol];
-   int rvol = volume_table[spl->rvol];
+   int lvol = spl->lvol;
+   int rvol = spl->rvol;
len >>= 1; #define MIX() \
-      *(buf++) += ((spl->data16[(spl->pos>>MIX_FIX_SHIFT)*2]-0x8000)*lvol)>>16;  \
-      *(buf++) += ((spl->data16[(spl->pos>>MIX_FIX_SHIFT)*2+1]-0x8000)*rvol)>>16;
+	  *(buf++) += ((spl->data.u16[(spl->pos>>MIX_FIX_SHIFT)*2]-0x8000)*lvol)>>8;  \
+	  *(buf++) += ((spl->data.u16[(spl->pos>>MIX_FIX_SHIFT)*2+1]-0x8000)*rvol)>>8;
MIXER(); @@ -876,16 +1003,18 @@
 END_OF_STATIC_FUNCTION(mix_hq1_16x2_samples);
+/* Helper to apply a 16-bit volume to a 24-bit sample */
+#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))
/* mix_hq2_8x1_samples: * Mixes from a mono 8 bit sample into an interpolated stereo buffer, * until either len samples have been mixed or until the end of the * sample is reached.
  */
-static void mix_hq2_8x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_hq2_8x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   int lvol = volume_table[spl->lvol];
-   int rvol = volume_table[spl->rvol];
+   int lvol = spl->lvol;
+   int rvol = spl->rvol;
    int v, v1, v2;
len >>= 1;
@@ -893,24 +1022,24 @@
    #define MIX()                                                             \
       v = spl->pos>>MIX_FIX_SHIFT;                                           \
 									     \
-      v1 = spl->data8[v];                                                    \
-                                                                             \
+      v1 = spl->data.u8[v] << 16;                                            \
+                                         \
       if (spl->pos >= spl->len-MIX_FIX_SCALE) {                              \
          if ((voice->playmode & (PLAYMODE_LOOP |                             \
                                  PLAYMODE_BIDIR)) == PLAYMODE_LOOP &&        \
              spl->loop_start < spl->loop_end && spl->loop_end == spl->len)   \
-            v2 = spl->data8[spl->loop_start>>MIX_FIX_SHIFT];                 \
+            v2 = spl->data.u8[spl->loop_start>>MIX_FIX_SHIFT] << 16;         \
          else                                                                \
-            v2 = 0x80;                                                       \
+            v2 = 0x800000;                                                   \
       }                                                                      \
       else                                                                   \
-	 v2 = spl->data8[v+1];                                               \
-									     \
-      v = spl->pos & (MIX_FIX_SCALE-1);                                      \
-      v = (v1*(MIX_FIX_SCALE-v) + v2*v) / MIX_FIX_SCALE;                     \
+	 v2 = spl->data.u8[v+1] << 16;                                           \
 									     \
-      *(buf++) += ((v-0x80)*lvol)>>8;                                        \
-      *(buf++) += ((v-0x80)*rvol)>>8;
+      v = (spl->pos & (MIX_FIX_SCALE-1)) >> 1;                               \
+	  v = (((v2 - v1) * v) >> (MIX_FIX_SHIFT-1)) + v1;                       \
+										 \
+	  *(buf++) += MULSC(v-0x800000, lvol);                                   \
+	  *(buf++) += MULSC(v-0x800000, rvol);
MIXER(); @@ -926,41 +1055,41 @@ * until either len samples have been mixed or until the end of the * sample is reached.
  */
-static void mix_hq2_8x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_hq2_8x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   int lvol = volume_table[spl->lvol];
-   int rvol = volume_table[spl->rvol];
+   int lvol = spl->lvol;
+   int rvol = spl->rvol;
    int v, va, v1a, v2a, vb, v1b, v2b;
len >>= 1; #define MIX() \
       v = (spl->pos>>MIX_FIX_SHIFT) << 1; /* x2 for stereo */                \
-                                                                             \
-      v1a = spl->data8[v];                                                   \
-      v1b = spl->data8[v+1];                                                 \
+	\
+      v1a = spl->data.u8[v] << 16;                                           \
+      v1b = spl->data.u8[v+1] << 16;                                         \
 									     \
       if (spl->pos >= spl->len-MIX_FIX_SCALE) {                              \
          if ((voice->playmode & (PLAYMODE_LOOP |                             \
                                  PLAYMODE_BIDIR)) == PLAYMODE_LOOP &&        \
              spl->loop_start < spl->loop_end && spl->loop_end == spl->len) { \
-            v2a = spl->data8[((spl->loop_start>>MIX_FIX_SHIFT)<<1)];         \
-            v2b = spl->data8[((spl->loop_start>>MIX_FIX_SHIFT)<<1)+1];       \
+            v2a = spl->data.u8[((spl->loop_start>>MIX_FIX_SHIFT)<<1)] << 16; \
+            v2b = spl->data.u8[((spl->loop_start>>MIX_FIX_SHIFT)<<1)+1] << 16; \
          }                                                                   \
          else                                                                \
-            v2a = v2b = 0x80;                                                \
+            v2a = v2b = 0x800000;                                            \
       }                                                                      \
       else {                                                                 \
-	 v2a = spl->data8[v+2];                                              \
-	 v2b = spl->data8[v+3];                                              \
+	 v2a = spl->data.u8[v+2] << 16;                                          \
+	 v2b = spl->data.u8[v+3] << 16;                                          \
       }                                                                      \
 									     \
-      v = spl->pos & (MIX_FIX_SCALE-1);                                      \
-      va = (v1a*(MIX_FIX_SCALE-v) + v2a*v) / MIX_FIX_SCALE;                  \
-      vb = (v1b*(MIX_FIX_SCALE-v) + v2b*v) / MIX_FIX_SCALE;                  \
+      v = (spl->pos & (MIX_FIX_SCALE-1)) >> 1;                               \
+      va = (((v2a - v1a) * v) >> (MIX_FIX_SHIFT-1)) + v1a;                       \
+      vb = (((v2b - v1b) * v) >> (MIX_FIX_SHIFT-1)) + v1b;                       \
 									     \
-      *(buf++) += ((va-0x80)*lvol)>>8;                                       \
-      *(buf++) += ((vb-0x80)*rvol)>>8;
+	  *(buf++) += MULSC(va-0x800000, lvol);                                  \
+	  *(buf++) += MULSC(vb-0x800000, rvol);
MIXER(); @@ -976,10 +1105,10 @@ * until either len samples have been mixed or until the end of the sample * is reached.
  */
-static void mix_hq2_16x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_hq2_16x1_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   int lvol = volume_table[spl->lvol];
-   int rvol = volume_table[spl->rvol];
+   int lvol = spl->lvol;
+   int rvol = spl->rvol;
    int v, v1, v2;
len >>= 1;
@@ -987,24 +1116,24 @@
    #define MIX()                                                             \
       v = spl->pos>>MIX_FIX_SHIFT;                                           \
                                                                              \
-      v1 = spl->data16[v];                                                   \
+      v1 = spl->data.u16[v] << 8;                                            \
 									     \
       if (spl->pos >= spl->len-MIX_FIX_SCALE) {                              \
          if ((voice->playmode & (PLAYMODE_LOOP |                             \
                                  PLAYMODE_BIDIR)) == PLAYMODE_LOOP &&        \
              spl->loop_start < spl->loop_end && spl->loop_end == spl->len)   \
-            v2 = spl->data16[spl->loop_start>>MIX_FIX_SHIFT];                \
+            v2 = spl->data.u16[spl->loop_start>>MIX_FIX_SHIFT] << 8;         \
          else                                                                \
-            v2 = 0x8000;                                                     \
+            v2 = 0x800000;                                                   \
       }                                                                      \
       else                                                                   \
-	 v2 = spl->data16[v+1];                                              \
+	 v2 = spl->data.u16[v+1] << 8;                                           \
 									     \
-      v = spl->pos & (MIX_FIX_SCALE-1);                                      \
-      v = (v1*(MIX_FIX_SCALE-v) + v2*v) / MIX_FIX_SCALE;                     \
+      v = (spl->pos & (MIX_FIX_SCALE-1)) >> 1;                               \
+	  v = (((v2 - v1) * v) >> (MIX_FIX_SHIFT-1)) + v1;                       \
 									     \
-      *(buf++) += ((v-0x8000)*lvol)>>16;                                     \
-      *(buf++) += ((v-0x8000)*rvol)>>16;
+	  *(buf++) += MULSC(v-0x800000, lvol);                                   \
+	  *(buf++) += MULSC(v-0x800000, rvol);
MIXER(); @@ -1020,10 +1149,10 @@ * until either len samples have been mixed or until the end of the sample * is reached.
  */
-static void mix_hq2_16x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, unsigned short *buf, int len)
+static void mix_hq2_16x2_samples(MIXER_VOICE *spl, PHYS_VOICE *voice, signed int *buf, int len)
 {
-   int lvol = volume_table[spl->lvol];
-   int rvol = volume_table[spl->rvol];
+   int lvol = spl->lvol;
+   int rvol = spl->rvol;
    int v, va, v1a, v2a, vb, v1b, v2b;
len >>= 1;
@@ -1031,30 +1160,30 @@
    #define MIX()                                                             \
       v = (spl->pos>>MIX_FIX_SHIFT) << 1; /* x2 for stereo */                \
                                                                              \
-      v1a = spl->data16[v];                                                  \
-      v1b = spl->data16[v+1];                                                \
+      v1a = spl->data.u16[v] << 8;                                           \
+      v1b = spl->data.u16[v+1] << 8;                                         \
 									     \
       if (spl->pos >= spl->len-MIX_FIX_SCALE) {                              \
          if ((voice->playmode & (PLAYMODE_LOOP |                             \
                                  PLAYMODE_BIDIR)) == PLAYMODE_LOOP &&        \
              spl->loop_start < spl->loop_end && spl->loop_end == spl->len) { \
-            v2a = spl->data16[((spl->loop_start>>MIX_FIX_SHIFT)<<1)];        \
-            v2b = spl->data16[((spl->loop_start>>MIX_FIX_SHIFT)<<1)+1];      \
+            v2a = spl->data.u16[((spl->loop_start>>MIX_FIX_SHIFT)<<1)] << 8; \
+            v2b = spl->data.u16[((spl->loop_start>>MIX_FIX_SHIFT)<<1)+1] << 8; \
          }                                                                   \
          else                                                                \
-            v2a = v2b = 0x8000;                                              \
+            v2a = v2b = 0x800000;                                            \
       }                                                                      \
       else {                                                                 \
-	 v2a = spl->data16[v+2];                                             \
-	 v2b = spl->data16[v+3];                                             \
+	 v2a = spl->data.u16[v+2] << 8;                                          \
+	 v2b = spl->data.u16[v+3] << 8;                                          \
       }                                                                      \
 									     \
-      v = spl->pos & (MIX_FIX_SCALE-1);                                      \
-      va = (v1a*(MIX_FIX_SCALE-v) + v2a*v) / MIX_FIX_SCALE;                  \
-      vb = (v1b*(MIX_FIX_SCALE-v) + v2b*v) / MIX_FIX_SCALE;                  \
+      v = (spl->pos & (MIX_FIX_SCALE-1)) >> 1;                               \
+      va = (((v2a - v1a) * v) >> (MIX_FIX_SHIFT-1)) + v1a;                       \
+      vb = (((v2b - v1b) * v) >> (MIX_FIX_SHIFT-1)) + v1b;                       \
 									     \
-      *(buf++) += ((va-0x8000)*lvol)>>16;                                    \
-      *(buf++) += ((vb-0x8000)*rvol)>>16;
+	  *(buf++) += MULSC(va-0x800000, lvol);                                   \
+	  *(buf++) += MULSC(vb-0x800000, rvol);
MIXER(); @@ -1064,6 +1193,322 @@
 END_OF_STATIC_FUNCTION(mix_hq2_16x2_samples);
+static INLINE void next_mixer_buffer(MIXER_STREAM *mixer)
+{
+	mixer->data.buffer = mixer->ext.buffer;
+	mixer->end_pos = mixer->ext.buffer_len;
+	mixer->pos = 0;
+
+	mixer->ext.buffer = NULL;
+	mixer->ext.buffer_len = 0;
+}
+
+void mix_8bit_to_buffer(MIXER_STREAM *mixer, signed int *buf, int len)
+{
+	int v, v1, v2;
+
+	/* Mono output, never interpolate */
+	if(mix_channels == 1)
+	{
+		if(mixer->channels == 2)
+		{
+			while(len--)
+			{
+				*(buf)   += (mixer->data.u8[(mixer->pos>>MIX_FIX_SHIFT)*2  ]-0x80)*mixer->lvol;
+				*(buf++) += (mixer->data.u8[(mixer->pos>>MIX_FIX_SHIFT)*2+1]-0x80)*mixer->rvol;
+				if((mixer->pos += mixer->step) >= mixer->end_pos)
+				{
+					next_mixer_buffer(mixer);
+					if(!mixer->data.buffer)
+						break;
+				}
+			}
+		}
+		else
+		{
+			while(len--)
+			{
+				*(buf++) += (mixer->data.u8[mixer->pos>>MIX_FIX_SHIFT]-0x80)*mixer->lvol;
+				if((mixer->pos += mixer->step) >= mixer->end_pos)
+				{
+					next_mixer_buffer(mixer);
+					if(!mixer->data.buffer)
+						break;
+				}
+			}
+		}
+		return;
+	}
+
+	/* Stereo output */
+	len >>= 1;
+
+	/* No interpolation */
+	if(_sound_hq < 2 || !(mixer->step & (MIX_FIX_SCALE-1)))
+	{
+		if(mixer->channels == 2)
+		{
+			while(len--)
+			{
+				*(buf++) += (mixer->data.u8[(mixer->pos>>MIX_FIX_SHIFT)*2  ]-0x80)*mixer->lvol;
+				*(buf++) += (mixer->data.u8[(mixer->pos>>MIX_FIX_SHIFT)*2+1]-0x80)*mixer->rvol;
+				if((mixer->pos += mixer->step) >= mixer->end_pos)
+				{
+					next_mixer_buffer(mixer);
+					if(!mixer->data.buffer)
+						break;
+				}
+			}
+		}
+		else
+		{
+			while(len--)
+			{
+				*(buf++) += (mixer->data.u8[mixer->pos>>MIX_FIX_SHIFT]-0x80)*mixer->lvol;
+				*(buf++) += (mixer->data.u8[mixer->pos>>MIX_FIX_SHIFT]-0x80)*mixer->rvol;
+				if((mixer->pos += mixer->step) >= mixer->end_pos)
+				{
+					next_mixer_buffer(mixer);
+					if(!mixer->data.buffer)
+						break;
+				}
+			}
+		}
+		return;
+	}
+
+	/* Linear interpolation */
+	if(mixer->channels == 2)
+	{
+		while(len--)
+		{
+			int v = (mixer->pos>>MIX_FIX_SHIFT) << 1;
+			int v1a = mixer->data.u8[v] << 16;
+			int v1b = mixer->data.u8[v+1] << 16;
+			int va, vb, v2a, v2b;
+
+			if(mixer->pos+MIX_FIX_SCALE >= mixer->end_pos)
+			{
+				if(mixer->ext.buffer)
+				{
+					v2a = ((unsigned char*)mixer->ext.buffer)[0] << 16;
+					v2b = ((unsigned char*)mixer->ext.buffer)[1] << 16;
+				}
+				else
+					v2a = v2b = 0x800000;
+			}
+			else
+			{
+				v2a = mixer->data.u8[v+2] << 16;
+				v2b = mixer->data.u8[v+3] << 16;
+			}
+
+			v = (mixer->pos & (MIX_FIX_SCALE-1)) >> 1;
+			va = (((v2a - v1a) * v) >> (MIX_FIX_SHIFT-1)) + v1a;
+			vb = (((v2b - v1b) * v) >> (MIX_FIX_SHIFT-1)) + v1b;
+
+			*(buf++) += MULSC(va-0x800000, mixer->lvol);
+			*(buf++) += MULSC(vb-0x800000, mixer->rvol);
+			if((mixer->pos += mixer->step) >= mixer->end_pos)
+			{
+				next_mixer_buffer(mixer);
+				if(!mixer->data.buffer)
+					break;
+			}
+		}
+	}
+	else
+	{
+		while(len--)
+		{
+			int v = mixer->pos >> MIX_FIX_SHIFT;
+			int v1 = mixer->data.u8[v] << 16;
+			int v2;
+
+			if(mixer->pos+MIX_FIX_SCALE >= mixer->end_pos)
+			{
+				if(mixer->ext.buffer)
+					v2 = ((unsigned char*)mixer->ext.buffer)[0] << 16;
+				else
+					v2 = 0x800000;
+			}
+			else
+				v2 = mixer->data.u8[v+1] << 16;
+
+			v = (mixer->pos & (MIX_FIX_SCALE-1)) >> 1;
+			v = (((v2 - v1) * v) >> (MIX_FIX_SHIFT-1)) + v1;
+
+			*(buf++) += MULSC(v-0x800000, mixer->lvol);
+			*(buf++) += MULSC(v-0x800000, mixer->rvol);
+			if((mixer->pos += mixer->step) >= mixer->end_pos)
+			{
+				next_mixer_buffer(mixer);
+				if(!mixer->data.buffer)
+					break;
+			}
+		}
+	}
+}
+
+void mix_16bit_to_buffer(MIXER_STREAM *mixer, signed int *buf, int len)
+{
+	if(mix_channels == 1)
+	{
+		if(mixer->channels == 2)
+		{
+			while(len--)
+			{
+				*(buf)   += ((mixer->data.u16[(mixer->pos>>MIX_FIX_SHIFT)*2  ]-0x8000)*mixer->lvol)>>8;
+				*(buf++) += ((mixer->data.u16[(mixer->pos>>MIX_FIX_SHIFT)*2+1]-0x8000)*mixer->rvol)>>8;
+				if((mixer->pos += mixer->step) >= mixer->end_pos)
+				{
+					next_mixer_buffer(mixer);
+					if(!mixer->data.buffer)
+						break;
+				}
+			}
+		}
+		else
+		{
+			while(len--)
+			{
+				*(buf++) += ((mixer->data.u16[mixer->pos>>MIX_FIX_SHIFT]-0x8000)*mixer->lvol)>>8;
+				if((mixer->pos += mixer->step) >= mixer->end_pos)
+				{
+					next_mixer_buffer(mixer);
+					if(!mixer->data.buffer)
+						break;
+				}
+			}
+		}
+		return;
+	}
+
+	len >>= 1;
+
+	if(_sound_hq < 2 || !(mixer->step & (MIX_FIX_SCALE-1)))
+	{
+		if(mixer->channels == 2)
+		{
+			while(len--)
+			{
+				*(buf++) += ((mixer->data.u16[(mixer->pos>>MIX_FIX_SHIFT)*2  ]-0x8000)*mixer->lvol)>>8;
+				*(buf++) += ((mixer->data.u16[(mixer->pos>>MIX_FIX_SHIFT)*2+1]-0x8000)*mixer->rvol)>>8;
+				if((mixer->pos += mixer->step) >= mixer->end_pos)
+				{
+					next_mixer_buffer(mixer);
+					if(!mixer->data.buffer)
+						break;
+				}
+			}
+		}
+		else
+		{
+			while(len--)
+			{
+				*(buf++) += ((mixer->data.u16[mixer->pos>>MIX_FIX_SHIFT]-0x8000)*mixer->lvol)>>8;
+				*(buf++) += ((mixer->data.u16[mixer->pos>>MIX_FIX_SHIFT]-0x8000)*mixer->rvol)>>8;
+				if((mixer->pos += mixer->step) >= mixer->end_pos)
+				{
+					next_mixer_buffer(mixer);
+					if(!mixer->data.buffer)
+						break;
+				}
+			}
+		}
+		return;
+	}
+
+	if(mixer->channels == 2)
+	{
+		while(len--)
+		{
+			int v = (mixer->pos>>MIX_FIX_SHIFT) << 1;
+			int v1a = mixer->data.u16[v] << 8;
+			int v1b = mixer->data.u16[v+1] << 8;
+			int va, vb, v2a, v2b;
+
+			if(mixer->pos+MIX_FIX_SCALE >= mixer->end_pos)
+			{
+				if(mixer->ext.buffer)
+				{
+					v2a = ((unsigned short*)mixer->ext.buffer)[0] << 8;
+					v2b = ((unsigned short*)mixer->ext.buffer)[1] << 8;
+				}
+				else
+					v2a = v2b = 0x800000;
+			}
+			else
+			{
+				v2a = mixer->data.u16[v+2] << 8;
+				v2b = mixer->data.u16[v+3] << 8;
+			}
+
+			v = (mixer->pos & (MIX_FIX_SCALE-1)) >> 1;
+			va = (((v2a - v1a) * v) >> (MIX_FIX_SHIFT-1)) + v1a;
+			vb = (((v2b - v1b) * v) >> (MIX_FIX_SHIFT-1)) + v1b;
+
+			*(buf++) += MULSC(va-0x800000, mixer->lvol);
+			*(buf++) += MULSC(vb-0x800000, mixer->rvol);
+			if((mixer->pos += mixer->step) >= mixer->end_pos)
+			{
+				next_mixer_buffer(mixer);
+				if(!mixer->data.buffer)
+					break;
+			}
+		}
+	}
+	else
+	{
+		while(len--)
+		{
+			int v = mixer->pos >> MIX_FIX_SHIFT;
+			int v1 = mixer->data.u16[v] << 8;
+			int v2;
+
+			if(mixer->pos+MIX_FIX_SCALE >= mixer->end_pos)
+			{
+				if(mixer->ext.buffer)
+					v2 = ((unsigned short*)mixer->ext.buffer)[0] << 8;
+				else
+					v2 = 0x800000;
+			}
+			else
+				v2 = mixer->data.u16[v+1] << 8;
+
+			v = (mixer->pos & (MIX_FIX_SCALE-1)) >> 1;
+			v = (((v2 - v1) * v) >> (MIX_FIX_SHIFT-1)) + v1;
+
+			*(buf++) += MULSC(v-0x800000, mixer->lvol);
+			*(buf++) += MULSC(v-0x800000, mixer->rvol);
+			if((mixer->pos += mixer->step) >= mixer->end_pos)
+			{
+				next_mixer_buffer(mixer);
+				if(!mixer->data.buffer)
+					break;
+			}
+		}
+	}
+}
+
+/* clamp_val:
+ *  Clamps the given sample volume to a signed 24-bit value
+ */
+static INLINE int clamp_val(int s)
+{
+	/* Clamp to min */
+	s -= -(1<<23);
+	s &= (~s) >> 31;
+	s += -(1<<23);
+
+	/* Clamp to max */
+	s -= (1<<23)-1;
+	s &= s >> 31;
+	s += (1<<23)-1;
+
+	return s;
+}
+
/* _mix_some_samples:
  *  Mixes samples into a buffer in conventional memory (the buf parameter
@@ -1074,117 +1519,79 @@
  */
 void _mix_some_samples(unsigned long buf, unsigned short seg, int issigned)
 {
+   signed int *p = mix_buffer;
+   MIXER_STREAM *mixer;
    int i;
-   unsigned short *p = mix_buffer;
-   unsigned long *l = (unsigned long *)p;
/* clear mixing buffer */
-   for (i=0; i<mix_size/2; i++)
-      *(l++) = 0x80008000;
+   memset(p, 0, mix_size * sizeof(*p));
#ifdef ALLEGRO_MULTITHREADED
    system_driver->lock_mutex(mixer_mutex);
 #endif
- if (_sound_hq >= 2) {
-      /* top quality interpolated 16 bit mixing */
-      for (i=0; i<mix_voices; i++) {
-	 if (mixer_voice[i].playing) {
-            if ((_phys_voice[i].vol > 0) || (_phys_voice[i].dvol > 0)) {
-	       if (mixer_voice[i].stereo) {
-	          /* stereo input -> interpolated output */
-	          if (mixer_voice[i].data8)
-		     mix_hq2_8x2_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	          else
-		     mix_hq2_16x2_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	       }
-	       else {
-	          /* mono input -> interpolated output */
-	          if (mixer_voice[i].data8)
-		     mix_hq2_8x1_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	          else
-		     mix_hq2_16x1_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	       }
-            }
-            else
-               mix_silent_samples(mixer_voice+i, _phys_voice+i, mix_size>>1);
-	 }
-      }
-   }
-   else if (_sound_hq) {
-      /* high quality 16 bit mixing */
-      for (i=0; i<mix_voices; i++) {
-	 if (mixer_voice[i].playing) {
-	    if ((_phys_voice[i].vol > 0) || (_phys_voice[i].dvol > 0)) {
-	       if (mixer_voice[i].stereo) {
-	          /* stereo input -> high quality output */
-	          if (mixer_voice[i].data8)
-		     mix_hq1_8x2_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	          else
-		     mix_hq1_16x2_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	       }
-	       else {
-	          /* mono input -> high quality output */
-	          if (mixer_voice[i].data8)
-		     mix_hq1_8x1_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	          else
-		     mix_hq1_16x1_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	       }
-            }
-            else
-               mix_silent_samples(mixer_voice+i, _phys_voice+i, mix_size>>1);
-	 }
-      }
-   }
- else if (mix_stereo) { - /* lower quality (faster) stereo mixing */
-      for (i=0; i<mix_voices; i++) {
-	 if (mixer_voice[i].playing) {
-	    if ((_phys_voice[i].vol > 0) || (_phys_voice[i].dvol > 0)) {
-	       if (mixer_voice[i].stereo) {
-	          /* stereo input -> stereo output */
-	          if (mixer_voice[i].data8)
-		     mix_stereo_8x2_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	          else
-		     mix_stereo_16x2_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	       }
-	       else {
-	          /* mono input -> stereo output */
-	          if (mixer_voice[i].data8)
-		     mix_stereo_8x1_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	          else
-		     mix_stereo_16x1_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	       }
-            }
-            else
-               mix_silent_samples(mixer_voice+i, _phys_voice+i, mix_size>>1);
-	 }
+   for (i=0; i<mix_voices; i++) {
+      if (mixer_voice[i].playing) {
+         if ((_phys_voice[i].vol > 0) || (_phys_voice[i].dvol > 0))
+            mixer_voice[i].mix_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
+         else
+            mix_silent_samples(mixer_voice+i, _phys_voice+i, mix_size>>1);
       }
    }
-   else {
-      /* lower quality (fast) mono mixing */
-      for (i=0; i<mix_voices; i++) {
-	 if (mixer_voice[i].playing) {
-	    if ((_phys_voice[i].vol > 0) || (_phys_voice[i].dvol > 0)) {
-	       if (mixer_voice[i].stereo) {
-	          /* stereo input -> mono output */
-	          if (mixer_voice[i].data8)
-		     mix_mono_8x2_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	          else
-		     mix_mono_16x2_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	       }
-	       else {
-	          /* mono input -> mono output */
-	          if (mixer_voice[i].data8)
-		     mix_mono_8x1_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	          else
-		     mix_mono_16x1_samples(mixer_voice+i, _phys_voice+i, p, mix_size);
-	       }
-            }
-            else
-               mix_silent_samples(mixer_voice+i, _phys_voice+i, mix_size);
-	 }
-      }
+
+   mixer = mixer_stream_list;
+   while(mixer) {
+	   if(mixer->kill > 0)
+	   {
+		   MIXER_STREAM **list = &mixer_stream_list;
+		   while(*list)
+		   {
+			   if((*list) == mixer)
+			   {
+				   *list = (MIXER_STREAM*)mixer->extra;
+				   free(mixer);
+				   mixer = *list;
+				   break;
+			   }
+			   list = (MIXER_STREAM**)&((*list)->extra);
+		   }
+		   continue;
+	   }
+
+       if(mixer->dvol || mixer->dpan)
+       {
+		   mixer->vol += mixer->dvol;
+		   mixer->pan += mixer->dpan;
+
+           mixer->lvol = mixer->vol * (255-mixer->pan);
+           mixer->rvol = mixer->vol * mixer->pan;
+           mixer->lvol += mixer->lvol >> 7;
+           mixer->rvol += mixer->rvol >> 7;
+
+		   mixer->dvol = 0;
+		   mixer->dpan = 0;
+	   }
+       if(mixer->dfreq)
+	   {
+		   mixer->freq += mixer->dfreq;
+		   mixer->step = mixer->freq * MIX_FIX_SCALE / mix_freq;
+		   mixer->dfreq = 0;
+	   }
+
+	   if(mixer->pos < mixer->end_pos)
+	   {
+		   if(mixer->bits == 16)
+			   mix_16bit_to_buffer(mixer, p, mix_size);
+		   else
+			   mix_8bit_to_buffer(mixer, p, mix_size);
+	   }
+	   else if(mixer->kill < 0)
+	   {
+		   mixer->kill = 1;
+		   continue;
+	   }
+
+	   mixer = (MIXER_STREAM*)mixer->extra;
    }
#ifdef ALLEGRO_MULTITHREADED
@@ -1193,28 +1600,37 @@
_farsetsel(seg); - /* transfer to conventional memory buffer using a clip table */
-   if (mix_16bit) {
+   /* transfer to the sound driver's buffer */
+   if (mix_bits == 16) {
       if (issigned) {
 	 for (i=0; i<mix_size; i++) {
-	    _farnspokew(buf, mix_clip_table[*p >> (16-MIX_RES_16)] ^ 0x8000);
+	    _farnspokew(buf, clamp_val(*p) >> 8);
 	    buf += sizeof(short);
 	    p++;
-         }
+     }
       }
       else {
 	 for (i=0; i<mix_size; i++) {
-	    _farnspokew(buf, mix_clip_table[*p >> (16-MIX_RES_16)]);
+	        _farnspokew(buf, (signed short)(clamp_val(*p) >> 8) ^ 0x8000);
             buf += sizeof(short);
             p++;
-         }
+     }
       }
    }
    else {
-      for (i=0; i<mix_size; i++) {
-	 _farnspokeb(buf, mix_clip_table[*p >> (16-MIX_RES_8)]);
-         buf++;
-         p++;
+	  if(issigned) {
+     for (i=0; i<mix_size; i++) {
+			_farnspokeb(buf, clamp_val(*p) >> 16);
+            buf++;
+            p++;
+	 }
+	  }
+	  else {
+     for (i=0; i<mix_size; i++) {
+			_farnspokeb(buf, (signed char)(clamp_val(*p) >> 16) ^ 0x80);
+            buf++;
+            p++;
+	 }
       }
    }
 }
@@ -1235,13 +1651,78 @@
    mixer_voice[voice].loop_start = sample->loop_start << MIX_FIX_SHIFT;
    mixer_voice[voice].loop_end = sample->loop_end << MIX_FIX_SHIFT;
- if (sample->bits == 8) {
-      mixer_voice[voice].data8 = sample->data;
-      mixer_voice[voice].data16 = NULL;
+   if (sample->bits == 8)
+      mixer_voice[voice].data.u8 = sample->data;
+   else
+      mixer_voice[voice].data.u16 = sample->data;
+
+   /* top quality interpolated 16 bit mixing */
+   if (_sound_hq >= 2) {
+       /* stereo input -> interpolated output */
+       if (sample->stereo) {
+          if (sample->bits == 8)
+		     mixer_voice[voice].mix_samples = mix_hq2_8x2_samples;
+          else
+		     mixer_voice[voice].mix_samples = mix_hq2_16x2_samples;
+       }
+       /* mono input -> interpolated output */
+       else {
+          if (sample->bits == 8)
+		     mixer_voice[voice].mix_samples = mix_hq2_8x1_samples;
+          else
+		     mixer_voice[voice].mix_samples = mix_hq2_16x1_samples;
+       }
    }
+   /* high quality 16 bit mixing */
+   else if (_sound_hq) {
+       /* stereo input -> high quality output */
+       if (sample->stereo) {
+          if (sample->bits == 8)
+		     mixer_voice[voice].mix_samples = mix_hq1_8x2_samples;
+          else
+		     mixer_voice[voice].mix_samples = mix_hq1_16x2_samples;
+       }
+       /* mono input -> high quality output */
+       else {
+          if (sample->bits == 8)
+		     mixer_voice[voice].mix_samples = mix_hq1_8x1_samples;
+          else
+		     mixer_voice[voice].mix_samples = mix_hq1_16x1_samples;
+       }
+   }
+   /* lower quality (faster) stereo mixing */
+ else if (mix_channels == 2) { + /* stereo input -> stereo output */
+       if (sample->stereo) {
+          if (sample->bits == 8)
+		     mixer_voice[voice].mix_samples = mix_stereo_8x2_samples;
+          else
+		     mixer_voice[voice].mix_samples = mix_stereo_16x2_samples;
+       }
+       /* mono input -> stereo output */
+       else {
+          if (sample->bits == 8)
+		     mixer_voice[voice].mix_samples = mix_stereo_8x1_samples;
+          else
+		     mixer_voice[voice].mix_samples = mix_stereo_16x1_samples;
+       }
+   }
+   /* lower quality (fast) mono mixing */
    else {
-      mixer_voice[voice].data8 = NULL;
-      mixer_voice[voice].data16 = sample->data;
+       /* stereo input -> mono output */
+       if (sample->stereo) {
+          if (sample->bits == 8)
+		     mixer_voice[voice].mix_samples = mix_mono_8x2_samples;
+          else
+		     mixer_voice[voice].mix_samples = mix_mono_16x2_samples;
+       }
+       /* mono input -> mono output */
+       else {
+          if (sample->bits == 8)
+		     mixer_voice[voice].mix_samples = mix_mono_8x1_samples;
+          else
+		     mixer_voice[voice].mix_samples = mix_mono_16x1_samples;
+       }
    }
update_mixer_volume(mixer_voice+voice, _phys_voice+voice);
@@ -1262,8 +1743,8 @@
 #endif
mixer_voice[voice].playing = FALSE;
-   mixer_voice[voice].data8 = NULL;
-   mixer_voice[voice].data16 = NULL;
+   mixer_voice[voice].data.u8 = NULL;
+   mixer_voice[voice].data.u16 = NULL;
#ifdef ALLEGRO_MULTITHREADED
    system_driver->unlock_mutex(mixer_mutex);
@@ -1544,12 +2025,27 @@
    LOCK_VARIABLE(mixer_voice);
    LOCK_VARIABLE(mix_buffer);
    LOCK_VARIABLE(mix_vol_table);
-   LOCK_VARIABLE(mix_clip_table);
    LOCK_VARIABLE(mix_voices);
    LOCK_VARIABLE(mix_size);
    LOCK_VARIABLE(mix_freq);
-   LOCK_VARIABLE(mix_stereo);
-   LOCK_VARIABLE(mix_16bit);
+   LOCK_VARIABLE(mix_channels);
+   LOCK_VARIABLE(mix_bits);
+   LOCK_VARIABLE(mixer_stream_list);
+   LOCK_FUNCTION(get_mixer_buffer_length);
+   LOCK_FUNCTION(get_mixer_frequency);
+   LOCK_FUNCTION(get_mixer_bits);
+   LOCK_FUNCTION(get_mixer_channels);
+   LOCK_FUNCTION(get_mixer_voices);
+   LOCK_FUNCTION(get_mixer_stream_position);
+   LOCK_FUNCTION(get_mixer_stream_freq);
+   LOCK_FUNCTION(get_mixer_stream_volume);
+   LOCK_FUNCTION(get_mixer_stream_pan);
+   LOCK_FUNCTION(set_mixer_stream_freq);
+   LOCK_FUNCTION(set_mixer_stream_volume);
+   LOCK_FUNCTION(set_mixer_stream_pan);
+   LOCK_FUNCTION(create_mixer_stream);
+   LOCK_FUNCTION(destroy_mixer_stream);
+   LOCK_FUNCTION(release_mixer_stream);
    LOCK_FUNCTION(mix_silent_samples);
    LOCK_FUNCTION(mix_mono_8x1_samples);
    LOCK_FUNCTION(mix_mono_8x2_samples);
@@ -1594,6 +2090,3 @@
    LOCK_FUNCTION(_mixer_set_tremolo);
    LOCK_FUNCTION(_mixer_set_vibrato);
 }
-
-
-




Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/