ref: 17c5a219af0c5622d1ec063ad21a222331fe1870
parent: ceccaa32be75e49c8fc0b27ff46770c668d853d7
author: Olav Sørensen <olav.sorensen@live.no>
date: Wed Nov 6 16:38:00 EST 2024
Some scope and interpolation fixes
--- a/src/ft2_main.c
+++ b/src/ft2_main.c
@@ -23,6 +23,7 @@
#include "ft2_sample_ed.h"
#include "ft2_diskop.h"
#include "scopes/ft2_scopes.h"
+#include "scopes/ft2_scopedraw.h"
#include "ft2_about.h"
#include "ft2_pattern_ed.h"
#include "ft2_module_loader.h"
@@ -367,6 +368,7 @@
freeTextBoxes();
freeMouseCursors();
freeBMPs();
+ freeScopeIntrpLUT();
if (editor.audioDevConfigFileLocationU != NULL)
{
--- a/src/mixer/ft2_cubic_spline.c
+++ b/src/mixer/ft2_cubic_spline.c
@@ -5,7 +5,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
-#include "ft2_cubic_spline.h"
+#include "ft2_cubic_spline.h" // CUBIC_SPLINE_TAPS, CUBIC_SPLINE_PHASES
#include "../ft2_video.h" // showErrorMsgBox()
float *fCubicSplineLUT = NULL; // globalized
--- a/src/mixer/ft2_gaussian.c
+++ b/src/mixer/ft2_gaussian.c
@@ -1,7 +1,10 @@
/*
-** Super Nintendo SPC700 interpolation LUT generator.
-** This has long believed to have a Gaussian curve, but it doesn't.
+** Super Nintendo (SPC700) Gaussian interpolation LUT generator
**
+** It was long believed that it uses a Gaussian curve, but it doesn't!
+** We still call it Gaussian interpolation in the FT2 clone though, so
+** that people recognize it.
+**
** Based on code by Mednafen and nocash:
** https://forums.nesdev.org/viewtopic.php?t=10586
**
@@ -10,11 +13,18 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
-#include "ft2_gaussian.h"
+#include "ft2_gaussian.h" // GAUSSIAN_TAPS, GAUSSIAN_PHASES
+#include "../ft2_header.h" // PI
#include "../ft2_video.h" // showErrorMsgBox()
-#define MY_PI 3.14159265358979323846264338327950288
+/*
+** 1.28 = Super Nintendo
+** 2.048 = Sony PlayStation (less aliasing on very low pitches)
+*/
+#define PI_MULTIPLIER 1.28
+#define TAP_SUM_SCALE 1.0
+
float *fGaussianLUT = NULL; // globalized
bool calcGaussianTable(void)
@@ -40,18 +50,18 @@
const double x4 = (0.5 + i4) * (1.0 / ((GAUSSIAN_PHASES*4)-1));
// Blackman window
- const double w1 = (0.42 + (0.50 * cos(2.0 * MY_PI * x1)) + (0.08 * cos(4.0 * MY_PI * x1))) / x1;
- const double w2 = (0.42 + (0.50 * cos(2.0 * MY_PI * x2)) + (0.08 * cos(4.0 * MY_PI * x2))) / x2;
- const double w3 = (0.42 + (0.50 * cos(2.0 * MY_PI * x3)) + (0.08 * cos(4.0 * MY_PI * x3))) / x3;
- const double w4 = (0.42 + (0.50 * cos(2.0 * MY_PI * x4)) + (0.08 * cos(4.0 * MY_PI * x4))) / x4;
+ const double w1 = (0.42 + (0.50 * cos(2.0 * PI * x1)) + (0.08 * cos(4.0 * PI * x1))) / x1;
+ const double w2 = (0.42 + (0.50 * cos(2.0 * PI * x2)) + (0.08 * cos(4.0 * PI * x2))) / x2;
+ const double w3 = (0.42 + (0.50 * cos(2.0 * PI * x3)) + (0.08 * cos(4.0 * PI * x3))) / x3;
+ const double w4 = (0.42 + (0.50 * cos(2.0 * PI * x4)) + (0.08 * cos(4.0 * PI * x4))) / x4;
- const double t1 = sin(1.28 * MY_PI * x1) * w1;
- const double t2 = sin(1.28 * MY_PI * x2) * w2;
- const double t3 = sin(1.28 * MY_PI * x3) * w3;
- const double t4 = sin(1.28 * MY_PI * x4) * w4;
+ const double t1 = sin(PI_MULTIPLIER * PI * x1) * w1;
+ const double t2 = sin(PI_MULTIPLIER * PI * x2) * w2;
+ const double t3 = sin(PI_MULTIPLIER * PI * x3) * w3;
+ const double t4 = sin(PI_MULTIPLIER * PI * x4) * w4;
- // normalization value (assures unity gain when summing taps)
- const double dScale = 1.0 / (t1 + t2 + t3 + t4);
+ // calculate normalization value (also assures unity gain when summing taps)
+ const double dScale = TAP_SUM_SCALE / (t1 + t2 + t3 + t4);
*fPtr++ = (float)(t1 * dScale);
*fPtr++ = (float)(t2 * dScale);
--- a/src/mixer/ft2_gaussian.h
+++ b/src/mixer/ft2_gaussian.h
@@ -6,7 +6,7 @@
#define GAUSSIAN_TAPS 4
#define GAUSSIAN_WIDTH_BITS 2 // log2(GAUSSIAN_TAPS)
-#define GAUSSIAN_PHASES 8192
+#define GAUSSIAN_PHASES 8192 /* originally 256 on SNES/PSX, but more is better! */
#define GAUSSIAN_PHASES_BITS 13 // log2(GAUSSIAN_PHASES)
#define GAUSSIAN_FSHIFT (MIXER_FRAC_BITS-(GAUSSIAN_PHASES_BITS+GAUSSIAN_WIDTH_BITS))
#define GAUSSIAN_FMASK ((GAUSSIAN_TAPS*GAUSSIAN_PHASES)-GAUSSIAN_TAPS)
--- a/src/mixer/ft2_mix.c
+++ b/src/mixer/ft2_mix.c
@@ -9,7 +9,7 @@
** (Note: Mixing macros can be found in ft2_mix_macros.h)
**
** Specifications:
-** - Interpolation: None, 2-tap linear, 4-tap cubic spline, 8-tap windowed-sinc, 16-tap windowed-sinc
+** - Interpolation: None, 2-tap linear, 4-tap "gaussian", 4-tap cubic hermite, 8-tap/16-tap windowed-sinc
** - FT2-styled linear volume ramping (can be turned off)
** - 32.32 fixed-point precision for resampling delta/position
** - 32-bit floating-point precision for mixing and interpolation
@@ -865,6 +865,7 @@
static void mix8bLoopGIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
+ int8_t *smpTapPtr;
float fSample, *fMixBufferL, *fMixBufferR;
int32_t position;
uint32_t i, samplesToMix, samplesLeft;
@@ -873,6 +874,7 @@
GET_VOL
GET_MIXER_VARS
SET_BASE8
+ PREPARE_TAP_FIX8
samplesLeft = numSamples;
while (samplesLeft > 0)
@@ -880,22 +882,45 @@
LIMIT_MIX_NUM
samplesLeft -= samplesToMix;
- for (i = 0; i < (samplesToMix & 3); i++)
+ if (v->hasLooped) // the negative interpolation taps need a special case after the sample has looped once
{
- RENDER_8BIT_SMP_GINTRP
- INC_POS
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ INC_POS
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ INC_POS
+ }
}
- samplesToMix >>= 2;
- for (i = 0; i < samplesToMix; i++)
+ else
{
- RENDER_8BIT_SMP_GINTRP
- INC_POS
- RENDER_8BIT_SMP_GINTRP
- INC_POS
- RENDER_8BIT_SMP_GINTRP
- INC_POS
- RENDER_8BIT_SMP_GINTRP
- INC_POS
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_8BIT_SMP_GINTRP
+ INC_POS
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_8BIT_SMP_GINTRP
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP
+ INC_POS
+ }
}
WRAP_LOOP
@@ -907,6 +932,7 @@
static void mix8bBidiLoopGIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *revBase, *smpPtr;
+ int8_t *smpTapPtr;
float fSample, *fMixBufferL, *fMixBufferR;
int32_t position;
uint32_t i, samplesToMix, samplesLeft;
@@ -915,6 +941,7 @@
GET_VOL
GET_MIXER_VARS
SET_BASE8_BIDI
+ PREPARE_TAP_FIX8
samplesLeft = numSamples;
while (samplesLeft > 0)
@@ -923,22 +950,45 @@
samplesLeft -= samplesToMix;
START_BIDI
- for (i = 0; i < (samplesToMix & 3); i++)
+ if (v->hasLooped) // the negative interpolation taps need a special case after the sample has looped once
{
- RENDER_8BIT_SMP_GINTRP
- INC_POS_BIDI
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ INC_POS_BIDI
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ INC_POS_BIDI
+ }
}
- samplesToMix >>= 2;
- for (i = 0; i < samplesToMix; i++)
+ else
{
- RENDER_8BIT_SMP_GINTRP
- INC_POS_BIDI
- RENDER_8BIT_SMP_GINTRP
- INC_POS_BIDI
- RENDER_8BIT_SMP_GINTRP
- INC_POS_BIDI
- RENDER_8BIT_SMP_GINTRP
- INC_POS_BIDI
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_8BIT_SMP_GINTRP
+ INC_POS_BIDI
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_8BIT_SMP_GINTRP
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP
+ INC_POS_BIDI
+ }
}
END_BIDI
@@ -1942,6 +1992,7 @@
static void mix8bRampLoopGIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *smpPtr;
+ int8_t *smpTapPtr;
float fSample, *fMixBufferL, *fMixBufferR;
int32_t position;
float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
@@ -1951,6 +2002,7 @@
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
SET_BASE8
+ PREPARE_TAP_FIX8
samplesLeft = numSamples;
while (samplesLeft > 0)
@@ -1958,28 +2010,56 @@
LIMIT_MIX_NUM
LIMIT_MIX_NUM_RAMP
samplesLeft -= samplesToMix;
-
- for (i = 0; i < (samplesToMix & 3); i++)
+
+ if (v->hasLooped) // the negative interpolation taps need a special case after the sample has looped once
{
- RENDER_8BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS
+ }
}
- samplesToMix >>= 2;
- for (i = 0; i < samplesToMix; i++)
+ else
{
- RENDER_8BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS
- RENDER_8BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS
- RENDER_8BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS
- RENDER_8BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_8BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_8BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_8BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS
+ }
}
WRAP_LOOP
@@ -1992,6 +2072,7 @@
static void mix8bRampBidiLoopGIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int8_t *base, *revBase, *smpPtr;
+ int8_t *smpTapPtr;
float fSample, *fMixBufferL, *fMixBufferR;
int32_t position;
float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
@@ -2001,6 +2082,7 @@
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
SET_BASE8_BIDI
+ PREPARE_TAP_FIX8
samplesLeft = numSamples;
while (samplesLeft > 0)
@@ -2010,27 +2092,55 @@
samplesLeft -= samplesToMix;
START_BIDI
- for (i = 0; i < (samplesToMix & 3); i++)
+ if (v->hasLooped) // the negative interpolation taps need a special case after the sample has looped once
{
- RENDER_8BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS_BIDI
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ }
}
- samplesToMix >>= 2;
- for (i = 0; i < samplesToMix; i++)
+ else
{
- RENDER_8BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS_BIDI
- RENDER_8BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS_BIDI
- RENDER_8BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS_BIDI
- RENDER_8BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS_BIDI
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_8BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_8BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_8BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ }
}
END_BIDI
@@ -2880,6 +2990,7 @@
static void mix16bLoopGIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
+ int16_t *smpTapPtr;
float fSample, *fMixBufferL, *fMixBufferR;
int32_t position;
uint32_t i, samplesToMix, samplesLeft;
@@ -2888,6 +2999,7 @@
GET_VOL
GET_MIXER_VARS
SET_BASE16
+ PREPARE_TAP_FIX16
samplesLeft = numSamples;
while (samplesLeft > 0)
@@ -2895,22 +3007,45 @@
LIMIT_MIX_NUM
samplesLeft -= samplesToMix;
- for (i = 0; i < (samplesToMix & 3); i++)
+ if (v->hasLooped) // the negative interpolation taps need a special case after the sample has looped once
{
- RENDER_16BIT_SMP_GINTRP
- INC_POS
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ INC_POS
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ INC_POS
+ }
}
- samplesToMix >>= 2;
- for (i = 0; i < samplesToMix; i++)
+ else
{
- RENDER_16BIT_SMP_GINTRP
- INC_POS
- RENDER_16BIT_SMP_GINTRP
- INC_POS
- RENDER_16BIT_SMP_GINTRP
- INC_POS
- RENDER_16BIT_SMP_GINTRP
- INC_POS
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_16BIT_SMP_GINTRP
+ INC_POS
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_16BIT_SMP_GINTRP
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP
+ INC_POS
+ }
}
WRAP_LOOP
@@ -2922,6 +3057,7 @@
static void mix16bBidiLoopGIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *revBase, *smpPtr;
+ int16_t *smpTapPtr;
float fSample, *fMixBufferL, *fMixBufferR;
int32_t position;
uint32_t i, samplesToMix, samplesLeft;
@@ -2930,6 +3066,7 @@
GET_VOL
GET_MIXER_VARS
SET_BASE16_BIDI
+ PREPARE_TAP_FIX16
samplesLeft = numSamples;
while (samplesLeft > 0)
@@ -2938,22 +3075,45 @@
samplesLeft -= samplesToMix;
START_BIDI
- for (i = 0; i < (samplesToMix & 3); i++)
+ if (v->hasLooped) // the negative interpolation taps need a special case after the sample has looped once
{
- RENDER_16BIT_SMP_GINTRP
- INC_POS_BIDI
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ INC_POS_BIDI
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ INC_POS_BIDI
+ }
}
- samplesToMix >>= 2;
- for (i = 0; i < samplesToMix; i++)
+ else
{
- RENDER_16BIT_SMP_GINTRP
- INC_POS_BIDI
- RENDER_16BIT_SMP_GINTRP
- INC_POS_BIDI
- RENDER_16BIT_SMP_GINTRP
- INC_POS_BIDI
- RENDER_16BIT_SMP_GINTRP
- INC_POS_BIDI
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_16BIT_SMP_GINTRP
+ INC_POS_BIDI
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_16BIT_SMP_GINTRP
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP
+ INC_POS_BIDI
+ }
}
END_BIDI
@@ -3956,6 +4116,7 @@
static void mix16bRampLoopGIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *smpPtr;
+ int16_t *smpTapPtr;
float fSample, *fMixBufferL, *fMixBufferR;
int32_t position;
float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
@@ -3965,6 +4126,7 @@
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
SET_BASE16
+ PREPARE_TAP_FIX16
samplesLeft = numSamples;
while (samplesLeft > 0)
@@ -3973,27 +4135,55 @@
LIMIT_MIX_NUM_RAMP
samplesLeft -= samplesToMix;
- for (i = 0; i < (samplesToMix & 3); i++)
+ if (v->hasLooped) // the negative interpolation taps need a special case after the sample has looped once
{
- RENDER_16BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS
+ }
}
- samplesToMix >>= 2;
- for (i = 0; i < samplesToMix; i++)
+ else
{
- RENDER_16BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS
- RENDER_16BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS
- RENDER_16BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS
- RENDER_16BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_16BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_16BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS
+ RENDER_16BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS
+ }
}
WRAP_LOOP
@@ -4006,6 +4196,7 @@
static void mix16bRampBidiLoopGIntrp(voice_t *v, uint32_t bufferPos, uint32_t numSamples)
{
const int16_t *base, *revBase, *smpPtr;
+ int16_t *smpTapPtr;
float fSample, *fMixBufferL, *fMixBufferR;
int32_t position;
float fVolumeLDelta, fVolumeRDelta, fVolumeL, fVolumeR;
@@ -4015,6 +4206,7 @@
GET_VOL_RAMP
GET_MIXER_VARS_RAMP
SET_BASE16_BIDI
+ PREPARE_TAP_FIX16
samplesLeft = numSamples;
while (samplesLeft > 0)
@@ -4024,28 +4216,57 @@
samplesLeft -= samplesToMix;
START_BIDI
- for (i = 0; i < (samplesToMix & 3); i++)
+ if (v->hasLooped) // the negative interpolation taps need a special case after the sample has looped once
{
- RENDER_16BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS_BIDI
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP_TAP_FIX
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ }
}
- samplesToMix >>= 2;
- for (i = 0; i < samplesToMix; i++)
+ else
{
- RENDER_16BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS_BIDI
- RENDER_16BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS_BIDI
- RENDER_16BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS_BIDI
- RENDER_16BIT_SMP_GINTRP
- VOLUME_RAMPING
- INC_POS_BIDI
+ for (i = 0; i < (samplesToMix & 3); i++)
+ {
+ RENDER_16BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ }
+ samplesToMix >>= 2;
+ for (i = 0; i < samplesToMix; i++)
+ {
+ RENDER_16BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ RENDER_16BIT_SMP_GINTRP
+ VOLUME_RAMPING
+ INC_POS_BIDI
+ }
}
+
END_BIDI
WRAP_BIDI_LOOP
--- a/src/mixer/ft2_mix_macros.h
+++ b/src/mixer/ft2_mix_macros.h
@@ -175,26 +175,44 @@
// through LUT: mixer/ft2_gaussian.c
/* 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 the right side, where correct tap are stored according
-** to loop mode (or no loop).
+** 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 GAUSSIAN_INTERPOLATION(s, f, scale) \
{ \
const float *t = fGaussianLUT + (((uint32_t)(f) >> GAUSSIAN_FSHIFT) & GAUSSIAN_FMASK); \
- fSample = ((s[0] * t[0]) + \
- (s[1] * t[1]) + \
- (s[2] * t[2]) + \
- (s[3] * t[3])) * (1.0f / scale); \
+ fSample = ((s[-1] * t[0]) + \
+ ( s[0] * t[1]) + \
+ ( s[1] * t[2]) + \
+ ( s[2] * t[3])) * (1.0f / scale); \
}
#define RENDER_8BIT_SMP_GINTRP \
- GAUSSIAN_INTERPOLATION(smpPtr, positionFrac, 128.0f) \
+ GAUSSIAN_INTERPOLATION(smpPtr, positionFrac, 128) \
*fMixBufferL++ += fSample * fVolumeL; \
*fMixBufferR++ += fSample * fVolumeR;
#define RENDER_16BIT_SMP_GINTRP \
- GAUSSIAN_INTERPOLATION(smpPtr, positionFrac, 32768.0f) \
+ GAUSSIAN_INTERPOLATION(smpPtr, positionFrac, 32768) \
+ *fMixBufferL++ += fSample * fVolumeL; \
+ *fMixBufferR++ += fSample * fVolumeR;
+
+/* Special left-edge case mixers to get proper tap data after one loop cycle.
+** These are only used on looped samples.
+*/
+
+#define RENDER_8BIT_SMP_GINTRP_TAP_FIX \
+ smpTapPtr = (smpPtr <= leftEdgePtr) ? (int8_t *)&v->leftEdgeTaps8[(int32_t)(smpPtr-loopStartPtr)] : (int8_t *)smpPtr; \
+ GAUSSIAN_INTERPOLATION(smpTapPtr, positionFrac, 128) \
+ *fMixBufferL++ += fSample * fVolumeL; \
+ *fMixBufferR++ += fSample * fVolumeR;
+
+#define RENDER_16BIT_SMP_GINTRP_TAP_FIX \
+ smpTapPtr = (smpPtr <= leftEdgePtr) ? (int16_t *)&v->leftEdgeTaps16[(int32_t)(smpPtr-loopStartPtr)] : (int16_t *)smpPtr; \
+ GAUSSIAN_INTERPOLATION(smpTapPtr, positionFrac, 32768) \
*fMixBufferL++ += fSample * fVolumeL; \
*fMixBufferR++ += fSample * fVolumeR;
--- a/src/mixer/ft2_windowed_sinc.c
+++ b/src/mixer/ft2_windowed_sinc.c
@@ -9,11 +9,10 @@
#include <stdbool.h>
#include <stdlib.h>
#include <math.h>
-#include "ft2_windowed_sinc.h"
+#include "ft2_windowed_sinc.h" // SINCx_TAPS, SINCx_PHASES
+#include "../ft2_header.h" // PI
#include "../ft2_video.h" // showErrorMsgBox()
-#define MY_PI 3.14159265358979323846264338327950288
-
// globalized
float *fKaiserSinc_8 = NULL, *fDownSample1_8 = NULL, *fDownSample2_8 = NULL;
float *fKaiserSinc_16 = NULL, *fDownSample1_16 = NULL, *fDownSample2_16 = NULL;
@@ -44,7 +43,7 @@
static void generateSincLUT(float *fOutput, uint32_t filterWidth, uint32_t numPhases, const double beta, const double lpCutoff)
{
const double I0Beta = besselI0(beta);
- const double kPi = MY_PI * lpCutoff;
+ const double kPi = PI * lpCutoff;
const double iMul = 1.0 / numPhases;
const double xMul = 1.0 / ((filterWidth / 2) * (filterWidth / 2));
--- a/src/scopes/ft2_scope_macros.h
+++ b/src/scopes/ft2_scope_macros.h
@@ -65,19 +65,43 @@
#define INTERPOLATE_SMP8(pos, frac) \
const int8_t *s8 = s->base8 + pos; \
- const int16_t *t = scopeGaussianLUT + (((frac) >> (SCOPE_FRAC_BITS-8)) << 2); \
- sample = ((s8[0] * t[0]) + \
- (s8[1] * t[1]) + \
- (s8[2] * t[2]) + \
- (s8[3] * t[3])) >> (15-8);
+ if (config.interpolation == INTERPOLATION_DISABLED) \
+ { \
+ sample = s8[0] << 8; \
+ } \
+ else if (config.interpolation == INTERPOLATION_LINEAR) \
+ { \
+ const int32_t f = (frac) >> (SCOPE_FRAC_BITS-15); \
+ sample = (s8[0] << 8) + ((((s8[1] - s8[0]) << 8) * f) >> 15); \
+ } \
+ else \
+ { \
+ const int16_t *t = scopeIntrpLUT + (((frac) >> (SCOPE_FRAC_BITS-SCOPE_INTRP_PHASES_BITS)) << 2); \
+ sample = ((s8[0] * t[0]) + \
+ (s8[1] * t[1]) + \
+ (s8[2] * t[2]) + \
+ (s8[3] * t[3])) >> (SCOPE_INTRP_SCALE_BITS-8); \
+ }
#define INTERPOLATE_SMP16(pos, frac) \
const int16_t *s16 = s->base16 + pos; \
- const int16_t *t = scopeGaussianLUT + (((frac) >> (SCOPE_FRAC_BITS-8)) << 2); \
- sample = ((s16[0] * t[0]) + \
- (s16[1] * t[1]) + \
- (s16[2] * t[2]) + \
- (s16[3] * t[3])) >> 15;
+ if (config.interpolation == INTERPOLATION_DISABLED) \
+ { \
+ sample = s16[0]; \
+ } \
+ else if (config.interpolation == INTERPOLATION_LINEAR) \
+ { \
+ const int32_t f = (frac) >> (SCOPE_FRAC_BITS-15); \
+ sample = s16[0] + (((s16[1] - s16[0]) * f) >> 15); \
+ } \
+ else \
+ { \
+ const int16_t *t = scopeIntrpLUT + (((frac) >> (SCOPE_FRAC_BITS-SCOPE_INTRP_PHASES_BITS)) << 2); \
+ sample = ((s16[0] * t[0]) + \
+ (s16[1] * t[1]) + \
+ (s16[2] * t[2]) + \
+ (s16[3] * t[3])) >> SCOPE_INTRP_SCALE_BITS; \
+ }
#define SCOPE_GET_SMP8 \
if (s->active) \
@@ -145,7 +169,7 @@
if (s->active) \
{ \
GET_BIDI_POSITION \
- INTERPOLATE_SMP8(actualPos, samplingBackwards ? ((uint32_t)positionFrac ^ UINT32_MAX) : positionFrac) \
+ INTERPOLATE_SMP8(actualPos, samplingBackwards ? ((uint32_t)positionFrac ^ UINT32_MAX) : (uint32_t)positionFrac) \
sample = (sample * volume) >> 16; \
} \
else \
@@ -157,7 +181,7 @@
if (s->active) \
{ \
GET_BIDI_POSITION \
- INTERPOLATE_SMP16(actualPos, samplingBackwards ? ((uint32_t)positionFrac ^ UINT32_MAX) : positionFrac) \
+ INTERPOLATE_SMP16(actualPos, samplingBackwards ? ((uint32_t)positionFrac ^ UINT32_MAX) : (uint32_t)positionFrac) \
sample = (sample * volume) >> 16; \
} \
else \
--- a/src/scopes/ft2_scopedraw.c
+++ b/src/scopes/ft2_scopedraw.c
@@ -1,3 +1,9 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <math.h>
+#include "../ft2_config.h"
#include "../ft2_video.h"
#include "../ft2_palette.h"
#include "../mixer/ft2_gaussian.h"
@@ -5,142 +11,62 @@
#include "ft2_scopedraw.h"
#include "ft2_scope_macros.h"
-/* 15-bit Gaussian interpolation LUT with no overshoot (sum <= 1.0).
-** Suitable for tracker scopes.
-*/
-static const int16_t scopeGaussianLUT[4 * 256] =
-{
- 4807,22963, 4871, -1, 4744,22962, 4935, -1,
- 4681,22960, 5000, -1, 4619,22957, 5065, -1,
- 4557,22953, 5131, -1, 4495,22948, 5197, -1,
- 4435,22942, 5264, -1, 4374,22935, 5332, -1,
- 4315,22927, 5399, -1, 4255,22918, 5468, -1,
- 4197,22908, 5536, -1, 4138,22897, 5606, -1,
- 4081,22885, 5676, -1, 4023,22872, 5746, -1,
- 3967,22857, 5817, -1, 3910,22842, 5888, -1,
- 3855,22826, 5959, 0, 3799,22809, 6032, 0,
- 3745,22791, 6104, 0, 3691,22772, 6177, 0,
- 3637,22752, 6251, 0, 3584,22731, 6325, 0,
- 3531,22709, 6400, 0, 3479,22686, 6475, 1,
- 3427,22662, 6550, 1, 3376,22637, 6626, 1,
- 3325,22611, 6702, 1, 3275,22584, 6779, 2,
- 3225,22556, 6856, 2, 3176,22527, 6934, 2,
- 3128,22498, 7012, 3, 3079,22467, 7091, 3,
- 3032,22435, 7170, 3, 2985,22402, 7249, 4,
- 2938,22369, 7329, 4, 2892,22334, 7409, 5,
- 2846,22299, 7490, 5, 2801,22262, 7571, 6,
- 2756,22225, 7653, 7, 2712,22187, 7735, 7,
- 2668,22148, 7817, 8, 2624,22107, 7900, 9,
- 2582,22066, 7983, 9, 2539,22025, 8066, 10,
- 2497,21982, 8150, 11, 2456,21938, 8234, 12,
- 2415,21893, 8319, 13, 2374,21848, 8404, 14,
- 2334,21801, 8489, 15, 2295,21754, 8575, 16,
- 2256,21706, 8661, 17, 2217,21657, 8748, 18,
- 2179,21607, 8834, 19, 2141,21556, 8922, 21,
- 2104,21505, 9009, 22, 2067,21452, 9097, 24,
- 2031,21399, 9185, 25, 1995,21345, 9273, 27,
- 1959,21290, 9362, 28, 1924,21235, 9451, 30,
- 1890,21178, 9541, 32, 1856,21121, 9630, 33,
- 1822,21063, 9720, 35, 1789,21004, 9811, 37,
- 1756,20944, 9901, 39, 1723,20884, 9992, 41,
- 1691,20822,10083, 44, 1660,20760,10174, 46,
- 1628,20698,10266, 48, 1598,20634,10358, 51,
- 1567,20570,10450, 53, 1537,20505,10542, 56,
- 1508,20439,10635, 58, 1479,20373,10727, 61,
- 1450,20306,10820, 64, 1422,20238,10913, 67,
- 1394,20169,11007, 70, 1366,20100,11100, 73,
- 1339,20030,11194, 77, 1312,19959,11288, 80,
- 1286,19888,11382, 84, 1260,19816,11476, 87,
- 1234,19744,11571, 91, 1209,19671,11665, 95,
- 1184,19597,11760, 99, 1160,19522,11855, 103,
- 1136,19447,11950, 107, 1112,19372,12045, 111,
- 1089,19295,12140, 116, 1066,19219,12236, 120,
- 1043,19141,12331, 125, 1020,19063,12427, 130,
- 999,18985,12522, 135, 977,18905,12618, 140,
- 956,18826,12714, 145, 935,18746,12809, 150,
- 914,18665,12905, 156, 894,18584,13001, 161,
- 874,18502,13097, 167, 854,18420,13193, 173,
- 835,18337,13289, 179, 816,18254,13385, 186,
- 797,18170,13481, 192, 779,18086,13577, 199,
- 761,18001,13673, 205, 743,17916,13769, 212,
- 726,17830,13865, 219, 708,17744,13961, 227,
- 692,17658,14056, 234, 675,17571,14152, 242,
- 659,17484,14248, 250, 643,17396,14343, 257,
- 627,17308,14439, 266, 612,17220,14534, 274,
- 597,17131,14630, 283, 582,17042,14725, 291,
- 567,16953,14820, 300, 553,16863,14915, 309,
- 539,16773,15010, 319, 525,16682,15104, 328,
- 512,16592,15199, 338, 498,16500,15293, 348,
- 485,16409,15387, 358, 473,16317,15481, 369,
- 460,16226,15575, 379, 448,16133,15669, 390,
- 436,16041,15762, 401, 424,15948,15855, 412,
- 412,15855,15948, 424, 401,15762,16041, 436,
- 390,15669,16133, 448, 379,15575,16226, 460,
- 369,15481,16317, 473, 358,15387,16409, 485,
- 348,15293,16500, 498, 338,15199,16592, 512,
- 328,15104,16682, 525, 319,15010,16773, 539,
- 309,14915,16863, 553, 300,14820,16953, 567,
- 291,14725,17042, 582, 283,14630,17131, 597,
- 274,14534,17220, 612, 266,14439,17308, 627,
- 257,14343,17396, 643, 250,14248,17484, 659,
- 242,14152,17571, 675, 234,14056,17658, 692,
- 227,13961,17744, 708, 219,13865,17830, 726,
- 212,13769,17916, 743, 205,13673,18001, 761,
- 199,13577,18086, 779, 192,13481,18170, 797,
- 186,13385,18254, 816, 179,13289,18337, 835,
- 173,13193,18420, 854, 167,13097,18502, 874,
- 161,13001,18584, 894, 156,12905,18665, 914,
- 150,12809,18746, 935, 145,12714,18826, 956,
- 140,12618,18905, 977, 135,12522,18985, 999,
- 130,12427,19063, 1020, 125,12331,19141, 1043,
- 120,12236,19219, 1066, 116,12140,19295, 1089,
- 111,12045,19372, 1112, 107,11950,19447, 1136,
- 103,11855,19522, 1160, 99,11760,19597, 1184,
- 95,11665,19671, 1209, 91,11571,19744, 1234,
- 87,11476,19816, 1260, 84,11382,19888, 1286,
- 80,11288,19959, 1312, 77,11194,20030, 1339,
- 73,11100,20100, 1366, 70,11007,20169, 1394,
- 67,10913,20238, 1422, 64,10820,20306, 1450,
- 61,10727,20373, 1479, 58,10635,20439, 1508,
- 56,10542,20505, 1537, 53,10450,20570, 1567,
- 51,10358,20634, 1598, 48,10266,20698, 1628,
- 46,10174,20760, 1660, 44,10083,20822, 1691,
- 41, 9992,20884, 1723, 39, 9901,20944, 1756,
- 37, 9811,21004, 1789, 35, 9720,21063, 1822,
- 33, 9630,21121, 1856, 32, 9541,21178, 1890,
- 30, 9451,21235, 1924, 28, 9362,21290, 1959,
- 27, 9273,21345, 1995, 25, 9185,21399, 2031,
- 24, 9097,21452, 2067, 22, 9009,21505, 2104,
- 21, 8922,21556, 2141, 19, 8834,21607, 2179,
- 18, 8748,21657, 2217, 17, 8661,21706, 2256,
- 16, 8575,21754, 2295, 15, 8489,21801, 2334,
- 14, 8404,21848, 2374, 13, 8319,21893, 2415,
- 12, 8234,21938, 2456, 11, 8150,21982, 2497,
- 10, 8066,22025, 2539, 9, 7983,22066, 2582,
- 9, 7900,22107, 2624, 8, 7817,22148, 2668,
- 7, 7735,22187, 2712, 7, 7653,22225, 2756,
- 6, 7571,22262, 2801, 5, 7490,22299, 2846,
- 5, 7409,22334, 2892, 4, 7329,22369, 2938,
- 4, 7249,22402, 2985, 3, 7170,22435, 3032,
- 3, 7091,22467, 3079, 3, 7012,22498, 3128,
- 2, 6934,22527, 3176, 2, 6856,22556, 3225,
- 2, 6779,22584, 3275, 1, 6702,22611, 3325,
- 1, 6626,22637, 3376, 1, 6550,22662, 3427,
- 1, 6475,22686, 3479, 0, 6400,22709, 3531,
- 0, 6325,22731, 3584, 0, 6251,22752, 3637,
- 0, 6177,22772, 3691, 0, 6104,22791, 3745,
- 0, 6032,22809, 3799, 0, 5959,22826, 3855,
- -1, 5888,22842, 3910, -1, 5817,22857, 3967,
- -1, 5746,22872, 4023, -1, 5676,22885, 4081,
- -1, 5606,22897, 4138, -1, 5536,22908, 4197,
- -1, 5468,22918, 4255, -1, 5399,22927, 4315,
- -1, 5332,22935, 4374, -1, 5264,22942, 4435,
- -1, 5197,22948, 4495, -1, 5131,22953, 4557,
- -1, 5065,22957, 4619, -1, 5000,22960, 4681,
- -1, 4935,22962, 4744, -1, 4871,22963, 4807
-};
+static int16_t *scopeIntrpLUT;
static void scopeLine(int32_t x1, int32_t y1, int32_t y2, uint32_t color);
+
+bool calcScopeIntrpLUT(void)
+{
+ scopeIntrpLUT = (int16_t *)malloc(4 * SCOPE_INTRP_PHASES * sizeof (int16_t));
+ if (scopeIntrpLUT == NULL)
+ return false;
+
+ int16_t *ptr = scopeIntrpLUT;
+ for (int32_t i = 0; i < SCOPE_INTRP_PHASES; i++)
+ {
+#define PI_MULTIPLIER 2.048
+
+ const int32_t i1 = SCOPE_INTRP_PHASES + i;
+ const int32_t i2 = i;
+ const int32_t i3 = (SCOPE_INTRP_PHASES-1) - i;
+ const int32_t i4 = ((SCOPE_INTRP_PHASES*2)-1) - i;
+
+ const double x1 = (0.5 + i1) * (1.0 / ((SCOPE_INTRP_PHASES*4)-1));
+ const double x2 = (0.5 + i2) * (1.0 / ((SCOPE_INTRP_PHASES*4)-1));
+ const double x3 = (0.5 + i3) * (1.0 / ((SCOPE_INTRP_PHASES*4)-1));
+ const double x4 = (0.5 + i4) * (1.0 / ((SCOPE_INTRP_PHASES*4)-1));
+
+ // Blackman window
+ const double w1 = (0.42 + (0.50 * cos(2.0 * PI * x1)) + (0.08 * cos(4.0 * PI * x1))) / x1;
+ const double w2 = (0.42 + (0.50 * cos(2.0 * PI * x2)) + (0.08 * cos(4.0 * PI * x2))) / x2;
+ const double w3 = (0.42 + (0.50 * cos(2.0 * PI * x3)) + (0.08 * cos(4.0 * PI * x3))) / x3;
+ const double w4 = (0.42 + (0.50 * cos(2.0 * PI * x4)) + (0.08 * cos(4.0 * PI * x4))) / x4;
+
+ const double t1 = sin(PI_MULTIPLIER * PI * x1) * w1;
+ const double t2 = sin(PI_MULTIPLIER * PI * x2) * w2;
+ const double t3 = sin(PI_MULTIPLIER * PI * x3) * w3;
+ const double t4 = sin(PI_MULTIPLIER * PI * x4) * w4;
+
+ // calculate normalization value (also assures unity gain when summing taps)
+ const double dScale = SCOPE_INTRP_SCALE / (t1 + t2 + t3 + t4);
+
+ *ptr++ = (int16_t)((t1 * dScale) + 0.5);
+ *ptr++ = (int16_t)((t2 * dScale) + 0.5);
+ *ptr++ = (int16_t)((t3 * dScale) + 0.5);
+ *ptr++ = (int16_t)((t4 * dScale) + 0.5);
+ }
+
+ return true;
+}
+
+void freeScopeIntrpLUT(void)
+{
+ if (scopeIntrpLUT != NULL)
+ {
+ free(scopeIntrpLUT);
+ scopeIntrpLUT = NULL;
+ }
+}
/* ----------------------------------------------------------------------- */
/* SCOPE DRAWING ROUTINES */
--- a/src/scopes/ft2_scopedraw.h
+++ b/src/scopes/ft2_scopedraw.h
@@ -6,3 +6,7 @@
typedef void (*scopeDrawRoutine)(const scope_t *, uint32_t, uint32_t, uint32_t);
extern const scopeDrawRoutine scopeDrawRoutineTable[12]; // ft2_scopedraw.c
+
+bool calcScopeIntrpLUT(void);
+void freeScopeIntrpLUT(void);
+
--- a/src/scopes/ft2_scopes.c
+++ b/src/scopes/ft2_scopes.c
@@ -544,6 +544,12 @@
return false;
}
+ if (!calcScopeIntrpLUT())
+ {
+ showErrorMsgBox("Not enough memory!");
+ return false;
+ }
+
SDL_DetachThread(scopeThread);
return true;
}
--- a/src/scopes/ft2_scopes.h
+++ b/src/scopes/ft2_scopes.h
@@ -5,6 +5,11 @@
#include "../ft2_header.h"
#include "../ft2_audio.h"
+#define SCOPE_INTRP_SCALE 32767
+#define SCOPE_INTRP_SCALE_BITS 15 /* ceil(log2(SCOPE_INTRP_SCALE)) */
+#define SCOPE_INTRP_PHASES 1024 /* good enough for the FT2 scopes */
+#define SCOPE_INTRP_PHASES_BITS 10 /* log2(SCOPE_INTRP_PHASES) */
+
#define SCOPE_HEIGHT 36
#define SCOPE_FRAC_BITS 32
--
⑨