2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "biquad-float.h"
21 #include "config-api.h"
35 #define MODULE_PARAMS feedback_reducer_params
37 #define MAX_FBR_BANDS 16
39 #define ANALYSIS_BUFFER_SIZE 8192
40 #define ANALYSIS_BUFFER_BITS 13
43 static complex float euler_table
[ANALYSIS_BUFFER_SIZE
];
46 static int map_table
[ANALYSIS_BUFFER_SIZE
];
48 // Bit-reversed von Hann window
49 static float von_hann_window_transposed
[ANALYSIS_BUFFER_SIZE
];
51 struct feedback_reducer_params
53 struct eq_band bands
[MAX_FBR_BANDS
];
56 struct feedback_reducer_module
58 struct cbox_module module
;
60 struct feedback_reducer_params
*params
, *old_params
;
62 struct cbox_biquadf_coeffs coeffs
[MAX_FBR_BANDS
];
63 struct cbox_biquadf_state state
[MAX_FBR_BANDS
][2];
65 float analysis_buffer
[ANALYSIS_BUFFER_SIZE
];
69 complex float fft_buffers
[2][ANALYSIS_BUFFER_SIZE
];
72 // Trivial implementation of Cooley-Tukey (+ my own mistakes) + von Hann window
73 static int do_fft(struct feedback_reducer_module
*m
)
75 // Copy + bit reversal addressing
76 for (int i
= 0; i
< ANALYSIS_BUFFER_SIZE
; i
++)
78 m
->fft_buffers
[0][i
] = von_hann_window_transposed
[i
] * m
->analysis_buffer
[map_table
[i
]] * (2.0 / ANALYSIS_BUFFER_SIZE
);
81 for (int i
= 0; i
< ANALYSIS_BUFFER_BITS
; i
++)
83 complex float *src
= m
->fft_buffers
[i
& 1];
84 complex float *dst
= m
->fft_buffers
[(~i
) & 1];
85 int invi
= ANALYSIS_BUFFER_BITS
- i
- 1;
89 for (int j
= 0; j
< ANALYSIS_BUFFER_SIZE
/ 2; j
++)
91 int jj1
= (j
& mask
) + ((j
& ~mask
) << 1); // insert 0 at ith bit to get the left arm of the butterfly
92 int jj2
= jj1
+ disp
; // insert 1 at ith bit to get the right arm
95 complex float eiw1
= euler_table
[(jj1
<< invi
) & (ANALYSIS_BUFFER_SIZE
- 1)];
96 complex float eiw2
= euler_table
[(jj2
<< invi
) & (ANALYSIS_BUFFER_SIZE
- 1)];
98 // printf("%d -> %d, %d\n", j, jj, jj + disp);
99 butterfly(&dst
[jj1
], &dst
[jj2
], src
[jj1
], src
[jj2
], eiw1
, eiw2
);
102 return ANALYSIS_BUFFER_BITS
& 1;
105 #define PEAK_REGION_RADIUS 3
107 struct potential_peak_info
117 static int peak_compare(const void *peak1
, const void *peak2
)
119 const struct potential_peak_info
*pi1
= peak1
;
120 const struct potential_peak_info
*pi2
= peak2
;
122 if (pi1
->points
< pi2
->points
)
124 if (pi1
->points
> pi2
->points
)
129 static int find_peaks(complex float *spectrum
, float srate
, float peak_freqs
[16])
131 struct potential_peak_info pki
[ANALYSIS_BUFFER_SIZE
/ 2 + 1];
132 for (int i
= 0; i
<= ANALYSIS_BUFFER_SIZE
/ 2; i
++)
138 for (int i
= PEAK_REGION_RADIUS
; i
<= ANALYSIS_BUFFER_SIZE
/ 2 - PEAK_REGION_RADIUS
; i
++)
140 struct potential_peak_info
*pi
= &pki
[i
];
144 for (int j
= -PEAK_REGION_RADIUS
; j
<= PEAK_REGION_RADIUS
; j
++)
147 float bin
= cabs(spectrum
[i
+ j
]);
153 pi
->avg
= sum
/ (2 * PEAK_REGION_RADIUS
+ 1);
155 pi
->centre
= sumf
/ sum
;
156 pi
->dist
= (sumf
/ sum
- i
);
159 // printf("Bin %d sumf/sum %f avg %f peak %f p/a %f dist %f val %f\n", i, sumf / sum, pki[i].avg, peak, peak / pki[i].avg, sumf/sum - i, cabs(spectrum[i]));
161 for (int i
= PEAK_REGION_RADIUS
; i
<= ANALYSIS_BUFFER_SIZE
/ 2 - PEAK_REGION_RADIUS
; i
++)
163 struct potential_peak_info
*tpi
= &pki
[i
];
164 // ignore peaks below -40dB of the max bin
165 if (pki
[(int)tpi
->centre
].peak
< gmax
* 0.01)
167 pki
[(int)tpi
->centre
].points
+= 1;
170 for (int i
= 0; i
<= ANALYSIS_BUFFER_SIZE
/ 2; i
++)
172 float freq
= i
* srate
/ ANALYSIS_BUFFER_SIZE
;
173 printf("Bin %d freq %f points %f\n", i
, freq
, pki
[i
].points
);
176 qsort(pki
, ANALYSIS_BUFFER_SIZE
/ 2 + 1, sizeof(struct potential_peak_info
), peak_compare
);
180 for (int i
= 0; i
<= ANALYSIS_BUFFER_SIZE
/ 2; i
++)
182 if (pki
[i
].points
<= 1)
184 if (pki
[i
].peak
<= 0.0001)
186 gboolean dupe
= FALSE
;
187 for (int j
= 0; j
< peak_count
; j
++)
189 if (fabs(peaks
[j
] - pki
[i
].centre
) < PEAK_REGION_RADIUS
)
197 peak_freqs
[peak_count
] = pki
[i
].centre
* srate
/ ANALYSIS_BUFFER_SIZE
;
198 peaks
[peak_count
++] = pki
[i
].centre
;
199 printf("Mul %f freq %f points %f peak %f\n", pki
[i
].centre
, pki
[i
].centre
* srate
/ ANALYSIS_BUFFER_SIZE
, pki
[i
].points
, pki
[i
].peak
);
206 static void redo_filters(struct feedback_reducer_module
*m
)
208 for (int i
= 0; i
< MAX_FBR_BANDS
; i
++)
210 struct eq_band
*band
= &m
->params
->bands
[i
];
213 cbox_biquadf_set_peakeq_rbj(&m
->coeffs
[i
], band
->center
, band
->q
, band
->gain
, m
->module
.srate
);
216 m
->old_params
= m
->params
;
219 gboolean
feedback_reducer_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
)
221 struct feedback_reducer_module
*m
= (struct feedback_reducer_module
*)ct
->user_data
;
223 EFFECT_PARAM_ARRAY("/active", "i", bands
, active
, int, , 0, 1) else
224 EFFECT_PARAM_ARRAY("/center", "f", bands
, center
, double, , 10, 20000) else
225 EFFECT_PARAM_ARRAY("/q", "f", bands
, q
, double, , 0.01, 100) else
226 EFFECT_PARAM_ARRAY("/gain", "f", bands
, gain
, double, dB2gain_simple
, -100, 100) else
227 if (!strcmp(cmd
->command
, "/start") && !strcmp(cmd
->arg_types
, ""))
230 cbox_rt_swap_pointers(m
->module
.rt
, (void **)&m
->wrptr
, m
->analysis_buffer
);
232 else if (!strcmp(cmd
->command
, "/status") && !strcmp(cmd
->arg_types
, ""))
234 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
237 if (m
->wrptr
== m
->analysis_buffer
+ ANALYSIS_BUFFER_SIZE
&& m
->analysed
== 0)
240 int count
= find_peaks(m
->fft_buffers
[do_fft(m
)], m
->module
.srate
, freqs
);
241 struct feedback_reducer_params
*p
= malloc(sizeof(struct feedback_reducer_params
));
242 memcpy(p
->bands
+ count
, &m
->params
->bands
[0], sizeof(struct eq_band
) * (MAX_FBR_BANDS
- count
));
243 for (int i
= 0; i
< count
; i
++)
245 p
->bands
[i
].active
= TRUE
;
246 p
->bands
[i
].center
= freqs
[i
];
247 p
->bands
[i
].q
= freqs
[i
] / 50; // each band ~100 Hz (not really sure about filter Q vs bandwidth)
248 p
->bands
[i
].gain
= 0.125;
250 free(cbox_rt_swap_pointers(m
->module
.rt
, (void **)&m
->params
, p
)); \
252 if (!cbox_execute_on(fb
, NULL
, "/refresh", "i", error
, 1))
255 if (!cbox_execute_on(fb
, NULL
, "/finished", "i", error
, m
->analysed
))
257 for (int i
= 0; i
< MAX_FBR_BANDS
; i
++)
259 if (!cbox_execute_on(fb
, NULL
, "/active", "ii", error
, i
, (int)m
->params
->bands
[i
].active
))
261 if (!cbox_execute_on(fb
, NULL
, "/center", "if", error
, i
, m
->params
->bands
[i
].center
))
263 if (!cbox_execute_on(fb
, NULL
, "/q", "if", error
, i
, m
->params
->bands
[i
].q
))
265 if (!cbox_execute_on(fb
, NULL
, "/gain", "if", error
, i
, gain2dB_simple(m
->params
->bands
[i
].gain
)))
268 // return cbox_execute_on(fb, NULL, "/wet_dry", "f", error, m->params->wet_dry);
269 return CBOX_OBJECT_DEFAULT_STATUS(&m
->module
, fb
, error
);
272 return cbox_object_default_process_cmd(ct
, fb
, cmd
, error
);
276 void feedback_reducer_process_event(struct cbox_module
*module
, const uint8_t *data
, uint32_t len
)
278 // struct feedback_reducer_module *m = module->user_data;
281 void feedback_reducer_process_block(struct cbox_module
*module
, cbox_sample_t
**inputs
, cbox_sample_t
**outputs
)
283 struct feedback_reducer_module
*m
= module
->user_data
;
285 if (m
->params
!= m
->old_params
)
288 if (m
->wrptr
&& m
->wrptr
!= m
->analysis_buffer
+ ANALYSIS_BUFFER_SIZE
)
290 for (int i
= 0; i
< CBOX_BLOCK_SIZE
; i
++)
292 if (m
->wrptr
== m
->analysis_buffer
+ ANALYSIS_BUFFER_SIZE
)
294 *m
->wrptr
++ = inputs
[0][i
] + inputs
[1][i
];
297 for (int c
= 0; c
< 2; c
++)
299 gboolean first
= TRUE
;
300 for (int i
= 0; i
< MAX_FBR_BANDS
; i
++)
302 if (!m
->params
->bands
[i
].active
)
306 cbox_biquadf_process_to(&m
->state
[i
][c
], &m
->coeffs
[i
], inputs
[c
], outputs
[c
]);
311 cbox_biquadf_process(&m
->state
[i
][c
], &m
->coeffs
[i
], outputs
[c
]);
315 memcpy(outputs
[c
], inputs
[c
], sizeof(float) * CBOX_BLOCK_SIZE
);
319 MODULE_SIMPLE_DESTROY_FUNCTION(feedback_reducer
)
321 MODULE_CREATE_FUNCTION(feedback_reducer
)
323 static int inited
= 0;
326 for (int i
= 0; i
< ANALYSIS_BUFFER_SIZE
; i
++)
328 euler_table
[i
] = cos(i
* 2 * M_PI
/ ANALYSIS_BUFFER_SIZE
) + I
* sin(i
* 2 * M_PI
/ ANALYSIS_BUFFER_SIZE
);
330 for (int j
= 0; j
< ANALYSIS_BUFFER_BITS
; j
++)
332 if (i
& (1 << (ANALYSIS_BUFFER_BITS
- 1 - j
)))
336 von_hann_window_transposed
[i
] = 0.5 * (1 - cos (ni
* 2 * M_PI
/ (ANALYSIS_BUFFER_SIZE
- 1)));
342 struct feedback_reducer_module
*m
= malloc(sizeof(struct feedback_reducer_module
));
343 CALL_MODULE_INIT(m
, 2, 2, feedback_reducer
);
344 m
->module
.process_event
= feedback_reducer_process_event
;
345 m
->module
.process_block
= feedback_reducer_process_block
;
346 struct feedback_reducer_params
*p
= malloc(sizeof(struct feedback_reducer_params
));
348 m
->old_params
= NULL
;
352 for (int b
= 0; b
< MAX_FBR_BANDS
; b
++)
354 p
->bands
[b
].active
= cbox_eq_get_band_param(cfg_section
, b
, "active", 0) > 0;
355 p
->bands
[b
].center
= cbox_eq_get_band_param(cfg_section
, b
, "center", 50 * pow(2.0, b
/ 2.0));
356 p
->bands
[b
].q
= cbox_eq_get_band_param(cfg_section
, b
, "q", 0.707 * 2);
357 p
->bands
[b
].gain
= cbox_eq_get_band_param_db(cfg_section
, b
, "gain", 0);
360 cbox_eq_reset_bands(m
->state
, MAX_FBR_BANDS
);
366 struct cbox_module_keyrange_metadata feedback_reducer_keyranges
[] = {
369 struct cbox_module_livecontroller_metadata feedback_reducer_controllers
[] = {
372 DEFINE_MODULE(feedback_reducer
, 2, 2)