mirror of
https://github.com/radio95-rnt/fm95.git
synced 2026-02-26 19:23:51 +01:00
remove lpf
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
FM95 is a audio processor for FM, it does:
|
||||
|
||||
- Pre-Emphasis
|
||||
- Low Pass Filter
|
||||
- Stereo
|
||||
- Polar Stereo
|
||||
- SCA
|
||||
@@ -34,7 +33,7 @@ Done!
|
||||
|
||||
## CPU Usage?
|
||||
|
||||
Should run completly fine on a pi 5, right now with the preemp and rds2, on a pi 3b, its 50-70% (without lpf its more like 25%-27%, lpf with neon optimization is about 50%)
|
||||
Should run completly fine on a pi 5, fine on a pi 3b
|
||||
|
||||
## Other Apps
|
||||
|
||||
|
||||
@@ -14,48 +14,3 @@ float apply_preemphasis(ResistorCapacitor *filter, float sample) {
|
||||
float hard_clip(float sample, float threshold) {
|
||||
return fmaxf(-threshold, fminf(threshold, sample));
|
||||
}
|
||||
|
||||
void init_lpf(LPFFilter *filter, float cutoff, int sample_rate) {
|
||||
float a = tanf(M_PI * cutoff / sample_rate);
|
||||
float a2 = a * a;
|
||||
float r, e;
|
||||
|
||||
for (int i = 0; i < LPF_ORDER; i++) {
|
||||
r = sinf(M_PI * (2.0f * i + 1.0f) / (4.0f * LPF_ORDER));
|
||||
e = a2 + 2.0f * a * r + 1.0f;
|
||||
float inv_e = 1.0f / e;
|
||||
|
||||
filter->A[i] = a2 * inv_e;
|
||||
filter->d1[i] = 2.0f * (1.0f - a2) * inv_e;
|
||||
filter->d2[i] = -(a2 - 2.0f * a * r + 1.0f) * inv_e;
|
||||
}
|
||||
}
|
||||
|
||||
float process_lpf(LPFFilter *filter, float x) {
|
||||
#if USE_NEON
|
||||
float32x4_t y_vec = vdupq_n_f32(x);
|
||||
for (int i = 0; i < LPF_ORDER; i += 4) {
|
||||
float32x4_t d1_vec = vld1q_f32(&filter->d1[i]);
|
||||
float32x4_t d2_vec = vld1q_f32(&filter->d2[i]);
|
||||
float32x4_t w1_vec = vld1q_f32(&filter->w1[i]);
|
||||
float32x4_t w2_vec = vld1q_f32(&filter->w2[i]);
|
||||
float32x4_t A_vec = vld1q_f32(&filter->A[i]);
|
||||
|
||||
float32x4_t w0_new_vec = vmlaq_f32(vmlaq_f32(y_vec, d1_vec, w1_vec), d2_vec, w2_vec);
|
||||
y_vec = vmulq_f32(A_vec, vaddq_f32(vaddq_f32(w0_new_vec, w1_vec), vaddq_f32(w1_vec, w2_vec)));
|
||||
|
||||
vst1q_f32(&filter->w2[i], w1_vec);
|
||||
vst1q_f32(&filter->w1[i], w0_new_vec);
|
||||
}
|
||||
return vgetq_lane_f32(y_vec, 0);
|
||||
#else
|
||||
float y = x;
|
||||
for (int i = 0; i < LPF_ORDER; i++) {
|
||||
float w0_new = filter->d1[i] * filter->w1[i] + filter->d2[i] * filter->w2[i] + y;
|
||||
y = filter->A[i] * (w0_new + 2.0f * filter->w1[i] + filter->w2[i]);
|
||||
filter->w2[i] = filter->w1[i];
|
||||
filter->w1[i] = w0_new;
|
||||
}
|
||||
return y;
|
||||
#endif
|
||||
}
|
||||
@@ -24,15 +24,3 @@ void init_preemphasis(ResistorCapacitor *filter, float tau, float sample_rate);
|
||||
float apply_preemphasis(ResistorCapacitor *filter, float sample);
|
||||
|
||||
float hard_clip(float sample, float threshold);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float A[LPF_ORDER];
|
||||
float d1[LPF_ORDER];
|
||||
float d2[LPF_ORDER];
|
||||
float w0[LPF_ORDER];
|
||||
float w1[LPF_ORDER];
|
||||
float w2[LPF_ORDER];
|
||||
} LPFFilter;
|
||||
void init_lpf(LPFFilter *filter, float cutoff, int sample_rate);
|
||||
float process_lpf(LPFFilter *filter, float x);
|
||||
|
||||
@@ -414,10 +414,6 @@ int main(int argc, char **argv) {
|
||||
init_preemphasis(&preemp_l, preemphasis_tau, sample_rate);
|
||||
init_preemphasis(&preemp_r, preemphasis_tau, sample_rate);
|
||||
|
||||
LPFFilter lpf_l, lpf_r;
|
||||
init_lpf(&lpf_l, 15000, sample_rate);
|
||||
init_lpf(&lpf_r, 15000, sample_rate);
|
||||
|
||||
signal(SIGINT, stop);
|
||||
signal(SIGTERM, stop);
|
||||
|
||||
@@ -473,8 +469,6 @@ int main(int argc, char **argv) {
|
||||
|
||||
float ready_l = apply_preemphasis(&preemp_l, l_in);
|
||||
float ready_r = apply_preemphasis(&preemp_r, r_in);
|
||||
ready_l = process_lpf(&lpf_l, ready_l);
|
||||
ready_r = process_lpf(&lpf_r, ready_r);
|
||||
ready_l = hard_clip(ready_l*audio_volume, clipper_threshold);
|
||||
ready_r = hard_clip(ready_r*audio_volume, clipper_threshold);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user