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
;
108 float *H
;//frequency response filter (magnitude based)
109 float *W
;//windowing function (time domain)
110 float *work_buffer
, **input
, **overlap_accum
;
111 fftwf_complex
*output_window
;
112 fftwf_plan forward_plan
, inverse_plan
;
116 float *Hs
[2];//thread updatable copies
118 pa_memchunk conv_buffer
;
119 pa_memblockq
*input_q
;
120 pa_bool_t first_iteration
;
122 pa_dbus_protocol
*dbus_protocol
;
125 pa_database
*database
;
128 static const char* const valid_modargs
[] = {
141 #define SINKLIST "equalized_sinklist"
142 #define EQDB "equalizer_db"
143 #define FILTER_SIZE (u->fft_size / 2 + 1)
144 #define PROFILE_SIZE (FILTER_SIZE + 1)
145 static void dbus_init(struct userdata
*u
);
146 static void dbus_done(struct userdata
*u
);
148 static void hanning_window(float *W
, size_t window_size
){
149 //h=.5*(1-cos(2*pi*j/(window_size+1)), COLA for R=(M+1)/2
150 for(size_t i
=0; i
< window_size
;++i
){
151 W
[i
] = (float).5*(1-cos(2*M_PI
*i
/(window_size
+1)));
155 static void fix_filter(float *H
, size_t fft_size
){
156 //divide out the fft gain
157 for(size_t i
= 0; i
< fft_size
/ 2 + 1; ++i
){
162 static void interpolate(float *signal
, size_t length
, uint32_t *xs
, float *ys
, size_t n_points
){
163 //Note that xs must be monotonically increasing!
164 float x_range_lower
, x_range_upper
, c0
;
165 pa_assert_se(n_points
>=2);
166 pa_assert_se(xs
[0] == 0);
167 pa_assert_se(xs
[n_points
- 1] == length
- 1);
168 for(size_t x
= 0, x_range_lower_i
= 0; x
< length
-1; ++x
){
169 pa_assert(x_range_lower_i
< n_points
-1);
170 x_range_lower
= (float) (xs
[x_range_lower_i
]);
171 x_range_upper
= (float) (xs
[x_range_lower_i
+1]);
172 pa_assert_se(x_range_lower
< x_range_upper
);
173 pa_assert_se(x
>= x_range_lower
);
174 pa_assert_se(x
<= x_range_upper
);
175 //bilinear-interpolation of coefficients specified
176 c0
= (x
-x_range_lower
)/(x_range_upper
-x_range_lower
);
177 pa_assert_se(c0
>= 0&&c0
<= 1.0);
178 signal
[x
] = ((1.0f
- c0
) * ys
[x_range_lower_i
] + c0
* ys
[x_range_lower_i
+ 1]);
179 while(x
>= xs
[x_range_lower_i
+ 1]){
183 signal
[length
-1]=ys
[n_points
-1];
186 static int is_monotonic(const uint32_t *xs
,size_t length
){
190 for(size_t i
= 1; i
< length
; ++i
){
199 /* Called from I/O thread context */
200 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
201 struct userdata
*u
= PA_SINK(o
)->userdata
;
205 case PA_SINK_MESSAGE_GET_LATENCY
: {
206 //size_t fs=pa_frame_size(&u->sink->sample_spec);
208 /* The sink is _put() before the sink input is, so let's
209 * make sure we don't access it in that time. Also, the
210 * sink input is first shut down, the sink second. */
211 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
212 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
)) {
213 *((pa_usec_t
*) data
) = 0;
217 *((pa_usec_t
*) data
) =
218 /* Get the latency of the master sink */
219 pa_sink_get_latency_within_thread(u
->sink_input
->sink
) +
221 /* Add the latency internal to our sink input on top */
222 pa_bytes_to_usec(pa_memblockq_get_length(u
->sink_input
->thread_info
.render_memblockq
), &u
->sink_input
->sink
->sample_spec
);
223 // pa_bytes_to_usec(u->samples_gathered * fs, &u->sink->sample_spec);
224 //+ pa_bytes_to_usec(u->latency * fs, ss)
225 //+ pa_bytes_to_usec(pa_memblockq_get_length(u->input_q), ss);
230 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
234 /* Called from main context */
235 static int sink_set_state(pa_sink
*s
, pa_sink_state_t state
) {
238 pa_sink_assert_ref(s
);
239 pa_assert_se(u
= s
->userdata
);
241 if (!PA_SINK_IS_LINKED(state
) ||
242 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u
->sink_input
)))
245 pa_sink_input_cork(u
->sink_input
, state
== PA_SINK_SUSPENDED
);
249 /* Called from I/O thread context */
250 static void sink_request_rewind(pa_sink
*s
) {
253 pa_sink_assert_ref(s
);
254 pa_assert_se(u
= s
->userdata
);
256 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
257 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
))
260 /* Just hand this one over to the master sink */
261 pa_sink_input_request_rewind(u
->sink_input
, s
->thread_info
.rewind_nbytes
+pa_memblockq_get_length(u
->input_q
), TRUE
, FALSE
, FALSE
);
264 /* Called from I/O thread context */
265 static void sink_update_requested_latency(pa_sink
*s
) {
268 pa_sink_assert_ref(s
);
269 pa_assert_se(u
= s
->userdata
);
271 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
272 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
))
275 /* Just hand this one over to the master sink */
276 pa_sink_input_set_requested_latency_within_thread(
278 pa_sink_get_requested_latency_within_thread(s
));
281 //reference implementation
282 static void dsp_logic(
283 float * restrict dst
,//used as a temp array too, needs to be fft_length!
284 float * restrict src
,/*input data w/ overlap at start,
285 *automatically cycled in routine
287 float * restrict overlap
,//The size of the overlap
288 const float * restrict H
,//The freq. magnitude scalers filter
289 const float * restrict W
,//The windowing function
290 fftwf_complex
* restrict output_window
,//The transformed window'd src
292 //use a linear-phase sliding STFT and overlap-add method (for each channel)
294 memset(dst
+ u
->window_size
, 0, (u
->fft_size
- u
->window_size
) * sizeof(float));
296 for(size_t j
= 0;j
< u
->window_size
; ++j
){
297 dst
[j
] = u
->X
* W
[j
] * src
[j
];
299 //Processing is done here!
301 fftwf_execute_dft_r2c(u
->forward_plan
, dst
, output_window
);
303 for(size_t j
= 0; j
< FILTER_SIZE
; ++j
){
304 u
->output_window
[j
][0] *= u
->H
[j
];
305 u
->output_window
[j
][1] *= u
->H
[j
];
308 fftwf_execute_dft_c2r(u
->inverse_plan
, output_window
, dst
);
309 ////debug: tests overlaping add
310 ////and negates ALL PREVIOUS processing
311 ////yields a perfect reconstruction if COLA is held
312 //for(size_t j = 0; j < u->window_size; ++j){
313 // u->work_buffer[j] = u->W[j] * u->input[c][j];
316 //overlap add and preserve overlap component from this window (linear phase)
317 for(size_t j
= 0;j
< u
->overlap_size
; ++j
){
318 u
->work_buffer
[j
] += overlap
[j
];
319 overlap
[j
] = dst
[u
->R
+j
];
321 ////debug: tests if basic buffering works
322 ////shouldn't modify the signal AT ALL (beyond roundoff)
323 //for(size_t j = 0; j < u->window_size;++j){
324 // u->work_buffer[j] = u->input[c][j];
327 //preseve the needed input for the next window's overlap
328 memmove(src
, src
+u
->R
,
329 ((u
->overlap_size
+ u
->samples_gathered
) - u
->R
)*sizeof(float)
333 typedef float v4sf
__attribute__ ((__aligned__(v_size
* sizeof(float))));
334 typedef union float_vector
{
342 ////regardless of sse enabled, the loops in here assume
343 ////16 byte aligned addresses and memory allocations divisible by v_size
345 // float * restrict dst,//used as a temp array too, needs to be fft_length!
346 // float * restrict src,/*input data w/ overlap at start,
347 // *automatically cycled in routine
349 // float * restrict overlap,//The size of the overlap
350 // const float * restrict H,//The freq. magnitude scalers filter
351 // const float * restrict W,//The windowing function
352 // fftwf_complex * restrict output_window,//The transformed window'd src
353 // struct userdata *u){//Collection of constants
354 //float_vector_t x = {u->X, u->X, u->X, u->X};
355 // const size_t window_size = PA_ROUND_UP(u->window_size,v_size);
356 // const size_t fft_h = PA_ROUND_UP(FILTER_SIZE, v_size / 2);
357 // //const size_t R = PA_ROUND_UP(u->R, v_size);
358 // const size_t overlap_size = PA_ROUND_UP(u->overlap_size, v_size);
359 // overlap_size = PA_ROUND_UP(u->overlap_size, v_size);
361 // //assert(u->samples_gathered >= u->R);
362 // //zero out the bit beyond the real overlap so we don't add garbage
363 // for(size_t j = overlap_size; j > u->overlap_size; --j){
366 // //use a linear-phase sliding STFT and overlap-add method
367 // //zero padd the data
368 // memset(dst + u->window_size, 0, (u->fft_size - u->window_size)*sizeof(float));
370 // for(size_t j = 0; j < window_size; j += v_size){
371 // //dst[j] = W[j]*src[j];
372 // float_vector_t *d = (float_vector_t*) (dst+j);
373 // float_vector_t *w = (float_vector_t*) (W+j);
374 // float_vector_t *s = (float_vector_t*) (src+j);
376 // d->m = _mm_mul_ps(x->m, _mm_mul_ps(w->m, s->m));
378 // d->v = x->v * w->v * s->v;
381 // //Processing is done here!
383 // fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
386 // //perform filtering - purely magnitude based
387 // for(size_t j = 0;j < fft_h; j+=v_size/2){
388 // //output_window[j][0]*=H[j];
389 // //output_window[j][1]*=H[j];
390 // float_vector_t *d = (float_vector_t*)(output_window+j);
392 // h.f[0] = h.f[1] = H[j];
393 // h.f[2] = h.f[3] = H[j+1];
395 // d->m = _mm_mul_ps(d->m, h.m);
401 // fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
403 // ////debug: tests overlaping add
404 // ////and negates ALL PREVIOUS processing
405 // ////yields a perfect reconstruction if COLA is held
406 // //for(size_t j = 0; j < u->window_size; ++j){
407 // // dst[j] = W[j]*src[j];
410 // //overlap add and preserve overlap component from this window (linear phase)
411 // for(size_t j = 0; j < overlap_size; j+=v_size){
412 // //dst[j]+=overlap[j];
413 // //overlap[j]+=dst[j+R];
414 // float_vector_t *d = (float_vector_t*)(dst+j);
415 // float_vector_t *o = (float_vector_t*)(overlap+j);
417 // d->m = _mm_add_ps(d->m, o->m);
418 // o->m = ((float_vector_t*)(dst+u->R+j))->m;
421 // o->v = ((float_vector_t*)(dst+u->R+j))->v;
424 // //memcpy(overlap, dst+u->R, u->overlap_size*sizeof(float));
426 // //////debug: tests if basic buffering works
427 // //////shouldn't modify the signal AT ALL (beyond roundoff)
428 // //for(size_t j = 0; j < u->window_size; ++j){
429 // // dst[j] = src[j];
432 // //preseve the needed input for the next window's overlap
433 // memmove(src, src+u->R,
434 // ((u->overlap_size+u->samples_gathered)+-u->R)*sizeof(float)
438 static void process_samples(struct userdata
*u
, pa_memchunk
*tchunk
){
439 size_t fs
=pa_frame_size(&(u
->sink
->sample_spec
));
441 pa_assert(u
->samples_gathered
>= u
->R
);
443 tchunk
->length
= u
->R
* fs
;
444 tchunk
->memblock
= pa_memblock_new(u
->sink
->core
->mempool
, tchunk
->length
);
445 dst
= ((float*)pa_memblock_acquire(tchunk
->memblock
));
446 for(size_t c
=0;c
< u
->channels
; c
++) {
456 if(u
->first_iteration
){
457 /* The windowing function will make the audio ramped in, as a cheap fix we can
458 * undo the windowing (for non-zero window values)
460 for(size_t i
= 0;i
< u
->overlap_size
; ++i
){
461 u
->work_buffer
[i
] = u
->W
[i
] <= FLT_EPSILON
? u
->work_buffer
[i
] : u
->work_buffer
[i
] / u
->W
[i
];
464 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, dst
+ c
, fs
, u
->work_buffer
, sizeof(float), u
->R
);
466 pa_memblock_release(tchunk
->memblock
);
467 u
->samples_gathered
-= u
->R
;
470 static void initialize_buffer(struct userdata
*u
, pa_memchunk
*in
){
471 size_t fs
= pa_frame_size(&u
->sink
->sample_spec
);
472 size_t samples
= in
->length
/ fs
;
473 float *src
= (float*) ((uint8_t*) pa_memblock_acquire(in
->memblock
) + in
->index
);
474 pa_assert_se(u
->samples_gathered
+ samples
<= u
->window_size
);
475 for(size_t c
= 0; c
< u
->channels
; c
++) {
476 //buffer with an offset after the overlap from previous
478 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, u
->input
[c
] + u
->samples_gathered
, sizeof(float), src
+ c
, fs
, samples
);
480 u
->samples_gathered
+= samples
;
481 pa_memblock_release(in
->memblock
);
484 static void input_buffer(struct userdata
*u
, pa_memchunk
*in
){
485 size_t fs
= pa_frame_size(&(u
->sink
->sample_spec
));
486 size_t samples
= in
->length
/fs
;
487 float *src
= (float*) ((uint8_t*) pa_memblock_acquire(in
->memblock
) + in
->index
);
488 pa_assert_se(samples
<= u
->window_size
- u
->samples_gathered
);
489 for(size_t c
= 0; c
< u
->channels
; c
++) {
490 //buffer with an offset after the overlap from previous
493 u
->input
[c
]+u
->samples_gathered
+samples
<= u
->input
[c
]+u
->window_size
495 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, u
->input
[c
]+u
->overlap_size
+u
->samples_gathered
, sizeof(float), src
+ c
, fs
, samples
);
497 u
->samples_gathered
+= samples
;
498 pa_memblock_release(in
->memblock
);
501 /* Called from I/O thread context */
502 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
505 struct timeval start
, end
;
508 pa_sink_input_assert_ref(i
);
509 pa_assert_se(u
= i
->userdata
);
512 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
513 chunk
->memblock
= NULL
;
515 /* Hmm, process any rewind request that might be queued up */
516 pa_sink_process_rewind(u
->sink
, 0);
518 //pa_log_debug("start output-buffered %ld, input-buffered %ld, requested %ld",buffered_samples,u->samples_gathered,samples_requested);
519 pa_rtclock_get(&start
);
521 size_t input_remaining
= u
->window_size
- u
->samples_gathered
;
522 pa_assert(input_remaining
> 0);
525 //buffer = &u->conv_buffer;
526 //buffer->length = input_remaining*fs;
528 //pa_memblock_ref(buffer->memblock);
529 //pa_sink_render_into(u->sink, buffer);
530 while(pa_memblockq_peek(u
->input_q
, &tchunk
) < 0){
531 pa_sink_render(u
->sink
, input_remaining
*fs
, &tchunk
);
532 pa_assert(tchunk
.memblock
);
533 pa_memblockq_push(u
->input_q
, &tchunk
);
534 pa_memblock_unref(tchunk
.memblock
);
536 pa_assert(tchunk
.memblock
);
537 tchunk
.length
= PA_MIN(input_remaining
* fs
, tchunk
.length
);
538 pa_memblockq_drop(u
->input_q
, tchunk
.length
);
539 //pa_log_debug("asked for %ld input samples, got %ld samples",input_remaining,buffer->length/fs);
541 //pa_rtclock_get(start);
542 if(u
->first_iteration
){
543 initialize_buffer(u
, &tchunk
);
545 input_buffer(u
, &tchunk
);
547 //pa_rtclock_get(&end);
548 //pa_log_debug("Took %0.5f seconds to setup", pa_timeval_diff(end, start) / (double) PA_USEC_PER_SEC);
549 pa_memblock_unref(tchunk
.memblock
);
550 }while(u
->samples_gathered
< u
->window_size
);
551 pa_rtclock_get(&end
);
552 pa_log_debug("Took %0.6f seconds to get data", (double) pa_timeval_diff(&end
, &start
) / PA_USEC_PER_SEC
);
554 pa_assert(u
->fft_size
>= u
->window_size
);
555 pa_assert(u
->R
< u
->window_size
);
556 /* set the H filter */
557 a_i
= pa_aupdate_read_begin(u
->a_H
);
560 pa_rtclock_get(&start
);
561 /* process a block */
562 process_samples(u
, chunk
);
563 pa_rtclock_get(&end
);
564 pa_log_debug("Took %0.6f seconds to process", (double) pa_timeval_diff(&end
, &start
) / PA_USEC_PER_SEC
);
565 pa_aupdate_read_end(u
->a_H
);
567 pa_assert(chunk
->memblock
);
568 //pa_log_debug("gave %ld", chunk->length/fs);
569 //pa_log_debug("end pop");
570 if(u
->first_iteration
){
571 u
->first_iteration
= FALSE
;
576 static void reset_filter(struct userdata
*u
){
577 u
->samples_gathered
= 0;
578 for(size_t i
= 0;i
< u
->channels
; ++i
){
579 memset(u
->overlap_accum
[i
], 0, u
->overlap_size
* sizeof(float));
581 u
->first_iteration
= TRUE
;
584 /* Called from I/O thread context */
585 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
589 pa_log_debug("Rewind callback!");
590 pa_sink_input_assert_ref(i
);
591 pa_assert_se(u
= i
->userdata
);
593 if (u
->sink
->thread_info
.rewind_nbytes
> 0) {
596 //max_rewrite = nbytes;
597 max_rewrite
= nbytes
+ pa_memblockq_get_length(u
->input_q
);
598 //PA_MIN(pa_memblockq_get_length(u->input_q), nbytes);
599 amount
= PA_MIN(u
->sink
->thread_info
.rewind_nbytes
, max_rewrite
);
600 u
->sink
->thread_info
.rewind_nbytes
= 0;
603 //pa_sample_spec *ss = &u->sink->sample_spec;
604 //invalidate the output q
605 pa_memblockq_seek(u
->input_q
, - (int64_t) amount
, PA_SEEK_RELATIVE
, TRUE
);
606 //pa_memblockq_drop(u->input_q, pa_memblockq_get_length(u->input_q));
607 //pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
608 pa_log("Resetting filter");
613 pa_sink_process_rewind(u
->sink
, amount
);
614 pa_memblockq_rewind(u
->input_q
, nbytes
);
617 /* Called from I/O thread context */
618 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
621 pa_sink_input_assert_ref(i
);
622 pa_assert_se(u
= i
->userdata
);
624 pa_memblockq_set_maxrewind(u
->input_q
, nbytes
);
625 pa_sink_set_max_rewind_within_thread(u
->sink
, nbytes
);
628 /* Called from I/O thread context */
629 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
632 pa_sink_input_assert_ref(i
);
633 pa_assert_se(u
= i
->userdata
);
635 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
636 //pa_sink_set_max_request_within_thread(u->sink, nbytes);
637 //pa_sink_set_max_request_within_thread(u->sink, u->R*fs);
638 pa_sink_set_max_request_within_thread(u
->sink
, ((nbytes
+u
->R
*fs
-1)/(u
->R
*fs
))*(u
->R
*fs
));
641 /* Called from I/O thread context */
642 static void sink_input_update_sink_latency_range_cb(pa_sink_input
*i
) {
645 pa_sink_input_assert_ref(i
);
646 pa_assert_se(u
= i
->userdata
);
648 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs);
649 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs );
650 pa_sink_set_latency_range_within_thread(u
->sink
, i
->sink
->thread_info
.min_latency
, i
->sink
->thread_info
.max_latency
);
653 /* Called from I/O thread context */
654 static void sink_input_update_sink_fixed_latency_cb(pa_sink_input
*i
) {
657 pa_sink_input_assert_ref(i
);
658 pa_assert_se(u
= i
->userdata
);
660 pa_sink_set_fixed_latency_within_thread(u
->sink
, i
->sink
->thread_info
.fixed_latency
);
663 /* Called from I/O thread context */
664 static void sink_input_detach_cb(pa_sink_input
*i
) {
667 pa_sink_input_assert_ref(i
);
668 pa_assert_se(u
= i
->userdata
);
670 pa_sink_detach_within_thread(u
->sink
);
672 pa_sink_set_rtpoll(u
->sink
, NULL
);
675 /* Called from I/O thread context */
676 static void sink_input_attach_cb(pa_sink_input
*i
) {
679 pa_sink_input_assert_ref(i
);
680 pa_assert_se(u
= i
->userdata
);
682 pa_sink_set_rtpoll(u
->sink
, i
->sink
->thread_info
.rtpoll
);
683 pa_sink_set_latency_range_within_thread(u
->sink
, i
->sink
->thread_info
.min_latency
, i
->sink
->thread_info
.max_latency
);
685 pa_sink_set_fixed_latency_within_thread(u
->sink
, i
->sink
->thread_info
.fixed_latency
);
686 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
687 pa_sink_set_max_request_within_thread(u
->sink
, PA_ROUND_UP(pa_sink_input_get_max_request(i
), u
->R
*fs
));
689 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs);
690 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->master->thread_info.max_latency);
691 //TODO: setting this guy minimizes drop outs but doesn't get rid
692 //of them completely, figure out why
693 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs);
694 //TODO: this guy causes dropouts constantly+rewinds, it's unusable
695 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->master->thread_info.max_latency);
696 pa_sink_attach_within_thread(u
->sink
);
699 /* Called from main context */
700 static void sink_input_kill_cb(pa_sink_input
*i
) {
703 pa_sink_input_assert_ref(i
);
704 pa_assert_se(u
= i
->userdata
);
706 /* The order here matters! We first kill the sink input, followed
707 * by the sink. That means the sink callbacks must be protected
708 * against an unconnected sink input! */
709 pa_sink_input_unlink(u
->sink_input
);
710 pa_sink_unlink(u
->sink
);
712 pa_sink_input_unref(u
->sink_input
);
713 u
->sink_input
= NULL
;
715 pa_sink_unref(u
->sink
);
718 pa_module_unload_request(u
->module
, TRUE
);
721 /* Called from IO thread context */
722 static void sink_input_state_change_cb(pa_sink_input
*i
, pa_sink_input_state_t state
) {
725 pa_sink_input_assert_ref(i
);
726 pa_assert_se(u
= i
->userdata
);
728 /* If we are added for the first time, ask for a rewinding so that
729 * we are heard right-away. */
730 if (PA_SINK_INPUT_IS_LINKED(state
) &&
731 i
->thread_info
.state
== PA_SINK_INPUT_INIT
) {
732 pa_log_debug("Requesting rewind due to state change.");
733 pa_sink_input_request_rewind(i
, 0, FALSE
, TRUE
, TRUE
);
737 static void save_profile(struct userdata
*u
, char *name
){
739 const size_t profile_size
= PROFILE_SIZE
* sizeof(float);
740 float *H_n
, *profile
;
743 profile
= pa_xnew0(float, profile_size
);
744 a_i
= pa_aupdate_read_begin(u
->a_H
);
747 profile
[0] = u
->Xs
[a_i
];
748 for(size_t i
= 0 ; i
<= FILTER_SIZE
; ++i
){
749 //H_n[i] = H[i] * u->fft_size;
752 pa_aupdate_read_end(u
->a_H
);
754 key
.size
= strlen(key
.data
);
756 data
.size
= profile_size
;
757 pa_database_set(u
->database
, &key
, &data
, TRUE
);
758 pa_database_sync(u
->database
);
761 static void save_state(struct userdata
*u
){
762 char *state_name
= pa_sprintf_malloc("%s-previous-state", u
->name
);
763 save_profile(u
, state_name
);
764 pa_xfree(state_name
);
767 static void remove_profile(pa_core
*c
, char *name
){
769 pa_database
*database
;
771 key
.size
= strlen(key
.data
);
772 pa_assert_se(database
= pa_shared_get(c
, EQDB
));
773 pa_database_unset(database
, &key
);
774 pa_database_sync(database
);
777 static const char* load_profile(struct userdata
*u
, char *name
){
780 const size_t profile_size
= PROFILE_SIZE
* sizeof(float);
782 key
.size
= strlen(key
.data
);
783 if(pa_database_get(u
->database
, &key
, &value
) != NULL
){
784 if(value
.size
== profile_size
){
785 float *H
= (float *) value
.data
;
786 a_i
= pa_aupdate_write_begin(u
->a_H
);
788 memcpy(u
->Hs
[a_i
], H
+ 1, (FILTER_SIZE
) * sizeof(float));
789 pa_aupdate_write_end(u
->a_H
);
791 return "incompatible size";
793 pa_datum_free(&value
);
795 return "profile doesn't exist";
798 //fix_filter(u->H, u->fft_size);
801 static void load_state(struct userdata
*u
){
802 char *state_name
=pa_sprintf_malloc("%s-previous-state", u
->name
);
803 load_profile(u
,state_name
);
804 pa_xfree(state_name
);
807 /* Called from main context */
808 static pa_bool_t
sink_input_may_move_to_cb(pa_sink_input
*i
, pa_sink
*dest
) {
811 pa_sink_input_assert_ref(i
);
812 pa_assert_se(u
= i
->userdata
);
814 return u
->sink
!= dest
;
817 /* Called from main context */
818 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
821 pa_sink_input_assert_ref(i
);
822 pa_assert_se(u
= i
->userdata
);
824 pa_sink_set_asyncmsgq(u
->sink
, dest
->asyncmsgq
);
825 pa_sink_update_flags(u
->sink
, PA_SINK_LATENCY
|PA_SINK_DYNAMIC_LATENCY
, dest
->flags
);
828 //ensure's memory allocated is a multiple of v_size
830 static void * alloc(size_t x
,size_t s
){
831 size_t f
= PA_ROUND_UP(x
*s
, sizeof(float)*v_size
);
834 //printf("requested %ld floats=%ld bytes, rem=%ld\n", x, x*sizeof(float), x*sizeof(float)%16);
835 //printf("giving %ld floats=%ld bytes, rem=%ld\n", f, f*sizeof(float), f*sizeof(float)%16);
841 int pa__init(pa_module
*m
) {
848 pa_sink_input_new_data sink_input_data
;
849 pa_sink_new_data sink_data
;
850 pa_bool_t
*use_default
= NULL
;
857 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
858 pa_log("Failed to parse module arguments.");
862 if (!(master
= pa_namereg_get(m
->core
, pa_modargs_get_value(ma
, "master", NULL
), PA_NAMEREG_SINK
))) {
863 pa_log("Master sink not found");
867 ss
= master
->sample_spec
;
868 ss
.format
= PA_SAMPLE_FLOAT32
;
869 map
= master
->channel_map
;
870 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
871 pa_log("Invalid sample format specification or channel map");
874 fs
= pa_frame_size(&ss
);
876 u
= pa_xnew0(struct userdata
, 1);
880 u
->channels
= ss
.channels
;
881 u
->fft_size
= pow(2, ceil(log(ss
.rate
)/log(2)));
882 pa_log_debug("fft size: %ld", u
->fft_size
);
883 u
->window_size
= 15999;
884 u
->R
= (u
->window_size
+ 1) / 2;
885 u
->overlap_size
= u
->window_size
- u
->R
;
886 u
->samples_gathered
= 0;
887 u
->a_H
= pa_aupdate_new();
888 u
->latency
= u
->window_size
- u
->R
;
889 for(size_t i
= 0; i
< 2; ++i
){
890 u
->Hs
[i
] = alloc((FILTER_SIZE
), sizeof(float));
892 u
->W
= alloc(u
->window_size
, sizeof(float));
893 u
->work_buffer
= alloc(u
->fft_size
, sizeof(float));
894 memset(u
->work_buffer
, 0, u
->fft_size
*sizeof(float));
895 u
->input
= pa_xnew0(float *, u
->channels
);
896 u
->overlap_accum
= pa_xnew0(float *, u
->channels
);
897 for(size_t c
= 0; c
< u
->channels
; ++c
){
898 u
->input
[c
] = alloc(u
->window_size
, sizeof(float));
899 memset(u
->input
[c
], 0, (u
->window_size
)*sizeof(float));
900 u
->overlap_accum
[c
] = alloc(u
->overlap_size
, sizeof(float));
901 memset(u
->overlap_accum
[c
], 0, u
->overlap_size
*sizeof(float));
903 u
->output_window
= alloc((FILTER_SIZE
), sizeof(fftwf_complex
));
904 u
->forward_plan
= fftwf_plan_dft_r2c_1d(u
->fft_size
, u
->work_buffer
, u
->output_window
, FFTW_ESTIMATE
);
905 u
->inverse_plan
= fftwf_plan_dft_c2r_1d(u
->fft_size
, u
->output_window
, u
->work_buffer
, FFTW_ESTIMATE
);
907 hanning_window(u
->W
, u
->window_size
);
908 u
->first_iteration
= TRUE
;
911 pa_sink_new_data_init(&sink_data
);
912 sink_data
.driver
= __FILE__
;
913 sink_data
.module
= m
;
914 if (!(sink_data
.name
= pa_xstrdup(pa_modargs_get_value(ma
, "sink_name", NULL
))))
915 sink_data
.name
= pa_sprintf_malloc("%s.equalizer", master
->name
);
916 pa_sink_new_data_set_sample_spec(&sink_data
, &ss
);
917 pa_sink_new_data_set_channel_map(&sink_data
, &map
);
918 z
= pa_proplist_gets(master
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
919 pa_proplist_setf(sink_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "FFT based equalizer on %s",z
? z
: master
->name
);
920 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_MASTER_DEVICE
, master
->name
);
921 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_CLASS
, "filter");
923 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
924 pa_log("Invalid properties");
925 pa_sink_new_data_done(&sink_data
);
929 u
->sink
= pa_sink_new(m
->core
, &sink_data
, master
->flags
& (PA_SINK_LATENCY
|PA_SINK_DYNAMIC_LATENCY
));
930 pa_sink_new_data_done(&sink_data
);
933 pa_log("Failed to create sink.");
936 u
->name
=pa_xstrdup(u
->sink
->name
);
937 u
->sink
->parent
.process_msg
= sink_process_msg
;
938 u
->sink
->set_state
= sink_set_state
;
939 u
->sink
->update_requested_latency
= sink_update_requested_latency
;
940 u
->sink
->request_rewind
= sink_request_rewind
;
941 u
->sink
->userdata
= u
;
942 u
->input_q
= pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH
, 0, fs
, 1, 1, 0, &u
->sink
->silence
);
944 pa_sink_set_asyncmsgq(u
->sink
, master
->asyncmsgq
);
945 //pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->R*fs, &ss));
947 /* Create sink input */
948 pa_sink_input_new_data_init(&sink_input_data
);
949 sink_input_data
.driver
= __FILE__
;
950 sink_input_data
.module
= m
;
951 sink_input_data
.sink
= master
;
952 pa_proplist_sets(sink_input_data
.proplist
, PA_PROP_MEDIA_NAME
, "Equalized Stream");
953 pa_proplist_sets(sink_input_data
.proplist
, PA_PROP_MEDIA_ROLE
, "filter");
954 pa_sink_input_new_data_set_sample_spec(&sink_input_data
, &ss
);
955 pa_sink_input_new_data_set_channel_map(&sink_input_data
, &map
);
957 pa_sink_input_new(&u
->sink_input
, m
->core
, &sink_input_data
, 0);
958 pa_sink_input_new_data_done(&sink_input_data
);
963 u
->sink_input
->pop
= sink_input_pop_cb
;
964 u
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
965 u
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
966 u
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
967 u
->sink_input
->update_sink_latency_range
= sink_input_update_sink_latency_range_cb
;
968 u
->sink_input
->update_sink_fixed_latency
= sink_input_update_sink_fixed_latency_cb
;
969 u
->sink_input
->kill
= sink_input_kill_cb
;
970 u
->sink_input
->attach
= sink_input_attach_cb
;
971 u
->sink_input
->detach
= sink_input_detach_cb
;
972 u
->sink_input
->state_change
= sink_input_state_change_cb
;
973 u
->sink_input
->may_move_to
= sink_input_may_move_to_cb
;
974 u
->sink_input
->moving
= sink_input_moving_cb
;
975 u
->sink_input
->userdata
= u
;
977 pa_sink_put(u
->sink
);
978 pa_sink_input_put(u
->sink_input
);
982 pa_xfree(use_default
);
986 //default filter to these
987 a_i
= pa_aupdate_write_begin(u
->a_H
);
990 for(size_t i
= 0; i
< FILTER_SIZE
; ++i
){
991 H
[i
] = 1.0 / sqrtf(2.0f
);
993 fix_filter(H
, u
->fft_size
);
994 pa_aupdate_write_end(u
->a_H
);
995 //load old parameters
1002 pa_modargs_free(ma
);
1004 pa_xfree(use_default
);
1011 int pa__get_n_used(pa_module
*m
) {
1015 pa_assert_se(u
= m
->userdata
);
1017 return pa_sink_linked_by(u
->sink
);
1020 void pa__done(pa_module
*m
) {
1025 if (!(u
= m
->userdata
))
1032 /* See comments in sink_input_kill_cb() above regarding
1033 * destruction order! */
1036 pa_sink_input_unlink(u
->sink_input
);
1039 pa_sink_unlink(u
->sink
);
1042 pa_sink_input_unref(u
->sink_input
);
1045 pa_sink_unref(u
->sink
);
1047 pa_aupdate_free(u
->a_H
);
1048 pa_memblockq_free(u
->input_q
);
1050 fftwf_destroy_plan(u
->inverse_plan
);
1051 fftwf_destroy_plan(u
->forward_plan
);
1052 pa_xfree(u
->output_window
);
1053 for(size_t c
=0; c
< u
->channels
; ++c
){
1054 pa_xfree(u
->overlap_accum
[c
]);
1055 pa_xfree(u
->input
[c
]);
1057 pa_xfree(u
->overlap_accum
);
1059 pa_xfree(u
->work_buffer
);
1061 for(size_t i
= 0; i
< 2; ++i
){
1071 * DBus Routines and Callbacks
1073 #define EXTNAME "org.PulseAudio.Ext.Equalizing1"
1074 #define MANAGER_PATH "/org/pulseaudio/equalizing1"
1075 #define MANAGER_IFACE EXTNAME ".Manager"
1076 #define EQUALIZER_IFACE EXTNAME ".Equalizer"
1077 static void manager_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1078 static void manager_get_sinks(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1079 static void manager_get_profiles(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1080 static void manager_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1081 static void manager_handle_remove_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1082 static void equalizer_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1083 static void equalizer_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1084 static void equalizer_get_filter_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1085 static void equalizer_get_n_coefs(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1086 static void equalizer_get_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1087 static void equalizer_set_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1088 static void equalizer_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1089 static void equalizer_handle_seed_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1090 static void equalizer_handle_get_filter_points(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1091 static void equalizer_handle_save_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1092 static void equalizer_handle_load_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1093 enum manager_method_index
{
1094 MANAGER_METHOD_REMOVE_PROFILE
,
1098 pa_dbus_arg_info remove_profile_args
[]={
1102 static pa_dbus_method_handler manager_methods
[MANAGER_METHOD_MAX
]={
1103 [MANAGER_METHOD_REMOVE_PROFILE
]{
1104 .method_name
="RemoveProfile",
1105 .arguments
=remove_profile_args
,
1106 .n_arguments
=sizeof(remove_profile_args
)/sizeof(pa_dbus_arg_info
),
1107 .receive_cb
=manager_handle_remove_profile
}
1110 enum manager_handler_index
{
1111 MANAGER_HANDLER_REVISION
,
1112 MANAGER_HANDLER_EQUALIZED_SINKS
,
1113 MANAGER_HANDLER_PROFILES
,
1117 static pa_dbus_property_handler manager_handlers
[MANAGER_HANDLER_MAX
]={
1118 [MANAGER_HANDLER_REVISION
]={.property_name
="InterfaceRevision",.type
="u",.get_cb
=manager_get_revision
,.set_cb
=NULL
},
1119 [MANAGER_HANDLER_EQUALIZED_SINKS
]={.property_name
="EqualizedSinks",.type
="ao",.get_cb
=manager_get_sinks
,.set_cb
=NULL
},
1120 [MANAGER_HANDLER_PROFILES
]={.property_name
="Profiles",.type
="as",.get_cb
=manager_get_profiles
,.set_cb
=NULL
}
1123 pa_dbus_arg_info sink_args
[]={
1127 enum manager_signal_index
{
1128 MANAGER_SIGNAL_SINK_ADDED
,
1129 MANAGER_SIGNAL_SINK_REMOVED
,
1130 MANAGER_SIGNAL_PROFILES_CHANGED
,
1134 static pa_dbus_signal_info manager_signals
[MANAGER_SIGNAL_MAX
]={
1135 [MANAGER_SIGNAL_SINK_ADDED
]={.name
="SinkAdded", .arguments
=sink_args
, .n_arguments
=sizeof(sink_args
)/sizeof(pa_dbus_arg_info
)},
1136 [MANAGER_SIGNAL_SINK_REMOVED
]={.name
="SinkRemoved", .arguments
=sink_args
, .n_arguments
=sizeof(sink_args
)/sizeof(pa_dbus_arg_info
)},
1137 [MANAGER_SIGNAL_PROFILES_CHANGED
]={.name
="ProfilesChanged", .arguments
=NULL
, .n_arguments
=0}
1140 static pa_dbus_interface_info manager_info
={
1141 .name
=MANAGER_IFACE
,
1142 .method_handlers
=manager_methods
,
1143 .n_method_handlers
=MANAGER_METHOD_MAX
,
1144 .property_handlers
=manager_handlers
,
1145 .n_property_handlers
=MANAGER_HANDLER_MAX
,
1146 .get_all_properties_cb
=manager_get_all
,
1147 .signals
=manager_signals
,
1148 .n_signals
=MANAGER_SIGNAL_MAX
1151 enum equalizer_method_index
{
1152 EQUALIZER_METHOD_FILTER_POINTS
,
1153 EQUALIZER_METHOD_SEED_FILTER
,
1154 EQUALIZER_METHOD_SAVE_PROFILE
,
1155 EQUALIZER_METHOD_LOAD_PROFILE
,
1156 EQUALIZER_METHOD_MAX
1159 enum equalizer_handler_index
{
1160 EQUALIZER_HANDLER_REVISION
,
1161 EQUALIZER_HANDLER_SAMPLERATE
,
1162 EQUALIZER_HANDLER_FILTERSAMPLERATE
,
1163 EQUALIZER_HANDLER_N_COEFS
,
1164 EQUALIZER_HANDLER_FILTER
,
1165 EQUALIZER_HANDLER_PREAMP
,
1166 EQUALIZER_HANDLER_MAX
1169 pa_dbus_arg_info filter_points_args
[]={
1172 {"preamp", "d","out"},
1174 pa_dbus_arg_info seed_filter_args
[]={
1177 {"preamp", "d","in"},
1179 pa_dbus_arg_info save_profile_args
[]={
1182 pa_dbus_arg_info load_profile_args
[]={
1186 static pa_dbus_method_handler equalizer_methods
[EQUALIZER_METHOD_MAX
]={
1187 [EQUALIZER_METHOD_SEED_FILTER
]{
1188 .method_name
="SeedFilter",
1189 .arguments
=seed_filter_args
,
1190 .n_arguments
=sizeof(seed_filter_args
)/sizeof(pa_dbus_arg_info
),
1191 .receive_cb
=equalizer_handle_seed_filter
},
1192 [EQUALIZER_METHOD_FILTER_POINTS
]{
1193 .method_name
="FilterAtPoints",
1194 .arguments
=filter_points_args
,
1195 .n_arguments
=sizeof(filter_points_args
)/sizeof(pa_dbus_arg_info
),
1196 .receive_cb
=equalizer_handle_get_filter_points
},
1197 [EQUALIZER_METHOD_SAVE_PROFILE
]{
1198 .method_name
="SaveProfile",
1199 .arguments
=save_profile_args
,
1200 .n_arguments
=sizeof(save_profile_args
)/sizeof(pa_dbus_arg_info
),
1201 .receive_cb
=equalizer_handle_save_profile
},
1202 [EQUALIZER_METHOD_LOAD_PROFILE
]{
1203 .method_name
="LoadProfile",
1204 .arguments
=load_profile_args
,
1205 .n_arguments
=sizeof(load_profile_args
)/sizeof(pa_dbus_arg_info
),
1206 .receive_cb
=equalizer_handle_load_profile
},
1209 static pa_dbus_property_handler equalizer_handlers
[EQUALIZER_HANDLER_MAX
]={
1210 [EQUALIZER_HANDLER_REVISION
]={.property_name
="InterfaceRevision",.type
="u",.get_cb
=equalizer_get_revision
,.set_cb
=NULL
},
1211 [EQUALIZER_HANDLER_SAMPLERATE
]{.property_name
="SampleRate",.type
="u",.get_cb
=equalizer_get_sample_rate
,.set_cb
=NULL
},
1212 [EQUALIZER_HANDLER_FILTERSAMPLERATE
]{.property_name
="FilterSampleRate",.type
="u",.get_cb
=equalizer_get_filter_rate
,.set_cb
=NULL
},
1213 [EQUALIZER_HANDLER_N_COEFS
]{.property_name
="NFilterCoefficients",.type
="u",.get_cb
=equalizer_get_n_coefs
,.set_cb
=NULL
},
1214 [EQUALIZER_HANDLER_FILTER
]{.property_name
="Filter",.type
="ad",.get_cb
=equalizer_get_filter
,.set_cb
=equalizer_set_filter
}
1217 enum equalizer_signal_index
{
1218 EQUALIZER_SIGNAL_FILTER_CHANGED
,
1219 EQUALIZER_SIGNAL_SINK_RECONFIGURED
,
1220 EQUALIZER_SIGNAL_MAX
1223 static pa_dbus_signal_info equalizer_signals
[EQUALIZER_SIGNAL_MAX
]={
1224 [EQUALIZER_SIGNAL_FILTER_CHANGED
]={.name
="FilterChanged", .arguments
=NULL
, .n_arguments
=0},
1225 [EQUALIZER_SIGNAL_SINK_RECONFIGURED
]={.name
="SinkReconfigured", .arguments
=NULL
, .n_arguments
=0},
1228 static pa_dbus_interface_info equalizer_info
={
1229 .name
=EQUALIZER_IFACE
,
1230 .method_handlers
=equalizer_methods
,
1231 .n_method_handlers
=EQUALIZER_METHOD_MAX
,
1232 .property_handlers
=equalizer_handlers
,
1233 .n_property_handlers
=EQUALIZER_HANDLER_MAX
,
1234 .get_all_properties_cb
=equalizer_get_all
,
1235 .signals
=equalizer_signals
,
1236 .n_signals
=EQUALIZER_SIGNAL_MAX
1239 void dbus_init(struct userdata
*u
){
1241 DBusMessage
*signal
= NULL
;
1242 pa_idxset
*sink_list
= NULL
;
1243 u
->dbus_protocol
=pa_dbus_protocol_get(u
->sink
->core
);
1244 u
->dbus_path
=pa_sprintf_malloc("/org/pulseaudio/core1/sink%d", u
->sink
->index
);
1246 pa_dbus_protocol_add_interface(u
->dbus_protocol
, u
->dbus_path
, &equalizer_info
, u
);
1247 sink_list
= pa_shared_get(u
->sink
->core
, SINKLIST
);
1248 u
->database
=pa_shared_get(u
->sink
->core
, EQDB
);
1249 if(sink_list
==NULL
){
1251 sink_list
=pa_idxset_new(&pa_idxset_trivial_hash_func
, &pa_idxset_trivial_compare_func
);
1252 pa_shared_set(u
->sink
->core
, SINKLIST
, sink_list
);
1253 pa_assert_se(dbname
= pa_state_path("equalizers", TRUE
));
1254 pa_assert_se(u
->database
= pa_database_open(dbname
, TRUE
));
1256 pa_shared_set(u
->sink
->core
,EQDB
,u
->database
);
1257 pa_dbus_protocol_add_interface(u
->dbus_protocol
, MANAGER_PATH
, &manager_info
, u
->sink
->core
);
1258 pa_dbus_protocol_register_extension(u
->dbus_protocol
, EXTNAME
);
1260 pa_idxset_put(sink_list
, u
, &dummy
);
1262 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_SINK_ADDED
].name
)));
1263 dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &u
->dbus_path
, DBUS_TYPE_INVALID
);
1264 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1265 dbus_message_unref(signal
);
1268 void dbus_done(struct userdata
*u
){
1269 pa_idxset
*sink_list
;
1272 DBusMessage
*signal
= NULL
;
1273 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_SINK_REMOVED
].name
)));
1274 dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &u
->dbus_path
, DBUS_TYPE_INVALID
);
1275 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1276 dbus_message_unref(signal
);
1278 pa_assert_se(sink_list
=pa_shared_get(u
->sink
->core
,SINKLIST
));
1279 pa_idxset_remove_by_data(sink_list
,u
,&dummy
);
1280 if(pa_idxset_size(sink_list
)==0){
1281 pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, EXTNAME
);
1282 pa_dbus_protocol_remove_interface(u
->dbus_protocol
, MANAGER_PATH
, manager_info
.name
);
1283 pa_shared_remove(u
->sink
->core
, EQDB
);
1284 pa_database_close(u
->database
);
1285 pa_shared_remove(u
->sink
->core
, SINKLIST
);
1286 pa_xfree(sink_list
);
1288 pa_dbus_protocol_remove_interface(u
->dbus_protocol
, u
->dbus_path
, equalizer_info
.name
);
1289 pa_xfree(u
->dbus_path
);
1290 pa_dbus_protocol_unref(u
->dbus_protocol
);
1293 void manager_handle_remove_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1295 pa_core
*c
= (pa_core
*)_u
;
1296 DBusMessage
*signal
= NULL
;
1297 pa_dbus_protocol
*dbus_protocol
;
1302 dbus_error_init(&error
);
1303 if(!dbus_message_get_args(msg
, &error
,
1304 DBUS_TYPE_STRING
, &name
,
1305 DBUS_TYPE_INVALID
)){
1306 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1307 dbus_error_free(&error
);
1310 remove_profile(c
,name
);
1311 pa_dbus_send_empty_reply(conn
, msg
);
1313 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_PROFILES_CHANGED
].name
)));
1314 dbus_protocol
= pa_dbus_protocol_get(c
);
1315 pa_dbus_protocol_send_signal(dbus_protocol
, signal
);
1316 pa_dbus_protocol_unref(dbus_protocol
);
1317 dbus_message_unref(signal
);
1320 void manager_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1322 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rev
);
1325 static void get_sinks(pa_core
*u
, char ***names
, unsigned *n_sinks
){
1327 struct userdata
*sink_u
= NULL
;
1329 pa_idxset
*sink_list
;
1334 pa_assert_se(sink_list
= pa_shared_get(u
, SINKLIST
));
1335 *n_sinks
= (unsigned) pa_idxset_size(sink_list
);
1336 *names
= *n_sinks
> 0 ? pa_xnew0(char *,*n_sinks
) : NULL
;
1337 for(uint32_t i
= 0; i
< *n_sinks
; ++i
){
1338 sink_u
= (struct userdata
*) pa_idxset_iterate(sink_list
, &iter
, &dummy
);
1339 (*names
)[i
] = pa_xstrdup(sink_u
->dbus_path
);
1343 void manager_get_sinks(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1345 char **names
= NULL
;
1350 get_sinks((pa_core
*) _u
, &names
, &n
);
1351 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, names
, n
);
1352 for(unsigned i
= 0; i
< n
; ++i
){
1358 static void get_profiles(pa_core
*c
, char ***names
, unsigned *n
){
1360 pa_database
*database
;
1361 pa_datum key
, next_key
;
1362 pa_strlist
*head
=NULL
, *iter
;
1364 pa_assert_se(database
= pa_shared_get(c
, EQDB
));
1369 done
= !pa_database_first(database
, &key
, NULL
);
1372 done
= !pa_database_next(database
, &key
, &next_key
, NULL
);
1373 name
=pa_xmalloc(key
.size
+ 1);
1374 memcpy(name
, key
.data
, key
.size
);
1375 name
[key
.size
] = '\0';
1376 pa_datum_free(&key
);
1377 head
= pa_strlist_prepend(head
, name
);
1382 (*names
) = *n
> 0 ? pa_xnew0(char *, *n
) : NULL
;
1384 for(unsigned i
= 0; i
< *n
; ++i
){
1385 (*names
)[*n
- 1 - i
] = pa_xstrdup(pa_strlist_data(iter
));
1386 iter
= pa_strlist_next(iter
);
1388 pa_strlist_free(head
);
1391 void manager_get_profiles(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1398 get_profiles((pa_core
*)_u
, &names
, &n
);
1399 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, names
, n
);
1400 for(unsigned i
= 0; i
< n
; ++i
){
1406 void manager_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1408 char **names
= NULL
;
1410 DBusMessage
*reply
= NULL
;
1411 DBusMessageIter msg_iter
, dict_iter
;
1415 pa_assert_se(c
= _u
);
1417 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1418 dbus_message_iter_init_append(reply
, &msg_iter
);
1419 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1422 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, manager_handlers
[MANAGER_HANDLER_REVISION
].property_name
, DBUS_TYPE_UINT32
, &rev
);
1424 get_sinks(c
, &names
, &n
);
1425 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
,manager_handlers
[MANAGER_HANDLER_EQUALIZED_SINKS
].property_name
, DBUS_TYPE_OBJECT_PATH
, names
, n
);
1426 for(unsigned i
= 0; i
< n
; ++i
){
1431 get_profiles(c
, &names
, &n
);
1432 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, manager_handlers
[MANAGER_HANDLER_PROFILES
].property_name
, DBUS_TYPE_STRING
, names
, n
);
1433 for(unsigned i
= 0; i
< n
; ++i
){
1437 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1438 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1439 dbus_message_unref(reply
);
1442 void equalizer_handle_seed_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1443 struct userdata
*u
=(struct userdata
*) _u
;
1445 DBusMessage
*signal
= NULL
;
1448 double *_ys
, preamp
;
1449 unsigned x_npoints
, y_npoints
, a_i
;
1451 pa_bool_t points_good
= TRUE
;
1456 dbus_error_init(&error
);
1458 if(!dbus_message_get_args(msg
, &error
,
1459 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &xs
, &x_npoints
,
1460 DBUS_TYPE_ARRAY
, DBUS_TYPE_DOUBLE
, &_ys
, &y_npoints
,
1461 DBUS_TYPE_DOUBLE
, &preamp
,
1462 DBUS_TYPE_INVALID
)){
1463 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1464 dbus_error_free(&error
);
1467 for(size_t i
= 0; i
< x_npoints
; ++i
){
1468 if(xs
[i
] >= FILTER_SIZE
){
1469 points_good
= FALSE
;
1473 if(!is_monotonic(xs
, x_npoints
) || !points_good
){
1474 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs must be monotonic and 0<=x<=%ld", u
->fft_size
/ 2);
1475 dbus_error_free(&error
);
1478 }else if(x_npoints
!= y_npoints
|| x_npoints
< 2 || x_npoints
> FILTER_SIZE
){
1479 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs and ys must be the same length and 2<=l<=%ld!", FILTER_SIZE
);
1480 dbus_error_free(&error
);
1482 }else if(xs
[0] != 0 || xs
[x_npoints
- 1] != u
->fft_size
/ 2){
1483 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs[0] must be 0 and xs[-1]=fft_size/2");
1484 dbus_error_free(&error
);
1488 ys
= pa_xmalloc(x_npoints
* sizeof(float));
1489 for(uint32_t i
= 0; i
< x_npoints
; ++i
){
1490 ys
[i
] = (float) _ys
[i
];
1492 a_i
= pa_aupdate_write_begin(u
->a_H
);
1494 u
->Xs
[a_i
] = preamp
;
1495 interpolate(H
, FILTER_SIZE
, xs
, ys
, x_npoints
);
1496 fix_filter(H
, u
->fft_size
);
1497 pa_aupdate_write_end(u
->a_H
);
1500 //Stupid for IO reasons? Add a save signal to dbus instead
1503 pa_dbus_send_empty_reply(conn
, msg
);
1505 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1506 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1507 dbus_message_unref(signal
);
1510 void equalizer_handle_get_filter_points(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1511 struct userdata
*u
= (struct userdata
*) _u
;
1515 unsigned x_npoints
, a_i
;
1517 pa_bool_t points_good
=TRUE
;
1518 DBusMessage
*reply
= NULL
;
1519 DBusMessageIter msg_iter
;
1525 dbus_error_init(&error
);
1527 if(!dbus_message_get_args(msg
, &error
,
1528 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &xs
, &x_npoints
,
1529 DBUS_TYPE_INVALID
)){
1530 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1531 dbus_error_free(&error
);
1534 for(size_t i
= 0; i
< x_npoints
; ++i
){
1535 if(xs
[i
] >= FILTER_SIZE
){
1541 if(x_npoints
> FILTER_SIZE
|| !points_good
){
1542 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs indices/length must be <= %ld!", FILTER_SIZE
);
1543 dbus_error_free(&error
);
1547 ys
= pa_xmalloc(x_npoints
* sizeof(double));
1548 a_i
= pa_aupdate_read_begin(u
->a_H
);
1550 preamp
= u
->Xs
[a_i
];
1551 for(uint32_t i
= 0; i
< x_npoints
; ++i
){
1552 ys
[i
] = H
[xs
[i
]] * u
->fft_size
;
1554 pa_aupdate_read_end(u
->a_H
);
1556 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1557 dbus_message_iter_init_append(reply
, &msg_iter
);
1559 pa_dbus_append_basic_array(&msg_iter
, DBUS_TYPE_DOUBLE
, ys
, x_npoints
);
1560 pa_dbus_append_basic_variant(&msg_iter
, DBUS_TYPE_DOUBLE
, &preamp
);
1562 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1563 dbus_message_unref(reply
);
1567 void equalizer_handle_save_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1568 struct userdata
*u
= (struct userdata
*) _u
;
1570 DBusMessage
*signal
= NULL
;
1575 dbus_error_init(&error
);
1577 if(!dbus_message_get_args(msg
, &error
,
1578 DBUS_TYPE_STRING
, &name
,
1579 DBUS_TYPE_INVALID
)){
1580 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1581 dbus_error_free(&error
);
1584 save_profile(u
,name
);
1585 pa_dbus_send_empty_reply(conn
, msg
);
1587 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_PROFILES_CHANGED
].name
)));
1588 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1589 dbus_message_unref(signal
);
1592 void equalizer_handle_load_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1593 struct userdata
*u
=(struct userdata
*) _u
;
1596 const char *err_msg
= NULL
;
1597 DBusMessage
*signal
= NULL
;
1602 dbus_error_init(&error
);
1604 if(!dbus_message_get_args(msg
, &error
,
1605 DBUS_TYPE_STRING
, &name
,
1606 DBUS_TYPE_INVALID
)){
1607 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1608 dbus_error_free(&error
);
1611 err_msg
= load_profile(u
, name
);
1612 if(err_msg
!= NULL
){
1613 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
, "error loading profile %s: %s", name
, err_msg
);
1614 dbus_error_free(&error
);
1617 pa_dbus_send_empty_reply(conn
, msg
);
1619 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1620 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1621 dbus_message_unref(signal
);
1624 void equalizer_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1626 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rev
);
1629 void equalizer_get_n_coefs(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1632 pa_assert_se(u
= (struct userdata
*) _u
);
1636 n_coefs
= (uint32_t) PROFILE_SIZE
;
1637 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &n_coefs
);
1640 void equalizer_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1643 pa_assert_se(u
= (struct userdata
*) _u
);
1647 rate
= (uint32_t) u
->sink
->sample_spec
.rate
;
1648 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rate
);
1651 void equalizer_get_filter_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1654 pa_assert_se(u
= (struct userdata
*) _u
);
1658 fft_size
= (uint32_t) u
->fft_size
;
1659 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &fft_size
);
1662 static double * get_filter(struct userdata
*u
){
1666 H_
= pa_xnew0(double, PROFILE_SIZE
);
1667 a_i
= pa_aupdate_read_begin(u
->a_H
);
1670 for(size_t i
= 0;i
< FILTER_SIZE
; ++i
){
1671 H_
[i
+ 1] = H
[i
] * u
->fft_size
;
1673 pa_aupdate_read_end(u
->a_H
);
1677 void equalizer_get_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1681 pa_assert_se(u
= (struct userdata
*) _u
);
1683 n_coefs
= PROFILE_SIZE
;
1687 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_DOUBLE
, H_
, n_coefs
);
1691 static void set_filter(struct userdata
*u
, double *H_
){
1692 unsigned a_i
= pa_aupdate_write_begin(u
->a_H
);
1693 float *H
= u
->Hs
[a_i
];
1695 for(size_t i
= 0; i
< FILTER_SIZE
; ++i
){
1696 H
[i
] = (float) H_
[i
+ 1];
1698 fix_filter(H
+ 1, u
->fft_size
);
1699 pa_aupdate_write_end(u
->a_H
);
1702 void equalizer_set_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1706 DBusMessage
*signal
= NULL
;
1707 pa_assert_se(u
= (struct userdata
*) _u
);
1711 if(pa_dbus_get_fixed_array_set_property_arg(conn
, msg
, DBUS_TYPE_DOUBLE
, &H
, &_n_coefs
)){
1714 if(_n_coefs
!= PROFILE_SIZE
){
1715 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "This filter takes exactly %ld coefficients, you gave %d", PROFILE_SIZE
, _n_coefs
);
1720 pa_dbus_send_empty_reply(conn
, msg
);
1722 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1723 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1724 dbus_message_unref(signal
);
1727 void equalizer_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1729 DBusMessage
*reply
= NULL
;
1730 DBusMessageIter msg_iter
, dict_iter
;
1731 uint32_t rev
, n_coefs
, rate
, fft_size
;
1733 pa_assert_se(u
= (struct userdata
*) _u
);
1737 n_coefs
= (uint32_t) PROFILE_SIZE
;
1738 rate
= (uint32_t) u
->sink
->sample_spec
.rate
;
1739 fft_size
= (uint32_t) u
->fft_size
;
1741 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1742 dbus_message_iter_init_append(reply
, &msg_iter
);
1743 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1745 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_REVISION
].property_name
, DBUS_TYPE_UINT32
, &rev
);
1746 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_SAMPLERATE
].property_name
, DBUS_TYPE_UINT32
, &rate
);
1747 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_FILTERSAMPLERATE
].property_name
, DBUS_TYPE_UINT32
, &fft_size
);
1748 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_N_COEFS
].property_name
, DBUS_TYPE_UINT32
, &n_coefs
);
1750 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_FILTER
].property_name
, DBUS_TYPE_UINT32
, &H
);
1753 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1754 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1755 dbus_message_unref(reply
);