Skip to content

Commit

Permalink
filters.c: Make LPF24 work under floating-point; Add TestLowerVcf to …
Browse files Browse the repository at this point in the history
…check sub-fundamental resonance.
  • Loading branch information
dpwe committed Feb 14, 2024
1 parent f62f2b0 commit dfd4d1d
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 50 deletions.
1 change: 0 additions & 1 deletion src/amy_fixedpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@

#define AMY_USE_FIXEDPOINT


#ifndef AMY_USE_FIXEDPOINT

//#warning "floating point calc"
Expand Down
88 changes: 39 additions & 49 deletions src/filters.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,43 +213,36 @@ int8_t dsps_biquad_f32_ansi_split_fb(const SAMPLE *input, SAMPLE *output, int le

static inline int headroom(SAMPLE a) {
// How many bits bigger can this value get before overflow?
#ifdef AMY_USE_FIXEDPOINT
return __builtin_clz(ABS(a)) - 1; // -1 for sign bit.
#else // !AMY_USE_FIXEDPOINT
// How many bits can you shift before this max overflows?
int bits = 0;
while(a < F2S(128.0) && bits < 32) {
a = SHIFTL(a, 1);
++bits;
}
return bits;
#endif // AMY_USE_FIXEDPOINT
}

#ifdef AMY_USE_FIXEDPOINT

SAMPLE top16SMUL(SAMPLE a, SAMPLE b) {
// Multiply the top 15 bits of a and b.
int adropped = MAX(0, 16 - headroom(a));
if (adropped) {
a = (a + (1 << (adropped - 1))) >> adropped;
a = SHIFTR(a + (1 << (adropped - 1)), adropped);
}
int resultdrop = 23 - adropped;
int bdropped = MIN(resultdrop, MAX(0, 16 - headroom(b)));
if (bdropped) {
b = (b + (1 << (bdropped - 1))) >> bdropped;
b = SHIFTR(b + (1 << (bdropped - 1)), bdropped);
}
resultdrop -= bdropped;
SAMPLE result = a * b;
if (resultdrop) {
return (result + (1 << (resultdrop - 1))) >> resultdrop;
}
return result;
}

SAMPLE top16SMUL_preheadroom(SAMPLE a, SAMPLE b, int aheadroom, int bheadroom) {
// Multiply the top 15 bits of a and b.
int adropped = MAX(0, 16 - aheadroom);
if (adropped) {
a = (a + (1 << (adropped - 1))) >> adropped;
}
int resultdrop = 23 - adropped;
int bdropped = MIN(resultdrop, MAX(0, 16 - bheadroom));
if (bdropped) {
b = (b + (1 << (bdropped - 1))) >> bdropped;
}
resultdrop -= bdropped;
SAMPLE result = a * b;
if (resultdrop) {
return (result + (1 << (resultdrop - 1))) >> resultdrop;
return SHIFTR(result + (1 << (resultdrop - 1)), resultdrop);
}
return result;
}
Expand All @@ -258,7 +251,7 @@ SAMPLE top16SMUL_a_part(SAMPLE a, int *p_adropped) {
// Just the processing of a, so we can split it out
int adropped = MAX(0, 16 - headroom(a));
if (adropped) {
a = (a + (1 << (adropped - 1))) >> adropped;
a = SHIFTR(a + (1 << (adropped - 1)), adropped);
}
*p_adropped = adropped;
return a;
Expand All @@ -269,16 +262,35 @@ SAMPLE top16SMUL_after_a(SAMPLE a_processed, SAMPLE b, int adropped, int bheadro
int resultdrop = 23 - adropped;
int bdropped = MIN(resultdrop, MAX(0, 16 - bheadroom));
if (bdropped) {
b = (b + (1 << (bdropped - 1))) >> bdropped;
b = SHIFTR(b + (1 << (bdropped - 1)), bdropped);
}
resultdrop -= bdropped;
SAMPLE result = a_processed * b;
if (resultdrop) {
return (result + (1 << (resultdrop - 1))) >> resultdrop;
return SHIFTR(result + (1 << (resultdrop - 1)), resultdrop);
}
return result;
}

#else // !AMY_USE_FIXEDPOINT

// Sidestep all this logic for SAMPLE == float.

SAMPLE top16SMUL(SAMPLE a, SAMPLE b) {
return a * b;
}

SAMPLE top16SMUL_a_part(SAMPLE a, int *p_adropped) {
*p_adropped = 0; // dropped_bits registration unused in float.
return a;
}

SAMPLE top16SMUL_after_a(SAMPLE a_processed, SAMPLE b, int adropped_unused, int bheadroom_unused) {
return a_processed * b;
}

#endif // AMY_USE_FIXEDPOINT

SAMPLE scan_max(SAMPLE* block, int len) {
AMY_PROFILE_START(SCAN_MAX)

Expand Down Expand Up @@ -532,28 +544,6 @@ void check_overflow(SAMPLE* block, int osc, char *msg) {
#endif // AMY_DEBUG
}

// CLZ saves about 10% of total filtering time.
#ifdef USE_FIXEDPOINT
#define USE_CLZ
#endif

int encl_log2(SAMPLE max) {
AMY_PROFILE_START(ENCL_LOG2)

#ifdef USE_CLZ
return __builtin_clz(max) - 1;
#else // !USE_CLZ
// How many bits can you shift before this max overflows?
int bits = 0;
while(max < F2S(128.0) && bits < 24) {
max = SHIFTL(max, 1);
++bits;
}
AMY_PROFILE_STOP(ENCL_LOG2)
return bits;
#endif // USE_CLZ
}

void block_norm(SAMPLE* block, int len, int bits) {
AMY_PROFILE_START(BLOCK_NORM)

Expand Down Expand Up @@ -604,10 +594,10 @@ void filter_process(SAMPLE * block, uint16_t osc, SAMPLE max_val) {
// Also have to consider the filter state.
#define USE_BLOCK_FLOATING_POINT
#ifdef USE_BLOCK_FLOATING_POINT
int filtnormbits = synth[osc].last_filt_norm_bits + encl_log2(filtmax);
int filtnormbits = synth[osc].last_filt_norm_bits + headroom(filtmax);
#define HEADROOM_BITS 6
#define STATE_HEADROOM_BITS 2
int normbits = MIN(MAX(0, encl_log2(max_val) - HEADROOM_BITS), MAX(0, filtnormbits - STATE_HEADROOM_BITS));
int normbits = MIN(MAX(0, headroom(max_val) - HEADROOM_BITS), MAX(0, filtnormbits - STATE_HEADROOM_BITS));
normbits = MIN(normbits, synth[osc].last_filt_norm_bits + 1); // Increase at most one bit per block.
normbits = MIN(8, normbits); // Without this, I get a weird sign flip at the end of TestLFO - intermediate overflow?
#else // No block floating point
Expand Down
13 changes: 13 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,19 @@ def run(self):
amy.send(time=100, osc=0, note=48, vel=3)
amy.send(time=800, osc=0, vel=0)

class TestLowerVcf(AmyTest):
"""Top16 LPF24 has issues with cf below fundamental?"""

def run(self):
amy.send(time=0, osc=0, wave=amy.SAW_DOWN,
filter_type=amy.FILTER_LPF24, resonance=4.0,
amp='0,0,0.85,1',
filter_freq='50,0,0,0,6',
bp0='0,1,0,0',
bp1='0,1,300,0,1,0')
amy.send(time=100, osc=0, note=48, vel=3)
amy.send(time=800, osc=0, vel=0)


def main(argv):
if len(argv) > 1:
Expand Down

0 comments on commit dfd4d1d

Please sign in to comment.