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 *W
;//windowing function (time domain)
108 float *work_buffer
, **input
, **overlap_accum
;
109 fftwf_complex
*output_window
;
110 fftwf_plan forward_plan
, inverse_plan
;
114 float ***Hs
;//thread updatable copies of the freq response filters (magintude based)
116 pa_memchunk conv_buffer
;
117 pa_memblockq
*input_q
;
118 pa_bool_t first_iteration
;
120 pa_dbus_protocol
*dbus_protocol
;
122 pa_bool_t set_default
;
124 pa_database
*database
;
127 static const char* const valid_modargs
[] = {
141 #define SINKLIST "equalized_sinklist"
142 #define EQDB "equalizer_db"
143 #define EQ_STATE_DB "equalizer-state"
144 #define FILTER_SIZE (u->fft_size / 2 + 1)
145 #define CHANNEL_PROFILE_SIZE (FILTER_SIZE + 1)
146 #define STATE_SIZE (CHANNEL_PROFILE_SIZE * u->channels)
147 static void dbus_init(struct userdata
*u
);
148 static void dbus_done(struct userdata
*u
);
150 static void hanning_window(float *W
, size_t window_size
){
151 //h=.5*(1-cos(2*pi*j/(window_size+1)), COLA for R=(M+1)/2
152 for(size_t i
=0; i
< window_size
;++i
){
153 W
[i
] = (float).5*(1-cos(2*M_PI
*i
/(window_size
+1)));
157 static void fix_filter(float *H
, size_t fft_size
){
158 //divide out the fft gain
159 for(size_t i
= 0; i
< fft_size
/ 2 + 1; ++i
){
164 static void interpolate(float *signal
, size_t length
, uint32_t *xs
, float *ys
, size_t n_points
){
165 //Note that xs must be monotonically increasing!
166 float x_range_lower
, x_range_upper
, c0
;
167 pa_assert_se(n_points
>=2);
168 pa_assert_se(xs
[0] == 0);
169 pa_assert_se(xs
[n_points
- 1] == length
- 1);
170 for(size_t x
= 0, x_range_lower_i
= 0; x
< length
-1; ++x
){
171 pa_assert(x_range_lower_i
< n_points
-1);
172 x_range_lower
= (float) (xs
[x_range_lower_i
]);
173 x_range_upper
= (float) (xs
[x_range_lower_i
+1]);
174 pa_assert_se(x_range_lower
< x_range_upper
);
175 pa_assert_se(x
>= x_range_lower
);
176 pa_assert_se(x
<= x_range_upper
);
177 //bilinear-interpolation of coefficients specified
178 c0
= (x
-x_range_lower
)/(x_range_upper
-x_range_lower
);
179 pa_assert_se(c0
>= 0&&c0
<= 1.0);
180 signal
[x
] = ((1.0f
- c0
) * ys
[x_range_lower_i
] + c0
* ys
[x_range_lower_i
+ 1]);
181 while(x
>= xs
[x_range_lower_i
+ 1]){
185 signal
[length
-1]=ys
[n_points
-1];
188 static int is_monotonic(const uint32_t *xs
,size_t length
){
192 for(size_t i
= 1; i
< length
; ++i
){
201 /* Called from I/O thread context */
202 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
203 struct userdata
*u
= PA_SINK(o
)->userdata
;
207 case PA_SINK_MESSAGE_GET_LATENCY
: {
208 //size_t fs=pa_frame_size(&u->sink->sample_spec);
210 /* The sink is _put() before the sink input is, so let's
211 * make sure we don't access it in that time. Also, the
212 * sink input is first shut down, the sink second. */
213 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
214 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
)) {
215 *((pa_usec_t
*) data
) = 0;
219 *((pa_usec_t
*) data
) =
220 /* Get the latency of the master sink */
221 pa_sink_get_latency_within_thread(u
->sink_input
->sink
) +
223 /* Add the latency internal to our sink input on top */
224 pa_bytes_to_usec(pa_memblockq_get_length(u
->sink_input
->thread_info
.render_memblockq
), &u
->sink_input
->sink
->sample_spec
);
225 // pa_bytes_to_usec(u->samples_gathered * fs, &u->sink->sample_spec);
226 //+ pa_bytes_to_usec(u->latency * fs, ss)
227 //+ pa_bytes_to_usec(pa_memblockq_get_length(u->input_q), ss);
232 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
236 /* Called from main context */
237 static int sink_set_state(pa_sink
*s
, pa_sink_state_t state
) {
240 pa_sink_assert_ref(s
);
241 pa_assert_se(u
= s
->userdata
);
243 if (!PA_SINK_IS_LINKED(state
) ||
244 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u
->sink_input
)))
247 pa_sink_input_cork(u
->sink_input
, state
== PA_SINK_SUSPENDED
);
251 /* Called from I/O thread context */
252 static void sink_request_rewind(pa_sink
*s
) {
255 pa_sink_assert_ref(s
);
256 pa_assert_se(u
= s
->userdata
);
258 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
259 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
))
262 /* Just hand this one over to the master sink */
263 pa_sink_input_request_rewind(u
->sink_input
, s
->thread_info
.rewind_nbytes
+pa_memblockq_get_length(u
->input_q
), TRUE
, FALSE
, FALSE
);
266 /* Called from I/O thread context */
267 static void sink_update_requested_latency(pa_sink
*s
) {
270 pa_sink_assert_ref(s
);
271 pa_assert_se(u
= s
->userdata
);
273 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
274 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
))
277 /* Just hand this one over to the master sink */
278 pa_sink_input_set_requested_latency_within_thread(
280 pa_sink_get_requested_latency_within_thread(s
));
283 //reference implementation
284 static void dsp_logic(
285 float * restrict dst
,//used as a temp array too, needs to be fft_length!
286 float * restrict src
,/*input data w/ overlap at start,
287 *automatically cycled in routine
289 float * restrict overlap
,
290 const float X
,//multipliar
291 const float * restrict H
,//The freq. magnitude scalers filter
292 const float * restrict W
,//The windowing function
293 fftwf_complex
* restrict output_window
,//The transformed window'd src
295 //use a linear-phase sliding STFT and overlap-add method (for each channel)
297 memset(dst
+ u
->window_size
, 0, (u
->fft_size
- u
->window_size
) * sizeof(float));
299 for(size_t j
= 0; j
< u
->window_size
; ++j
){
300 dst
[j
] = X
* W
[j
] * src
[j
];
302 //Processing is done here!
304 fftwf_execute_dft_r2c(u
->forward_plan
, dst
, output_window
);
306 for(size_t j
= 0; j
< FILTER_SIZE
; ++j
){
307 u
->output_window
[j
][0] *= H
[j
];
308 u
->output_window
[j
][1] *= H
[j
];
311 fftwf_execute_dft_c2r(u
->inverse_plan
, output_window
, dst
);
312 ////debug: tests overlaping add
313 ////and negates ALL PREVIOUS processing
314 ////yields a perfect reconstruction if COLA is held
315 //for(size_t j = 0; j < u->window_size; ++j){
316 // u->work_buffer[j] = u->W[j] * u->input[c][j];
319 //overlap add and preserve overlap component from this window (linear phase)
320 for(size_t j
= 0; j
< u
->overlap_size
; ++j
){
321 u
->work_buffer
[j
] += overlap
[j
];
322 overlap
[j
] = dst
[u
->R
+ j
];
324 ////debug: tests if basic buffering works
325 ////shouldn't modify the signal AT ALL (beyond roundoff)
326 //for(size_t j = 0; j < u->window_size;++j){
327 // u->work_buffer[j] = u->input[c][j];
330 //preseve the needed input for the next window's overlap
331 memmove(src
, src
+ u
->R
,
332 u
->overlap_size
* sizeof(float)
336 typedef float v4sf
__attribute__ ((__aligned__(v_size
* sizeof(float))));
337 typedef union float_vector
{
345 ////regardless of sse enabled, the loops in here assume
346 ////16 byte aligned addresses and memory allocations divisible by v_size
348 // float * restrict dst,//used as a temp array too, needs to be fft_length!
349 // float * restrict src,/*input data w/ overlap at start,
350 // *automatically cycled in routine
352 // float * restrict overlap,//The size of the overlap
353 // const float X,//multipliar
354 // const float * restrict H,//The freq. magnitude scalers filter
355 // const float * restrict W,//The windowing function
356 // fftwf_complex * restrict output_window,//The transformed window'd src
357 // struct userdata *u){//Collection of constants
358 //float_vector_t x = {X, X, X, X};
359 // const size_t window_size = PA_ROUND_UP(u->window_size,v_size);
360 // const size_t fft_h = PA_ROUND_UP(FILTER_SIZE, v_size / 2);
361 // //const size_t R = PA_ROUND_UP(u->R, v_size);
362 // const size_t overlap_size = PA_ROUND_UP(u->overlap_size, v_size);
363 // overlap_size = PA_ROUND_UP(u->overlap_size, v_size);
365 // //assert(u->samples_gathered >= u->R);
366 // //zero out the bit beyond the real overlap so we don't add garbage
367 // for(size_t j = overlap_size; j > u->overlap_size; --j){
370 // //use a linear-phase sliding STFT and overlap-add method
371 // //zero padd the data
372 // memset(dst + u->window_size, 0, (u->fft_size - u->window_size)*sizeof(float));
374 // for(size_t j = 0; j < window_size; j += v_size){
375 // //dst[j] = W[j]*src[j];
376 // float_vector_t *d = (float_vector_t*) (dst+j);
377 // float_vector_t *w = (float_vector_t*) (W+j);
378 // float_vector_t *s = (float_vector_t*) (src+j);
380 // d->m = _mm_mul_ps(x->m, _mm_mul_ps(w->m, s->m));
382 // d->v = x->v * w->v * s->v;
385 // //Processing is done here!
387 // fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
390 // //perform filtering - purely magnitude based
391 // for(size_t j = 0;j < fft_h; j+=v_size/2){
392 // //output_window[j][0]*=H[j];
393 // //output_window[j][1]*=H[j];
394 // float_vector_t *d = (float_vector_t*)(output_window+j);
396 // h.f[0] = h.f[1] = H[j];
397 // h.f[2] = h.f[3] = H[j+1];
399 // d->m = _mm_mul_ps(d->m, h.m);
405 // fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
407 // ////debug: tests overlaping add
408 // ////and negates ALL PREVIOUS processing
409 // ////yields a perfect reconstruction if COLA is held
410 // //for(size_t j = 0; j < u->window_size; ++j){
411 // // dst[j] = W[j]*src[j];
414 // //overlap add and preserve overlap component from this window (linear phase)
415 // for(size_t j = 0; j < overlap_size; j+=v_size){
416 // //dst[j]+=overlap[j];
417 // //overlap[j]+=dst[j+R];
418 // float_vector_t *d = (float_vector_t*)(dst+j);
419 // float_vector_t *o = (float_vector_t*)(overlap+j);
421 // d->m = _mm_add_ps(d->m, o->m);
422 // o->m = ((float_vector_t*)(dst+u->R+j))->m;
425 // o->v = ((float_vector_t*)(dst+u->R+j))->v;
428 // //memcpy(overlap, dst+u->R, u->overlap_size*sizeof(float));
430 // //////debug: tests if basic buffering works
431 // //////shouldn't modify the signal AT ALL (beyond roundoff)
432 // //for(size_t j = 0; j < u->window_size; ++j){
433 // // dst[j] = src[j];
436 // //preseve the needed input for the next window's overlap
437 // memmove(src, src + u->R,
438 // u->overlap_size * sizeof(float)
442 static void process_samples(struct userdata
*u
, pa_memchunk
*tchunk
){
443 size_t fs
=pa_frame_size(&(u
->sink
->sample_spec
));
447 pa_assert(u
->samples_gathered
>= u
->R
);
449 tchunk
->length
= u
->R
* fs
;
450 tchunk
->memblock
= pa_memblock_new(u
->sink
->core
->mempool
, tchunk
->length
);
451 dst
= ((float*)pa_memblock_acquire(tchunk
->memblock
));
453 for(size_t c
=0;c
< u
->channels
; c
++) {
454 a_i
= pa_aupdate_read_begin(u
->a_H
[c
]);
467 pa_aupdate_read_end(u
->a_H
[c
]);
468 if(u
->first_iteration
){
469 /* The windowing function will make the audio ramped in, as a cheap fix we can
470 * undo the windowing (for non-zero window values)
472 for(size_t i
= 0;i
< u
->overlap_size
; ++i
){
473 u
->work_buffer
[i
] = u
->W
[i
] <= FLT_EPSILON
? u
->work_buffer
[i
] : u
->work_buffer
[i
] / u
->W
[i
];
476 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, dst
+ c
, fs
, u
->work_buffer
, sizeof(float), u
->R
);
478 pa_memblock_release(tchunk
->memblock
);
479 u
->samples_gathered
-= u
->R
;
482 static void initialize_buffer(struct userdata
*u
, pa_memchunk
*in
){
483 size_t fs
= pa_frame_size(&u
->sink
->sample_spec
);
484 size_t samples
= in
->length
/ fs
;
485 float *src
= (float*) ((uint8_t*) pa_memblock_acquire(in
->memblock
) + in
->index
);
486 pa_assert_se(u
->samples_gathered
+ samples
<= u
->window_size
);
487 for(size_t c
= 0; c
< u
->channels
; c
++) {
488 //buffer with an offset after the overlap from previous
490 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, u
->input
[c
] + u
->samples_gathered
, sizeof(float), src
+ c
, fs
, samples
);
492 u
->samples_gathered
+= samples
;
493 pa_memblock_release(in
->memblock
);
496 static void input_buffer(struct userdata
*u
, pa_memchunk
*in
){
497 size_t fs
= pa_frame_size(&(u
->sink
->sample_spec
));
498 size_t samples
= in
->length
/fs
;
499 float *src
= (float*) ((uint8_t*) pa_memblock_acquire(in
->memblock
) + in
->index
);
500 pa_assert_se(samples
<= u
->window_size
- u
->samples_gathered
);
501 for(size_t c
= 0; c
< u
->channels
; c
++) {
502 //buffer with an offset after the overlap from previous
505 u
->input
[c
]+u
->samples_gathered
+samples
<= u
->input
[c
]+u
->window_size
507 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, u
->input
[c
]+u
->samples_gathered
, sizeof(float), src
+ c
, fs
, samples
);
509 u
->samples_gathered
+= samples
;
510 pa_memblock_release(in
->memblock
);
513 /* Called from I/O thread context */
514 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
517 struct timeval start
, end
;
519 pa_sink_input_assert_ref(i
);
520 pa_assert_se(u
= i
->userdata
);
523 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
524 chunk
->memblock
= NULL
;
526 /* Hmm, process any rewind request that might be queued up */
527 pa_sink_process_rewind(u
->sink
, 0);
529 //pa_log_debug("start output-buffered %ld, input-buffered %ld, requested %ld",buffered_samples,u->samples_gathered,samples_requested);
530 pa_rtclock_get(&start
);
532 size_t input_remaining
= u
->window_size
- u
->samples_gathered
;
533 pa_assert(input_remaining
> 0);
536 //buffer = &u->conv_buffer;
537 //buffer->length = input_remaining*fs;
539 //pa_memblock_ref(buffer->memblock);
540 //pa_sink_render_into(u->sink, buffer);
541 while(pa_memblockq_peek(u
->input_q
, &tchunk
) < 0){
542 pa_sink_render(u
->sink
, input_remaining
*fs
, &tchunk
);
543 //pa_sink_render_full(u->sink, input_remaining*fs, &tchunk);
544 pa_assert(tchunk
.memblock
);
545 pa_memblockq_push(u
->input_q
, &tchunk
);
546 pa_memblock_unref(tchunk
.memblock
);
548 pa_assert(tchunk
.memblock
);
549 tchunk
.length
= PA_MIN(input_remaining
* fs
, tchunk
.length
);
550 pa_memblockq_drop(u
->input_q
, tchunk
.length
);
551 //pa_log_debug("asked for %ld input samples, got %ld samples",input_remaining,buffer->length/fs);
553 //pa_rtclock_get(start);
554 if(u
->first_iteration
){
555 initialize_buffer(u
, &tchunk
);
557 input_buffer(u
, &tchunk
);
559 //pa_rtclock_get(&end);
560 //pa_log_debug("Took %0.5f seconds to setup", pa_timeval_diff(end, start) / (double) PA_USEC_PER_SEC);
561 pa_memblock_unref(tchunk
.memblock
);
562 }while(u
->samples_gathered
< u
->window_size
);
563 pa_rtclock_get(&end
);
564 pa_log_debug("Took %0.6f seconds to get data", (double) pa_timeval_diff(&end
, &start
) / PA_USEC_PER_SEC
);
566 pa_assert(u
->fft_size
>= u
->window_size
);
567 pa_assert(u
->R
< u
->window_size
);
568 /* set the H filter */
569 pa_rtclock_get(&start
);
570 /* process a block */
571 process_samples(u
, chunk
);
572 pa_rtclock_get(&end
);
573 pa_log_debug("Took %0.6f seconds to process", (double) pa_timeval_diff(&end
, &start
) / PA_USEC_PER_SEC
);
575 pa_assert(chunk
->memblock
);
576 //pa_log_debug("gave %ld", chunk->length/fs);
577 //pa_log_debug("end pop");
578 if(u
->first_iteration
){
579 u
->first_iteration
= FALSE
;
584 static void reset_filter(struct userdata
*u
){
585 u
->samples_gathered
= 0;
586 for(size_t i
= 0;i
< u
->channels
; ++i
){
587 memset(u
->overlap_accum
[i
], 0, u
->overlap_size
* sizeof(float));
589 u
->first_iteration
= TRUE
;
592 /* Called from I/O thread context */
593 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
597 pa_log_debug("Rewind callback!");
598 pa_sink_input_assert_ref(i
);
599 pa_assert_se(u
= i
->userdata
);
601 if (u
->sink
->thread_info
.rewind_nbytes
> 0) {
604 //max_rewrite = nbytes;
605 max_rewrite
= nbytes
+ pa_memblockq_get_length(u
->input_q
);
606 //PA_MIN(pa_memblockq_get_length(u->input_q), nbytes);
607 amount
= PA_MIN(u
->sink
->thread_info
.rewind_nbytes
, max_rewrite
);
608 u
->sink
->thread_info
.rewind_nbytes
= 0;
611 //pa_sample_spec *ss = &u->sink->sample_spec;
612 //invalidate the output q
613 pa_memblockq_seek(u
->input_q
, - (int64_t) amount
, PA_SEEK_RELATIVE
, TRUE
);
614 //pa_memblockq_drop(u->input_q, pa_memblockq_get_length(u->input_q));
615 //pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
616 pa_log("Resetting filter");
621 pa_sink_process_rewind(u
->sink
, amount
);
622 pa_memblockq_rewind(u
->input_q
, nbytes
);
625 /* Called from I/O thread context */
626 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
629 pa_sink_input_assert_ref(i
);
630 pa_assert_se(u
= i
->userdata
);
632 pa_memblockq_set_maxrewind(u
->input_q
, nbytes
);
633 pa_sink_set_max_rewind_within_thread(u
->sink
, nbytes
);
636 /* Called from I/O thread context */
637 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
640 pa_sink_input_assert_ref(i
);
641 pa_assert_se(u
= i
->userdata
);
643 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
644 //pa_sink_set_max_request_within_thread(u->sink, nbytes);
645 //pa_sink_set_max_request_within_thread(u->sink, u->R*fs);
646 pa_sink_set_max_request_within_thread(u
->sink
, ((nbytes
+u
->R
*fs
-1)/(u
->R
*fs
))*(u
->R
*fs
));
649 /* Called from I/O thread context */
650 static void sink_input_update_sink_latency_range_cb(pa_sink_input
*i
) {
653 pa_sink_input_assert_ref(i
);
654 pa_assert_se(u
= i
->userdata
);
656 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs);
657 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs );
658 pa_sink_set_latency_range_within_thread(u
->sink
, i
->sink
->thread_info
.min_latency
, i
->sink
->thread_info
.max_latency
);
661 /* Called from I/O thread context */
662 static void sink_input_update_sink_fixed_latency_cb(pa_sink_input
*i
) {
665 pa_sink_input_assert_ref(i
);
666 pa_assert_se(u
= i
->userdata
);
668 pa_sink_set_fixed_latency_within_thread(u
->sink
, i
->sink
->thread_info
.fixed_latency
);
671 /* Called from I/O thread context */
672 static void sink_input_detach_cb(pa_sink_input
*i
) {
675 pa_sink_input_assert_ref(i
);
676 pa_assert_se(u
= i
->userdata
);
678 pa_sink_detach_within_thread(u
->sink
);
680 pa_sink_set_rtpoll(u
->sink
, NULL
);
683 /* Called from I/O thread context */
684 static void sink_input_attach_cb(pa_sink_input
*i
) {
687 pa_sink_input_assert_ref(i
);
688 pa_assert_se(u
= i
->userdata
);
690 pa_sink_set_rtpoll(u
->sink
, i
->sink
->thread_info
.rtpoll
);
691 pa_sink_set_latency_range_within_thread(u
->sink
, i
->sink
->thread_info
.min_latency
, i
->sink
->thread_info
.max_latency
);
693 pa_sink_set_fixed_latency_within_thread(u
->sink
, i
->sink
->thread_info
.fixed_latency
);
694 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
695 pa_sink_set_max_request_within_thread(u
->sink
, PA_ROUND_UP(pa_sink_input_get_max_request(i
), u
->R
*fs
));
697 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs);
698 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->master->thread_info.max_latency);
699 //TODO: setting this guy minimizes drop outs but doesn't get rid
700 //of them completely, figure out why
701 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs);
702 //TODO: this guy causes dropouts constantly+rewinds, it's unusable
703 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->master->thread_info.max_latency);
704 pa_sink_attach_within_thread(u
->sink
);
706 pa_namereg_set_default_sink(u
->module
->core
, u
->sink
);
710 /* Called from main context */
711 static void sink_input_kill_cb(pa_sink_input
*i
) {
714 pa_sink_input_assert_ref(i
);
715 pa_assert_se(u
= i
->userdata
);
717 /* The order here matters! We first kill the sink input, followed
718 * by the sink. That means the sink callbacks must be protected
719 * against an unconnected sink input! */
720 pa_sink_input_unlink(u
->sink_input
);
721 pa_sink_unlink(u
->sink
);
723 pa_sink_input_unref(u
->sink_input
);
724 u
->sink_input
= NULL
;
726 pa_sink_unref(u
->sink
);
729 pa_module_unload_request(u
->module
, TRUE
);
732 /* Called from IO thread context */
733 static void sink_input_state_change_cb(pa_sink_input
*i
, pa_sink_input_state_t state
) {
736 pa_sink_input_assert_ref(i
);
737 pa_assert_se(u
= i
->userdata
);
739 /* If we are added for the first time, ask for a rewinding so that
740 * we are heard right-away. */
741 if (PA_SINK_INPUT_IS_LINKED(state
) &&
742 i
->thread_info
.state
== PA_SINK_INPUT_INIT
) {
743 pa_log_debug("Requesting rewind due to state change.");
744 pa_sink_input_request_rewind(i
, 0, FALSE
, TRUE
, TRUE
);
748 static void save_profile(struct userdata
*u
, size_t channel
, char *name
){
750 const size_t profile_size
= CHANNEL_PROFILE_SIZE
* sizeof(float);
751 float *H_n
, *profile
;
754 profile
= pa_xnew0(float, profile_size
);
755 a_i
= pa_aupdate_read_begin(u
->a_H
[channel
]);
756 profile
[0] = u
->Xs
[a_i
][channel
];
757 H
= u
->Hs
[channel
][a_i
];
759 for(size_t i
= 0 ; i
<= FILTER_SIZE
; ++i
){
760 H_n
[i
] = H
[i
] * u
->fft_size
;
763 pa_aupdate_read_end(u
->a_H
[channel
]);
765 key
.size
= strlen(key
.data
);
767 data
.size
= profile_size
;
768 pa_database_set(u
->database
, &key
, &data
, TRUE
);
769 pa_database_sync(u
->database
);
772 static void save_state(struct userdata
*u
){
774 const size_t state_size
= STATE_SIZE
* sizeof(float);
778 pa_database
*database
;
780 char *state_name
= u
->name
;
781 state
= pa_xnew0(float, STATE_SIZE
);
783 for(size_t c
= 0; c
< u
->channels
; ++c
){
784 a_i
= pa_aupdate_read_begin(u
->a_H
[c
]);
785 state
[c
* CHANNEL_PROFILE_SIZE
] = u
->Xs
[a_i
][c
];
787 H_n
= state
+ c
* CHANNEL_PROFILE_SIZE
+ 1;
788 memcpy(H_n
, H
, FILTER_SIZE
* sizeof(float));
789 pa_aupdate_read_end(u
->a_H
[c
]);
792 key
.data
= state_name
;
793 key
.size
= strlen(key
.data
);
795 data
.size
= state_size
;
796 //thread safety for 0.9.17?
797 pa_assert_se(dbname
= pa_state_path(EQ_STATE_DB
, TRUE
));
798 pa_assert_se(database
= pa_database_open(dbname
, TRUE
));
801 pa_database_set(database
, &key
, &data
, TRUE
);
802 pa_database_sync(database
);
803 pa_database_close(database
);
807 static void remove_profile(pa_core
*c
, char *name
){
809 pa_database
*database
;
811 key
.size
= strlen(key
.data
);
812 pa_assert_se(database
= pa_shared_get(c
, EQDB
));
813 pa_database_unset(database
, &key
);
814 pa_database_sync(database
);
817 static const char* load_profile(struct userdata
*u
, size_t channel
, char *name
){
820 const size_t profile_size
= CHANNEL_PROFILE_SIZE
* sizeof(float);
822 key
.size
= strlen(key
.data
);
823 if(pa_database_get(u
->database
, &key
, &value
) != NULL
){
824 if(value
.size
== profile_size
){
825 float *profile
= (float *) value
.data
;
826 a_i
= pa_aupdate_write_begin(u
->a_H
[channel
]);
827 u
->Xs
[channel
][a_i
] = profile
[0];
828 memcpy(u
->Hs
[channel
][a_i
], profile
+ 1, CHANNEL_PROFILE_SIZE
* sizeof(float));
829 fix_filter(u
->Hs
[channel
][a_i
], u
->fft_size
);
830 pa_aupdate_write_end(u
->a_H
[channel
]);
832 return "incompatible size";
834 pa_datum_free(&value
);
836 return "profile doesn't exist";
841 static void load_state(struct userdata
*u
){
845 pa_database
*database
;
847 char *state_name
= u
->name
;
849 pa_assert_se(dbname
= pa_state_path(EQ_STATE_DB
, FALSE
));
850 database
= pa_database_open(dbname
, FALSE
);
856 key
.data
= state_name
;
857 key
.size
= strlen(key
.data
);
859 if(pa_database_get(database
, &key
, &value
) != NULL
){
860 size_t states
= PA_MIN(value
.size
/ (CHANNEL_PROFILE_SIZE
* sizeof(float)), u
->channels
);
861 float *state
= (float *) value
.data
;
862 for(size_t c
= 0; c
< states
; ++c
){
863 a_i
= pa_aupdate_write_begin(u
->a_H
[c
]);
864 H
= state
+ c
* CHANNEL_PROFILE_SIZE
+ 1;
865 u
->Xs
[c
][a_i
] = state
[c
* CHANNEL_PROFILE_SIZE
];
866 memcpy(u
->Hs
[c
][a_i
], H
, FILTER_SIZE
* sizeof(float));
867 pa_aupdate_write_end(u
->a_H
[c
]);
869 pa_datum_free(&value
);
871 pa_database_close(database
);
874 /* Called from main context */
875 static pa_bool_t
sink_input_may_move_to_cb(pa_sink_input
*i
, pa_sink
*dest
) {
878 pa_sink_input_assert_ref(i
);
879 pa_assert_se(u
= i
->userdata
);
881 return u
->sink
!= dest
;
884 /* Called from main context */
885 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
888 pa_sink_input_assert_ref(i
);
889 pa_assert_se(u
= i
->userdata
);
891 pa_sink_set_asyncmsgq(u
->sink
, dest
->asyncmsgq
);
892 pa_sink_update_flags(u
->sink
, PA_SINK_LATENCY
|PA_SINK_DYNAMIC_LATENCY
, dest
->flags
);
895 //ensure's memory allocated is a multiple of v_size
897 static void * alloc(size_t x
,size_t s
){
898 size_t f
= PA_ROUND_UP(x
*s
, sizeof(float)*v_size
);
901 //printf("requested %ld floats=%ld bytes, rem=%ld\n", x, x*sizeof(float), x*sizeof(float)%16);
902 //printf("giving %ld floats=%ld bytes, rem=%ld\n", f, f*sizeof(float), f*sizeof(float)%16);
908 int pa__init(pa_module
*m
) {
915 pa_sink_input_new_data sink_input_data
;
916 pa_sink_new_data sink_data
;
917 pa_bool_t
*use_default
= NULL
;
924 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
925 pa_log("Failed to parse module arguments.");
929 if (!(master
= pa_namereg_get(m
->core
, pa_modargs_get_value(ma
, "master", NULL
), PA_NAMEREG_SINK
))) {
930 pa_log("Master sink not found, trying default");
931 master
= pa_namereg_get_default_sink(m
->core
);
933 pa_log("no default sink found!");
938 ss
= master
->sample_spec
;
939 ss
.format
= PA_SAMPLE_FLOAT32
;
940 map
= master
->channel_map
;
941 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
942 pa_log("Invalid sample format specification or channel map");
945 fs
= pa_frame_size(&ss
);
947 u
= pa_xnew0(struct userdata
, 1);
951 u
->set_default
= TRUE
;
952 u
->set_default
= pa_modargs_get_value_boolean(ma
, "set_default", &u
->set_default
);
954 u
->channels
= ss
.channels
;
955 u
->fft_size
= pow(2, ceil(log(ss
.rate
)/log(2)));
956 pa_log_debug("fft size: %ld", u
->fft_size
);
957 u
->window_size
= 15999;
958 u
->R
= (u
->window_size
+ 1) / 2;
959 u
->overlap_size
= u
->window_size
- u
->R
;
960 u
->samples_gathered
= 0;
961 u
->a_H
= pa_xnew0(pa_aupdate
*, u
->channels
);
962 u
->latency
= u
->window_size
- u
->R
;
963 u
->Xs
= pa_xnew0(float *, u
->channels
);
964 u
->Hs
= pa_xnew0(float **, u
->channels
);
965 for(size_t c
= 0; c
< u
->channels
; ++c
){
966 u
->Xs
[c
] = pa_xnew0(float, 2);
967 u
->Hs
[c
] = pa_xnew0(float *, 2);
968 for(size_t i
= 0; i
< 2; ++i
){
969 u
->Hs
[c
][i
] = alloc((FILTER_SIZE
), sizeof(float));
972 u
->W
= alloc(u
->window_size
, sizeof(float));
973 u
->work_buffer
= alloc(u
->fft_size
, sizeof(float));
974 memset(u
->work_buffer
, 0, u
->fft_size
*sizeof(float));
975 u
->input
= pa_xnew0(float *, u
->channels
);
976 u
->overlap_accum
= pa_xnew0(float *, u
->channels
);
977 for(size_t c
= 0; c
< u
->channels
; ++c
){
978 u
->a_H
[c
] = pa_aupdate_new();
979 u
->input
[c
] = alloc(u
->window_size
, sizeof(float));
980 memset(u
->input
[c
], 0, (u
->window_size
)*sizeof(float));
981 u
->overlap_accum
[c
] = alloc(u
->overlap_size
, sizeof(float));
982 memset(u
->overlap_accum
[c
], 0, u
->overlap_size
*sizeof(float));
984 u
->output_window
= alloc((FILTER_SIZE
), sizeof(fftwf_complex
));
985 u
->forward_plan
= fftwf_plan_dft_r2c_1d(u
->fft_size
, u
->work_buffer
, u
->output_window
, FFTW_ESTIMATE
);
986 u
->inverse_plan
= fftwf_plan_dft_c2r_1d(u
->fft_size
, u
->output_window
, u
->work_buffer
, FFTW_ESTIMATE
);
988 hanning_window(u
->W
, u
->window_size
);
989 u
->first_iteration
= TRUE
;
992 pa_sink_new_data_init(&sink_data
);
993 sink_data
.driver
= __FILE__
;
994 sink_data
.module
= m
;
995 if (!(sink_data
.name
= pa_xstrdup(pa_modargs_get_value(ma
, "sink_name", NULL
))))
996 sink_data
.name
= pa_sprintf_malloc("%s.equalizer", master
->name
);
997 pa_sink_new_data_set_sample_spec(&sink_data
, &ss
);
998 pa_sink_new_data_set_channel_map(&sink_data
, &map
);
999 z
= pa_proplist_gets(master
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
1000 pa_proplist_setf(sink_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "FFT based equalizer on %s",z
? z
: master
->name
);
1001 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_MASTER_DEVICE
, master
->name
);
1002 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_CLASS
, "filter");
1004 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
1005 pa_log("Invalid properties");
1006 pa_sink_new_data_done(&sink_data
);
1010 u
->sink
= pa_sink_new(m
->core
, &sink_data
, master
->flags
& (PA_SINK_LATENCY
|PA_SINK_DYNAMIC_LATENCY
));
1011 pa_sink_new_data_done(&sink_data
);
1014 pa_log("Failed to create sink.");
1017 u
->name
=pa_xstrdup(u
->sink
->name
);
1018 u
->sink
->parent
.process_msg
= sink_process_msg
;
1019 u
->sink
->set_state
= sink_set_state
;
1020 u
->sink
->update_requested_latency
= sink_update_requested_latency
;
1021 u
->sink
->request_rewind
= sink_request_rewind
;
1022 u
->sink
->userdata
= u
;
1023 u
->input_q
= pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH
, 0, fs
, 1, 1, 0, &u
->sink
->silence
);
1025 pa_sink_set_asyncmsgq(u
->sink
, master
->asyncmsgq
);
1026 //pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->R*fs, &ss));
1028 /* Create sink input */
1029 pa_sink_input_new_data_init(&sink_input_data
);
1030 sink_input_data
.driver
= __FILE__
;
1031 sink_input_data
.module
= m
;
1032 sink_input_data
.sink
= master
;
1033 pa_proplist_sets(sink_input_data
.proplist
, PA_PROP_MEDIA_NAME
, "Equalized Stream");
1034 pa_proplist_sets(sink_input_data
.proplist
, PA_PROP_MEDIA_ROLE
, "filter");
1035 pa_sink_input_new_data_set_sample_spec(&sink_input_data
, &ss
);
1036 pa_sink_input_new_data_set_channel_map(&sink_input_data
, &map
);
1038 pa_sink_input_new(&u
->sink_input
, m
->core
, &sink_input_data
, 0);
1039 pa_sink_input_new_data_done(&sink_input_data
);
1044 u
->sink_input
->pop
= sink_input_pop_cb
;
1045 u
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
1046 u
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
1047 u
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
1048 u
->sink_input
->update_sink_latency_range
= sink_input_update_sink_latency_range_cb
;
1049 u
->sink_input
->update_sink_fixed_latency
= sink_input_update_sink_fixed_latency_cb
;
1050 u
->sink_input
->kill
= sink_input_kill_cb
;
1051 u
->sink_input
->attach
= sink_input_attach_cb
;
1052 u
->sink_input
->detach
= sink_input_detach_cb
;
1053 u
->sink_input
->state_change
= sink_input_state_change_cb
;
1054 u
->sink_input
->may_move_to
= sink_input_may_move_to_cb
;
1055 u
->sink_input
->moving
= sink_input_moving_cb
;
1056 u
->sink_input
->userdata
= u
;
1058 pa_sink_put(u
->sink
);
1059 pa_sink_input_put(u
->sink_input
);
1061 pa_modargs_free(ma
);
1063 pa_xfree(use_default
);
1067 //default filter to these
1068 for(size_t c
= 0; c
< u
->channels
; ++c
){
1069 a_i
= pa_aupdate_write_begin(u
->a_H
[c
]);
1071 u
->Xs
[c
][a_i
] = 1.0f
;
1072 for(size_t i
= 0; i
< FILTER_SIZE
; ++i
){
1073 H
[i
] = 1.0 / sqrtf(2.0f
);
1075 fix_filter(H
, u
->fft_size
);
1076 pa_aupdate_write_end(u
->a_H
[c
]);
1078 //load old parameters
1085 pa_modargs_free(ma
);
1087 pa_xfree(use_default
);
1094 int pa__get_n_used(pa_module
*m
) {
1098 pa_assert_se(u
= m
->userdata
);
1100 return pa_sink_linked_by(u
->sink
);
1103 void pa__done(pa_module
*m
) {
1108 if (!(u
= m
->userdata
))
1115 /* See comments in sink_input_kill_cb() above regarding
1116 * destruction order! */
1119 pa_sink_input_unlink(u
->sink_input
);
1122 pa_sink_unlink(u
->sink
);
1125 pa_sink_input_unref(u
->sink_input
);
1128 pa_sink_unref(u
->sink
);
1130 pa_memblockq_free(u
->input_q
);
1132 fftwf_destroy_plan(u
->inverse_plan
);
1133 fftwf_destroy_plan(u
->forward_plan
);
1134 pa_xfree(u
->output_window
);
1135 for(size_t c
=0; c
< u
->channels
; ++c
){
1136 pa_aupdate_free(u
->a_H
[c
]);
1137 pa_xfree(u
->overlap_accum
[c
]);
1138 pa_xfree(u
->input
[c
]);
1141 pa_xfree(u
->overlap_accum
);
1143 pa_xfree(u
->work_buffer
);
1145 for(size_t c
= 0; c
< u
->channels
; ++c
){
1147 for(size_t i
= 0; i
< 2; ++i
){
1148 pa_xfree(u
->Hs
[c
][i
]);
1161 * DBus Routines and Callbacks
1163 #define EXTNAME "org.PulseAudio.Ext.Equalizing1"
1164 #define MANAGER_PATH "/org/pulseaudio/equalizing1"
1165 #define MANAGER_IFACE EXTNAME ".Manager"
1166 #define EQUALIZER_IFACE EXTNAME ".Equalizer"
1167 static void manager_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1168 static void manager_get_sinks(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1169 static void manager_get_profiles(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1170 static void manager_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1171 static void manager_handle_remove_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1172 static void equalizer_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1173 static void equalizer_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1174 static void equalizer_get_filter_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1175 static void equalizer_get_n_coefs(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1176 static void equalizer_get_n_channels(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1177 static void equalizer_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1178 static void equalizer_handle_seed_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1179 static void equalizer_handle_get_filter_points(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1180 static void equalizer_handle_get_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1181 static void equalizer_handle_set_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1182 static void equalizer_handle_save_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1183 static void equalizer_handle_load_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1184 enum manager_method_index
{
1185 MANAGER_METHOD_REMOVE_PROFILE
,
1189 pa_dbus_arg_info remove_profile_args
[]={
1193 static pa_dbus_method_handler manager_methods
[MANAGER_METHOD_MAX
]={
1194 [MANAGER_METHOD_REMOVE_PROFILE
]{
1195 .method_name
="RemoveProfile",
1196 .arguments
=remove_profile_args
,
1197 .n_arguments
=sizeof(remove_profile_args
)/sizeof(pa_dbus_arg_info
),
1198 .receive_cb
=manager_handle_remove_profile
}
1201 enum manager_handler_index
{
1202 MANAGER_HANDLER_REVISION
,
1203 MANAGER_HANDLER_EQUALIZED_SINKS
,
1204 MANAGER_HANDLER_PROFILES
,
1208 static pa_dbus_property_handler manager_handlers
[MANAGER_HANDLER_MAX
]={
1209 [MANAGER_HANDLER_REVISION
]={.property_name
="InterfaceRevision",.type
="u",.get_cb
=manager_get_revision
,.set_cb
=NULL
},
1210 [MANAGER_HANDLER_EQUALIZED_SINKS
]={.property_name
="EqualizedSinks",.type
="ao",.get_cb
=manager_get_sinks
,.set_cb
=NULL
},
1211 [MANAGER_HANDLER_PROFILES
]={.property_name
="Profiles",.type
="as",.get_cb
=manager_get_profiles
,.set_cb
=NULL
}
1214 pa_dbus_arg_info sink_args
[]={
1218 enum manager_signal_index
{
1219 MANAGER_SIGNAL_SINK_ADDED
,
1220 MANAGER_SIGNAL_SINK_REMOVED
,
1221 MANAGER_SIGNAL_PROFILES_CHANGED
,
1225 static pa_dbus_signal_info manager_signals
[MANAGER_SIGNAL_MAX
]={
1226 [MANAGER_SIGNAL_SINK_ADDED
]={.name
="SinkAdded", .arguments
=sink_args
, .n_arguments
=sizeof(sink_args
)/sizeof(pa_dbus_arg_info
)},
1227 [MANAGER_SIGNAL_SINK_REMOVED
]={.name
="SinkRemoved", .arguments
=sink_args
, .n_arguments
=sizeof(sink_args
)/sizeof(pa_dbus_arg_info
)},
1228 [MANAGER_SIGNAL_PROFILES_CHANGED
]={.name
="ProfilesChanged", .arguments
=NULL
, .n_arguments
=0}
1231 static pa_dbus_interface_info manager_info
={
1232 .name
=MANAGER_IFACE
,
1233 .method_handlers
=manager_methods
,
1234 .n_method_handlers
=MANAGER_METHOD_MAX
,
1235 .property_handlers
=manager_handlers
,
1236 .n_property_handlers
=MANAGER_HANDLER_MAX
,
1237 .get_all_properties_cb
=manager_get_all
,
1238 .signals
=manager_signals
,
1239 .n_signals
=MANAGER_SIGNAL_MAX
1242 enum equalizer_method_index
{
1243 EQUALIZER_METHOD_FILTER_POINTS
,
1244 EQUALIZER_METHOD_SEED_FILTER
,
1245 EQUALIZER_METHOD_SAVE_PROFILE
,
1246 EQUALIZER_METHOD_LOAD_PROFILE
,
1247 EQUALIZER_METHOD_SET_FILTER
,
1248 EQUALIZER_METHOD_GET_FILTER
,
1249 EQUALIZER_METHOD_MAX
1252 enum equalizer_handler_index
{
1253 EQUALIZER_HANDLER_REVISION
,
1254 EQUALIZER_HANDLER_SAMPLERATE
,
1255 EQUALIZER_HANDLER_FILTERSAMPLERATE
,
1256 EQUALIZER_HANDLER_N_COEFS
,
1257 EQUALIZER_HANDLER_N_CHANNELS
,
1258 EQUALIZER_HANDLER_MAX
1261 pa_dbus_arg_info filter_points_args
[]={
1262 {"channel", "u","in"},
1265 {"preamp", "d","out"}
1267 pa_dbus_arg_info seed_filter_args
[]={
1268 {"channel", "u","in"},
1271 {"preamp", "d","in"}
1274 pa_dbus_arg_info set_filter_args
[]={
1275 {"channel", "u","in"},
1277 {"preamp", "d","in"}
1279 pa_dbus_arg_info get_filter_args
[]={
1280 {"channel", "u","in"},
1282 {"preamp", "d","out"}
1285 pa_dbus_arg_info save_profile_args
[]={
1286 {"channel", "u","in"},
1289 pa_dbus_arg_info load_profile_args
[]={
1290 {"channel", "u","in"},
1294 static pa_dbus_method_handler equalizer_methods
[EQUALIZER_METHOD_MAX
]={
1295 [EQUALIZER_METHOD_SEED_FILTER
]{
1296 .method_name
="SeedFilter",
1297 .arguments
=seed_filter_args
,
1298 .n_arguments
=sizeof(seed_filter_args
)/sizeof(pa_dbus_arg_info
),
1299 .receive_cb
=equalizer_handle_seed_filter
},
1300 [EQUALIZER_METHOD_FILTER_POINTS
]{
1301 .method_name
="FilterAtPoints",
1302 .arguments
=filter_points_args
,
1303 .n_arguments
=sizeof(filter_points_args
)/sizeof(pa_dbus_arg_info
),
1304 .receive_cb
=equalizer_handle_get_filter_points
},
1305 [EQUALIZER_METHOD_SET_FILTER
]{
1306 .method_name
="SetFilter",
1307 .arguments
=set_filter_args
,
1308 .n_arguments
=sizeof(set_filter_args
)/sizeof(pa_dbus_arg_info
),
1309 .receive_cb
=equalizer_handle_set_filter
},
1310 [EQUALIZER_METHOD_GET_FILTER
]{
1311 .method_name
="GetFilter",
1312 .arguments
=get_filter_args
,
1313 .n_arguments
=sizeof(get_filter_args
)/sizeof(pa_dbus_arg_info
),
1314 .receive_cb
=equalizer_handle_get_filter
},
1315 [EQUALIZER_METHOD_SAVE_PROFILE
]{
1316 .method_name
="SaveProfile",
1317 .arguments
=save_profile_args
,
1318 .n_arguments
=sizeof(save_profile_args
)/sizeof(pa_dbus_arg_info
),
1319 .receive_cb
=equalizer_handle_save_profile
},
1320 [EQUALIZER_METHOD_LOAD_PROFILE
]{
1321 .method_name
="LoadProfile",
1322 .arguments
=load_profile_args
,
1323 .n_arguments
=sizeof(load_profile_args
)/sizeof(pa_dbus_arg_info
),
1324 .receive_cb
=equalizer_handle_load_profile
}
1327 static pa_dbus_property_handler equalizer_handlers
[EQUALIZER_HANDLER_MAX
]={
1328 [EQUALIZER_HANDLER_REVISION
]={.property_name
="InterfaceRevision",.type
="u",.get_cb
=equalizer_get_revision
,.set_cb
=NULL
},
1329 [EQUALIZER_HANDLER_SAMPLERATE
]{.property_name
="SampleRate",.type
="u",.get_cb
=equalizer_get_sample_rate
,.set_cb
=NULL
},
1330 [EQUALIZER_HANDLER_FILTERSAMPLERATE
]{.property_name
="FilterSampleRate",.type
="u",.get_cb
=equalizer_get_filter_rate
,.set_cb
=NULL
},
1331 [EQUALIZER_HANDLER_N_COEFS
]{.property_name
="NFilterCoefficients",.type
="u",.get_cb
=equalizer_get_n_coefs
,.set_cb
=NULL
},
1332 [EQUALIZER_HANDLER_N_CHANNELS
]{.property_name
="NChannels",.type
="u",.get_cb
=equalizer_get_n_channels
,.set_cb
=NULL
},
1335 enum equalizer_signal_index
{
1336 EQUALIZER_SIGNAL_FILTER_CHANGED
,
1337 EQUALIZER_SIGNAL_SINK_RECONFIGURED
,
1338 EQUALIZER_SIGNAL_MAX
1341 static pa_dbus_signal_info equalizer_signals
[EQUALIZER_SIGNAL_MAX
]={
1342 [EQUALIZER_SIGNAL_FILTER_CHANGED
]={.name
="FilterChanged", .arguments
=NULL
, .n_arguments
=0},
1343 [EQUALIZER_SIGNAL_SINK_RECONFIGURED
]={.name
="SinkReconfigured", .arguments
=NULL
, .n_arguments
=0},
1346 static pa_dbus_interface_info equalizer_info
={
1347 .name
=EQUALIZER_IFACE
,
1348 .method_handlers
=equalizer_methods
,
1349 .n_method_handlers
=EQUALIZER_METHOD_MAX
,
1350 .property_handlers
=equalizer_handlers
,
1351 .n_property_handlers
=EQUALIZER_HANDLER_MAX
,
1352 .get_all_properties_cb
=equalizer_get_all
,
1353 .signals
=equalizer_signals
,
1354 .n_signals
=EQUALIZER_SIGNAL_MAX
1357 void dbus_init(struct userdata
*u
){
1359 DBusMessage
*signal
= NULL
;
1360 pa_idxset
*sink_list
= NULL
;
1361 u
->dbus_protocol
=pa_dbus_protocol_get(u
->sink
->core
);
1362 u
->dbus_path
=pa_sprintf_malloc("/org/pulseaudio/core1/sink%d", u
->sink
->index
);
1364 pa_dbus_protocol_add_interface(u
->dbus_protocol
, u
->dbus_path
, &equalizer_info
, u
);
1365 sink_list
= pa_shared_get(u
->sink
->core
, SINKLIST
);
1366 u
->database
= pa_shared_get(u
->sink
->core
, EQDB
);
1367 if(sink_list
== NULL
){
1369 sink_list
=pa_idxset_new(&pa_idxset_trivial_hash_func
, &pa_idxset_trivial_compare_func
);
1370 pa_shared_set(u
->sink
->core
, SINKLIST
, sink_list
);
1371 pa_assert_se(dbname
= pa_state_path("equalizer-presets", FALSE
));
1372 pa_assert_se(u
->database
= pa_database_open(dbname
, TRUE
));
1374 pa_shared_set(u
->sink
->core
, EQDB
, u
->database
);
1375 pa_dbus_protocol_add_interface(u
->dbus_protocol
, MANAGER_PATH
, &manager_info
, u
->sink
->core
);
1376 pa_dbus_protocol_register_extension(u
->dbus_protocol
, EXTNAME
);
1378 pa_idxset_put(sink_list
, u
, &dummy
);
1380 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_SINK_ADDED
].name
)));
1381 dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &u
->dbus_path
, DBUS_TYPE_INVALID
);
1382 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1383 dbus_message_unref(signal
);
1386 void dbus_done(struct userdata
*u
){
1387 pa_idxset
*sink_list
;
1390 DBusMessage
*signal
= NULL
;
1391 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_SINK_REMOVED
].name
)));
1392 dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &u
->dbus_path
, DBUS_TYPE_INVALID
);
1393 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1394 dbus_message_unref(signal
);
1396 pa_assert_se(sink_list
=pa_shared_get(u
->sink
->core
,SINKLIST
));
1397 pa_idxset_remove_by_data(sink_list
,u
,&dummy
);
1398 if(pa_idxset_size(sink_list
)==0){
1399 pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, EXTNAME
);
1400 pa_dbus_protocol_remove_interface(u
->dbus_protocol
, MANAGER_PATH
, manager_info
.name
);
1401 pa_shared_remove(u
->sink
->core
, EQDB
);
1402 pa_database_close(u
->database
);
1403 pa_shared_remove(u
->sink
->core
, SINKLIST
);
1404 pa_xfree(sink_list
);
1406 pa_dbus_protocol_remove_interface(u
->dbus_protocol
, u
->dbus_path
, equalizer_info
.name
);
1407 pa_xfree(u
->dbus_path
);
1408 pa_dbus_protocol_unref(u
->dbus_protocol
);
1411 void manager_handle_remove_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1413 pa_core
*c
= (pa_core
*)_u
;
1414 DBusMessage
*signal
= NULL
;
1415 pa_dbus_protocol
*dbus_protocol
;
1420 dbus_error_init(&error
);
1421 if(!dbus_message_get_args(msg
, &error
,
1422 DBUS_TYPE_STRING
, &name
,
1423 DBUS_TYPE_INVALID
)){
1424 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1425 dbus_error_free(&error
);
1428 remove_profile(c
,name
);
1429 pa_dbus_send_empty_reply(conn
, msg
);
1431 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_PROFILES_CHANGED
].name
)));
1432 dbus_protocol
= pa_dbus_protocol_get(c
);
1433 pa_dbus_protocol_send_signal(dbus_protocol
, signal
);
1434 pa_dbus_protocol_unref(dbus_protocol
);
1435 dbus_message_unref(signal
);
1438 void manager_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1440 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rev
);
1443 static void get_sinks(pa_core
*u
, char ***names
, unsigned *n_sinks
){
1445 struct userdata
*sink_u
= NULL
;
1447 pa_idxset
*sink_list
;
1452 pa_assert_se(sink_list
= pa_shared_get(u
, SINKLIST
));
1453 *n_sinks
= (unsigned) pa_idxset_size(sink_list
);
1454 *names
= *n_sinks
> 0 ? pa_xnew0(char *,*n_sinks
) : NULL
;
1455 for(uint32_t i
= 0; i
< *n_sinks
; ++i
){
1456 sink_u
= (struct userdata
*) pa_idxset_iterate(sink_list
, &iter
, &dummy
);
1457 (*names
)[i
] = pa_xstrdup(sink_u
->dbus_path
);
1461 void manager_get_sinks(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1463 char **names
= NULL
;
1468 get_sinks((pa_core
*) _u
, &names
, &n
);
1469 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, names
, n
);
1470 for(unsigned i
= 0; i
< n
; ++i
){
1476 static void get_profiles(pa_core
*c
, char ***names
, unsigned *n
){
1478 pa_database
*database
;
1479 pa_datum key
, next_key
;
1480 pa_strlist
*head
=NULL
, *iter
;
1482 pa_assert_se(database
= pa_shared_get(c
, EQDB
));
1487 done
= !pa_database_first(database
, &key
, NULL
);
1490 done
= !pa_database_next(database
, &key
, &next_key
, NULL
);
1491 name
=pa_xmalloc(key
.size
+ 1);
1492 memcpy(name
, key
.data
, key
.size
);
1493 name
[key
.size
] = '\0';
1494 pa_datum_free(&key
);
1495 head
= pa_strlist_prepend(head
, name
);
1500 (*names
) = *n
> 0 ? pa_xnew0(char *, *n
) : NULL
;
1502 for(unsigned i
= 0; i
< *n
; ++i
){
1503 (*names
)[*n
- 1 - i
] = pa_xstrdup(pa_strlist_data(iter
));
1504 iter
= pa_strlist_next(iter
);
1506 pa_strlist_free(head
);
1509 void manager_get_profiles(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1516 get_profiles((pa_core
*)_u
, &names
, &n
);
1517 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, names
, n
);
1518 for(unsigned i
= 0; i
< n
; ++i
){
1524 void manager_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1526 char **names
= NULL
;
1528 DBusMessage
*reply
= NULL
;
1529 DBusMessageIter msg_iter
, dict_iter
;
1533 pa_assert_se(c
= _u
);
1535 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1536 dbus_message_iter_init_append(reply
, &msg_iter
);
1537 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1540 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, manager_handlers
[MANAGER_HANDLER_REVISION
].property_name
, DBUS_TYPE_UINT32
, &rev
);
1542 get_sinks(c
, &names
, &n
);
1543 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
,manager_handlers
[MANAGER_HANDLER_EQUALIZED_SINKS
].property_name
, DBUS_TYPE_OBJECT_PATH
, names
, n
);
1544 for(unsigned i
= 0; i
< n
; ++i
){
1549 get_profiles(c
, &names
, &n
);
1550 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, manager_handlers
[MANAGER_HANDLER_PROFILES
].property_name
, DBUS_TYPE_STRING
, names
, n
);
1551 for(unsigned i
= 0; i
< n
; ++i
){
1555 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1556 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1557 dbus_message_unref(reply
);
1560 void equalizer_handle_seed_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1561 struct userdata
*u
=(struct userdata
*) _u
;
1563 DBusMessage
*signal
= NULL
;
1565 uint32_t *xs
, channel
, r_channel
;
1566 double *_ys
, preamp
;
1567 unsigned x_npoints
, y_npoints
, a_i
;
1569 pa_bool_t points_good
= TRUE
;
1574 dbus_error_init(&error
);
1576 if(!dbus_message_get_args(msg
, &error
,
1577 DBUS_TYPE_UINT32
, &channel
,
1578 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &xs
, &x_npoints
,
1579 DBUS_TYPE_ARRAY
, DBUS_TYPE_DOUBLE
, &_ys
, &y_npoints
,
1580 DBUS_TYPE_DOUBLE
, &preamp
,
1581 DBUS_TYPE_INVALID
)){
1582 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1583 dbus_error_free(&error
);
1586 if(channel
> u
->channels
){
1587 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "invalid channel: %d", channel
);
1588 dbus_error_free(&error
);
1591 for(size_t i
= 0; i
< x_npoints
; ++i
){
1592 if(xs
[i
] >= FILTER_SIZE
){
1593 points_good
= FALSE
;
1597 if(!is_monotonic(xs
, x_npoints
) || !points_good
){
1598 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs must be monotonic and 0<=x<=%ld", u
->fft_size
/ 2);
1599 dbus_error_free(&error
);
1601 }else if(x_npoints
!= y_npoints
|| x_npoints
< 2 || x_npoints
> FILTER_SIZE
){
1602 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs and ys must be the same length and 2<=l<=%ld!", FILTER_SIZE
);
1603 dbus_error_free(&error
);
1605 }else if(xs
[0] != 0 || xs
[x_npoints
- 1] != u
->fft_size
/ 2){
1606 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs[0] must be 0 and xs[-1]=fft_size/2");
1607 dbus_error_free(&error
);
1611 ys
= pa_xmalloc(x_npoints
* sizeof(float));
1612 for(uint32_t i
= 0; i
< x_npoints
; ++i
){
1613 ys
[i
] = (float) _ys
[i
];
1615 r_channel
= channel
== u
->channels
? 0 : channel
;
1616 a_i
= pa_aupdate_write_begin(u
->a_H
[r_channel
]);
1617 H
= u
->Hs
[r_channel
][a_i
];
1618 u
->Xs
[r_channel
][a_i
] = preamp
;
1619 interpolate(H
, FILTER_SIZE
, xs
, ys
, x_npoints
);
1620 fix_filter(H
, u
->fft_size
);
1621 if(channel
== u
->channels
){
1622 for(size_t c
= 1; c
< u
->channels
; ++c
){
1623 unsigned b_i
= pa_aupdate_write_begin(u
->a_H
[c
]);
1624 float *H_p
= u
->Hs
[c
][b_i
];
1625 u
->Xs
[c
][b_i
] = preamp
;
1626 memcpy(H_p
, H
, FILTER_SIZE
* sizeof(float));
1627 pa_aupdate_write_end(u
->a_H
[c
]);
1630 pa_aupdate_write_end(u
->a_H
[r_channel
]);
1634 //Stupid for IO reasons? Add a save signal to dbus instead
1637 pa_dbus_send_empty_reply(conn
, msg
);
1639 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1640 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1641 dbus_message_unref(signal
);
1644 void equalizer_handle_get_filter_points(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1645 struct userdata
*u
= (struct userdata
*) _u
;
1646 uint32_t *xs
, channel
, r_channel
;
1648 unsigned x_npoints
, a_i
;
1650 pa_bool_t points_good
=TRUE
;
1651 DBusMessage
*reply
= NULL
;
1652 DBusMessageIter msg_iter
;
1659 dbus_error_init(&error
);
1660 if(!dbus_message_get_args(msg
, &error
,
1661 DBUS_TYPE_UINT32
, &channel
,
1662 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &xs
, &x_npoints
,
1663 DBUS_TYPE_INVALID
)){
1664 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1665 dbus_error_free(&error
);
1668 if(channel
> u
->channels
){
1669 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "invalid channel: %d", channel
);
1670 dbus_error_free(&error
);
1674 for(size_t i
= 0; i
< x_npoints
; ++i
){
1675 if(xs
[i
] >= FILTER_SIZE
){
1681 if(x_npoints
> FILTER_SIZE
|| !points_good
){
1682 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs indices/length must be <= %ld!", FILTER_SIZE
);
1683 dbus_error_free(&error
);
1687 r_channel
= channel
== u
->channels
? 0 : channel
;
1688 ys
= pa_xmalloc(x_npoints
* sizeof(double));
1689 a_i
= pa_aupdate_read_begin(u
->a_H
[r_channel
]);
1690 H
= u
->Hs
[r_channel
][a_i
];
1691 preamp
= u
->Xs
[r_channel
][a_i
];
1692 for(uint32_t i
= 0; i
< x_npoints
; ++i
){
1693 ys
[i
] = H
[xs
[i
]] * u
->fft_size
;
1695 pa_aupdate_read_end(u
->a_H
[r_channel
]);
1697 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1698 dbus_message_iter_init_append(reply
, &msg_iter
);
1700 pa_dbus_append_basic_array(&msg_iter
, DBUS_TYPE_DOUBLE
, ys
, x_npoints
);
1701 pa_dbus_append_basic_variant(&msg_iter
, DBUS_TYPE_DOUBLE
, &preamp
);
1703 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1704 dbus_message_unref(reply
);
1708 static void get_filter(struct userdata
*u
, size_t channel
, double **H_
, double *preamp
){
1711 size_t r_channel
= channel
== u
->channels
? 0 : channel
;
1712 *H_
= pa_xnew0(double, FILTER_SIZE
);
1713 a_i
= pa_aupdate_read_begin(u
->a_H
[r_channel
]);
1714 H
= u
->Hs
[r_channel
][a_i
];
1715 for(size_t i
= 0;i
< FILTER_SIZE
; ++i
){
1716 (*H_
)[i
] = H
[i
] * u
->fft_size
;
1718 *preamp
= u
->Xs
[r_channel
][a_i
];
1720 pa_aupdate_read_end(u
->a_H
[r_channel
]);
1723 void equalizer_handle_get_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1728 DBusMessage
*reply
= NULL
;
1729 DBusMessageIter msg_iter
;
1731 pa_assert_se(u
= (struct userdata
*) _u
);
1735 dbus_error_init(&error
);
1736 if(!dbus_message_get_args(msg
, &error
,
1737 DBUS_TYPE_UINT32
, &channel
,
1738 DBUS_TYPE_INVALID
)){
1739 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1740 dbus_error_free(&error
);
1743 if(channel
> u
->channels
){
1744 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "invalid channel: %d", channel
);
1745 dbus_error_free(&error
);
1749 n_coefs
= CHANNEL_PROFILE_SIZE
;
1752 get_filter(u
, channel
, &H_
, &preamp
);
1753 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1754 dbus_message_iter_init_append(reply
, &msg_iter
);
1756 pa_dbus_append_basic_array(&msg_iter
, DBUS_TYPE_DOUBLE
, H_
, n_coefs
);
1757 pa_dbus_append_basic_variant(&msg_iter
, DBUS_TYPE_DOUBLE
, &preamp
);
1759 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1760 dbus_message_unref(reply
);
1764 static void set_filter(struct userdata
*u
, size_t channel
, double *H_
, double preamp
){
1766 size_t r_channel
= channel
== u
->channels
? 0 : channel
;
1769 a_i
= pa_aupdate_write_begin(u
->a_H
[r_channel
]);
1770 u
->Xs
[r_channel
][a_i
] = (float) preamp
;
1771 H
= u
->Hs
[r_channel
][a_i
];
1772 for(size_t i
= 0; i
< FILTER_SIZE
; ++i
){
1773 H
[i
] = (float) H_
[i
];
1775 fix_filter(H
, u
->fft_size
);
1776 if(channel
== u
->channels
){
1777 for(size_t c
= 1; c
< u
->channels
; ++c
){
1778 unsigned b_i
= pa_aupdate_write_begin(u
->a_H
[c
]);
1779 u
->Xs
[c
][b_i
] = u
->Xs
[r_channel
][a_i
];
1780 memcpy(u
->Hs
[c
][b_i
], u
->Hs
[r_channel
][a_i
], FILTER_SIZE
* sizeof(float));
1781 pa_aupdate_write_end(u
->a_H
[c
]);
1784 pa_aupdate_write_end(u
->a_H
[r_channel
]);
1787 void equalizer_handle_set_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1792 DBusMessage
*signal
= NULL
;
1794 pa_assert_se(u
= (struct userdata
*) _u
);
1798 dbus_error_init(&error
);
1799 if(!dbus_message_get_args(msg
, &error
,
1800 DBUS_TYPE_UINT32
, &channel
,
1801 DBUS_TYPE_ARRAY
, DBUS_TYPE_DOUBLE
, &H
, &_n_coefs
,
1802 DBUS_TYPE_DOUBLE
, &preamp
,
1803 DBUS_TYPE_INVALID
)){
1804 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1805 dbus_error_free(&error
);
1808 if(channel
> u
->channels
){
1809 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "invalid channel: %d", channel
);
1810 dbus_error_free(&error
);
1813 if(_n_coefs
!= FILTER_SIZE
){
1814 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "This filter takes exactly %ld coefficients, you gave %d", FILTER_SIZE
, _n_coefs
);
1817 set_filter(u
, channel
, H
, preamp
);
1819 pa_dbus_send_empty_reply(conn
, msg
);
1821 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1822 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1823 dbus_message_unref(signal
);
1826 void equalizer_handle_save_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1827 struct userdata
*u
= (struct userdata
*) _u
;
1829 uint32_t channel
, r_channel
;
1830 DBusMessage
*signal
= NULL
;
1835 dbus_error_init(&error
);
1837 if(!dbus_message_get_args(msg
, &error
,
1838 DBUS_TYPE_UINT32
, &channel
,
1839 DBUS_TYPE_STRING
, &name
,
1840 DBUS_TYPE_INVALID
)){
1841 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1842 dbus_error_free(&error
);
1845 if(channel
> u
->channels
){
1846 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "invalid channel: %d", channel
);
1847 dbus_error_free(&error
);
1850 r_channel
= channel
== u
->channels
? 0 : channel
;
1851 save_profile(u
, r_channel
, name
);
1852 pa_dbus_send_empty_reply(conn
, msg
);
1854 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_PROFILES_CHANGED
].name
)));
1855 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1856 dbus_message_unref(signal
);
1859 void equalizer_handle_load_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1860 struct userdata
*u
= (struct userdata
*) _u
;
1863 uint32_t channel
, r_channel
;
1864 const char *err_msg
= NULL
;
1865 DBusMessage
*signal
= NULL
;
1870 dbus_error_init(&error
);
1872 if(!dbus_message_get_args(msg
, &error
,
1873 DBUS_TYPE_UINT32
, &channel
,
1874 DBUS_TYPE_STRING
, &name
,
1875 DBUS_TYPE_INVALID
)){
1876 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1877 dbus_error_free(&error
);
1880 if(channel
> u
->channels
){
1881 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "invalid channel: %d", channel
);
1882 dbus_error_free(&error
);
1885 r_channel
= channel
== u
->channels
? 0 : channel
;
1887 err_msg
= load_profile(u
, r_channel
, name
);
1888 if(err_msg
!= NULL
){
1889 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
, "error loading profile %s: %s", name
, err_msg
);
1890 dbus_error_free(&error
);
1893 if(channel
== u
->channels
){
1894 for(uint32_t c
= 1; c
< u
->channels
; ++c
){
1895 load_profile(u
, c
, name
);
1898 pa_dbus_send_empty_reply(conn
, msg
);
1900 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1901 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1902 dbus_message_unref(signal
);
1905 void equalizer_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1907 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rev
);
1910 void equalizer_get_n_channels(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1913 pa_assert_se(u
= (struct userdata
*) _u
);
1917 channels
= (uint32_t) u
->channels
;
1918 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &channels
);
1921 void equalizer_get_n_coefs(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1924 pa_assert_se(u
= (struct userdata
*) _u
);
1928 n_coefs
= (uint32_t) CHANNEL_PROFILE_SIZE
;
1929 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &n_coefs
);
1932 void equalizer_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1935 pa_assert_se(u
= (struct userdata
*) _u
);
1939 rate
= (uint32_t) u
->sink
->sample_spec
.rate
;
1940 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rate
);
1943 void equalizer_get_filter_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1946 pa_assert_se(u
= (struct userdata
*) _u
);
1950 fft_size
= (uint32_t) u
->fft_size
;
1951 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &fft_size
);
1954 void equalizer_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1956 DBusMessage
*reply
= NULL
;
1957 DBusMessageIter msg_iter
, dict_iter
;
1958 uint32_t rev
, n_coefs
, rate
, fft_size
, channels
;
1959 pa_assert_se(u
= (struct userdata
*) _u
);
1963 n_coefs
= (uint32_t) CHANNEL_PROFILE_SIZE
;
1964 rate
= (uint32_t) u
->sink
->sample_spec
.rate
;
1965 fft_size
= (uint32_t) u
->fft_size
;
1966 channels
= (uint32_t) u
->channels
;
1968 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1969 dbus_message_iter_init_append(reply
, &msg_iter
);
1970 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1972 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_REVISION
].property_name
, DBUS_TYPE_UINT32
, &rev
);
1973 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_SAMPLERATE
].property_name
, DBUS_TYPE_UINT32
, &rate
);
1974 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_FILTERSAMPLERATE
].property_name
, DBUS_TYPE_UINT32
, &fft_size
);
1975 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_N_COEFS
].property_name
, DBUS_TYPE_UINT32
, &n_coefs
);
1976 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_N_CHANNELS
].property_name
, DBUS_TYPE_UINT32
, &channels
);
1978 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1979 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1980 dbus_message_unref(reply
);