ref: 13b187b846a221708d0d18e4475e230f0b639e2e
dir: /src/mixer/ft2_mix_macros.h/
#pragma once
#include "../ft2_audio.h"
#include "ft2_windowed_sinc.h"
/* ----------------------------------------------------------------------- */
/* GENERAL MIXER MACROS */
/* ----------------------------------------------------------------------- */
#define GET_VOL \
const float fVolumeL = v->fVolumeL; \
const float fVolumeR = v->fVolumeR;
#define GET_VOL_MONO \
const float fVolumeL = v->fVolumeL;
#define GET_VOL_RAMP \
fVolumeL = v->fVolumeL; \
fVolumeR = v->fVolumeR;
#define GET_VOL_MONO_RAMP \
fVolumeL = v->fVolumeL;
#define SET_VOL_BACK \
v->fVolumeL = fVolumeL; \
v->fVolumeR = fVolumeR;
#define SET_VOL_BACK_MONO \
v->fVolumeL = fVolumeL; \
v->fVolumeR = fVolumeL;
#define GET_MIXER_VARS \
const uintCPUWord_t delta = v->delta; \
fMixBufferL = audio.fMixBufferL + bufferPos; \
fMixBufferR = audio.fMixBufferR + bufferPos; \
position = v->position; \
positionFrac = v->positionFrac;
#define GET_MIXER_VARS_RAMP \
const uintCPUWord_t delta = v->delta; \
fMixBufferL = audio.fMixBufferL + bufferPos; \
fMixBufferR = audio.fMixBufferR + bufferPos; \
fVolumeLDelta = v->fVolumeLDelta; \
fVolumeRDelta = v->fVolumeRDelta; \
position = v->position; \
positionFrac = v->positionFrac;
#define GET_MIXER_VARS_MONO_RAMP \
const uintCPUWord_t delta = v->delta; \
fMixBufferL = audio.fMixBufferL + bufferPos; \
fMixBufferR = audio.fMixBufferR + bufferPos; \
fVolumeLDelta = v->fVolumeLDelta; \
position = v->position; \
positionFrac = v->positionFrac;
#define PREPARE_TAP_FIX8 \
const int8_t *loopStartPtr = &v->base8[v->loopStart]; \
const int8_t *leftEdgePtr = loopStartPtr+SINC_LEFT_TAPS;
#define PREPARE_TAP_FIX16 \
const int16_t *loopStartPtr = &v->base16[v->loopStart]; \
const int16_t *leftEdgePtr = loopStartPtr+SINC_LEFT_TAPS;
#define SET_BASE8 \
base = v->base8; \
smpPtr = base + position;
#define SET_BASE16 \
base = v->base16; \
smpPtr = base + position;
#define SET_BASE8_BIDI \
base = v->base8; \
revBase = v->revBase8;
#define SET_BASE16_BIDI \
base = v->base16; \
revBase = v->revBase16;
#define INC_POS \
positionFrac += delta; \
smpPtr += positionFrac >> MIXER_FRAC_BITS; \
positionFrac &= MIXER_FRAC_MASK;
#define INC_POS_BIDI \
positionFrac += deltaLo; \
smpPtr += positionFrac >> MIXER_FRAC_BITS; \
smpPtr += deltaHi; \
positionFrac &= MIXER_FRAC_MASK;
#define SET_BACK_MIXER_POS \
v->positionFrac = positionFrac; \
v->position = position;
/* ----------------------------------------------------------------------- */
/* SAMPLE RENDERING MACROS */
/* ----------------------------------------------------------------------- */
#define VOLUME_RAMPING \
fVolumeL += fVolumeLDelta; \
fVolumeR += fVolumeRDelta;
#define VOLUME_RAMPING_MONO \
fVolumeL += fVolumeLDelta;
#define RENDER_8BIT_SMP \
fSample = *smpPtr * (1.0f / 128.0f); \
*fMixBufferL++ += fSample * fVolumeL; \
*fMixBufferR++ += fSample * fVolumeR;
#define RENDER_8BIT_SMP_MONO \
fSample = (*smpPtr * (1.0f / 128.0f)) * fVolumeL; \
*fMixBufferL++ += fSample; \
*fMixBufferR++ += fSample;
#define RENDER_16BIT_SMP \
fSample = *smpPtr * (1.0f / 32768.0f); \
*fMixBufferL++ += fSample * fVolumeL; \
*fMixBufferR++ += fSample * fVolumeR;
#define RENDER_16BIT_SMP_MONO \
fSample = (*smpPtr * (1.0f / 32768.0f)) * fVolumeL; \
*fMixBufferL++ += fSample; \
*fMixBufferR++ += fSample;
// 2-tap linear interpolation (like FT2)
/* 8bitbubsy: It may look like we are potentially going out of bounds while looking up the sample points,
** but the sample data has a fixed sample after the end (sampleEnd/loopEnd).
*/
#define LINEAR_INTERPOLATION(s, f, scale) \
{ \
const int32_t frac = (uint32_t)(f) >> 1; /* uint32 -> int32 range, faster int->float conv. (x86/x86_64) */ \
const float fFrac = frac * (1.0f / (MIXER_FRAC_SCALE/2)); /* 0.0f .. 0.9999999f */ \
fSample = ((s[0] + (s[1]-s[0]) * fFrac)) * (1.0f / scale); \
}
#define RENDER_8BIT_SMP_LINTRP \
LINEAR_INTERPOLATION(smpPtr, positionFrac, 128) \
*fMixBufferL++ += fSample * fVolumeL; \
*fMixBufferR++ += fSample * fVolumeR;
#define RENDER_8BIT_SMP_MONO_LINTRP \
LINEAR_INTERPOLATION(smpPtr, positionFrac, 128) \
fSample *= fVolumeL; \
*fMixBufferL++ += fSample; \
*fMixBufferR++ += fSample;
#define RENDER_16BIT_SMP_LINTRP \
LINEAR_INTERPOLATION(smpPtr, positionFrac, 32768) \
*fMixBufferL++ += fSample * fVolumeL; \
*fMixBufferR++ += fSample * fVolumeR;
#define RENDER_16BIT_SMP_MONO_LINTRP \
LINEAR_INTERPOLATION(smpPtr, positionFrac, 32768) \
fSample *= fVolumeL; \
*fMixBufferL++ += fSample; \
*fMixBufferR++ += fSample;
// 8-tap windowed-sinc interpolation (better quality, through LUT: mixer/ft2_windowed_sinc.c)
/* 8bitbubsy: It may look like we are potentially going out of bounds while looking up the sample points,
** but the sample data is actually padded on both the left (negative) and right side, where correct tap
** samples are stored according to loop mode (or no loop).
**
** There is also a second special case for the left edge (negative taps) after the sample has looped once.
**
*/
#define WINDOWED_SINC_INTERPOLATION(s, f, scale) \
{ \
const float *t = v->fSincLUT + (((uint32_t)(f) >> SINC_FSHIFT) & SINC_FMASK); \
fSample = ((s[-3] * t[0]) + \
(s[-2] * t[1]) + \
(s[-1] * t[2]) + \
( s[0] * t[3]) + \
( s[1] * t[4]) + \
( s[2] * t[5]) + \
( s[3] * t[6]) + \
( s[4] * t[7])) * (1.0f / scale); \
}
#define RENDER_8BIT_SMP_SINTRP \
WINDOWED_SINC_INTERPOLATION(smpPtr, positionFrac, 128) \
*fMixBufferL++ += fSample * fVolumeL; \
*fMixBufferR++ += fSample * fVolumeR;
#define RENDER_8BIT_SMP_MONO_SINTRP \
WINDOWED_SINC_INTERPOLATION(smpPtr, positionFrac, 128) \
fSample *= fVolumeL; \
*fMixBufferL++ += fSample; \
*fMixBufferR++ += fSample;
#define RENDER_16BIT_SMP_SINTRP \
WINDOWED_SINC_INTERPOLATION(smpPtr, positionFrac, 32768) \
*fMixBufferL++ += fSample * fVolumeL; \
*fMixBufferR++ += fSample * fVolumeR;
#define RENDER_16BIT_SMP_MONO_SINTRP \
WINDOWED_SINC_INTERPOLATION(smpPtr, positionFrac, 32768) \
fSample *= fVolumeL; \
*fMixBufferL++ += fSample; \
*fMixBufferR++ += fSample;
/* Special left-edge case mixers to get proper tap data after one loop cycle.
** These are only used with sinc interpolation on looped samples.
*/
#define RENDER_8BIT_SMP_SINTRP_TAP_FIX \
smpTapPtr = (smpPtr <= leftEdgePtr) ? (int8_t *)&v->leftEdgeTaps8[(int32_t)(smpPtr-loopStartPtr)] : (int8_t *)smpPtr; \
WINDOWED_SINC_INTERPOLATION(smpTapPtr, positionFrac, 128) \
*fMixBufferL++ += fSample * fVolumeL; \
*fMixBufferR++ += fSample * fVolumeR;
#define RENDER_8BIT_SMP_MONO_SINTRP_TAP_FIX \
smpTapPtr = (smpPtr <= leftEdgePtr) ? (int8_t *)&v->leftEdgeTaps8[(int32_t)(smpPtr-loopStartPtr)] : (int8_t *)smpPtr; \
WINDOWED_SINC_INTERPOLATION(smpTapPtr, positionFrac, 128) \
fSample *= fVolumeL; \
*fMixBufferL++ += fSample; \
*fMixBufferR++ += fSample;
#define RENDER_16BIT_SMP_SINTRP_TAP_FIX \
smpTapPtr = (smpPtr <= leftEdgePtr) ? (int16_t *)&v->leftEdgeTaps16[(int32_t)(smpPtr-loopStartPtr)] : (int16_t *)smpPtr; \
WINDOWED_SINC_INTERPOLATION(smpTapPtr, positionFrac, 32768) \
*fMixBufferL++ += fSample * fVolumeL; \
*fMixBufferR++ += fSample * fVolumeR;
#define RENDER_16BIT_SMP_MONO_SINTRP_TAP_FIX \
smpTapPtr = (smpPtr <= leftEdgePtr) ? (int16_t *)&v->leftEdgeTaps16[(int32_t)(smpPtr-loopStartPtr)] : (int16_t *)smpPtr; \
WINDOWED_SINC_INTERPOLATION(smpTapPtr, positionFrac, 32768) \
fSample *= fVolumeL; \
*fMixBufferL++ += fSample; \
*fMixBufferR++ += fSample;
/* ----------------------------------------------------------------------- */
/* SAMPLES-TO-MIX LIMITING MACROS */
/* ----------------------------------------------------------------------- */
#if CPU_64BIT
#define LIMIT_NUM
#else
#define LIMIT_NUM if (i > (1<<(32-MIXER_FRAC_BITS))-1) i = (1<<(32-MIXER_FRAC_BITS))-1;
#endif
#define LIMIT_MIX_NUM \
samplesToMix = INT32_MAX; \
if (v->delta != 0) \
{ \
i = (v->sampleEnd - 1) - position; \
LIMIT_NUM \
const uintCPUWord_t dividend = ((uintCPUWord_t)i << MIXER_FRAC_BITS) | ((uint32_t)positionFrac ^ MIXER_FRAC_MASK); \
samplesToMix = (uint32_t)(dividend / (uintCPUWord_t)v->delta) + 1; \
} \
\
if (samplesToMix > samplesLeft) \
samplesToMix = samplesLeft;
#define START_BIDI \
if (v->samplingBackwards) \
{ \
tmpDelta = 0 - delta; \
position = ~position; \
smpPtr = revBase + position; \
positionFrac ^= MIXER_FRAC_MASK; \
} \
else \
{ \
tmpDelta = delta; \
smpPtr = base + position; \
} \
\
const int32_t deltaHi = (intCPUWord_t)tmpDelta >> MIXER_FRAC_BITS; \
const uint32_t deltaLo = tmpDelta & MIXER_FRAC_MASK;
#define LIMIT_MIX_NUM_RAMP \
if (v->volumeRampLength == 0) \
{ \
fVolumeLDelta = 0.0; \
fVolumeRDelta = 0.0; \
\
if (v->isFadeOutVoice) \
{ \
v->active = false; /* volume ramp fadeout-voice is done, shut it down */ \
return; \
} \
} \
else \
{ \
if (samplesToMix > v->volumeRampLength) \
samplesToMix = v->volumeRampLength; \
\
v->volumeRampLength -= samplesToMix; \
}
#define LIMIT_MIX_NUM_MONO_RAMP \
if (v->volumeRampLength == 0) \
{ \
fVolumeLDelta = 0.0; \
if (v->isFadeOutVoice) \
{ \
v->active = false; /* volume ramp fadeout-voice is done, shut it down */ \
return; \
} \
} \
else \
{ \
if (samplesToMix > v->volumeRampLength) \
samplesToMix = v->volumeRampLength; \
\
v->volumeRampLength -= samplesToMix; \
}
#define HANDLE_SAMPLE_END \
position = (int32_t)(smpPtr - base); \
if (position >= v->sampleEnd) \
{ \
v->active = false; \
return; \
}
#define WRAP_LOOP \
position = (int32_t)(smpPtr - base); \
if (position >= v->sampleEnd) \
{ \
do \
{ \
position -= v->loopLength; \
} \
while (position >= v->sampleEnd); \
\
smpPtr = base + position; \
\
v->hasLooped = true; \
}
#define WRAP_BIDI_LOOP \
if (position >= v->sampleEnd) \
{ \
do \
{ \
position -= v->loopLength; \
v->samplingBackwards ^= 1; \
} \
while (position >= v->sampleEnd); \
v->hasLooped = true; \
}
#define END_BIDI \
if (v->samplingBackwards) \
{ \
positionFrac ^= MIXER_FRAC_MASK; \
position = ~(int32_t)(smpPtr - revBase); \
} \
else \
{ \
position = (int32_t)(smpPtr - base); \
}