1
/* This file is part of the KDE project
2
Copyright (C) 2009 Artur Szymiec <artur.szymiec@gmail.com>
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License as published by the Free Software Foundation; either
7
version 2 of the License, or (at your option) any later version.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
Boston, MA 02110-1301, USA.
21
/* Equalizer GPL code Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au
22
Equalizer filter, implementation of a 10 band time domain graphic
23
equalizer using IIR filters. The IIR filters are implemented using a
24
Direct Form II approach, but has been modified (b1 == 0 always) to
27
Adopted to phnon xine engine plugin by Artur Szymiec in 2009 artur.szymiec@gmail.com
31
#define I18N_NOOP(x) x
39
#define __STDC_FORMAT_MACROS
44
// xine headers use the reserved keyword this:
45
#define this this_xine
46
#include <xine/compat.h>
47
#include <xine/post.h>
48
#include <xine/xineutils.h>
51
#define KEQUALIZER_MAX_GAIN 12.0
52
#define KEQUALIZER_L 2 // Storage for filter taps
53
#define KEQUALIZER_KM 10 // Max number of bands
54
#define KEQUALIZER_Q 1.2247449
55
/* Q value for band-pass filters 1.2247=(3/2)^(1/2)
56
gives 4dB suppression @ Fc*2 and Fc/2 */
57
#define KEQUALIZER_CF {60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000}
58
// Maximum and minimum gain for the bands
59
#define KEQUALIZER_G_MAX +12.0
60
#define KEQUALIZER_G_MIN -12.0
61
#define KEQUALIZER_CHANNELS_MAX 6
65
post_class_t post_class;
69
typedef struct KEqualizerPlugin
75
xine_post_in_t params_input;
81
//kequalizer_s kequalizer_t;
82
float a[KEQUALIZER_KM][KEQUALIZER_L]; // A weights
83
float b[KEQUALIZER_KM][KEQUALIZER_L]; // B weights
84
float wq[KEQUALIZER_CHANNELS_MAX][KEQUALIZER_KM][KEQUALIZER_L]; // Circular buffer for W data
85
float g[KEQUALIZER_CHANNELS_MAX][KEQUALIZER_KM]; // Gain factor for each channel and band
86
int K; // Number of used eq bands
87
int channels; // Number of channels
89
void equalize_Buffer(xine_post_t *this_gen,audio_buffer_t *buf);
90
void eq_calc_Bp2(float* a, float* b, float fc, float q);
91
void eq_calc_Gains(xine_post_t *this_gen);
92
void eq_setup_Filters(xine_post_t *this_gen);
93
} kequalizer_plugin_t;
95
/**************************************************************************
97
*************************************************************************/
103
} kequalizer_parameters_t;
106
* description of params struct
108
START_PARAM_DESCR(kequalizer_parameters_t)
110
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, preAmp, NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Equalizer pre-amp gain"))
111
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, eqBands[0], NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Band 1 60Hz Gain"))
112
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, eqBands[1], NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Band 2 170Hz Gain"))
113
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, eqBands[2], NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Band 3 310Hz Gain"))
114
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, eqBands[3], NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Band 4 600Hz Gain"))
115
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, eqBands[4], NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Band 5 1000Hz Gain"))
116
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, eqBands[5], NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Band 6 3000Hz Gain"))
117
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, eqBands[6], NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Band 7 6000Hz Gain"))
118
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, eqBands[7], NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Band 8 12000Hz Gain"))
119
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, eqBands[8], NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Band 9 14000Hz Gain"))
120
PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, eqBands[9], NULL, -KEQUALIZER_MAX_GAIN, KEQUALIZER_MAX_GAIN, 0, I18N_NOOP("Band 10 16000Hz Gain"))
122
END_PARAM_DESCR(param_descr)
124
static int set_parameters (xine_post_t *this_gen, void *param_gen)
126
kequalizer_plugin_t *that = reinterpret_cast<kequalizer_plugin_t *>(this_gen);
127
kequalizer_parameters_t *param = static_cast<kequalizer_parameters_t *>(param_gen);
129
pthread_mutex_lock (&that->lock);
131
that->preAmp = param->preAmp;
132
for (int i=0;i<=9;i++){
133
that->eqBands[i]=param->eqBands[i];
136
that->eq_calc_Gains(this_gen);
138
const char *x = "kequalizer:";
139
Phonon::Xine::debug() << Q_FUNC_INFO
153
pthread_mutex_unlock (&that->lock);
158
static int get_parameters (xine_post_t *this_gen, void *param_gen)
160
kequalizer_plugin_t *that = reinterpret_cast<kequalizer_plugin_t *>(this_gen);
161
kequalizer_parameters_t *param = static_cast<kequalizer_parameters_t *>(param_gen);
163
pthread_mutex_lock (&that->lock);
165
param->preAmp = that->preAmp;
166
for (int i=0;i<=9;i++){
167
param->eqBands[i]=that->eqBands[i];
170
pthread_mutex_unlock (&that->lock);
175
static xine_post_api_descr_t *get_param_descr()
180
static char *get_help ()
182
static QByteArray helpText(
183
QObject::tr("Equalizes audio using the very good IIR equalizer code by "
184
"Anders Johansson adopted from Audacious project.\n"
187
"Preamp gain - used to alter up or down all gain values\n"
188
"10 Equalizer bands - actual IIR equalizer parameters.\n").toUtf8());
189
return helpText.data();
192
static xine_post_api_t post_api = {
200
/**************************************************************************
201
* xine audio post plugin functions
202
*************************************************************************/
204
static int kequalizer_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
205
uint32_t bits, uint32_t rate, int mode)
207
post_audio_port_t *port = reinterpret_cast<post_audio_port_t *>(port_gen);
208
kequalizer_plugin_t *that = reinterpret_cast<kequalizer_plugin_t *>(port->post);
209
xine_post_t *post = reinterpret_cast<xine_post_t *>(port->post);
211
_x_post_rewire(&that->post);
212
_x_post_inc_usage(port);
214
port->stream = stream;
222
case AO_CAP_MODE_STEREO:
225
case AO_CAP_MODE_4CHANNEL:
228
case AO_CAP_MODE_4_1CHANNEL:
229
case AO_CAP_MODE_5CHANNEL:
230
case AO_CAP_MODE_5_1CHANNEL:
235
that->eq_setup_Filters(post);
236
that->eq_calc_Gains(post);
238
return port->original_port->open(port->original_port, stream, bits, rate, mode);
241
static void kequalizer_port_close(xine_audio_port_t *port_gen, xine_stream_t *stream)
243
post_audio_port_t *port = reinterpret_cast<post_audio_port_t *>(port_gen);
246
port->original_port->close(port->original_port, stream);
247
_x_post_dec_usage(port);
250
static void kequalizer_port_put_buffer(xine_audio_port_t *port_gen,
251
audio_buffer_t *buf, xine_stream_t *stream)
253
post_audio_port_t *port = reinterpret_cast<post_audio_port_t *>(port_gen);
254
kequalizer_plugin_t *that = reinterpret_cast<kequalizer_plugin_t *>(port->post);
255
xine_post_t *post = reinterpret_cast<xine_post_t *>(port->post);
257
// Do actual equalization
258
that->equalize_Buffer(post,buf);
259
// and send the modified buffer to the original port
260
port->original_port->put_buffer(port->original_port, buf, stream);
264
static void kequalizer_dispose(post_plugin_t *this_gen)
266
kequalizer_plugin_t *that = reinterpret_cast<kequalizer_plugin_t *>(this_gen);
268
if (_x_post_dispose(this_gen)) {
269
pthread_mutex_destroy(&that->lock);
274
/* plugin class functions */
275
static post_plugin_t *kequalizer_open_plugin(post_class_t *class_gen, int inputs,
276
xine_audio_port_t **audio_target,
277
xine_video_port_t **video_target)
281
Q_UNUSED(video_target);
282
kequalizer_plugin_t *that;
283
//deprecated: kequalizer_plugin_t *that = static_cast<kequalizer_plugin_t *>(xine_xmalloc(sizeof(kequalizer_plugin_t)));
284
xine_xmalloc_aligned(2,sizeof(kequalizer_plugin_t),(void**)(&that));
287
xine_post_in_t *input_api;
288
post_audio_port_t *port;
290
// refuse to work without an audio port to decorate
291
if (!that || !audio_target || !audio_target[0]) {
296
// creates 1 audio I/O, 0 video I/O
297
_x_post_init(&that->post, 1, 0);
298
pthread_mutex_init (&that->lock, NULL);
302
// the following call wires our plugin in front of the given audio_target
303
port = _x_post_intercept_audio_port(&that->post, audio_target[0], &input, &output);
304
// the methods of new_port are all forwarded to audio_target, overwrite a few of them here:
305
port->new_port.open = kequalizer_port_open;
306
port->new_port.close = kequalizer_port_close;
307
port->new_port.put_buffer = kequalizer_port_put_buffer;
309
// add a parameter input to the plugin
310
input_api = &that->params_input;
311
input_api->name = "parameters";
312
input_api->type = XINE_POST_DATA_PARAMETERS;
313
input_api->data = &post_api;
314
xine_list_push_back(that->post.input, input_api);
316
that->post.xine_post.audio_input[0] = &port->new_port;
318
// our own cleanup function
319
that->post.dispose = kequalizer_dispose;
324
#if XINE_MAJOR_VERSION < 1 || (XINE_MAJOR_VERSION == 1 && (XINE_MINOR_VERSION < 1 || (XINE_MINOR_VERSION == 1 && XINE_SUB_VERSION < 90)))
325
#define NEED_DESCRIPTION_FUNCTION 1
327
#define NEED_DESCRIPTION_FUNCTION 0
330
#define PLUGIN_DESCRIPTION I18N_NOOP("Fade in or fade out with different fade curves")
331
#define PLUGIN_IDENTIFIER "KVolumeFader"
333
#if NEED_DESCRIPTION_FUNCTION
334
static char *kequalizer_get_identifier(post_class_t *class_gen)
337
return PLUGIN_IDENTIFIER;
340
static char *kequalizer_get_description(post_class_t *class_gen)
343
static QByteArray description(QObject::tr(PLUGIN_DESCRIPTION).toUtf8());
344
return description.data();
348
static void kequalizer_class_dispose(post_class_t *class_gen)
353
/* plugin class initialization function */
354
void *init_kequalizer_plugin (xine_t *xine, void *)
356
kequalizer_class_t *_class = static_cast<kequalizer_class_t *>(malloc(sizeof(kequalizer_class_t)));
362
_class->post_class.open_plugin = kequalizer_open_plugin;
363
#if NEED_DESCRIPTION_FUNCTION
364
_class->post_class.get_identifier = kequalizer_get_identifier;
365
_class->post_class.get_description = kequalizer_get_description;
367
_class->post_class.description = PLUGIN_DESCRIPTION;
368
_class->post_class.text_domain = "phonon-xine";
369
_class->post_class.identifier = PLUGIN_IDENTIFIER;
371
_class->post_class.dispose = kequalizer_class_dispose;
378
/* Filter functions */
380
// 2nd order Band-pass Filter design
381
void KEqualizerPlugin::eq_calc_Bp2(float* a, float* b, float fc, float q)
383
double th= 2.0 * M_PI * fc;
384
double C = (1.0 - tan(th*q/2.0))/(1.0 + tan(th*q/2.0));
386
a[0] = (1.0 + C) * cos(th);
389
b[0] = (1.0 - C)/2.0;
393
void KEqualizerPlugin::eq_calc_Gains(xine_post_t *this_gen)
395
kequalizer_plugin_t *that = reinterpret_cast<kequalizer_plugin_t *>(this_gen);
397
if(that->channels<1 || that->channels>KEQUALIZER_CHANNELS_MAX)
399
// adjust gains including preamp value
403
// Get bands from config
404
for(int i = 0; i < 10; i++){
405
b[i] = that->eqBands[i] + that->preAmp;
408
for(int i = 0; i < 10; i++)
409
if(fabsf(b[i]) > fabsf(adj)) adj = b[i];
411
if(fabsf(adj) > KEQUALIZER_G_MAX) {
412
adj = adj > 0.0 ? KEQUALIZER_G_MAX - adj : -KEQUALIZER_G_MAX - adj;
413
for(int i = 0; i < 10; i++) b[i] += adj;
415
// Recalculate set gains to internal coeficient gains
416
for(int i=0;i<that->channels;i++){
418
for(int k = 0 ; k<KEQUALIZER_KM ; k++){
419
if(b[k] > KEQUALIZER_G_MAX){
420
b[k]=KEQUALIZER_G_MAX;
421
}else if(b[k] < KEQUALIZER_G_MIN){
422
b[k]=KEQUALIZER_G_MIN;
424
that->g[i][k] = pow(10.0,b[k]/20.0)-1.0;
429
void KEqualizerPlugin::eq_setup_Filters(xine_post_t *this_gen)
431
kequalizer_plugin_t *that = reinterpret_cast<kequalizer_plugin_t *>(this_gen);
433
float F[KEQUALIZER_KM] = KEQUALIZER_CF;
435
// Calculate number of active filters
436
that->K=KEQUALIZER_KM;
437
while(F[that->K-1] > (float)that->rate/(KEQUALIZER_Q*2.0))
440
if(that->K != KEQUALIZER_KM){
441
Phonon::Xine::debug() << Q_FUNC_INFO
442
<< "[kequalizer] Limiting the number of filters to"
443
<< "due to low sample rate =>"
446
// Generate filter taps
447
for(k=0;k<that->K;k++)
448
that->eq_calc_Bp2(that->a[k],that->b[k],F[k]/((float)that->rate),KEQUALIZER_Q);
451
void KEqualizerPlugin::equalize_Buffer(xine_post_t *this_gen, audio_buffer_t *buf)
453
kequalizer_plugin_t *that = reinterpret_cast<kequalizer_plugin_t *>(this_gen);
454
const int bufferLength = buf->num_frames * that->channels;
456
if (buf->format.bits == 16 || buf->format.bits == 0) {
457
int16_t ci = that->channels; // Index for channels
458
int16_t nch = that->channels; // Number of channels
461
float* g = that->g[ci]; // Gain factor
462
int16_t* in = ((int16_t*)static_cast<int16_t *>(buf->mem))+ci;
463
int16_t* out = ((int16_t*)static_cast<int16_t *>(buf->mem))+ci;
464
int16_t* end = in + bufferLength;//sizeof(int16_t); // Block loop end
467
register int k = 0; // Frequency band index
468
register float yt = *in; // Current input sample
473
// Pointer to circular buffer wq
474
register float* wq = that->wq[ci][k];
475
// Calculate output from AR part of current filter
476
register float w=yt*that->b[k][0] + wq[0]*that->a[k][0] + wq[1]*that->a[k][1];
477
// Calculate output form MA part of current filter
478
yt+=(w + wq[1]*that->b[k][1])*g[k];
479
// Update circular buffer
483
// Output data to buffer
484
// NOTE maybe we need to add more sophisticated convertion method from float to ine like in libSAD with dithering ??
485
// NOTE for now this clipping have to be enough
486
*out = yt <= (float)32767 ? ( yt >= (float)-32768 ? (int16_t)yt : -32768 ) : 32767;
491
Phonon::Xine::debug() << Q_FUNC_INFO << "broken bits " << buf->format.bits;