[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
New update. :)
The mixer now does full signed 24-bit mixing in a signed 32-bit buffer.
This should mean there's a theoretical max of 255 samples without risk
of wrapping (or 127 stereo samples with mono output). Also, the
interpolation mixer interpolates in full 24-bits, though it dropped from
an 8-bit interpolation level to 7-bit (maybe this can be fixed?). I
would also be curious to see if the hq1 mixer out performs the low
quality stereo mixer now. It's a definate possibility, IMHO. It
definately has a better performance-to-quality ratio. Any performance
loss (if any) is more than made up with the added quality and preciseness.
The default set_volume_per_voice has been set to 1, so 1 panned sample
will never be clamped and distort. It should be easy enough to set it to
be -1 again if you wish (just change the default value of the global),
but this way closer emulates the DX mixer that Allegro can, and most
often does, use. I would also recommend discouraging future use of
set_volume_per_voice without good reason. There is absolutely no risk of
overflow with Allegro's maximum of 64 digital voices, even with an
over-sampled volume level (via set_volume_per_voice(0)) and 64
simultanious stereo samples on a mono buffer. Any resulting distortion
can be controlled with set_volume, which is a lot easier for both using
in the program, and exposing for the end user should you want to
(exposing set_volume_per_voice to the end user has always been
discouraged anyway).
This time I attached a .diff file, to be applied to the original mixer.c
from the 4.1.13 source tree (from within the src subdir).
--- mixer.c.orig 2004-03-21 03:08:55.000000000 +0000
+++ mixer.c 2004-03-21 03:00:10.000000000 +0000
@@ -35,8 +35,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 +46,12 @@
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
+
#define MIX_FIX_SHIFT 8
#define MIX_FIX_SCALE (1<<MIX_FIX_SHIFT)
@@ -59,32 +63,12 @@
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];
+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;
@@ -93,7 +77,7 @@
static int mix_16bit;
/* shift factor for volume per voice */
-static int voice_volume_scale = -1;
+static int voice_volume_scale = 1;
static void mixer_lock_mem(void);
@@ -114,41 +98,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;
+ int i;
- for (i=0; i<ENTRIES_VOL_TABLE; i++, acum+=step)
- volume_table[i] = acum;
-
- 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;
+ }
+
+ voice_volume_scale = scale;
+
+ /* Scale 0 could overflow the lq volume table */
+ if((!_sound_hq) && (scale < 1))
+ voice_volume_scale = 1;
+
+ /* 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,28 +141,10 @@
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;
@@ -192,75 +153,37 @@
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));
+ LOCK_DATA(mix_buffer, mix_size * sizeof(*mix_buffer));
- /* 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);
-
- 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_stereo)) {
+ /* 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();
@@ -294,20 +217,9 @@
free(mix_vol_table);
mix_vol_table = NULL;
}
-
- if (mix_clip_table) {
- free(mix_clip_table);
- mix_clip_table = NULL;
- }
-
- if (volume_table) {
- free(volume_table);
- volume_table = NULL;
- }
}
-
/* update_mixer_volume:
* Called whenever the voice volume or pan changes, to update the mixer
* amplification table indexes.
@@ -317,37 +229,37 @@
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);
+ 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);
+ /* 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;
+ 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 +378,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 +513,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 +533,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 +555,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 +575,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 +597,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 +621,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 +645,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 +669,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 +687,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 +717,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 +742,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 +767,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 +786,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 +805,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 +838,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 +888,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 +899,24 @@
#define MIX() \
v = spl->pos>>MIX_FIX_SHIFT; \
\
- v1 = spl->data16[v]; \
+ v1 = (int)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 = (int)spl->data.u16[spl->loop_start>>MIX_FIX_SHIFT] << 8; \
else \
- v2 = 0x8000; \
+ v2 = 0x800000; \
} \
else \
- v2 = spl->data16[v+1]; \
+ v2 = (int)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 +932,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 +943,30 @@
#define MIX() \
v = (spl->pos>>MIX_FIX_SHIFT) << 1; /* x2 for stereo */ \
\
- v1a = spl->data16[v]; \
- v1b = spl->data16[v+1]; \
+ v1a = (int)spl->data.u16[v] << 8; \
+ v1b = (int)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 = (int)spl->data.u16[((spl->loop_start>>MIX_FIX_SHIFT)<<1)] << 8; \
+ v2b = (int)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 = (int)spl->data.u16[v+2] << 8; \
+ v2b = (int)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 +976,24 @@
END_OF_STATIC_FUNCTION(mix_hq2_16x2_samples);
+/* 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,116 +1004,22 @@
*/
void _mix_some_samples(unsigned long buf, unsigned short seg, int issigned)
{
+ signed int *p = mix_buffer;
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);
- }
- }
- }
- 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);
- }
+ 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);
}
}
@@ -1193,18 +1029,18 @@
_farsetsel(seg);
- /* transfer to conventional memory buffer using a clip table */
+ /* transfer to the sound driver's buffer */
if (mix_16bit) {
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++;
}
@@ -1212,7 +1048,7 @@
}
else {
for (i=0; i<mix_size; i++) {
- _farnspokeb(buf, mix_clip_table[*p >> (16-MIX_RES_8)]);
+ _farnspokeb(buf, (signed char)(clamp_val(*p) >> 16) ^ 0x80);
buf++;
p++;
}
@@ -1235,13 +1071,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_stereo) {
+ /* 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 +1163,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,7 +1445,6 @@
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);