kobodl/sound/a_mixers.h
Ville Lindholm dbc223eb84
Initial commit
Import existing source tree; original VCS history is no longer available.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-28 16:35:31 +03:00

360 lines
8.8 KiB
C

/*(LGPL)
---------------------------------------------------------------------------
a_mixers.h - Mixer Core Code
---------------------------------------------------------------------------
* Copyright (C) 2001, 2002, 2007 David Olofson
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This is to be included multiple times, with various definitions
* of some macros - that's why it looks so weird for a "header"...
*/
#define __FOR_SAMPLES frames <<= 1; for(s = 0; s < frames; s += 2)
#ifdef __STEREO
/* Paste the stereo-only lines */
# define __ST(x) x
/* Index unit: two per sample */
# define __INDEX ((sp >> (FREQ_BITS - 1)) & 0xfffffffe)
/* Right output from right input */
# define __INDINC 2
# define __R r
#else
/* Don't paste stereo stuff */
# define __ST(x)
/* Index unit: one per sample */
# define __INDEX (sp >> FREQ_BITS)
# define __INDINC 1
/* Right output from mono input */
# define __R l
#endif
#ifdef __16BIT
# define __NORMALIZE VOL_BITS
#else
# define __NORMALIZE (VOL_BITS-8)
#endif
#if defined(__16BIT) && (FREQ_BITS > 15)
# define __FRAC (int)((sp >> (FREQ_BITS - 15)) & 0x7fff)
# define __IFRAC(x) (0x8000 - x)
# define __FRACBITS 15
#else
# define __FRAC (int)(sp & ((1 << FREQ_BITS) - 1))
# define __IFRAC(x) ((1 << FREQ_BITS) - x)
# define __FRACBITS FREQ_BITS
#endif
#ifdef __SEND
# define __SND(x) x
#else
# define __SND(x)
#endif
#define LVOL (v->ic[VIC_LVOL].v >> RAMP_BITS)
#define RVOL (v->ic[VIC_RVOL].v >> RAMP_BITS)
#define LSEND (v->ic[VIC_LSEND].v >> RAMP_BITS)
#define RSEND (v->ic[VIC_RSEND].v >> RAMP_BITS)
#define CSEND ((v->ic[VIC_LSEND].v + v->ic[VIC_RSEND].v) >> (RAMP_BITS + 1))
#define __OUTPUT \
out[s] += l * LVOL >> __NORMALIZE; \
out[s + 1] += __R * RVOL >> __NORMALIZE; \
__SND( sout[s] += l * LSEND >> __NORMALIZE; \
sout[s + 1] += __R * RSEND >> __NORMALIZE;)
#define __RAMP \
v->ic[VIC_LVOL].v += v->ic[VIC_LVOL].dv; \
v->ic[VIC_RVOL].v += v->ic[VIC_RVOL].dv; \
__SND( v->ic[VIC_LSEND].v += v->ic[VIC_LSEND].dv; \
v->ic[VIC_RSEND].v += v->ic[VIC_RSEND].dv;)
#ifdef AUDIO_USE_VU
int vu;
#endif
unsigned s;
unsigned int sp = ((v->position << FREQ_BITS) & 0x7fffffff) +
(v->position_frac >> (32 - FREQ_BITS));
#ifdef __16BIT
Sint16 *in = (Sint16 *)(wavetab[v->c[VC_WAVE]].data.si16) +
#else
Sint8 *in = (Sint8 *)(wavetab[v->c[VC_WAVE]].data.si8) +
#endif
/*
* Adjust pointer according to bits 31+ of the position.
* Note that this overlap in bit 31 is important; it
* allows windows to cross "block" boundaries!
*/
#ifdef __STEREO
2 *
#endif
(v->position & ~((1<<(31-FREQ_BITS)) - 1));
#ifdef AUDIO_USE_VU
#ifdef __STEREO
vu = in[__INDEX] + in[__INDEX+1];
#else
vu = in[__INDEX] << 1;
#endif
#ifndef __16BIT
vu <<= 8;
#endif
if(vu > v->vu)
v->vu = vu;
else if(-vu > v->vu)
v->vu = -vu;
#endif /*AUDIO_USE_VU*/
switch(v->c[VC_RESAMPLE])
{
default:
case AR_NEAREST:
{
int lvol = LVOL;
int rvol = RVOL;
__SND(int csend = CSEND;)
v->ic[VIC_LVOL].v += v->ic[VIC_LVOL].dv * frames;
v->ic[VIC_RVOL].v += v->ic[VIC_RVOL].dv * frames;
__SND( v->ic[VIC_LSEND].v += v->ic[VIC_LSEND].dv * frames;
v->ic[VIC_RSEND].v += v->ic[VIC_RSEND].dv * frames;)
__FOR_SAMPLES
{
unsigned ind = __INDEX;
int l = in[ind];
__ST(int r = in[ind + 1];)
__SND(int ss;)
out[s] += l * lvol >> __NORMALIZE;
out[s + 1] += __R * rvol >> __NORMALIZE;
__SND(ss = (l + __R) * csend >> __NORMALIZE;)
__SND(sout[s] += ss;)
__SND(sout[s + 1] += ss;)
sp += v->step;
}
break;
}
case AR_NEAREST_4X:
{
/*
* Should be cheaper than AR_LINEAR on machines
* with slow multiplications. Doesn't sound much
* better than NEAREST most of the time, though...
*/
int lvol = LVOL;
int rvol = RVOL;
unsigned step = v->step >> 2;
__SND(int csend = CSEND;)
v->ic[VIC_LVOL].v += v->ic[VIC_LVOL].dv * frames;
v->ic[VIC_RVOL].v += v->ic[VIC_RVOL].dv * frames;
__SND( v->ic[VIC_LSEND].v += v->ic[VIC_LSEND].dv * frames;
v->ic[VIC_RSEND].v += v->ic[VIC_RSEND].dv * frames;)
__FOR_SAMPLES
{
unsigned ind;
int l;
__ST(int r;)
__SND(int ss;)
ind = __INDEX; l = in[ind]; __ST(r = in[ind + 1];) sp += step;
ind = __INDEX; l += in[ind]; __ST(r += in[ind + 1];) sp += step;
ind = __INDEX; l += in[ind]; __ST(r += in[ind + 1];) sp += step;
ind = __INDEX; l += in[ind]; __ST(r += in[ind + 1];) sp += step;
l >>= 2;
__ST(r >>= 2);
out[s] += l * lvol >> __NORMALIZE ;
out[s + 1] += __R * rvol >> __NORMALIZE;
__SND(ss = (l + __R) * csend >> __NORMALIZE;)
__SND(sout[s] += ss;)
__SND(sout[s + 1] += ss;)
}
break;
}
case AR_LINEAR:
{
int lvol = LVOL;
int rvol = RVOL;
__SND( int lsend = LSEND;
int rsend = RSEND;)
v->ic[VIC_LVOL].v += v->ic[VIC_LVOL].dv * frames;
v->ic[VIC_RVOL].v += v->ic[VIC_RVOL].dv * frames;
__SND( v->ic[VIC_LSEND].v += v->ic[VIC_LSEND].dv * frames;
v->ic[VIC_RSEND].v += v->ic[VIC_RSEND].dv * frames;)
__FOR_SAMPLES
{
int l;
__ST(int r;)
unsigned ind = __INDEX;
int frac = __FRAC;
int ifrac = __IFRAC(frac);
l = in[ind + __INDINC] * frac;
__ST(r = in[ind + 3] * frac;)
l += in[ind] * ifrac;
__ST(r += in[ind + 1] * ifrac;)
l >>= __FRACBITS;
__ST(r >>= __FRACBITS;)
out[s] += l * lvol >> __NORMALIZE;
out[s + 1] += __R * rvol >> __NORMALIZE;
__SND(sout[s] += l * lsend >> __NORMALIZE;)
__SND(sout[s + 1] += __R * rsend >> __NORMALIZE;)
sp += v->step;
}
break;
}
case AR_LINEAR_2X_R:
{
unsigned step1 = v->step >> 1;
unsigned step2 = (v->step + 1) >> 1;
__FOR_SAMPLES
{
int l, l2;
__ST(int r;)
__ST(int r2;)
unsigned ind = __INDEX;
int frac = __FRAC;
int ifrac = __IFRAC(frac);
l = in[ind + __INDINC] * frac;
__ST(r = in[ind + 3] * frac;)
l += in[ind] * ifrac;
__ST(r += in[ind + 1] * ifrac;)
sp += step1;
ind = __INDEX;
frac = __FRAC;
ifrac = __IFRAC(frac);
l2 = in[ind + __INDINC] * frac;
__ST(r2 = in[ind + 3] * frac;)
l2 += in[ind] * ifrac;
__ST(r2 += in[ind + 1] * ifrac;)
sp += step2;
l = ((l >> 1) + (l2 >> 1)) >> __FRACBITS;
__ST(r = ((r >> 1) + (r2 >> 1)) >> __FRACBITS;)
__OUTPUT
__RAMP
}
break;
}
case AR_LINEAR_4X_R:
case AR_LINEAR_8X_R:
case AR_LINEAR_16X_R:
{
int over_shift = v->c[VC_RESAMPLE] - AR_LINEAR_4X_R + 2;
int over = 1 << over_shift;
unsigned step = v->step >> over_shift;
__FOR_SAMPLES
{
int i, l = 0;
__ST(int r = 0;)
for(i = 0; i < over; ++i)
{
int ll;
__ST(int rr;)
unsigned ind = __INDEX;
int frac = __FRAC;
int ifrac = __IFRAC(frac);
ll = in[ind + __INDINC] * frac;
__ST(rr = in[ind + 3] * frac;)
ll += in[ind] * ifrac;
__ST(rr += in[ind + 1] * ifrac;)
l += ll >> over_shift;
__ST(r += rr >> over_shift;)
sp += step;
}
l >>= __FRACBITS;
__ST(r >>= __FRACBITS;)
__OUTPUT
__RAMP
}
break;
}
case AR_CUBIC_R:
{
/*
* Interpolation formulae by Olli Niemitalo.
* Converted to integer arithmetics by David Olofson.
*/
__FOR_SAMPLES
{
int a, b, c, lm1, l, l1, l2;
#ifdef __STEREO
int rm1, r, r1, r2;
#endif
int ind = __INDEX;
int frac = __FRAC;
lm1 = in[ind];
l = in[ind + __INDINC];
l1 = in[ind + __INDINC*2];
l2 = in[ind + __INDINC*3];
a = (3 * (l-l1) - lm1 + l2) >> 1;
b = (l1 << 1) + lm1 - ((5*l + l2) >> 1);
c = (l1 - lm1) >> 1;
a = a * frac >> __FRACBITS;
a = (a + b) * frac >> __FRACBITS;
l += (a + c) * frac >> __FRACBITS;
sp += v->step;
#ifdef __STEREO
rm1 = in[ind + 1];
r = in[ind + 3];
r1 = in[ind + 5];
r2 = in[ind + 7];
a = (3 * (r-r1) - rm1 + r2) >> 1;
b = (r1 << 1) + rm1 - ((5*r + r2) >> 1);
c = (r1 - rm1) >> 1;
a = a * frac >> __FRACBITS;
a = (a + b) * frac >> __FRACBITS;
r += (a + c) * frac >> __FRACBITS;
#endif
__OUTPUT
__RAMP
}
break;
}
}
/*
* Put the position back, *adding* to the integer part,
* to handle the bit 31 overlap properly. (The block
* hack requires us to start with bit 31 == 0, so it can
* serve as a "carry flag" as an extra bonus.)
*/
v->position &= ~(0x7fffffff >> FREQ_BITS);
v->position += sp >> FREQ_BITS;
/*
* For the fractional part, we just leave the bits
* below our resolution unaffected.
*/
v->position_frac &= (1<<(32-FREQ_BITS))-1;
v->position_frac |= sp << (32-FREQ_BITS);
#undef __FOR_SAMPLES
#undef __NORMALIZE
#undef __SND
#undef __ST
#undef __INDEX
#undef __INDINC
#undef __R
#undef __FRAC
#undef __IFRAC
#undef __FRACBITS