2 This file is part of PulseAudio.
4 This module is based off Lennart Poettering's LADSPA sink and swaps out
5 LADSPA functionality for a STFT OLA based digital equalizer. All new work
6 is published under Pulseaudio's original license.
7 Copyright 2009 Jason Newton <nevion@gmail.com>
10 Copyright 2004-2008 Lennart Poettering
12 PulseAudio is free software; you can redistribute it and/or modify
13 it under the terms of the GNU Lesser General Public License as published
14 by the Free Software Foundation; either version 2.1 of the License,
15 or (at your option) any later version.
17 PulseAudio is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public License
23 along with PulseAudio; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
38 #include <pulse/xmalloc.h>
39 #include <pulse/i18n.h>
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/namereg.h>
43 #include <pulsecore/sink.h>
44 #include <pulsecore/module.h>
45 #include <pulsecore/core-util.h>
46 #include <pulsecore/modargs.h>
47 #include <pulsecore/log.h>
48 #include <pulsecore/thread.h>
49 #include <pulsecore/thread-mq.h>
50 #include <pulsecore/rtpoll.h>
51 #include <pulsecore/sample-util.h>
52 #include <pulsecore/ltdl-helper.h>
58 #include "module-equalizer-sink-symdef.h"
60 PA_MODULE_AUTHOR("Jason Newton");
61 PA_MODULE_DESCRIPTION(_("General Purpose Equalizer"));
62 PA_MODULE_VERSION(PACKAGE_VERSION
);
63 PA_MODULE_LOAD_ONCE(FALSE
);
64 PA_MODULE_USAGE(_("sink=<sink to connect to> "));
66 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
71 pa_sink
*sink
, *master
;
72 pa_sink_input
*sink_input
;
75 size_t fft_size
;//length (res) of fft
78 *effectively chooses R
80 size_t R
;/* the hop size between overlapping windows
81 * the latency of the filter, calculated from window_size
82 * based on constraints of COLA and window function
84 size_t samples_gathered
;
85 size_t n_buffered_output
;
87 float *H
;//frequency response filter (magnitude based)
88 float *W
;//windowing function (time domain)
89 float *work_buffer
,**input
,**overlap_accum
,**output_buffer
;
90 fftwf_complex
*output_window
;
91 fftwf_plan forward_plan
,inverse_plan
;
94 pa_memblockq
*memblockq
;
97 static const char* const valid_modargs
[] = {
108 uint64_t time_diff(struct timespec
*timeA_p
, struct timespec
*timeB_p
)
110 return ((timeA_p
->tv_sec
* 1000000000) + timeA_p
->tv_nsec
) -
111 ((timeB_p
->tv_sec
* 1000000000) + timeB_p
->tv_nsec
);
114 void hanning_normalized_window(float *W
,size_t window_size
){
115 //h = sqrt(2)/2 * (1+cos(t*pi)) ./ sqrt( 1+cos(t*pi).^2 )
117 for(size_t i
=0;i
<window_size
;++i
){
118 c
=cos(M_PI
*i
/(window_size
-1));
119 W
[i
]=sqrt(2.0)/2.0*(1.0+c
) / sqrt(1.0+c
*c
);
122 void hanning_window(float *W
,size_t window_size
){
123 //h=.5*(1-cos(2*pi*j/(window_size+1)), COLA for R=(M+1)/2
124 for(size_t i
=0;i
<window_size
;++i
){
125 W
[i
]=.5*(1-cos(2*M_PI
*i
/(window_size
+1)));
128 void hamming_window(float *W
,size_t window_size
){
129 //h=.54-.46*cos(2*pi*j/(window_size-1))
130 //COLA for R=(M-1)/2,(M-1)/4 etc when endpoints are divided by 2
131 //or one endpoint is zeroed
133 for(size_t i
=0;i
<window_size
;++i
){
136 W
[i
]=.54-.46*cos(2*M_PI
*m
);
140 //W[window_size-1]/=2;
142 void blackman_window(float *W
,size_t window_size
){
143 //h=.42-.5*cos(2*pi*m)+.08*cos(4*pi*m), m=(0:W-1)/(W-1)
144 //COLA for R=(M-1)/3 when M is odd and R is an integer
145 //R=M/3 when M is even and R is an integer
147 for(size_t i
=0;i
<window_size
;++i
){
150 W
[i
]=.42-.5*cos(2*M_PI
*m
)+.08*cos(4*M_PI
*m
);
155 void sin_window(float *W
,size_t window_size
){
156 //h = (cos(t*pi)+1)/2 .* float(abs(t)<1);
157 for(size_t i
=0;i
<window_size
;++i
){
158 W
[i
]=sin(M_PI
*i
/(window_size
-1));
163 void array_out(const char *name
,float *a
,size_t length
){
164 FILE *p
=fopen(name
,"w");
166 pa_log("opening %s failed!",name
);
169 for(size_t i
=0;i
<length
;++i
){
170 fprintf(p
,"%e,",a
[i
]);
180 /* Called from I/O thread context */
181 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
182 struct userdata
*u
= PA_SINK(o
)->userdata
;
186 case PA_SINK_MESSAGE_GET_LATENCY
: {
188 pa_sample_spec
*ss
=&u
->sink
->sample_spec
;
190 /* Get the latency of the master sink */
191 if (PA_MSGOBJECT(u
->master
)->process_msg(PA_MSGOBJECT(u
->master
), PA_SINK_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
194 usec
+=pa_bytes_to_usec(u
->n_buffered_output
*pa_frame_size(ss
),ss
);
195 /* Add the latency internal to our sink input on top */
196 usec
+= pa_bytes_to_usec(pa_memblockq_get_length(u
->sink_input
->thread_info
.render_memblockq
), &u
->master
->sample_spec
);
197 *((pa_usec_t
*) data
) = usec
;
202 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
206 /* Called from main context */
207 static int sink_set_state(pa_sink
*s
, pa_sink_state_t state
) {
210 pa_sink_assert_ref(s
);
211 pa_assert_se(u
= s
->userdata
);
213 if (PA_SINK_IS_LINKED(state
) &&
215 PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u
->sink_input
)))
217 pa_sink_input_cork(u
->sink_input
, state
== PA_SINK_SUSPENDED
);
222 /* Called from I/O thread context */
223 static void sink_request_rewind(pa_sink
*s
) {
226 pa_sink_assert_ref(s
);
227 pa_assert_se(u
= s
->userdata
);
229 /* Just hand this one over to the master sink */
230 pa_sink_input_request_rewind(u
->sink_input
, s
->thread_info
.rewind_nbytes
+ pa_memblockq_get_length(u
->memblockq
), TRUE
, FALSE
, FALSE
);
233 /* Called from I/O thread context */
234 static void sink_update_requested_latency(pa_sink
*s
) {
237 pa_sink_assert_ref(s
);
238 pa_assert_se(u
= s
->userdata
);
240 /* Just hand this one over to the master sink */
241 pa_sink_input_set_requested_latency_within_thread(
243 pa_sink_get_requested_latency_within_thread(s
));
246 /* Called from I/O thread context */
247 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
251 pa_sink_input_assert_ref(i
);
253 pa_assert_se(u
= i
->userdata
);
254 pa_assert_se(u
->sink
);
255 size_t fs
= pa_frame_size(&(u
->sink
->sample_spec
));
256 size_t ss
=pa_sample_size(&(u
->sink
->sample_spec
));
259 if (!u
->sink
|| !PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
))
262 //output any buffered outputs first
263 if(u
->n_buffered_output
>0){
264 //pa_log("outputing %ld buffered samples",u->n_buffered_output);
266 size_t n_outputable
=PA_MIN(u
->n_buffered_output
,u
->max_output
);
267 chunk
->length
= n_outputable
*fs
;
268 chunk
->memblock
= pa_memblock_new(i
->sink
->core
->mempool
, chunk
->length
);
269 pa_memblockq_drop(u
->memblockq
, chunk
->length
);
270 dst
= (float*) pa_memblock_acquire(chunk
->memblock
);
271 for(size_t j
=0;j
<u
->channels
;++j
){
272 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, dst
+j
, fs
, u
->output_buffer
[j
], sizeof(float),n_outputable
);
273 memmove(u
->output_buffer
[j
],u
->output_buffer
[j
]+n_outputable
,(u
->n_buffered_output
-n_outputable
)*sizeof(float));
275 u
->n_buffered_output
-=n_outputable
;
276 pa_memblock_release(chunk
->memblock
);
279 pa_assert_se(u
->n_buffered_output
==0);
281 //collect the minimum number of samples
282 //TODO figure out a better way of buffering the needed
283 //number of samples, this doesn't seem to work correctly
284 while(u
->samples_gathered
< u
->R
){
285 //render some new fragments to our memblockq
286 size_t desired_samples
=PA_MIN(u
->R
-u
->samples_gathered
,u
->max_output
);
287 while (pa_memblockq_peek(u
->memblockq
, &tchunk
) < 0) {
290 pa_sink_render(u
->sink
, desired_samples
*fs
, &nchunk
);
291 pa_memblockq_push(u
->memblockq
, &nchunk
);
292 pa_memblock_unref(nchunk
.memblock
);
294 if(tchunk
.length
/fs
!=desired_samples
){
295 pa_log("got %ld samples, asked for %ld",tchunk
.length
/fs
,desired_samples
);
297 size_t n_samples
=PA_MIN(tchunk
.length
/fs
,u
->R
-u
->samples_gathered
);
298 //TODO: figure out what to do with rest of the samples when there's too many (rare?)
299 src
= (float*) ((uint8_t*) pa_memblock_acquire(tchunk
.memblock
) + tchunk
.index
);
300 for (size_t c
=0;c
<u
->channels
;c
++) {
301 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
,u
->input
[c
]+(u
->window_size
-u
->R
)+u
->samples_gathered
,sizeof(float), src
+c
, fs
, n_samples
);
303 u
->samples_gathered
+=n_samples
;
304 pa_memblock_release(tchunk
.memblock
);
305 pa_memblock_unref(tchunk
.memblock
);
307 //IT should be this guy if we're buffering like how its supposed to
308 //size_t n_outputable=PA_MIN(u->window_size-u->R,u->max_output);
309 //This one takes into account the actual data gathered but then the dsp
310 //stuff is wrong when the buffer "underruns"
311 size_t n_outputable
=PA_MIN(u
->R
,u
->max_output
);
315 chunk
->length
=n_outputable
*fs
;
316 chunk
->memblock
= pa_memblock_new(i
->sink
->core
->mempool
, chunk
->length
);
317 pa_memblockq_drop(u
->memblockq
, chunk
->length
);
318 dst
= (float*) pa_memblock_acquire(chunk
->memblock
);
320 pa_assert_se(u
->fft_size
>=u
->window_size
);
321 pa_assert_se(u
->R
<u
->window_size
);
322 pa_assert_se(u
->samples_gathered
>=u
->R
);
323 size_t sample_rem
=u
->R
-n_outputable
;
324 //use a linear-phase sliding STFT and overlap-add method (for each channel)
325 for (size_t c
=0;c
<u
->channels
;c
++) {
326 ////zero padd the data
327 //memset(u->work_buffer,0,u->fft_size*sizeof(float));
328 memset(u
->work_buffer
+u
->window_size
,0,(u
->fft_size
-u
->window_size
)*sizeof(float));
330 for(size_t j
=0;j
<u
->window_size
;++j
){
331 u
->work_buffer
[j
]=u
->W
[j
]*u
->input
[c
][j
];
333 //Processing is done here!
336 //if(u->samplings==200){
340 //this iterations input
341 //sprintf(fname,"/home/jason/input%ld-%ld.txt",u->samplings+1,c);
342 //array_out(fname,u->input[c]+(u->window_size-u->R),u->R);
344 fftwf_execute_dft_r2c(u
->forward_plan
,u
->work_buffer
,u
->output_window
);
346 for(size_t j
=0;j
<u
->fft_size
/2+1;++j
){
347 u
->output_window
[j
][0]*=u
->H
[j
];
348 u
->output_window
[j
][1]*=u
->H
[j
];
351 fftwf_execute_dft_c2r(u
->inverse_plan
,u
->output_window
,u
->work_buffer
);
352 //the output for the previous iteration's input
353 //sprintf(fname,"/home/jason/output%ld-%ld.txt",u->samplings,c);
354 //array_out(fname,u->work_buffer,u->window_size);
357 ////debug: tests overlaping add
358 ////and negates ALL PREVIOUS processing
359 ////yields a perfect reconstruction if COLA is held
360 //for(size_t j=0;j<u->window_size;++j){
361 // u->work_buffer[j]=u->W[j]*u->input[c][j];
364 //overlap add and preserve overlap component from this window (linear phase)
365 for(size_t j
=0;j
<u
->R
;++j
){
366 u
->work_buffer
[j
]+=u
->overlap_accum
[c
][j
];
367 u
->overlap_accum
[c
][j
]=u
->work_buffer
[u
->window_size
-u
->R
+j
];
372 //debug: tests if basic buffering works
373 //shouldn't modify the signal AT ALL
374 for(size_t j=0;j<u->window_size;++j){
375 u->work_buffer[j]=u->input[c][j];
379 //preseve the needed input for the next windows overlap
380 memmove(u
->input
[c
],u
->input
[c
]+u
->R
,
381 (u
->window_size
-u
->R
)*sizeof(float)
383 //output the samples that are outputable now
384 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, dst
+c
, fs
, u
->work_buffer
, sizeof(float),n_outputable
);
385 //buffer the rest of them
386 memcpy(u
->output_buffer
[c
]+u
->n_buffered_output
,u
->work_buffer
+n_outputable
,sample_rem
*sizeof(float));
390 u
->n_buffered_output
+=sample_rem
;
391 u
->samples_gathered
=0;
392 pa_memblock_release(chunk
->memblock
);
396 /* Called from I/O thread context */
397 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
401 pa_sink_input_assert_ref(i
);
402 pa_assert_se(u
= i
->userdata
);
404 if (!u
->sink
|| !PA_SINK_IS_OPENED(u
->sink
->thread_info
.state
))
407 if (u
->sink
->thread_info
.rewind_nbytes
> 0) {
410 max_rewrite
= nbytes
+ pa_memblockq_get_length(u
->memblockq
);
411 amount
= PA_MIN(u
->sink
->thread_info
.rewind_nbytes
, max_rewrite
);
412 u
->sink
->thread_info
.rewind_nbytes
= 0;
415 pa_memblockq_seek(u
->memblockq
, - (int64_t) amount
, PA_SEEK_RELATIVE
, TRUE
);
416 pa_log_debug("Resetting equalizer");
417 u
->n_buffered_output
=0;
418 u
->samples_gathered
=0;
422 pa_sink_process_rewind(u
->sink
, amount
);
423 pa_memblockq_rewind(u
->memblockq
, nbytes
);
426 /* Called from I/O thread context */
427 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
430 pa_sink_input_assert_ref(i
);
431 pa_assert_se(u
= i
->userdata
);
433 if (!u
->sink
|| !PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
))
436 pa_memblockq_set_maxrewind(u
->memblockq
, nbytes
);
437 pa_sink_set_max_rewind_within_thread(u
->sink
, nbytes
);
440 /* Called from I/O thread context */
441 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
444 pa_sink_input_assert_ref(i
);
445 pa_assert_se(u
= i
->userdata
);
447 if (!u
->sink
|| !PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
))
450 pa_sink_set_max_request_within_thread(u
->sink
, nbytes
);
453 /* Called from I/O thread context */
454 static void sink_input_update_sink_latency_range_cb(pa_sink_input
*i
) {
457 pa_sink_input_assert_ref(i
);
458 pa_assert_se(u
= i
->userdata
);
460 if (!u
->sink
|| !PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
))
463 pa_sink_set_latency_range_within_thread(u
->sink
, i
->sink
->thread_info
.min_latency
, i
->sink
->thread_info
.max_latency
);
466 /* Called from I/O thread context */
467 static void sink_input_detach_cb(pa_sink_input
*i
) {
470 pa_sink_input_assert_ref(i
);
471 pa_assert_se(u
= i
->userdata
);
473 if (!u
->sink
|| !PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
))
476 pa_sink_detach_within_thread(u
->sink
);
477 pa_sink_set_asyncmsgq(u
->sink
, NULL
);
478 pa_sink_set_rtpoll(u
->sink
, NULL
);
481 /* Called from I/O thread context */
482 static void sink_input_attach_cb(pa_sink_input
*i
) {
485 pa_sink_input_assert_ref(i
);
486 pa_assert_se(u
= i
->userdata
);
488 if (!u
->sink
|| !PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
))
491 pa_sink_set_asyncmsgq(u
->sink
, i
->sink
->asyncmsgq
);
492 pa_sink_set_rtpoll(u
->sink
, i
->sink
->rtpoll
);
493 pa_sink_attach_within_thread(u
->sink
);
495 pa_sink_set_latency_range_within_thread(u
->sink
, u
->master
->thread_info
.min_latency
, u
->master
->thread_info
.max_latency
);
498 /* Called from main context */
499 static void sink_input_kill_cb(pa_sink_input
*i
) {
502 pa_sink_input_assert_ref(i
);
503 pa_assert_se(u
= i
->userdata
);
505 pa_sink_unlink(u
->sink
);
506 pa_sink_input_unlink(u
->sink_input
);
508 pa_sink_unref(u
->sink
);
510 pa_sink_input_unref(u
->sink_input
);
511 u
->sink_input
= NULL
;
513 pa_module_unload_request(u
->module
, TRUE
);
516 /* Called from IO thread context */
517 static void sink_input_state_change_cb(pa_sink_input
*i
, pa_sink_input_state_t state
) {
520 pa_sink_input_assert_ref(i
);
521 pa_assert_se(u
= i
->userdata
);
523 /* If we are added for the first time, ask for a rewinding so that
524 * we are heard right-away. */
525 if (PA_SINK_INPUT_IS_LINKED(state
) &&
526 i
->thread_info
.state
== PA_SINK_INPUT_INIT
) {
527 pa_log_debug("Requesting rewind due to state change.");
528 pa_sink_input_request_rewind(i
, 0, FALSE
, TRUE
, TRUE
);
532 /* Called from main context */
533 static pa_bool_t
sink_input_may_move_to_cb(pa_sink_input
*i
, pa_sink
*dest
) {
536 pa_sink_input_assert_ref(i
);
537 pa_assert_se(u
= i
->userdata
);
539 return u
->sink
!= dest
;
542 int pa__init(pa_module
*m
) {
549 pa_sink_input_new_data sink_input_data
;
550 pa_sink_new_data sink_data
;
551 pa_bool_t
*use_default
= NULL
;
556 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
557 pa_log("Failed to parse module arguments.");
561 if (!(master
= pa_namereg_get(m
->core
, pa_modargs_get_value(ma
, "master", NULL
), PA_NAMEREG_SINK
))) {
562 pa_log("Master sink not found");
566 ss
= master
->sample_spec
;
567 ss
.format
= PA_SAMPLE_FLOAT32
;
568 map
= master
->channel_map
;
569 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
570 pa_log("Invalid sample format specification or channel map");
573 fs
=pa_frame_size(&ss
);
575 u
= pa_xnew0(struct userdata
, 1);
581 u
->sink_input
= NULL
;
582 u
->memblockq
= pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH
, 0, fs
, 1, 1, 0, NULL
);
585 u
->channels
=ss
.channels
;
586 u
->fft_size
=pow(2,ceil(log(ss
.rate
)/log(2)));
587 pa_log("fft size: %ld",u
->fft_size
);
589 u
->R
=(u
->window_size
+1)/2;
590 u
->samples_gathered
=0;
591 u
->n_buffered_output
=0;
592 u
->max_output
=pa_frame_align(pa_mempool_block_size_max(m
->core
->mempool
), &ss
)/pa_frame_size(&ss
);
593 u
->H
=(float*) fftwf_malloc((u
->fft_size
/2+1)*sizeof(float));
594 u
->W
=(float*) fftwf_malloc((u
->window_size
)*sizeof(float));
595 u
->work_buffer
=(float*) fftwf_malloc(u
->fft_size
*sizeof(float));
596 u
->input
=(float **)malloc(sizeof(float *)*u
->channels
);
597 u
->overlap_accum
=(float **)malloc(sizeof(float *)*u
->channels
);
598 u
->output_buffer
=(float **)malloc(sizeof(float *)*u
->channels
);
599 for(size_t c
=0;c
<u
->channels
;++c
){
600 u
->input
[c
]=(float*) fftwf_malloc(u
->window_size
*sizeof(float));
601 pa_assert_se(u
->input
[c
]);
602 memset(u
->input
[c
],0,u
->window_size
*sizeof(float));
603 pa_assert_se(u
->input
[c
]);
604 u
->overlap_accum
[c
]=(float*) fftwf_malloc(u
->R
*sizeof(float));
605 pa_assert_se(u
->overlap_accum
[c
]);
606 memset(u
->overlap_accum
[c
],0,u
->R
*sizeof(float));
607 u
->output_buffer
[c
]=(float*) fftwf_malloc(u
->window_size
*sizeof(float));
608 pa_assert_se(u
->output_buffer
[c
]);
610 u
->output_window
= (fftwf_complex
*) fftwf_malloc(sizeof(fftwf_complex
) * (u
->fft_size
/2+1));
611 u
->forward_plan
=fftwf_plan_dft_r2c_1d(u
->fft_size
, u
->work_buffer
, u
->output_window
, FFTW_ESTIMATE
);
612 u
->inverse_plan
=fftwf_plan_dft_c2r_1d(u
->fft_size
, u
->output_window
, u
->work_buffer
, FFTW_ESTIMATE
);
614 for(size_t j=0;j<u->window_size;++j){
618 hanning_window(u
->W
,u
->window_size
);
620 const int freqs
[]={0,25,50,100,200,300,400,800,1500,
621 2000,3000,4000,5000,6000,7000,8000,9000,10000,11000,12000,
622 13000,14000,15000,16000,17000,18000,19000,20000,21000,22000,23000,24000,INT_MAX
};
623 const float coefficients
[]={1,1,1,1,1,1,1,1,1,1,
625 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
626 const size_t ncoefficients
=sizeof(coefficients
)/sizeof(float);
627 pa_assert_se(sizeof(freqs
)/sizeof(int)==sizeof(coefficients
)/sizeof(float));
628 float *freq_translated
=(float *) malloc(sizeof(float)*(ncoefficients
));
629 freq_translated
[0]=1;
630 //Translate the frequencies in their natural sampling rate to the new sampling rate frequencies
631 for(size_t i
=1;i
<ncoefficients
-1;++i
){
632 freq_translated
[i
]=((float)freqs
[i
]*u
->fft_size
)/ss
.rate
;
633 //pa_log("i: %ld: %d , %g",i,freqs[i],freq_translated[i]);
634 pa_assert_se(freq_translated
[i
]>=freq_translated
[i
-1]);
636 freq_translated
[ncoefficients
-1]=FLT_MAX
;
637 //Interpolate the specified frequency band values
639 for(size_t i
=1,j
=0;i
<(u
->fft_size
/2+1);++i
){
640 pa_assert_se(j
<ncoefficients
);
641 //max frequency range passed, consider the rest as one band
642 if(freq_translated
[j
+1]>=FLT_MAX
){
643 for(;i
<(u
->fft_size
/2+1);++i
){
644 u
->H
[i
]=coefficients
[j
];
648 //pa_log("i: %d, j: %d, freq: %f",i,j,freq_translated[j]);
649 //pa_log("interp: %0.4f %0.4f",freq_translated[j],freq_translated[j+1]);
650 pa_assert_se(freq_translated
[j
]<freq_translated
[j
+1]);
651 pa_assert_se(i
>=freq_translated
[j
]);
652 pa_assert_se(i
<=freq_translated
[j
+1]);
653 //bilinear-inerpolation of coefficients specified
654 float c0
=(i
-freq_translated
[j
])/(freq_translated
[j
+1]-freq_translated
[j
]);
655 pa_assert_se(c0
>=0&&c0
<=1.0);
656 u
->H
[i
]=((1.0f
-c0
)*coefficients
[j
]+c0
*coefficients
[j
+1]);
657 pa_assert_se(u
->H
[i
]>0);
658 while(i
>=floor(freq_translated
[j
+1])){
662 //divide out the fft gain
663 for(size_t i
=0;i
<(u
->fft_size
/2+1);++i
){
664 u
->H
[i
]/=u
->fft_size
;
666 free(freq_translated
);
669 pa_sink_new_data_init(&sink_data
);
670 sink_data
.driver
= __FILE__
;
671 sink_data
.module
= m
;
672 if (!(sink_data
.name
= pa_xstrdup(pa_modargs_get_value(ma
, "sink_name", NULL
))))
673 sink_data
.name
= pa_sprintf_malloc("%s.equalizer", master
->name
);
674 sink_data
.namereg_fail
= FALSE
;
675 pa_sink_new_data_set_sample_spec(&sink_data
, &ss
);
676 pa_sink_new_data_set_channel_map(&sink_data
, &map
);
677 z
= pa_proplist_gets(master
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
678 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "FFT based equalizer");
679 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_MASTER_DEVICE
, master
->name
);
680 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_CLASS
, "filter");
682 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
683 pa_log("Invalid properties");
684 pa_sink_new_data_done(&sink_data
);
688 u
->sink
= pa_sink_new(m
->core
, &sink_data
, PA_SINK_LATENCY
|PA_SINK_DYNAMIC_LATENCY
);
689 pa_sink_new_data_done(&sink_data
);
692 pa_log("Failed to create sink.");
696 u
->sink
->parent
.process_msg
= sink_process_msg
;
697 u
->sink
->set_state
= sink_set_state
;
698 u
->sink
->update_requested_latency
= sink_update_requested_latency
;
699 u
->sink
->request_rewind
= sink_request_rewind
;
700 u
->sink
->userdata
= u
;
702 pa_sink_set_asyncmsgq(u
->sink
, master
->asyncmsgq
);
703 pa_sink_set_rtpoll(u
->sink
, master
->rtpoll
);
705 /* Create sink input */
706 pa_sink_input_new_data_init(&sink_input_data
);
707 sink_input_data
.driver
= __FILE__
;
708 sink_input_data
.module
= m
;
709 sink_input_data
.sink
= u
->master
;
710 pa_proplist_sets(sink_input_data
.proplist
, PA_PROP_MEDIA_NAME
, "Equalized Stream");
711 pa_proplist_sets(sink_input_data
.proplist
, PA_PROP_MEDIA_ROLE
, "filter");
712 pa_sink_input_new_data_set_sample_spec(&sink_input_data
, &ss
);
713 pa_sink_input_new_data_set_channel_map(&sink_input_data
, &map
);
715 pa_sink_input_new(&u
->sink_input
, m
->core
, &sink_input_data
, PA_SINK_INPUT_DONT_MOVE
);
716 pa_sink_input_new_data_done(&sink_input_data
);
721 u
->sink_input
->pop
= sink_input_pop_cb
;
722 u
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
723 u
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
724 u
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
725 u
->sink_input
->update_sink_latency_range
= sink_input_update_sink_latency_range_cb
;
726 u
->sink_input
->kill
= sink_input_kill_cb
;
727 u
->sink_input
->attach
= sink_input_attach_cb
;
728 u
->sink_input
->detach
= sink_input_detach_cb
;
729 u
->sink_input
->state_change
= sink_input_state_change_cb
;
730 u
->sink_input
->may_move_to
= sink_input_may_move_to_cb
;
731 u
->sink_input
->userdata
= u
;
733 pa_sink_put(u
->sink
);
734 pa_sink_input_put(u
->sink_input
);
738 pa_xfree(use_default
);
746 pa_xfree(use_default
);
753 int pa__get_n_used(pa_module
*m
) {
757 pa_assert_se(u
= m
->userdata
);
759 return pa_sink_linked_by(u
->sink
);
762 void pa__done(pa_module
*m
) {
767 if (!(u
= m
->userdata
))
771 pa_sink_unlink(u
->sink
);
772 pa_sink_unref(u
->sink
);
776 pa_sink_input_unlink(u
->sink_input
);
777 pa_sink_input_unref(u
->sink_input
);
781 pa_memblockq_free(u
->memblockq
);
783 fftwf_destroy_plan(u
->inverse_plan
);
784 fftwf_destroy_plan(u
->forward_plan
);
785 fftwf_free(u
->output_window
);
786 for(size_t c
=0;c
<u
->channels
;++c
){
787 fftwf_free(u
->output_buffer
[c
]);
788 fftwf_free(u
->overlap_accum
[c
]);
789 fftwf_free(u
->input
[c
]);
791 free(u
->output_buffer
);
792 free(u
->overlap_accum
);
794 fftwf_free(u
->work_buffer
);