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 dbus-aware STFT OLA based digital equalizer.
6 All new work 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
39 #include <pulse/xmalloc.h>
40 #include <pulse/i18n.h>
41 #include <pulse/timeval.h>
43 #include <pulsecore/core-rtclock.h>
44 #include <pulsecore/aupdate.h>
45 #include <pulsecore/core-error.h>
46 #include <pulsecore/namereg.h>
47 #include <pulsecore/sink.h>
48 #include <pulsecore/module.h>
49 #include <pulsecore/core-util.h>
50 #include <pulsecore/modargs.h>
51 #include <pulsecore/log.h>
52 #include <pulsecore/thread.h>
53 #include <pulsecore/thread-mq.h>
54 #include <pulsecore/rtpoll.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/shared.h>
57 #include <pulsecore/idxset.h>
58 #include <pulsecore/strlist.h>
59 #include <pulsecore/database.h>
60 #include <pulsecore/protocol-dbus.h>
61 #include <pulsecore/dbus-util.h>
69 #include <xmmintrin.h>
70 #include <emmintrin.h>
75 #include "module-equalizer-sink-symdef.h"
77 PA_MODULE_AUTHOR("Jason Newton");
78 PA_MODULE_DESCRIPTION(_("General Purpose Equalizer"));
79 PA_MODULE_VERSION(PACKAGE_VERSION
);
80 PA_MODULE_LOAD_ONCE(FALSE
);
81 PA_MODULE_USAGE(_("sink=<sink to connect to> "));
83 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
89 pa_sink_input
*sink_input
;
93 size_t fft_size
;//length (res) of fft
96 *effectively chooses R
98 size_t R
;/* the hop size between overlapping windows
99 * the latency of the filter, calculated from window_size
100 * based on constraints of COLA and window function
102 size_t latency
;//Really just R but made into it's own variable
103 //for twiddling with pulseaudio
104 size_t overlap_size
;//window_size-R
105 size_t samples_gathered
;
107 float *H
;//frequency response filter (magnitude based)
108 float *W
;//windowing function (time domain)
109 float *work_buffer
, **input
, **overlap_accum
;
110 fftwf_complex
*output_window
;
111 fftwf_plan forward_plan
, inverse_plan
;
114 float *Hs
[2];//thread updatable copies
116 pa_memchunk conv_buffer
;
117 pa_memblockq
*input_q
;
118 pa_bool_t first_iteration
;
120 pa_dbus_protocol
*dbus_protocol
;
123 pa_database
*database
;
126 static const char* const valid_modargs
[] = {
139 #define mround(x, y) ((x + y - 1) / y) * y
140 #define SINKLIST "equalized_sinklist"
141 #define EQDB "equalizer_db"
142 static void dbus_init(struct userdata
*u
);
143 static void dbus_done(struct userdata
*u
);
145 static void hanning_window(float *W
, size_t window_size
){
146 //h=.5*(1-cos(2*pi*j/(window_size+1)), COLA for R=(M+1)/2
147 for(size_t i
=0; i
< window_size
;++i
){
148 W
[i
] = (float).5*(1-cos(2*M_PI
*i
/(window_size
+1)));
152 static void fix_filter(float *H
, size_t fft_size
){
153 //divide out the fft gain
154 for(size_t i
= 0; i
< fft_size
/ 2 + 1; ++i
){
159 static void interpolate(float *signal
, size_t length
, uint32_t *xs
, float *ys
, size_t n_points
){
160 //Note that xs must be monotonically increasing!
161 float x_range_lower
, x_range_upper
, c0
;
162 pa_assert_se(n_points
>=2);
163 pa_assert_se(xs
[0] == 0);
164 pa_assert_se(xs
[n_points
- 1] == length
- 1);
165 for(size_t x
= 0, x_range_lower_i
= 0; x
< length
-1; ++x
){
166 pa_assert(x_range_lower_i
< n_points
-1);
167 x_range_lower
= (float) (xs
[x_range_lower_i
]);
168 x_range_upper
= (float) (xs
[x_range_lower_i
+1]);
169 pa_assert_se(x_range_lower
< x_range_upper
);
170 pa_assert_se(x
>= x_range_lower
);
171 pa_assert_se(x
<= x_range_upper
);
172 //bilinear-interpolation of coefficients specified
173 c0
= (x
-x_range_lower
)/(x_range_upper
-x_range_lower
);
174 pa_assert_se(c0
>= 0&&c0
<= 1.0);
175 signal
[x
] = ((1.0f
- c0
) * ys
[x_range_lower_i
] + c0
* ys
[x_range_lower_i
+ 1]);
176 while(x
>= xs
[x_range_lower_i
+ 1]){
180 signal
[length
-1]=ys
[n_points
-1];
183 static int is_monotonic(const uint32_t *xs
,size_t length
){
187 for(size_t i
= 1; i
< length
; ++i
){
196 /* Called from I/O thread context */
197 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
198 struct userdata
*u
= PA_SINK(o
)->userdata
;
202 case PA_SINK_MESSAGE_GET_LATENCY
: {
203 size_t fs
=pa_frame_size(&u
->sink
->sample_spec
);
205 /* The sink is _put() before the sink input is, so let's
206 * make sure we don't access it in that time. Also, the
207 * sink input is first shut down, the sink second. */
208 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
209 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
)) {
210 *((pa_usec_t
*) data
) = 0;
214 *((pa_usec_t
*) data
) =
215 /* Get the latency of the master sink */
216 pa_sink_get_latency_within_thread(u
->sink_input
->sink
) +
218 /* Add the latency internal to our sink input on top */
219 pa_bytes_to_usec(pa_memblockq_get_length(u
->sink_input
->thread_info
.render_memblockq
), &u
->sink_input
->sink
->sample_spec
) +
220 pa_bytes_to_usec(u
->samples_gathered
* fs
, &u
->sink
->sample_spec
);
221 //+ pa_bytes_to_usec(u->latency * fs, ss)
222 //+ pa_bytes_to_usec(pa_memblockq_get_length(u->input_q), ss);
227 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
231 /* Called from main context */
232 static int sink_set_state(pa_sink
*s
, pa_sink_state_t state
) {
235 pa_sink_assert_ref(s
);
236 pa_assert_se(u
= s
->userdata
);
238 if (!PA_SINK_IS_LINKED(state
) ||
239 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u
->sink_input
)))
242 pa_sink_input_cork(u
->sink_input
, state
== PA_SINK_SUSPENDED
);
246 /* Called from I/O thread context */
247 static void sink_request_rewind(pa_sink
*s
) {
250 pa_sink_assert_ref(s
);
251 pa_assert_se(u
= s
->userdata
);
253 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
254 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
))
257 /* Just hand this one over to the master sink */
258 pa_sink_input_request_rewind(u
->sink_input
, s
->thread_info
.rewind_nbytes
+pa_memblockq_get_length(u
->input_q
), TRUE
, FALSE
, FALSE
);
261 /* Called from I/O thread context */
262 static void sink_update_requested_latency(pa_sink
*s
) {
265 pa_sink_assert_ref(s
);
266 pa_assert_se(u
= s
->userdata
);
268 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
269 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
))
272 /* Just hand this one over to the master sink */
273 pa_sink_input_set_requested_latency_within_thread(
275 pa_sink_get_requested_latency_within_thread(s
));
278 typedef float v4sf
__attribute__ ((__aligned__(v_size
* sizeof(float))));
279 typedef union float_vector
{
287 //reference implementation
288 static void dsp_logic(
289 float * restrict dst
,//used as a temp array too, needs to be fft_length!
290 float * restrict src
,/*input data w/ overlap at start,
291 *automatically cycled in routine
293 float * restrict overlap
,//The size of the overlap
294 const float * restrict H
,//The freq. magnitude scalers filter
295 const float * restrict W
,//The windowing function
296 fftwf_complex
* restrict output_window
,//The transformed window'd src
298 //use a linear-phase sliding STFT and overlap-add method (for each channel)
300 memset(dst
+ u
->window_size
, 0, (u
->fft_size
- u
->window_size
) * sizeof(float));
302 for(size_t j
= 0;j
< u
->window_size
; ++j
){
303 dst
[j
] = W
[j
] * src
[j
];
305 //Processing is done here!
307 fftwf_execute_dft_r2c(u
->forward_plan
, dst
, output_window
);
309 for(size_t j
= 0; j
< u
->fft_size
/ 2 + 1; ++j
){
310 u
->output_window
[j
][0] *= u
->H
[j
];
311 u
->output_window
[j
][1] *= u
->H
[j
];
314 fftwf_execute_dft_c2r(u
->inverse_plan
, output_window
, dst
);
315 ////debug: tests overlaping add
316 ////and negates ALL PREVIOUS processing
317 ////yields a perfect reconstruction if COLA is held
318 //for(size_t j = 0; j < u->window_size; ++j){
319 // u->work_buffer[j] = u->W[j] * u->input[c][j];
322 //overlap add and preserve overlap component from this window (linear phase)
323 for(size_t j
= 0;j
< u
->overlap_size
; ++j
){
324 u
->work_buffer
[j
] += overlap
[j
];
325 overlap
[j
] = dst
[u
->R
+j
];
327 ////debug: tests if basic buffering works
328 ////shouldn't modify the signal AT ALL (beyond roundoff)
329 //for(size_t j = 0; j < u->window_size;++j){
330 // u->work_buffer[j] = u->input[c][j];
333 //preseve the needed input for the next window's overlap
334 memmove(src
, src
+u
->R
,
335 ((u
->overlap_size
+ u
->samples_gathered
) - u
->R
)*sizeof(float)
339 ////regardless of sse enabled, the loops in here assume
340 ////16 byte aligned addresses and memory allocations divisible by v_size
342 // float * restrict dst,//used as a temp array too, needs to be fft_length!
343 // float * restrict src,/*input data w/ overlap at start,
344 // *automatically cycled in routine
346 // float * restrict overlap,//The size of the overlap
347 // const float * restrict H,//The freq. magnitude scalers filter
348 // const float * restrict W,//The windowing function
349 // fftwf_complex * restrict output_window,//The transformed window'd src
350 // struct userdata *u){//Collection of constants
352 // const size_t window_size = mround(u->window_size,v_size);
353 // const size_t fft_h = mround(u->fft_size / 2 + 1, v_size / 2);
354 // //const size_t R = mround(u->R, v_size);
355 // const size_t overlap_size = mround(u->overlap_size, v_size);
357 // //assert(u->samples_gathered >= u->R);
358 // //zero out the bit beyond the real overlap so we don't add garbage
359 // for(size_t j = overlap_size; j > u->overlap_size; --j){
362 // //use a linear-phase sliding STFT and overlap-add method
363 // //zero padd the data
364 // memset(dst + u->window_size, 0, (u->fft_size - u->window_size)*sizeof(float));
366 // for(size_t j = 0; j < window_size; j += v_size){
367 // //dst[j] = W[j]*src[j];
368 // float_vector_t *d = (float_vector_t*) (dst+j);
369 // float_vector_t *w = (float_vector_t*) (W+j);
370 // float_vector_t *s = (float_vector_t*) (src+j);
372 // d->m = _mm_mul_ps(w->m, s->m);
374 // d->v = w->v * s->v;
377 // //Processing is done here!
379 // fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
382 // //perform filtering - purely magnitude based
383 // for(size_t j = 0;j < fft_h; j+=v_size/2){
384 // //output_window[j][0]*=H[j];
385 // //output_window[j][1]*=H[j];
386 // float_vector_t *d = (float_vector_t*)(output_window+j);
388 // h.f[0] = h.f[1] = H[j];
389 // h.f[2] = h.f[3] = H[j+1];
391 // d->m = _mm_mul_ps(d->m, h.m);
397 // fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
399 // ////debug: tests overlaping add
400 // ////and negates ALL PREVIOUS processing
401 // ////yields a perfect reconstruction if COLA is held
402 // //for(size_t j = 0; j < u->window_size; ++j){
403 // // dst[j] = W[j]*src[j];
406 // //overlap add and preserve overlap component from this window (linear phase)
407 // for(size_t j = 0; j < overlap_size; j+=v_size){
408 // //dst[j]+=overlap[j];
409 // //overlap[j]+=dst[j+R];
410 // float_vector_t *d = (float_vector_t*)(dst+j);
411 // float_vector_t *o = (float_vector_t*)(overlap+j);
413 // d->m = _mm_add_ps(d->m, o->m);
414 // o->m = ((float_vector_t*)(dst+u->R+j))->m;
417 // o->v = ((float_vector_t*)(dst+u->R+j))->v;
420 // //memcpy(overlap, dst+u->R, u->overlap_size*sizeof(float));
422 // //////debug: tests if basic buffering works
423 // //////shouldn't modify the signal AT ALL (beyond roundoff)
424 // //for(size_t j = 0; j < u->window_size; ++j){
425 // // dst[j] = src[j];
428 // //preseve the needed input for the next window's overlap
429 // memmove(src, src+u->R,
430 // ((u->overlap_size+u->samples_gathered)+-u->R)*sizeof(float)
434 static void process_samples(struct userdata
*u
, pa_memchunk
*tchunk
){
435 size_t fs
=pa_frame_size(&(u
->sink
->sample_spec
));
437 pa_assert(u
->samples_gathered
>= u
->R
);
439 tchunk
->length
= u
->R
* fs
;
440 tchunk
->memblock
= pa_memblock_new(u
->sink
->core
->mempool
, tchunk
->length
);
441 dst
= ((float*)pa_memblock_acquire(tchunk
->memblock
));
442 for(size_t c
=0;c
< u
->channels
; c
++) {
452 if(u
->first_iteration
){
453 /* The windowing function will make the audio ramped in, as a cheap fix we can
454 * undo the windowing (for non-zero window values)
456 for(size_t i
= 0;i
< u
->overlap_size
; ++i
){
457 u
->work_buffer
[i
] = u
->W
[i
] <= FLT_EPSILON
? u
->work_buffer
[i
] : u
->work_buffer
[i
] / u
->W
[i
];
460 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, dst
+ c
, fs
, u
->work_buffer
, sizeof(float), u
->R
);
462 pa_memblock_release(tchunk
->memblock
);
463 u
->samples_gathered
-= u
->R
;
466 static void initialize_buffer(struct userdata
*u
, pa_memchunk
*in
){
467 size_t fs
= pa_frame_size(&u
->sink
->sample_spec
);
468 size_t samples
= in
->length
/ fs
;
469 float *src
= (float*) ((uint8_t*) pa_memblock_acquire(in
->memblock
) + in
->index
);
470 pa_assert_se(u
->samples_gathered
+ samples
<= u
->window_size
);
471 for(size_t c
= 0; c
< u
->channels
; c
++) {
472 //buffer with an offset after the overlap from previous
474 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, u
->input
[c
] + u
->samples_gathered
, sizeof(float), src
+ c
, fs
, samples
);
476 u
->samples_gathered
+= samples
;
477 pa_memblock_release(in
->memblock
);
480 static void input_buffer(struct userdata
*u
, pa_memchunk
*in
){
481 size_t fs
= pa_frame_size(&(u
->sink
->sample_spec
));
482 size_t samples
= in
->length
/fs
;
483 float *src
= (float*) ((uint8_t*) pa_memblock_acquire(in
->memblock
) + in
->index
);
484 pa_assert_se(samples
<= u
->window_size
- u
->samples_gathered
);
485 for(size_t c
= 0; c
< u
->channels
; c
++) {
486 //buffer with an offset after the overlap from previous
489 u
->input
[c
]+u
->samples_gathered
+samples
<= u
->input
[c
]+u
->window_size
491 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, u
->input
[c
]+u
->overlap_size
+u
->samples_gathered
, sizeof(float), src
+ c
, fs
, samples
);
493 u
->samples_gathered
+= samples
;
494 pa_memblock_release(in
->memblock
);
497 /* Called from I/O thread context */
498 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
501 struct timeval start
, end
;
503 pa_sink_input_assert_ref(i
);
504 pa_assert_se(u
= i
->userdata
);
507 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
508 chunk
->memblock
= NULL
;
510 /* Hmm, process any rewind request that might be queued up */
511 pa_sink_process_rewind(u
->sink
, 0);
513 //pa_log_debug("start output-buffered %ld, input-buffered %ld, requested %ld",buffered_samples,u->samples_gathered,samples_requested);
514 pa_rtclock_get(&start
);
516 size_t input_remaining
= u
->window_size
- u
->samples_gathered
;
517 pa_assert(input_remaining
> 0);
520 //buffer = &u->conv_buffer;
521 //buffer->length = input_remaining*fs;
523 //pa_memblock_ref(buffer->memblock);
524 //pa_sink_render_into(u->sink, buffer);
525 while(pa_memblockq_peek(u
->input_q
, &tchunk
) < 0){
526 pa_sink_render(u
->sink
, input_remaining
*fs
, &tchunk
);
527 pa_assert(tchunk
.memblock
);
528 pa_memblockq_push(u
->input_q
, &tchunk
);
529 pa_memblock_unref(tchunk
.memblock
);
531 pa_assert(tchunk
.memblock
);
532 tchunk
.length
= PA_MIN(input_remaining
* fs
, tchunk
.length
);
533 pa_memblockq_drop(u
->input_q
, tchunk
.length
);
534 //pa_log_debug("asked for %ld input samples, got %ld samples",input_remaining,buffer->length/fs);
536 //pa_rtclock_get(start);
537 if(u
->first_iteration
){
538 initialize_buffer(u
, &tchunk
);
540 input_buffer(u
, &tchunk
);
542 //pa_rtclock_get(&end);
543 //pa_log_debug("Took %0.5f seconds to setup", pa_timeval_diff(end, start) / (double) PA_USEC_PER_SEC);
544 pa_memblock_unref(tchunk
.memblock
);
545 }while(u
->samples_gathered
< u
->window_size
);
546 pa_rtclock_get(&end
);
547 pa_log_debug("Took %0.6f seconds to get data", (double) pa_timeval_diff(&end
, &start
) / PA_USEC_PER_SEC
);
549 pa_assert(u
->fft_size
>= u
->window_size
);
550 pa_assert(u
->R
< u
->window_size
);
551 /* set the H filter */
552 u
->H
= u
->Hs
[pa_aupdate_read_begin(u
->a_H
)];
553 pa_rtclock_get(&start
);
554 /* process a block */
555 process_samples(u
, chunk
);
556 pa_rtclock_get(&end
);
557 pa_log_debug("Took %0.6f seconds to process", (double) pa_timeval_diff(&end
, &start
) / PA_USEC_PER_SEC
);
558 pa_aupdate_read_end(u
->a_H
);
560 pa_assert(chunk
->memblock
);
561 //pa_log_debug("gave %ld", chunk->length/fs);
562 //pa_log_debug("end pop");
563 if(u
->first_iteration
){
564 u
->first_iteration
= FALSE
;
569 static void reset_filter(struct userdata
*u
){
570 u
->samples_gathered
= 0;
571 for(size_t i
= 0;i
< u
->channels
; ++i
){
572 memset(u
->overlap_accum
[i
], 0, u
->overlap_size
* sizeof(float));
574 u
->first_iteration
= TRUE
;
577 /* Called from I/O thread context */
578 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
582 pa_log_debug("Rewind callback!");
583 pa_sink_input_assert_ref(i
);
584 pa_assert_se(u
= i
->userdata
);
586 if (u
->sink
->thread_info
.rewind_nbytes
> 0) {
589 //max_rewrite = nbytes;
590 max_rewrite
= nbytes
+ pa_memblockq_get_length(u
->input_q
);
591 //PA_MIN(pa_memblockq_get_length(u->input_q), nbytes);
592 amount
= PA_MIN(u
->sink
->thread_info
.rewind_nbytes
, max_rewrite
);
593 u
->sink
->thread_info
.rewind_nbytes
= 0;
596 //pa_sample_spec *ss = &u->sink->sample_spec;
597 //invalidate the output q
598 pa_memblockq_seek(u
->input_q
, - (int64_t) amount
, PA_SEEK_RELATIVE
, TRUE
);
599 //pa_memblockq_drop(u->input_q, pa_memblockq_get_length(u->input_q));
600 //pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
601 pa_log("Resetting filter");
606 pa_sink_process_rewind(u
->sink
, amount
);
607 pa_memblockq_rewind(u
->input_q
, nbytes
);
610 /* Called from I/O thread context */
611 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
614 pa_sink_input_assert_ref(i
);
615 pa_assert_se(u
= i
->userdata
);
617 pa_memblockq_set_maxrewind(u
->input_q
, nbytes
);
618 pa_sink_set_max_rewind_within_thread(u
->sink
, nbytes
);
621 /* Called from I/O thread context */
622 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
625 pa_sink_input_assert_ref(i
);
626 pa_assert_se(u
= i
->userdata
);
628 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
629 //pa_sink_set_max_request_within_thread(u->sink, nbytes);
630 //pa_sink_set_max_request_within_thread(u->sink, u->R*fs);
631 pa_sink_set_max_request_within_thread(u
->sink
, ((nbytes
+u
->R
*fs
-1)/(u
->R
*fs
))*(u
->R
*fs
));
634 /* Called from I/O thread context */
635 static void sink_input_update_sink_latency_range_cb(pa_sink_input
*i
) {
638 pa_sink_input_assert_ref(i
);
639 pa_assert_se(u
= i
->userdata
);
641 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs);
642 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs );
643 pa_sink_set_latency_range_within_thread(u
->sink
, i
->sink
->thread_info
.min_latency
, i
->sink
->thread_info
.max_latency
);
646 /* Called from I/O thread context */
647 static void sink_input_update_sink_fixed_latency_cb(pa_sink_input
*i
) {
650 pa_sink_input_assert_ref(i
);
651 pa_assert_se(u
= i
->userdata
);
653 pa_sink_set_fixed_latency_within_thread(u
->sink
, i
->sink
->thread_info
.fixed_latency
);
656 /* Called from I/O thread context */
657 static void sink_input_detach_cb(pa_sink_input
*i
) {
660 pa_sink_input_assert_ref(i
);
661 pa_assert_se(u
= i
->userdata
);
663 pa_sink_detach_within_thread(u
->sink
);
665 pa_sink_set_rtpoll(u
->sink
, NULL
);
668 /* Called from I/O thread context */
669 static void sink_input_attach_cb(pa_sink_input
*i
) {
672 pa_sink_input_assert_ref(i
);
673 pa_assert_se(u
= i
->userdata
);
675 pa_sink_set_rtpoll(u
->sink
, i
->sink
->thread_info
.rtpoll
);
676 pa_sink_set_latency_range_within_thread(u
->sink
, i
->sink
->thread_info
.min_latency
, i
->sink
->thread_info
.max_latency
);
678 pa_sink_set_fixed_latency_within_thread(u
->sink
, i
->sink
->thread_info
.fixed_latency
);
679 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
680 pa_sink_set_max_request_within_thread(u
->sink
, mround(pa_sink_input_get_max_request(i
), u
->R
*fs
));
682 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs);
683 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->master->thread_info.max_latency);
684 //TODO: setting this guy minimizes drop outs but doesn't get rid
685 //of them completely, figure out why
686 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs);
687 //TODO: this guy causes dropouts constantly+rewinds, it's unusable
688 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->master->thread_info.max_latency);
689 pa_sink_attach_within_thread(u
->sink
);
692 /* Called from main context */
693 static void sink_input_kill_cb(pa_sink_input
*i
) {
696 pa_sink_input_assert_ref(i
);
697 pa_assert_se(u
= i
->userdata
);
699 /* The order here matters! We first kill the sink input, followed
700 * by the sink. That means the sink callbacks must be protected
701 * against an unconnected sink input! */
702 pa_sink_input_unlink(u
->sink_input
);
703 pa_sink_unlink(u
->sink
);
705 pa_sink_input_unref(u
->sink_input
);
706 u
->sink_input
= NULL
;
708 pa_sink_unref(u
->sink
);
711 pa_module_unload_request(u
->module
, TRUE
);
714 /* Called from IO thread context */
715 static void sink_input_state_change_cb(pa_sink_input
*i
, pa_sink_input_state_t state
) {
718 pa_sink_input_assert_ref(i
);
719 pa_assert_se(u
= i
->userdata
);
721 /* If we are added for the first time, ask for a rewinding so that
722 * we are heard right-away. */
723 if (PA_SINK_INPUT_IS_LINKED(state
) &&
724 i
->thread_info
.state
== PA_SINK_INPUT_INIT
) {
725 pa_log_debug("Requesting rewind due to state change.");
726 pa_sink_input_request_rewind(i
, 0, FALSE
, TRUE
, TRUE
);
730 static void save_profile(struct userdata
*u
, char *name
){
731 float *H_n
= pa_xmalloc((u
->fft_size
/ 2 + 1) * sizeof(float));
732 const float *H
= u
->Hs
[pa_aupdate_read_begin(u
->a_H
)];
734 for(size_t i
= 0 ; i
<= u
->fft_size
/ 2 + 1; ++i
){
735 //H_n[i] = H[i] * u->fft_size;
738 pa_aupdate_read_end(u
->a_H
);
740 key
.size
= strlen(key
.data
);
742 data
.size
= (u
->fft_size
/ 2 + 1) * sizeof(float);
743 pa_database_set(u
->database
, &key
, &data
, TRUE
);
744 pa_database_sync(u
->database
);
747 static void save_state(struct userdata
*u
){
748 char *state_name
= pa_sprintf_malloc("%s-previous-state", u
->name
);
749 save_profile(u
, state_name
);
750 pa_xfree(state_name
);
753 static void remove_profile(pa_core
*c
, char *name
){
755 pa_database
*database
;
757 key
.size
= strlen(key
.data
);
758 pa_assert_se(database
= pa_shared_get(c
, EQDB
));
759 pa_database_unset(database
, &key
);
760 pa_database_sync(database
);
763 static const char* load_profile(struct userdata
*u
, char *name
){
766 key
.size
= strlen(key
.data
);
767 if(pa_database_get(u
->database
, &key
, &value
) != NULL
){
768 if(value
.size
== (u
->fft_size
/ 2 + 1) * sizeof(float)){
769 float *H
=u
->Hs
[pa_aupdate_write_begin(u
->a_H
)];
770 memcpy(H
, value
.data
, value
.size
);
771 pa_aupdate_write_end(u
->a_H
);
773 return "incompatible size";
775 pa_datum_free(&value
);
777 return "profile doesn't exist";
780 //fix_filter(u->H, u->fft_size);
783 static void load_state(struct userdata
*u
){
784 char *state_name
=pa_sprintf_malloc("%s-previous-state", u
->name
);
785 load_profile(u
,state_name
);
786 pa_xfree(state_name
);
789 /* Called from main context */
790 static pa_bool_t
sink_input_may_move_to_cb(pa_sink_input
*i
, pa_sink
*dest
) {
793 pa_sink_input_assert_ref(i
);
794 pa_assert_se(u
= i
->userdata
);
796 return u
->sink
!= dest
;
799 /* Called from main context */
800 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
803 pa_sink_input_assert_ref(i
);
804 pa_assert_se(u
= i
->userdata
);
806 pa_sink_set_asyncmsgq(u
->sink
, dest
->asyncmsgq
);
807 pa_sink_update_flags(u
->sink
, PA_SINK_LATENCY
|PA_SINK_DYNAMIC_LATENCY
, dest
->flags
);
810 //ensure's memory allocated is a multiple of v_size
812 static void * alloc(size_t x
,size_t s
){
813 size_t f
= mround(x
*s
, sizeof(float)*v_size
);
816 //printf("requested %ld floats=%ld bytes, rem=%ld\n", x, x*sizeof(float), x*sizeof(float)%16);
817 //printf("giving %ld floats=%ld bytes, rem=%ld\n", f, f*sizeof(float), f*sizeof(float)%16);
823 int pa__init(pa_module
*m
) {
830 pa_sink_input_new_data sink_input_data
;
831 pa_sink_new_data sink_data
;
832 pa_bool_t
*use_default
= NULL
;
838 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
839 pa_log("Failed to parse module arguments.");
843 if (!(master
= pa_namereg_get(m
->core
, pa_modargs_get_value(ma
, "master", NULL
), PA_NAMEREG_SINK
))) {
844 pa_log("Master sink not found");
848 ss
= master
->sample_spec
;
849 ss
.format
= PA_SAMPLE_FLOAT32
;
850 map
= master
->channel_map
;
851 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
852 pa_log("Invalid sample format specification or channel map");
855 fs
= pa_frame_size(&ss
);
857 u
= pa_xnew0(struct userdata
, 1);
861 u
->channels
= ss
.channels
;
862 u
->fft_size
= pow(2, ceil(log(ss
.rate
)/log(2)));
863 pa_log_debug("fft size: %ld", u
->fft_size
);
864 u
->window_size
= 15999;
865 u
->R
= (u
->window_size
+ 1) / 2;
866 u
->overlap_size
= u
->window_size
- u
->R
;
867 u
->samples_gathered
= 0;
868 u
->a_H
= pa_aupdate_new();
869 u
->latency
= u
->window_size
- u
->R
;
870 for(size_t i
= 0; i
< 2; ++i
){
871 u
->Hs
[i
] = alloc((u
->fft_size
/ 2 + 1), sizeof(float));
873 u
->W
= alloc(u
->window_size
, sizeof(float));
874 u
->work_buffer
= alloc(u
->fft_size
, sizeof(float));
875 memset(u
->work_buffer
, 0, u
->fft_size
*sizeof(float));
876 u
->input
= pa_xnew0(float *, u
->channels
);
877 u
->overlap_accum
= pa_xnew0(float *, u
->channels
);
878 for(size_t c
= 0; c
< u
->channels
; ++c
){
879 u
->input
[c
] = alloc(u
->window_size
, sizeof(float));
880 memset(u
->input
[c
], 0, (u
->window_size
)*sizeof(float));
881 u
->overlap_accum
[c
] = alloc(u
->overlap_size
, sizeof(float));
882 memset(u
->overlap_accum
[c
], 0, u
->overlap_size
*sizeof(float));
884 u
->output_window
= alloc((u
->fft_size
/ 2 + 1), sizeof(fftwf_complex
));
885 u
->forward_plan
= fftwf_plan_dft_r2c_1d(u
->fft_size
, u
->work_buffer
, u
->output_window
, FFTW_ESTIMATE
);
886 u
->inverse_plan
= fftwf_plan_dft_c2r_1d(u
->fft_size
, u
->output_window
, u
->work_buffer
, FFTW_ESTIMATE
);
888 hanning_window(u
->W
, u
->window_size
);
889 u
->first_iteration
= TRUE
;
892 pa_sink_new_data_init(&sink_data
);
893 sink_data
.driver
= __FILE__
;
894 sink_data
.module
= m
;
895 if (!(sink_data
.name
= pa_xstrdup(pa_modargs_get_value(ma
, "sink_name", NULL
))))
896 sink_data
.name
= pa_sprintf_malloc("%s.equalizer", master
->name
);
897 pa_sink_new_data_set_sample_spec(&sink_data
, &ss
);
898 pa_sink_new_data_set_channel_map(&sink_data
, &map
);
899 z
= pa_proplist_gets(master
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
900 pa_proplist_setf(sink_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "FFT based equalizer on %s",z
? z
: master
->name
);
901 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_MASTER_DEVICE
, master
->name
);
902 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_CLASS
, "filter");
904 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
905 pa_log("Invalid properties");
906 pa_sink_new_data_done(&sink_data
);
910 u
->sink
= pa_sink_new(m
->core
, &sink_data
, master
->flags
& (PA_SINK_LATENCY
|PA_SINK_DYNAMIC_LATENCY
));
911 pa_sink_new_data_done(&sink_data
);
914 pa_log("Failed to create sink.");
917 u
->name
=pa_xstrdup(u
->sink
->name
);
918 u
->sink
->parent
.process_msg
= sink_process_msg
;
919 u
->sink
->set_state
= sink_set_state
;
920 u
->sink
->update_requested_latency
= sink_update_requested_latency
;
921 u
->sink
->request_rewind
= sink_request_rewind
;
922 u
->sink
->userdata
= u
;
923 u
->input_q
= pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH
, 0, fs
, 1, 1, 0, &u
->sink
->silence
);
925 pa_sink_set_asyncmsgq(u
->sink
, master
->asyncmsgq
);
926 //pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->R*fs, &ss));
928 /* Create sink input */
929 pa_sink_input_new_data_init(&sink_input_data
);
930 sink_input_data
.driver
= __FILE__
;
931 sink_input_data
.module
= m
;
932 sink_input_data
.sink
= master
;
933 pa_proplist_sets(sink_input_data
.proplist
, PA_PROP_MEDIA_NAME
, "Equalized Stream");
934 pa_proplist_sets(sink_input_data
.proplist
, PA_PROP_MEDIA_ROLE
, "filter");
935 pa_sink_input_new_data_set_sample_spec(&sink_input_data
, &ss
);
936 pa_sink_input_new_data_set_channel_map(&sink_input_data
, &map
);
938 pa_sink_input_new(&u
->sink_input
, m
->core
, &sink_input_data
, 0);
939 pa_sink_input_new_data_done(&sink_input_data
);
944 u
->sink_input
->pop
= sink_input_pop_cb
;
945 u
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
946 u
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
947 u
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
948 u
->sink_input
->update_sink_latency_range
= sink_input_update_sink_latency_range_cb
;
949 u
->sink_input
->update_sink_fixed_latency
= sink_input_update_sink_fixed_latency_cb
;
950 u
->sink_input
->kill
= sink_input_kill_cb
;
951 u
->sink_input
->attach
= sink_input_attach_cb
;
952 u
->sink_input
->detach
= sink_input_detach_cb
;
953 u
->sink_input
->state_change
= sink_input_state_change_cb
;
954 u
->sink_input
->may_move_to
= sink_input_may_move_to_cb
;
955 u
->sink_input
->moving
= sink_input_moving_cb
;
956 u
->sink_input
->userdata
= u
;
958 pa_sink_put(u
->sink
);
959 pa_sink_input_put(u
->sink_input
);
963 pa_xfree(use_default
);
967 //default filter to these
968 H
=u
->Hs
[pa_aupdate_write_begin(u
->a_H
)];
969 for(size_t i
= 0; i
< u
->fft_size
/ 2 + 1; ++i
){
970 H
[i
] = 1.0 / sqrtf(2.0f
);
972 fix_filter(H
, u
->fft_size
);
973 pa_aupdate_write_end(u
->a_H
);
974 //load old parameters
983 pa_xfree(use_default
);
990 int pa__get_n_used(pa_module
*m
) {
994 pa_assert_se(u
= m
->userdata
);
996 return pa_sink_linked_by(u
->sink
);
999 void pa__done(pa_module
*m
) {
1004 if (!(u
= m
->userdata
))
1011 /* See comments in sink_input_kill_cb() above regarding
1012 * destruction order! */
1015 pa_sink_input_unlink(u
->sink_input
);
1018 pa_sink_unlink(u
->sink
);
1021 pa_sink_input_unref(u
->sink_input
);
1024 pa_sink_unref(u
->sink
);
1026 pa_aupdate_free(u
->a_H
);
1027 pa_memblockq_free(u
->input_q
);
1029 fftwf_destroy_plan(u
->inverse_plan
);
1030 fftwf_destroy_plan(u
->forward_plan
);
1031 pa_xfree(u
->output_window
);
1032 for(size_t c
=0; c
< u
->channels
; ++c
){
1033 pa_xfree(u
->overlap_accum
[c
]);
1034 pa_xfree(u
->input
[c
]);
1036 pa_xfree(u
->overlap_accum
);
1038 pa_xfree(u
->work_buffer
);
1040 for(size_t i
= 0; i
< 2; ++i
){
1050 * DBus Routines and Callbacks
1052 #define EXTNAME "org.PulseAudio.Ext.Equalizing1"
1053 #define MANAGER_PATH "/org/pulseaudio/equalizing1"
1054 #define MANAGER_IFACE EXTNAME ".Manager"
1055 #define EQUALIZER_IFACE EXTNAME ".Equalizer"
1056 static void manager_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1057 static void get_sinks(pa_core
*u
, char ***names
, unsigned *n_sinks
);
1058 static void manager_get_sinks(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1059 static void get_profiles(pa_core
*u
, char ***names
, unsigned *n_sinks
);
1060 static void manager_get_profiles(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1061 static void manager_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1062 static void manager_handle_remove_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1063 static void equalizer_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1064 static void equalizer_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1065 static void equalizer_get_filter_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1066 static void equalizer_get_n_coefs(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1067 static void equalizer_get_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1068 static void equalizer_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1069 static void equalizer_set_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1070 static void equalizer_handle_seed_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1071 static void equalizer_handle_get_filter_points(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1072 static void equalizer_handle_save_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1073 static void equalizer_handle_load_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1074 static void get_filter(struct userdata
*u
, double **H_
);
1075 static void set_filter(struct userdata
*u
, double **H_
);
1076 enum manager_method_index
{
1077 MANAGER_METHOD_REMOVE_PROFILE
,
1081 pa_dbus_arg_info remove_profile_args
[]={
1085 static pa_dbus_method_handler manager_methods
[MANAGER_METHOD_MAX
]={
1086 [MANAGER_METHOD_REMOVE_PROFILE
]{
1087 .method_name
="RemoveProfile",
1088 .arguments
=remove_profile_args
,
1089 .n_arguments
=sizeof(remove_profile_args
)/sizeof(pa_dbus_arg_info
),
1090 .receive_cb
=manager_handle_remove_profile
}
1093 enum manager_handler_index
{
1094 MANAGER_HANDLER_REVISION
,
1095 MANAGER_HANDLER_EQUALIZED_SINKS
,
1096 MANAGER_HANDLER_PROFILES
,
1100 static pa_dbus_property_handler manager_handlers
[MANAGER_HANDLER_MAX
]={
1101 [MANAGER_HANDLER_REVISION
]={.property_name
="InterfaceRevision",.type
="u",.get_cb
=manager_get_revision
,.set_cb
=NULL
},
1102 [MANAGER_HANDLER_EQUALIZED_SINKS
]={.property_name
="EqualizedSinks",.type
="ao",.get_cb
=manager_get_sinks
,.set_cb
=NULL
},
1103 [MANAGER_HANDLER_PROFILES
]={.property_name
="Profiles",.type
="as",.get_cb
=manager_get_profiles
,.set_cb
=NULL
}
1106 pa_dbus_arg_info sink_args
[]={
1110 enum manager_signal_index
{
1111 MANAGER_SIGNAL_SINK_ADDED
,
1112 MANAGER_SIGNAL_SINK_REMOVED
,
1113 MANAGER_SIGNAL_PROFILES_CHANGED
,
1117 static pa_dbus_signal_info manager_signals
[MANAGER_SIGNAL_MAX
]={
1118 [MANAGER_SIGNAL_SINK_ADDED
]={.name
="SinkAdded", .arguments
=sink_args
, .n_arguments
=sizeof(sink_args
)/sizeof(pa_dbus_arg_info
)},
1119 [MANAGER_SIGNAL_SINK_REMOVED
]={.name
="SinkRemoved", .arguments
=sink_args
, .n_arguments
=sizeof(sink_args
)/sizeof(pa_dbus_arg_info
)},
1120 [MANAGER_SIGNAL_PROFILES_CHANGED
]={.name
="ProfilesChanged", .arguments
=NULL
, .n_arguments
=0}
1123 static pa_dbus_interface_info manager_info
={
1124 .name
=MANAGER_IFACE
,
1125 .method_handlers
=manager_methods
,
1126 .n_method_handlers
=MANAGER_METHOD_MAX
,
1127 .property_handlers
=manager_handlers
,
1128 .n_property_handlers
=MANAGER_HANDLER_MAX
,
1129 .get_all_properties_cb
=manager_get_all
,
1130 .signals
=manager_signals
,
1131 .n_signals
=MANAGER_SIGNAL_MAX
1134 enum equalizer_method_index
{
1135 EQUALIZER_METHOD_FILTER_POINTS
,
1136 EQUALIZER_METHOD_SEED_FILTER
,
1137 EQUALIZER_METHOD_SAVE_PROFILE
,
1138 EQUALIZER_METHOD_LOAD_PROFILE
,
1139 EQUALIZER_METHOD_MAX
1142 enum equalizer_handler_index
{
1143 EQUALIZER_HANDLER_REVISION
,
1144 EQUALIZER_HANDLER_SAMPLERATE
,
1145 EQUALIZER_HANDLER_FILTERSAMPLERATE
,
1146 EQUALIZER_HANDLER_N_COEFS
,
1147 EQUALIZER_HANDLER_FILTER
,
1148 EQUALIZER_HANDLER_MAX
1151 pa_dbus_arg_info filter_points_args
[]={
1155 pa_dbus_arg_info seed_filter_args
[]={
1159 pa_dbus_arg_info save_profile_args
[]={
1162 pa_dbus_arg_info load_profile_args
[]={
1166 static pa_dbus_method_handler equalizer_methods
[EQUALIZER_METHOD_MAX
]={
1167 [EQUALIZER_METHOD_SEED_FILTER
]{
1168 .method_name
="SeedFilter",
1169 .arguments
=seed_filter_args
,
1170 .n_arguments
=sizeof(seed_filter_args
)/sizeof(pa_dbus_arg_info
),
1171 .receive_cb
=equalizer_handle_seed_filter
},
1172 [EQUALIZER_METHOD_FILTER_POINTS
]{
1173 .method_name
="FilterAtPoints",
1174 .arguments
=filter_points_args
,
1175 .n_arguments
=sizeof(filter_points_args
)/sizeof(pa_dbus_arg_info
),
1176 .receive_cb
=equalizer_handle_get_filter_points
},
1177 [EQUALIZER_METHOD_SAVE_PROFILE
]{
1178 .method_name
="SaveProfile",
1179 .arguments
=save_profile_args
,
1180 .n_arguments
=sizeof(save_profile_args
)/sizeof(pa_dbus_arg_info
),
1181 .receive_cb
=equalizer_handle_save_profile
},
1182 [EQUALIZER_METHOD_LOAD_PROFILE
]{
1183 .method_name
="LoadProfile",
1184 .arguments
=load_profile_args
,
1185 .n_arguments
=sizeof(load_profile_args
)/sizeof(pa_dbus_arg_info
),
1186 .receive_cb
=equalizer_handle_load_profile
},
1189 static pa_dbus_property_handler equalizer_handlers
[EQUALIZER_HANDLER_MAX
]={
1190 [EQUALIZER_HANDLER_REVISION
]={.property_name
="InterfaceRevision",.type
="u",.get_cb
=equalizer_get_revision
,.set_cb
=NULL
},
1191 [EQUALIZER_HANDLER_SAMPLERATE
]{.property_name
="SampleRate",.type
="u",.get_cb
=equalizer_get_sample_rate
,.set_cb
=NULL
},
1192 [EQUALIZER_HANDLER_FILTERSAMPLERATE
]{.property_name
="FilterSampleRate",.type
="u",.get_cb
=equalizer_get_filter_rate
,.set_cb
=NULL
},
1193 [EQUALIZER_HANDLER_N_COEFS
]{.property_name
="NFilterCoefficients",.type
="u",.get_cb
=equalizer_get_n_coefs
,.set_cb
=NULL
},
1194 [EQUALIZER_HANDLER_FILTER
]{.property_name
="Filter",.type
="ad",.get_cb
=equalizer_get_filter
,.set_cb
=equalizer_set_filter
},
1197 enum equalizer_signal_index
{
1198 EQUALIZER_SIGNAL_FILTER_CHANGED
,
1199 EQUALIZER_SIGNAL_SINK_RECONFIGURED
,
1200 EQUALIZER_SIGNAL_MAX
1203 static pa_dbus_signal_info equalizer_signals
[EQUALIZER_SIGNAL_MAX
]={
1204 [EQUALIZER_SIGNAL_FILTER_CHANGED
]={.name
="FilterChanged", .arguments
=NULL
, .n_arguments
=0},
1205 [EQUALIZER_SIGNAL_SINK_RECONFIGURED
]={.name
="SinkReconfigured", .arguments
=NULL
, .n_arguments
=0},
1208 static pa_dbus_interface_info equalizer_info
={
1209 .name
=EQUALIZER_IFACE
,
1210 .method_handlers
=equalizer_methods
,
1211 .n_method_handlers
=EQUALIZER_METHOD_MAX
,
1212 .property_handlers
=equalizer_handlers
,
1213 .n_property_handlers
=EQUALIZER_HANDLER_MAX
,
1214 .get_all_properties_cb
=equalizer_get_all
,
1215 .signals
=equalizer_signals
,
1216 .n_signals
=EQUALIZER_SIGNAL_MAX
1219 static void dbus_init(struct userdata
*u
){
1221 DBusMessage
*signal
= NULL
;
1222 pa_idxset
*sink_list
= NULL
;
1223 u
->dbus_protocol
=pa_dbus_protocol_get(u
->sink
->core
);
1224 u
->dbus_path
=pa_sprintf_malloc("/org/pulseaudio/core1/sink%d", u
->sink
->index
);
1226 pa_dbus_protocol_add_interface(u
->dbus_protocol
, u
->dbus_path
, &equalizer_info
, u
);
1227 sink_list
= pa_shared_get(u
->sink
->core
, SINKLIST
);
1228 u
->database
=pa_shared_get(u
->sink
->core
, EQDB
);
1229 if(sink_list
==NULL
){
1231 sink_list
=pa_idxset_new(&pa_idxset_trivial_hash_func
, &pa_idxset_trivial_compare_func
);
1232 pa_shared_set(u
->sink
->core
, SINKLIST
, sink_list
);
1233 pa_assert_se(dbname
= pa_state_path("equalizers", TRUE
));
1234 pa_assert_se(u
->database
= pa_database_open(dbname
, TRUE
));
1236 pa_shared_set(u
->sink
->core
,EQDB
,u
->database
);
1237 pa_dbus_protocol_add_interface(u
->dbus_protocol
, MANAGER_PATH
, &manager_info
, u
->sink
->core
);
1238 pa_dbus_protocol_register_extension(u
->dbus_protocol
, EXTNAME
);
1240 pa_idxset_put(sink_list
, u
, &dummy
);
1242 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_SINK_ADDED
].name
)));
1243 dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &u
->dbus_path
, DBUS_TYPE_INVALID
);
1244 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1245 dbus_message_unref(signal
);
1248 static void dbus_done(struct userdata
*u
){
1249 pa_idxset
*sink_list
;
1252 DBusMessage
*signal
= NULL
;
1253 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_SINK_REMOVED
].name
)));
1254 dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &u
->dbus_path
, DBUS_TYPE_INVALID
);
1255 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1256 dbus_message_unref(signal
);
1258 pa_assert_se(sink_list
=pa_shared_get(u
->sink
->core
,SINKLIST
));
1259 pa_idxset_remove_by_data(sink_list
,u
,&dummy
);
1260 if(pa_idxset_size(sink_list
)==0){
1261 pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, EXTNAME
);
1262 pa_dbus_protocol_remove_interface(u
->dbus_protocol
, MANAGER_PATH
, manager_info
.name
);
1263 pa_shared_remove(u
->sink
->core
, EQDB
);
1264 pa_database_close(u
->database
);
1265 pa_shared_remove(u
->sink
->core
, SINKLIST
);
1266 pa_xfree(sink_list
);
1268 pa_dbus_protocol_remove_interface(u
->dbus_protocol
, u
->dbus_path
, equalizer_info
.name
);
1269 pa_xfree(u
->dbus_path
);
1270 pa_dbus_protocol_unref(u
->dbus_protocol
);
1273 static void manager_handle_remove_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1275 pa_core
*c
= (pa_core
*)_u
;
1276 DBusMessage
*signal
= NULL
;
1277 pa_dbus_protocol
*dbus_protocol
;
1282 dbus_error_init(&error
);
1283 if(!dbus_message_get_args(msg
, &error
,
1284 DBUS_TYPE_STRING
, &name
,
1285 DBUS_TYPE_INVALID
)){
1286 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1287 dbus_error_free(&error
);
1290 remove_profile(c
,name
);
1291 pa_dbus_send_empty_reply(conn
, msg
);
1293 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_PROFILES_CHANGED
].name
)));
1294 dbus_protocol
= pa_dbus_protocol_get(c
);
1295 pa_dbus_protocol_send_signal(dbus_protocol
, signal
);
1296 pa_dbus_protocol_unref(dbus_protocol
);
1297 dbus_message_unref(signal
);
1300 static void manager_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1302 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rev
);
1305 static void get_sinks(pa_core
*u
, char ***names
, unsigned *n_sinks
){
1307 struct userdata
*sink_u
= NULL
;
1309 pa_idxset
*sink_list
;
1314 pa_assert_se(sink_list
= pa_shared_get(u
, SINKLIST
));
1315 *n_sinks
= (unsigned) pa_idxset_size(sink_list
);
1316 *names
= *n_sinks
> 0 ? pa_xnew0(char *,*n_sinks
) : NULL
;
1317 for(uint32_t i
= 0; i
< *n_sinks
; ++i
){
1318 sink_u
= (struct userdata
*) pa_idxset_iterate(sink_list
, &iter
, &dummy
);
1319 (*names
)[i
] = pa_xstrdup(sink_u
->dbus_path
);
1323 static void manager_get_sinks(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1325 char **names
= NULL
;
1330 get_sinks((pa_core
*) _u
, &names
, &n
);
1331 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, names
, n
);
1332 for(unsigned i
= 0; i
< n
; ++i
){
1338 static void get_profiles(pa_core
*c
, char ***names
, unsigned *n
){
1340 pa_database
*database
;
1341 pa_datum key
, next_key
;
1342 pa_strlist
*head
=NULL
, *iter
;
1344 pa_assert_se(database
= pa_shared_get(c
, EQDB
));
1349 done
= !pa_database_first(database
, &key
, NULL
);
1352 done
= !pa_database_next(database
, &key
, &next_key
, NULL
);
1353 name
=pa_xmalloc(key
.size
+ 1);
1354 memcpy(name
, key
.data
, key
.size
);
1355 name
[key
.size
] = '\0';
1356 pa_datum_free(&key
);
1357 head
= pa_strlist_prepend(head
, name
);
1362 (*names
) = *n
> 0 ? pa_xnew0(char *, *n
) : NULL
;
1364 for(unsigned i
= 0; i
< *n
; ++i
){
1365 (*names
)[*n
- 1 - i
] = pa_xstrdup(pa_strlist_data(iter
));
1366 iter
= pa_strlist_next(iter
);
1368 pa_strlist_free(head
);
1371 static void manager_get_profiles(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1378 get_profiles((pa_core
*)_u
, &names
, &n
);
1379 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, names
, n
);
1380 for(unsigned i
= 0; i
< n
; ++i
){
1386 static void manager_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1388 char **names
= NULL
;
1390 DBusMessage
*reply
= NULL
;
1391 DBusMessageIter msg_iter
, dict_iter
;
1395 pa_assert_se(c
= _u
);
1397 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1398 dbus_message_iter_init_append(reply
, &msg_iter
);
1399 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1402 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, manager_handlers
[MANAGER_HANDLER_REVISION
].property_name
, DBUS_TYPE_UINT32
, &rev
);
1404 get_sinks(c
, &names
, &n
);
1405 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
,manager_handlers
[MANAGER_HANDLER_EQUALIZED_SINKS
].property_name
, DBUS_TYPE_OBJECT_PATH
, names
, n
);
1406 for(unsigned i
= 0; i
< n
; ++i
){
1411 get_profiles(c
, &names
, &n
);
1412 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, manager_handlers
[MANAGER_HANDLER_PROFILES
].property_name
, DBUS_TYPE_STRING
, names
, n
);
1413 for(unsigned i
= 0; i
< n
; ++i
){
1417 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1418 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1419 dbus_message_unref(reply
);
1422 static void equalizer_handle_seed_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1423 struct userdata
*u
=(struct userdata
*) _u
;
1425 DBusMessage
*signal
= NULL
;
1429 unsigned x_npoints
, y_npoints
;
1431 pa_bool_t points_good
= TRUE
;
1436 dbus_error_init(&error
);
1438 if(!dbus_message_get_args(msg
, &error
,
1439 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &xs
, &x_npoints
,
1440 DBUS_TYPE_ARRAY
, DBUS_TYPE_DOUBLE
, &_ys
, &y_npoints
,
1441 DBUS_TYPE_INVALID
)){
1442 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1443 dbus_error_free(&error
);
1446 for(size_t i
= 0; i
< x_npoints
; ++i
){
1447 if(xs
[i
] >= u
->fft_size
/ 2 + 1){
1448 points_good
= FALSE
;
1452 if(!is_monotonic(xs
, x_npoints
) || !points_good
){
1453 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs must be monotonic and 0<=x<=%ld", u
->fft_size
/ 2);
1454 dbus_error_free(&error
);
1457 }else if(x_npoints
!= y_npoints
|| x_npoints
< 2 || x_npoints
> u
->fft_size
/ 2 +1 ){
1458 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs and ys must be the same length and 2<=l<=%ld!", u
->fft_size
/ 2 + 1);
1459 dbus_error_free(&error
);
1461 }else if(xs
[0] != 0 || xs
[x_npoints
- 1] != u
->fft_size
/ 2){
1462 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs[0] must be 0 and xs[-1]=fft_size/2");
1463 dbus_error_free(&error
);
1467 ys
= pa_xmalloc(x_npoints
* sizeof(float));
1468 for(uint32_t i
= 0; i
< x_npoints
; ++i
){
1469 ys
[i
] = (float) _ys
[i
];
1472 H
= u
->Hs
[pa_aupdate_write_begin(u
->a_H
)];
1473 interpolate(H
, u
->fft_size
/ 2 + 1, xs
, ys
, x_npoints
);
1474 fix_filter(H
, u
->fft_size
);
1475 pa_aupdate_write_end(u
->a_H
);
1478 //Stupid for IO reasons? Add a save signal to dbus instead
1481 pa_dbus_send_empty_reply(conn
, msg
);
1483 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1484 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1485 dbus_message_unref(signal
);
1488 static void equalizer_handle_get_filter_points(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1489 struct userdata
*u
= (struct userdata
*) _u
;
1495 pa_bool_t points_good
=TRUE
;
1501 dbus_error_init(&error
);
1503 if(!dbus_message_get_args(msg
, &error
,
1504 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &xs
, &x_npoints
,
1505 DBUS_TYPE_INVALID
)){
1506 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1507 dbus_error_free(&error
);
1510 for(size_t i
= 0; i
< x_npoints
; ++i
){
1511 if(xs
[i
] >= u
->fft_size
/ 2 + 1){
1517 if(x_npoints
> u
->fft_size
/ 2 +1 || !points_good
){
1518 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs indices/length must be <= %ld!", u
->fft_size
/ 2 + 1);
1519 dbus_error_free(&error
);
1523 ys
= pa_xmalloc(x_npoints
* sizeof(double));
1524 H
= u
->Hs
[pa_aupdate_read_begin(u
->a_H
)];
1525 for(uint32_t i
= 0; i
< x_npoints
; ++i
){
1526 ys
[i
] = H
[xs
[i
]] * u
->fft_size
;
1528 pa_aupdate_read_end(u
->a_H
);
1530 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_DOUBLE
, ys
, x_npoints
);
1534 static void equalizer_handle_save_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1535 struct userdata
*u
= (struct userdata
*) _u
;
1537 DBusMessage
*signal
= NULL
;
1542 dbus_error_init(&error
);
1544 if(!dbus_message_get_args(msg
, &error
,
1545 DBUS_TYPE_STRING
, &name
,
1546 DBUS_TYPE_INVALID
)){
1547 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1548 dbus_error_free(&error
);
1551 save_profile(u
,name
);
1552 pa_dbus_send_empty_reply(conn
, msg
);
1554 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_PROFILES_CHANGED
].name
)));
1555 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1556 dbus_message_unref(signal
);
1559 static void equalizer_handle_load_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1560 struct userdata
*u
=(struct userdata
*) _u
;
1563 const char *err_msg
= NULL
;
1564 DBusMessage
*signal
= NULL
;
1569 dbus_error_init(&error
);
1571 if(!dbus_message_get_args(msg
, &error
,
1572 DBUS_TYPE_STRING
, &name
,
1573 DBUS_TYPE_INVALID
)){
1574 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1575 dbus_error_free(&error
);
1578 err_msg
= load_profile(u
,name
);
1579 if(err_msg
!= NULL
){
1580 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
, "error loading profile %s: %s", name
, err_msg
);
1581 dbus_error_free(&error
);
1584 pa_dbus_send_empty_reply(conn
, msg
);
1586 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1587 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1588 dbus_message_unref(signal
);
1591 static void equalizer_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1593 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rev
);
1596 static void equalizer_get_n_coefs(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1599 pa_assert_se(u
= (struct userdata
*) _u
);
1603 n_coefs
= (uint32_t) (u
->fft_size
/ 2 + 1);
1604 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &n_coefs
);
1607 static void equalizer_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1610 pa_assert_se(u
= (struct userdata
*) _u
);
1614 rate
= (uint32_t) u
->sink
->sample_spec
.rate
;
1615 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rate
);
1618 static void equalizer_get_filter_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1621 pa_assert_se(u
= (struct userdata
*) _u
);
1625 fft_size
= (uint32_t) u
->fft_size
;
1626 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &fft_size
);
1629 static void get_filter(struct userdata
*u
, double **H_
){
1631 *H_
= pa_xnew0(double, u
->fft_size
/ 2 + 1);
1632 H
= u
->Hs
[pa_aupdate_read_begin(u
->a_H
)];
1633 for(size_t i
= 0;i
< u
->fft_size
/ 2 + 1; ++i
){
1634 (*H_
)[i
] = H
[i
] * u
->fft_size
;
1636 pa_aupdate_read_end(u
->a_H
);
1639 static void equalizer_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1641 DBusMessage
*reply
= NULL
;
1642 DBusMessageIter msg_iter
, dict_iter
;
1643 uint32_t rev
, n_coefs
, rate
, fft_size
;
1645 pa_assert_se(u
= (struct userdata
*) _u
);
1649 n_coefs
= (uint32_t) (u
->fft_size
/ 2 + 1);
1650 rate
= (uint32_t) u
->sink
->sample_spec
.rate
;
1651 fft_size
= (uint32_t) u
->fft_size
;
1653 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1654 dbus_message_iter_init_append(reply
, &msg_iter
);
1655 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1657 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_REVISION
].property_name
, DBUS_TYPE_UINT32
, &rev
);
1658 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_SAMPLERATE
].property_name
, DBUS_TYPE_UINT32
, &rate
);
1659 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_FILTERSAMPLERATE
].property_name
, DBUS_TYPE_UINT32
, &fft_size
);
1660 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_N_COEFS
].property_name
, DBUS_TYPE_UINT32
, &n_coefs
);
1662 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_FILTER
].property_name
, DBUS_TYPE_UINT32
, &H
);
1665 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1666 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1667 dbus_message_unref(reply
);
1670 static void equalizer_get_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1674 pa_assert_se(u
= (struct userdata
*) _u
);
1676 n_coefs
= u
->fft_size
/ 2 + 1;
1680 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_DOUBLE
, H_
, n_coefs
);
1684 static void set_filter(struct userdata
*u
, double **H_
){
1685 float *H
= u
->Hs
[pa_aupdate_write_begin(u
->a_H
)];
1686 for(size_t i
= 0; i
< u
->fft_size
/ 2 + 1; ++i
){
1687 H
[i
] = (float) (*H_
)[i
];
1689 fix_filter(H
, u
->fft_size
);
1690 pa_aupdate_write_end(u
->a_H
);
1693 static void equalizer_set_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1697 DBusMessage
*signal
= NULL
;
1698 pa_assert_se(u
= (struct userdata
*) _u
);
1702 if(pa_dbus_get_fixed_array_set_property_arg(conn
, msg
, DBUS_TYPE_DOUBLE
, &H
, &_n_coefs
)){
1705 if(_n_coefs
!=u
->fft_size
/ 2 + 1){
1706 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "This filter takes exactly %ld coefficients, you gave %d", u
->fft_size
/ 2 + 1, _n_coefs
);
1710 //Stupid for IO reasons? Add a save signal to dbus instead
1713 pa_dbus_send_empty_reply(conn
, msg
);
1715 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1716 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1717 dbus_message_unref(signal
);