Skip to content

Commit ee93d97

Browse files
* Take advantage of phase being in the range [0,1)
- Integrated from the integer phase code branch * Add linearly-interpolated noise - Uses IntegratedPolyBLEP for bandlimiting
1 parent bd62fc6 commit ee93d97

10 files changed

+181
-149
lines changed

Diff for: Wave.cpp

+12-8
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@ WaveEvaluate const wave_evaluate[WAVE_COUNT] =
2727
OscillatorTriangle, // WAVE_TRIANGLE,
2828
OscillatorNoise, // WAVE_NOISE,
2929
OscillatorNoiseHold, // WAVE_NOISE_HOLD
30-
OscillatorPoly4, // WAVE_POLY4,
31-
OscillatorPoly5, // WAVE_POLY5,
32-
OscillatorPeriod93, // WAVE_PERIOD93,
33-
OscillatorPoly9, // WAVE_POLY9,
34-
OscillatorPoly17, // WAVE_POLY17,
35-
OscillatorPulsePoly5, // WAVE_PULSE_POLY5,
36-
OscillatorPoly4Poly5, // WAVE_POLY4_POLY5,
37-
OscillatorPoly17Poly5, // WAVE_POLY17_POLY5,
30+
OscillatorNoiseSlope, // WAVE_NOISE_SLOPE
31+
OscillatorPoly, // WAVE_POLY4,
32+
OscillatorPoly, // WAVE_POLY5,
33+
OscillatorPoly, // WAVE_PERIOD93,
34+
OscillatorPoly, // WAVE_POLY9,
35+
OscillatorPoly, // WAVE_POLY17,
36+
OscillatorPoly, // WAVE_PULSE_POLY5,
37+
OscillatorPoly, // WAVE_POLY4_POLY5,
38+
OscillatorPoly, // WAVE_POLY17_POLY5,
3839
};
3940

4041
// names for wave types
@@ -46,6 +47,7 @@ char const * const wave_name[WAVE_COUNT] =
4647
"Triangle", // WAVE_TRIANGLE,
4748
"Noise", // WAVE_NOISE,
4849
"Noise Hold", // WAVE_NOISE_HOLD
50+
"Noise Slope", // WAVE_NOISE_SLOPE
4951
"Poly4", // WAVE_POLY4,
5052
"Poly5", // WAVE_POLY5,
5153
"Period-93", // WAVE_PERIOD93,
@@ -68,6 +70,7 @@ float const wave_adjust_frequency[WAVE_COUNT] =
6870
1.0f, // WAVE_TRIANGLE,
6971
1.0f, // WAVE_NOISE,
7072
1.0f, // WAVE_NOISE_HOLD,
73+
1.0f, // WAVE_NOISE_SLOPE,
7174
2.0f * 15.0f / 16.0f, // WAVE_POLY4,
7275
2.0f * 31.0f / 32.0f, // WAVE_POLY5,
7376
2.0f * 93.0f / 128.0f, // WAVE_PERIOD93,
@@ -88,6 +91,7 @@ int const wave_loop_cycle[WAVE_COUNT] =
8891
INT_MAX, // WAVE_TRIANGLE,
8992
INT_MAX, // WAVE_NOISE,
9093
ARRAY_SIZE(noise), // WAVE_NOISE_HOLD
94+
ARRAY_SIZE(noise), // WAVE_NOISE_SLOPE
9195
ARRAY_SIZE(poly4), // WAVE_POLY4,
9296
ARRAY_SIZE(poly5), // WAVE_POLY5,
9397
ARRAY_SIZE(period93), // WAVE_PERIOD93,

Diff for: Wave.h

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ enum Wave
2121
WAVE_TRIANGLE,
2222
WAVE_NOISE,
2323
WAVE_NOISE_HOLD,
24+
WAVE_NOISE_SLOPE,
2425

2526
WAVE_POLY4, // Atari POKEY AUDC 12
2627
WAVE_POLY5, // Atari TIA AUDC 7 or 9

Diff for: WaveHold.cpp

+58-1
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,65 @@ static float OscillatorHold(OscillatorConfig const &config, OscillatorState &sta
5858
return value;
5959
}
6060

61+
// shared data oscillator
62+
static float OscillatorLerp(OscillatorConfig const &config, OscillatorState &state, float data[], int cycle, float step)
63+
{
64+
if (step > 0.5f * cycle)
65+
return 0;
66+
67+
// current and next wavetable value
68+
int const index0 = state.index;
69+
float const value0 = data[index0];
70+
int const index1 = state.index < cycle ? state.index + 1 : 0;
71+
float const value1 = data[index1];
72+
float value = value0 + (value1 - value0) * state.phase;
73+
74+
#if ANTIALIAS == ANTIALIAS_POLYBLEP
75+
if (use_antialias)
76+
{
77+
float w = Min(step * INTEGRATED_POLYBLEP_WIDTH, 8.0f);
78+
79+
int const back = FloorInt(state.phase - w);
80+
int const ahead = FloorInt(state.phase + w);
81+
int const count = ahead - back;
82+
if (count > 0)
83+
{
84+
int i = index0 + back + cycle;
85+
if (i >= cycle)
86+
i -= cycle;
87+
float const vn1 = data[i];
88+
if (++i >= cycle)
89+
i -= cycle;
90+
float t = state.phase - back;
91+
float v0 = data[i];
92+
float s0 = v0 - vn1;
93+
for (int c = 0; c < count; ++c)
94+
{
95+
if (++i >= cycle)
96+
i -= cycle;
97+
t -= 1.0f;
98+
float const v1 = data[i];
99+
float const s1 = v1 - v0;
100+
if (s0 != s1)
101+
value += IntegratedPolyBLEP(t, w, s1 - s0);
102+
v0 = v1;
103+
s0 = s1;
104+
}
105+
}
106+
}
107+
#endif
108+
return value;
109+
}
110+
111+
61112
// sample-and-hold noise
62-
extern float OscillatorNoiseHold(OscillatorConfig const &config, OscillatorState &state, float step)
113+
float OscillatorNoiseHold(OscillatorConfig const &config, OscillatorState &state, float step)
63114
{
64115
return OscillatorHold(config, state, noise, ARRAY_SIZE(noise), step);
65116
}
117+
118+
// linear interpolated noise
119+
float OscillatorNoiseSlope(OscillatorConfig const &config, OscillatorState &state, float step)
120+
{
121+
return OscillatorLerp(config, state, noise, ARRAY_SIZE(noise), step);
122+
}

Diff for: WaveHold.h

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ extern void InitNoise();
88

99
// sample-and-hold noise
1010
extern float OscillatorNoiseHold(OscillatorConfig const &config, OscillatorState &state, float step);
11+
extern float OscillatorNoiseSlope(OscillatorConfig const &config, OscillatorState &state, float step);

Diff for: WavePoly.cpp

+25-55
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,25 @@ char pulsepoly5[ARRAY_SIZE(poly5) * 2];
2424
char poly4poly5[ARRAY_SIZE(poly5) * ARRAY_SIZE(poly4)];
2525
char poly17poly5[ARRAY_SIZE(poly5) * ARRAY_SIZE(poly17)];
2626

27+
static char const * const poly_data[WAVE_COUNT] =
28+
{
29+
NULL, // WAVE_SINE,
30+
NULL, // WAVE_PULSE,
31+
NULL, // WAVE_SAWTOOTH,
32+
NULL, // WAVE_TRIANGLE,
33+
NULL, // WAVE_NOISE,
34+
NULL, // WAVE_NOISE_HOLD,
35+
NULL, // WAVE_NOISE_SLOPE,
36+
poly4, // WAVE_POLY4,
37+
poly5, // WAVE_POLY5,
38+
period93, // WAVE_PERIOD93,
39+
poly9, // WAVE_POLY9,
40+
poly17, // WAVE_POLY17,
41+
pulsepoly5, // WAVE_PULSE_POLY5,
42+
poly4poly5, // WAVE_POLY4_POLY5,
43+
poly17poly5, // WAVE_POLY17_POLY5,
44+
};
45+
2746
// generate polynomial table
2847
// from Atari800 pokey.c
2948
static void InitPoly(char aOut[], int aSize, int aTap, unsigned int aSeed, char aInvert)
@@ -104,13 +123,17 @@ void InitPoly()
104123
}
105124

106125
// shared poly oscillator
107-
static float OscillatorPoly(OscillatorConfig const &config, OscillatorState &state, char poly[], int cycle, float step)
126+
float OscillatorPoly(OscillatorConfig const &config, OscillatorState &state, float step)
108127
{
128+
// poly info for the wave type
129+
int const cycle = wave_loop_cycle[config.wavetype];
109130
if (step > 0.5f * cycle)
110131
return 0;
111132

112133
// current wavetable value
134+
char const * const poly = poly_data[config.wavetype];
113135
float value = poly[state.index];
136+
114137
#if ANTIALIAS == ANTIALIAS_POLYBLEP
115138
if (use_antialias)
116139
{
@@ -139,59 +162,6 @@ static float OscillatorPoly(OscillatorConfig const &config, OscillatorState &sta
139162
}
140163
}
141164
#endif
142-
return value + value - 1.0f;
143-
}
144-
145-
// poly4 oscillator
146-
// 4-bit linear feedback shift register noise
147-
float OscillatorPoly4(OscillatorConfig const &config, OscillatorState &state, float step)
148-
{
149-
return OscillatorPoly(config, state, poly4, ARRAY_SIZE(poly4), step);
150-
}
151-
152-
// poly5 oscillator
153-
// 5-bit linear feedback shift register noise
154-
float OscillatorPoly5(OscillatorConfig const &config, OscillatorState &state, float step)
155-
{
156-
return OscillatorPoly(config, state, poly5, ARRAY_SIZE(poly5), step);
157-
}
158-
159-
// period93 oscillator
160-
// 15-bit linear feedback shift register noise with variant tap position
161-
float OscillatorPeriod93(OscillatorConfig const &config, OscillatorState &state, float step)
162-
{
163-
return OscillatorPoly(config, state, period93, ARRAY_SIZE(period93), step);
164-
}
165165

166-
// poly9 oscillator
167-
// 9-bit linear feedback shift register noise
168-
float OscillatorPoly9(OscillatorConfig const &config, OscillatorState &state, float step)
169-
{
170-
return OscillatorPoly(config, state, poly9, ARRAY_SIZE(poly9), step);
171-
}
172-
173-
// poly17 oscillator
174-
// 17-bit linear feedback shift register noise
175-
float OscillatorPoly17(OscillatorConfig const &config, OscillatorState &state, float step)
176-
{
177-
return OscillatorPoly(config, state, poly17, ARRAY_SIZE(poly17), step);
178-
}
179-
180-
// pulse wave clocked by poly5
181-
// (what the Atari POKEY actually does with poly5)
182-
float OscillatorPulsePoly5(OscillatorConfig const &config, OscillatorState &state, float step)
183-
{
184-
return OscillatorPoly(config, state, pulsepoly5, ARRAY_SIZE(pulsepoly5), step);
185-
}
186-
187-
// poly4 clocked by poly5
188-
float OscillatorPoly4Poly5(OscillatorConfig const &config, OscillatorState &state, float step)
189-
{
190-
return OscillatorPoly(config, state, poly4poly5, ARRAY_SIZE(poly4poly5), step);
191-
}
192-
193-
// poly17 clocked by poly5
194-
float OscillatorPoly17Poly5(OscillatorConfig const &config, OscillatorState &state, float step)
195-
{
196-
return OscillatorPoly(config, state, poly17poly5, ARRAY_SIZE(poly17poly5), step);
166+
return value + value - 1.0f;
197167
}

Diff for: WavePoly.h

+2-29
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,5 @@ extern char poly17poly5[ARRAY_SIZE(poly5) * ARRAY_SIZE(poly17)];
2424
// initialize polynomial noise tables
2525
extern void InitPoly();
2626

27-
// poly4 waveform
28-
// 4-bit linear feedback shift register noise
29-
extern float OscillatorPoly4(OscillatorConfig const &config, OscillatorState &state, float step);
30-
31-
// poly5 waveform
32-
// 5-bit linear feedback shift register noise
33-
extern float OscillatorPoly5(OscillatorConfig const &config, OscillatorState &state, float step);
34-
35-
// period-93 waveform
36-
// 15-bit linear feedback shift register noise with variant tap position
37-
extern float OscillatorPeriod93(OscillatorConfig const &config, OscillatorState &state, float step);
38-
39-
// poly9 waveform
40-
// 9-bit linear feedback shift register noise
41-
extern float OscillatorPoly9(OscillatorConfig const &config, OscillatorState &state, float step);
42-
43-
// poly17 waveform
44-
// 17-bit linear feedback shift register noise
45-
extern float OscillatorPoly17(OscillatorConfig const &config, OscillatorState &state, float step);
46-
47-
// pulse wave clocked by poly5
48-
// (what the Atari POKEY actually does with poly5)
49-
extern float OscillatorPulsePoly5(OscillatorConfig const &config, OscillatorState &state, float step);
50-
51-
// poly4 clocked by poly5
52-
extern float OscillatorPoly4Poly5(OscillatorConfig const &config, OscillatorState &state, float step);
53-
54-
// poly17 clocked by poly5
55-
extern float OscillatorPoly17Poly5(OscillatorConfig const &config, OscillatorState &state, float step);
27+
// poly waveform
28+
extern float OscillatorPoly(OscillatorConfig const &config, OscillatorState &state, float step);

Diff for: WavePulse.cpp

+32-24
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Pulse Wave
1919
// - smoothed transition to reduce aliasing
2020
static __forceinline float GetPulseValue(float const phase, float const width)
2121
{
22-
return phase - FloorInt(phase) < width ? 1.0f : -1.0f;
22+
return phase < width ? 1.0f : -1.0f;
2323
}
2424
float OscillatorPulse(OscillatorConfig const &config, OscillatorState &state, float step)
2525
{
@@ -29,60 +29,68 @@ float OscillatorPulse(OscillatorConfig const &config, OscillatorState &state, fl
2929
return -1.0f;
3030
if (config.waveparam >= 1.0f)
3131
return 1.0f;
32-
float value = GetPulseValue(state.phase, config.waveparam);
32+
float const phase = state.phase;
33+
float value = GetPulseValue(phase, config.waveparam);
3334
#if ANTIALIAS == ANTIALIAS_POLYBLEP
3435
if (use_antialias)
3536
{
3637
float const w = Min(step * POLYBLEP_WIDTH, 0.5f);
3738

3839
// nearest up edge
39-
float const up_nearest = float(RoundInt(state.phase));
40+
float const up_nearest = float(phase - 0.5f >= 0);
4041

4142
// nearest down edge
42-
float const down_nearest = float(RoundInt(state.phase - config.waveparam)) + config.waveparam;
43+
float const down_nearest = float(phase - 0.5f >= config.waveparam) - float(phase + 0.5f < config.waveparam) + config.waveparam;
4344

4445
if (config.sync_enable)
4546
{
4647
// short-circuit case
4748
if (config.sync_phase < config.waveparam)
4849
return 1.0f;
4950

51+
// shift sync phase into range
52+
int const index = state.index;
53+
float sync_phase = config.sync_phase - index;
54+
5055
// last up transition before sync
51-
float const up_before_sync = float(CeilingInt(config.sync_phase) - 1);
56+
float const up_before_sync = float(CeilingInt(sync_phase) - 1);
5257

53-
// handle discontinuity at zero phase
54-
if (config.sync_phase > up_before_sync + config.waveparam)
55-
{
56-
// down edge before sync wrapped before zero
57-
value -= PolyBLEP(state.phase - (up_before_sync + config.waveparam - config.sync_phase), w);
58-
// up edge at 0
59-
value += PolyBLEP(state.phase, w);
60-
}
61-
else
58+
if (index == 0)
6259
{
63-
// up edge before sync wrapped before zero
64-
value += PolyBLEP(state.phase - (up_before_sync - config.sync_phase), w);
60+
// handle discontinuity at zero phase
61+
if (sync_phase > up_before_sync + config.waveparam)
62+
{
63+
// down edge before sync wrapped before zero
64+
value -= PolyBLEP(phase - (up_before_sync + config.waveparam - sync_phase), w);
65+
// up edge at 0
66+
value += PolyBLEP(phase, w);
67+
}
68+
else
69+
{
70+
// up edge before sync wrapped before zero
71+
value += PolyBLEP(phase - (up_before_sync - sync_phase), w);
72+
}
6573
}
6674

6775
// handle nearest up transition if it's in range
68-
if (up_nearest > 0 && up_nearest <= up_before_sync)
69-
value += PolyBLEP(state.phase - up_nearest, w);
76+
if (up_nearest > -index && up_nearest <= up_before_sync)
77+
value += PolyBLEP(phase - up_nearest, w);
7078

7179
// handle nearest down transition if it's in range
72-
if (down_nearest > 0 && down_nearest < config.sync_phase)
73-
value -= PolyBLEP(state.phase - down_nearest, w);
80+
if (down_nearest > -index && down_nearest < sync_phase)
81+
value -= PolyBLEP(phase - down_nearest, w);
7482

7583
// handle discontinuity at sync phase
76-
if (config.sync_phase > up_before_sync + config.waveparam)
84+
if (sync_phase > up_before_sync + config.waveparam)
7785
{
7886
// up edge at config.sync_phase
79-
value += PolyBLEP(state.phase - config.sync_phase, w);
87+
value += PolyBLEP(phase - sync_phase, w);
8088
}
8189
}
8290
else
8391
{
84-
value += PolyBLEP(state.phase - up_nearest, w);
85-
value -= PolyBLEP(state.phase - down_nearest, w);
92+
value += PolyBLEP(phase - up_nearest, w);
93+
value -= PolyBLEP(phase - down_nearest, w);
8694
}
8795
}
8896
#endif

0 commit comments

Comments
 (0)