-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add 'matrix4_mb' effect; move some shared code to separate files.
The 'matrix4_mb' effect utilizes the same core algorithm as 'matrix4', but splits the signal into 10 independently steered bands for better separation of multiple simultaneous direct sources. The filter bank utilizes doubly complementary 5th-order butterworth filters implemented as a parallel sum and difference of two all pass sections. See [1] [2] and [3]. For reduced computational load, the event detection and matrix coefficient calculations for each band are done at a reduced sample rate (8x downsampling currently). This commit also adds 'surround_delay' and 'linear_phase' options. [1] P. P. Vaidyanathan, Sanjit K. Mitra, and Yrjö Neuvo, "A New Approach to the Realization of Low-Sensitivity IIR Digital Filters," IEEE Transactions on Acoustics, Speech, and Signal Processing, vol. 34, no. 2, pp. 350-361, 1986. [2] Lajos Gazsi, "Explicit Formulas for Lattice Wave Digital Filters," IEEE Transactions on Circuits and Systems, vol. 32, no. 1, pp. 68-88, 1985. [3] Alexis Favrot and Christof Faller, "Complementary N-Band IIR Filterbank Based on 2-Band Complementary Filters," Proc. Intl. Works. on Acoust. Echo and Noise Control (IWAENC), 2010.
- Loading branch information
Showing
12 changed files
with
1,449 additions
and
410 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#include <complex.h> | ||
#include <math.h> | ||
#include "cap5.h" | ||
|
||
void ap1_reset(struct ap1_state *state) | ||
{ | ||
state->i0 = 0.0; | ||
state->o0 = 0.0; | ||
} | ||
|
||
void ap2_reset(struct ap2_state *state) | ||
{ | ||
state->i0 = state->i1 = 0.0; | ||
state->o0 = state->o1 = 0.0; | ||
} | ||
|
||
void ap3_reset(struct ap3_state *state) | ||
{ | ||
ap2_reset(&state->ap2); | ||
ap1_reset(&state->ap1); | ||
} | ||
|
||
void cap5_reset(struct cap5_state *state) | ||
{ | ||
ap2_reset(&state->a1); | ||
ap3_reset(&state->a2); | ||
} | ||
|
||
/* doubly complementary 5th-order butterworth filters implemented as the | ||
sum (lowpass) and difference (highpass) of two allpass sections */ | ||
void cap5_init(struct cap5_state *state, double fs, double fc) | ||
{ | ||
const double fc_w = 2.0*fs*tan(M_PI*fc/fs); /* pre-warped corner frequency */ | ||
double complex p[3]; /* first two have a complex conjugate (not stored), third is real */ | ||
|
||
for (int i = 0; i < 3; ++i) { | ||
const double theta = (2.0*(i+1)-1.0)*M_PI/10.0; | ||
p[i] = -sin(theta) + cos(theta)*I; /* normalized pole in s-plane */ | ||
p[i] = p[i]*fc_w; /* scale */ | ||
p[i] = (2.0*fs + p[i]) / (2.0*fs - p[i]); /* bilinear transform */ | ||
//LOG_FMT(LL_VERBOSE, "%s(): fc=%gHz: p[%d] = %f%+fi", __func__, fc, i, creal(p[i]), cimag(p[i])); | ||
} | ||
|
||
state->a2.ap2.c0 = -2.0*creal(p[0]); | ||
state->a2.ap2.c1 = creal(p[0])*creal(p[0]) + cimag(p[0])*cimag(p[0]); | ||
|
||
state->a1.c0 = -2.0*creal(p[1]); | ||
state->a1.c1 = creal(p[1])*creal(p[1]) + cimag(p[1])*cimag(p[1]); | ||
|
||
state->a2.ap1.c0 = -creal(p[2]); | ||
|
||
//LOG_FMT(LL_VERBOSE, "%s(): fc=%gHz: a1: c0=%g c1=%g", __func__, fc, state->a1.c0, state->a1.c1); | ||
//LOG_FMT(LL_VERBOSE, "%s(): fc=%gHz: a2.ap2: c0=%g c1=%g", __func__, fc, state->a2.ap2.c0, state->a2.ap2.c1); | ||
//LOG_FMT(LL_VERBOSE, "%s(): fc=%gHz: a2.ap1: c0=%g", __func__, fc, state->a2.ap1.c0); | ||
|
||
cap5_reset(state); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#ifndef _CAP5_H | ||
#define _CAP5_H | ||
|
||
#include "dsp.h" | ||
|
||
struct ap1_state { | ||
sample_t c0; | ||
sample_t i0, o0; | ||
}; | ||
|
||
struct ap2_state { | ||
sample_t c0, c1; | ||
sample_t i0, i1, o0, o1; | ||
}; | ||
|
||
struct ap3_state { | ||
struct ap2_state ap2; | ||
struct ap1_state ap1; | ||
}; | ||
|
||
struct cap5_state { | ||
struct ap2_state a1; | ||
struct ap3_state a2; | ||
}; | ||
|
||
void ap1_reset(struct ap1_state *); | ||
void ap2_reset(struct ap2_state *); | ||
void ap3_reset(struct ap3_state *); | ||
void cap5_reset(struct cap5_state *); | ||
void cap5_init(struct cap5_state *, double, double); | ||
|
||
static __inline__ sample_t ap1_run(struct ap1_state *state, sample_t s) | ||
{ | ||
sample_t r = state->c0 * (s - state->o0) | ||
+ state->i0; | ||
|
||
state->i0 = s; | ||
state->o0 = r; | ||
|
||
return r; | ||
} | ||
|
||
static __inline__ sample_t ap2_run(struct ap2_state *state, sample_t s) | ||
{ | ||
sample_t r = state->c1 * (s - state->o1) | ||
+ state->c0 * (state->i0 - state->o0) | ||
+ state->i1; | ||
|
||
state->i1 = state->i0; | ||
state->i0 = s; | ||
|
||
state->o1 = state->o0; | ||
state->o0 = r; | ||
|
||
return r; | ||
} | ||
|
||
static __inline__ sample_t ap3_run(struct ap3_state *state, sample_t s) | ||
{ | ||
return ap1_run(&state->ap1, ap2_run(&state->ap2, s)); | ||
} | ||
|
||
static __inline__ void cap5_run(struct cap5_state *state, sample_t s, sample_t *lp, sample_t *hp) | ||
{ | ||
sample_t a1 = ap2_run(&state->a1, s); | ||
sample_t a2 = ap3_run(&state->a2, s); | ||
*lp = (a1+a2)*0.5; | ||
*hp = (a1-a2)*0.5; | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
#ifndef _EWMA_H | ||
#define _EWMA_H | ||
|
||
#include <math.h> | ||
|
||
struct ewma_state { | ||
double c0, c1, m0; | ||
}; | ||
|
||
#define EWMA_RISE_TIME(x) ((x)/1000.0/2.1972) /* 10%-90% rise time in ms */ | ||
|
||
/* note: tc is the time constant in seconds */ | ||
static __inline__ void ewma_init(struct ewma_state *state, double fs, double tc) | ||
{ | ||
const double a = 1.0-exp(-1.0/(fs*tc)); | ||
state->c0 = a; | ||
state->c1 = 1.0-a; | ||
state->m0 = 0.0; | ||
} | ||
|
||
static __inline__ double ewma_run(struct ewma_state *state, double s) | ||
{ | ||
const double r = state->c0*s + state->c1*state->m0; | ||
state->m0 = r; | ||
return r; | ||
} | ||
|
||
/* note: sf > 1.0 means a faster rise time */ | ||
static __inline__ double ewma_run_scale(struct ewma_state *state, double s, double sf) | ||
{ | ||
const double c = (state->c0*sf > 0.39) ? 0.39 : state->c0*sf; | ||
const double r = c*s + (1.0-c)*state->m0; | ||
state->m0 = r; | ||
return r; | ||
} | ||
|
||
static __inline__ double ewma_run_set_max(struct ewma_state *state, double s) | ||
{ | ||
if (s >= state->m0) s = ewma_run(state, s); | ||
else state->m0 = s; | ||
return s; | ||
} | ||
|
||
static __inline__ double ewma_set(struct ewma_state *state, double s) | ||
{ | ||
state->m0 = s; | ||
return s; | ||
} | ||
|
||
static __inline__ double ewma_get_last(struct ewma_state *state) | ||
{ | ||
return state->m0; | ||
} | ||
|
||
#endif |
Oops, something went wrong.