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.
8 Copyright 2009 Jason Newton <nevion@gmail.com>
11 Copyright 2004-2008 Lennart Poettering
13 PulseAudio is free software; you can redistribute it and/or modify
14 it under the terms of the GNU Lesser General Public License as
15 published by the Free Software Foundation; either version 2.1 of the
16 License, or (at your option) any later version.
18 PulseAudio is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU Lesser General Public
24 License along with PulseAudio; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
42 #include <xmmintrin.h>
43 #include <emmintrin.h>
48 #include <pulse/xmalloc.h>
49 #include <pulse/timeval.h>
51 #include <pulsecore/core-rtclock.h>
52 #include <pulsecore/i18n.h>
53 #include <pulsecore/aupdate.h>
54 #include <pulsecore/namereg.h>
55 #include <pulsecore/sink.h>
56 #include <pulsecore/module.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/modargs.h>
59 #include <pulsecore/log.h>
60 #include <pulsecore/rtpoll.h>
61 #include <pulsecore/sample-util.h>
62 #include <pulsecore/shared.h>
63 #include <pulsecore/idxset.h>
64 #include <pulsecore/strlist.h>
65 #include <pulsecore/database.h>
66 #include <pulsecore/protocol-dbus.h>
67 #include <pulsecore/dbus-util.h>
69 #include "module-equalizer-sink-symdef.h"
71 PA_MODULE_AUTHOR("Jason Newton");
72 PA_MODULE_DESCRIPTION(_("General Purpose Equalizer"));
73 PA_MODULE_VERSION(PACKAGE_VERSION);
74 PA_MODULE_LOAD_ONCE(FALSE);
76 _("sink_name=<name of the sink> "
77 "sink_properties=<properties for the sink> "
78 "sink_master=<sink to connect to> "
79 "format=<sample format> "
81 "channels=<number of channels> "
82 "channel_map=<channel map> "
83 "autoloaded=<set if this module is being loaded automatically> "
84 "use_volume_sharing=<yes or no> "
87 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
88 #define DEFAULT_AUTOLOADED FALSE
93 pa_sink_input *sink_input;
97 size_t fft_size;//length (res) of fft
100 *effectively chooses R
102 size_t R;/* the hop size between overlapping windows
103 * the latency of the filter, calculated from window_size
104 * based on constraints of COLA and window function
106 //for twiddling with pulseaudio
107 size_t overlap_size;//window_size-R
108 size_t samples_gathered;
109 size_t input_buffer_max;
111 float *W;//windowing function (time domain)
112 float *work_buffer, **input, **overlap_accum;
113 fftwf_complex *output_window;
114 fftwf_plan forward_plan, inverse_plan;
118 float ***Hs;//thread updatable copies of the freq response filters (magnitude based)
120 pa_memblockq *input_q;
122 size_t output_buffer_length;
123 size_t output_buffer_max_length;
124 pa_memblockq *output_q;
125 pa_bool_t first_iteration;
127 pa_dbus_protocol *dbus_protocol;
130 pa_database *database;
131 char **base_profiles;
134 static const char* const valid_modargs[] = {
143 "use_volume_sharing",
148 #define SINKLIST "equalized_sinklist"
149 #define EQDB "equalizer_db"
150 #define EQ_STATE_DB "equalizer-state"
151 #define FILTER_SIZE(u) ((u)->fft_size / 2 + 1)
152 #define CHANNEL_PROFILE_SIZE(u) (FILTER_SIZE(u) + 1)
153 #define FILTER_STATE_SIZE(u) (CHANNEL_PROFILE_SIZE(u) * (u)->channels)
155 static void dbus_init(struct userdata *u);
156 static void dbus_done(struct userdata *u);
158 static void hanning_window(float *W, size_t window_size){
159 /* h=.5*(1-cos(2*pi*j/(window_size+1)), COLA for R=(M+1)/2 */
160 for (size_t i = 0; i < window_size; ++i)
161 W[i] = (float).5 * (1 - cos(2*M_PI*i / (window_size+1)));
164 static void fix_filter(float *H, size_t fft_size){
165 /* divide out the fft gain */
166 for (size_t i = 0; i < fft_size / 2 + 1; ++i)
170 static void interpolate(float *signal, size_t length, uint32_t *xs, float *ys, size_t n_points){
171 /* Note that xs must be monotonically increasing! */
172 float x_range_lower, x_range_upper, c0;
174 pa_assert(n_points >= 2);
175 pa_assert(xs[0] == 0);
176 pa_assert(xs[n_points - 1] == length - 1);
178 for (size_t x = 0, x_range_lower_i = 0; x < length-1; ++x) {
179 pa_assert(x_range_lower_i < n_points-1);
181 x_range_lower = (float) xs[x_range_lower_i];
182 x_range_upper = (float) xs[x_range_lower_i+1];
184 pa_assert_se(x_range_lower < x_range_upper);
185 pa_assert_se(x >= x_range_lower);
186 pa_assert_se(x <= x_range_upper);
188 /* bilinear-interpolation of coefficients specified */
189 c0 = (x-x_range_lower) / (x_range_upper-x_range_lower);
190 pa_assert(c0 >= 0 && c0 <= 1.0);
192 signal[x] = ((1.0f - c0) * ys[x_range_lower_i] + c0 * ys[x_range_lower_i + 1]);
193 while(x >= xs[x_range_lower_i + 1])
197 signal[length-1] = ys[n_points-1];
200 static pa_bool_t is_monotonic(const uint32_t *xs, size_t length) {
206 for(size_t i = 1; i < length; ++i)
207 if (xs[i] <= xs[i-1])
213 /* ensures memory allocated is a multiple of v_size and aligned */
214 static void * alloc(size_t x, size_t s){
218 f = PA_ROUND_UP(x*s, sizeof(float)*v_size);
219 pa_assert_se(t = fftwf_malloc(f));
225 static void alloc_input_buffers(struct userdata *u, size_t min_buffer_length){
226 if (min_buffer_length <= u->input_buffer_max)
229 pa_assert(min_buffer_length >= u->window_size);
230 for (size_t c = 0; c < u->channels; ++c) {
231 float *tmp = alloc(min_buffer_length, sizeof(float));
233 if (!u->first_iteration)
234 memcpy(tmp, u->input[c], u->overlap_size * sizeof(float));
239 u->input_buffer_max = min_buffer_length;
242 /* Called from I/O thread context */
243 static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
244 struct userdata *u = PA_SINK(o)->userdata;
248 case PA_SINK_MESSAGE_GET_LATENCY: {
249 //size_t fs=pa_frame_size(&u->sink->sample_spec);
251 /* The sink is _put() before the sink input is, so let's
252 * make sure we don't access it in that time. Also, the
253 * sink input is first shut down, the sink second. */
254 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
255 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) {
256 *((pa_usec_t*) data) = 0;
260 *((pa_usec_t*) data) =
261 /* Get the latency of the master sink */
262 pa_sink_get_latency_within_thread(u->sink_input->sink) +
264 /* Add the latency internal to our sink input on top */
265 pa_bytes_to_usec(pa_memblockq_get_length(u->output_q) +
266 pa_memblockq_get_length(u->input_q), &u->sink_input->sink->sample_spec) +
267 pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
268 // pa_bytes_to_usec(u->samples_gathered * fs, &u->sink->sample_spec);
269 //+ pa_bytes_to_usec(u->latency * fs, ss)
274 return pa_sink_process_msg(o, code, data, offset, chunk);
278 /* Called from main context */
279 static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
282 pa_sink_assert_ref(s);
283 pa_assert_se(u = s->userdata);
285 if (!PA_SINK_IS_LINKED(state) ||
286 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
289 pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
293 /* Called from I/O thread context */
294 static void sink_request_rewind_cb(pa_sink *s) {
297 pa_sink_assert_ref(s);
298 pa_assert_se(u = s->userdata);
300 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
301 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
304 /* Just hand this one over to the master sink */
305 pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes+pa_memblockq_get_length(u->input_q), TRUE, FALSE, FALSE);
308 /* Called from I/O thread context */
309 static void sink_update_requested_latency_cb(pa_sink *s) {
312 pa_sink_assert_ref(s);
313 pa_assert_se(u = s->userdata);
315 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
316 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
319 /* Just hand this one over to the master sink */
320 pa_sink_input_set_requested_latency_within_thread(
322 pa_sink_get_requested_latency_within_thread(s));
325 /* Called from main context */
326 static void sink_set_volume_cb(pa_sink *s) {
329 pa_sink_assert_ref(s);
330 pa_assert_se(u = s->userdata);
332 if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
333 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
336 pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, TRUE);
339 /* Called from main context */
340 static void sink_set_mute_cb(pa_sink *s) {
343 pa_sink_assert_ref(s);
344 pa_assert_se(u = s->userdata);
346 if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
347 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
350 pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
354 //reference implementation
355 static void dsp_logic(
356 float * restrict dst,//used as a temp array too, needs to be fft_length!
357 float * restrict src,/*input data w/ overlap at start,
358 *automatically cycled in routine
360 float * restrict overlap,
361 const float X,//multiplier
362 const float * restrict H,//The freq. magnitude scalers filter
363 const float * restrict W,//The windowing function
364 fftwf_complex * restrict output_window,//The transformed windowed src
367 //use a linear-phase sliding STFT and overlap-add method (for each channel)
369 for(size_t j = 0; j < u->window_size; ++j){
370 dst[j] = X * W[j] * src[j];
372 //zero pad the remaining fft window
373 memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float));
374 //Processing is done here!
376 fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
378 for(size_t j = 0; j < FILTER_SIZE(u); ++j){
379 u->output_window[j][0] *= H[j];
380 u->output_window[j][1] *= H[j];
383 fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
384 ////debug: tests overlapping add
385 ////and negates ALL PREVIOUS processing
386 ////yields a perfect reconstruction if COLA is held
387 //for(size_t j = 0; j < u->window_size; ++j){
388 // u->work_buffer[j] = u->W[j] * u->input[c][j];
391 //overlap add and preserve overlap component from this window (linear phase)
392 for(size_t j = 0; j < u->overlap_size; ++j){
393 u->work_buffer[j] += overlap[j];
394 overlap[j] = dst[u->R + j];
396 ////debug: tests if basic buffering works
397 ////shouldn't modify the signal AT ALL (beyond roundoff)
398 //for(size_t j = 0; j < u->window_size;++j){
399 // u->work_buffer[j] = u->input[c][j];
402 //preserve the needed input for the next window's overlap
403 memmove(src, src + u->R,
404 (u->samples_gathered - u->R) * sizeof(float)
408 typedef float v4sf __attribute__ ((__aligned__(v_size * sizeof(float))));
409 typedef union float_vector {
415 //regardless of sse enabled, the loops in here assume
416 //16 byte aligned addresses and memory allocations divisible by v_size
417 static void dsp_logic(
418 float * restrict dst,//used as a temp array too, needs to be fft_length!
419 float * restrict src,/*input data w/ overlap at start,
420 *automatically cycled in routine
422 float * restrict overlap,//The size of the overlap
423 const float X,//multiplier
424 const float * restrict H,//The freq. magnitude scalers filter
425 const float * restrict W,//The windowing function
426 fftwf_complex * restrict output_window,//The transformed windowed src
427 struct userdata *u){//Collection of constants
428 const size_t overlap_size = PA_ROUND_UP(u->overlap_size, v_size);
430 x.f[0] = x.f[1] = x.f[2] = x.f[3] = X;
432 //assert(u->samples_gathered >= u->R);
433 //use a linear-phase sliding STFT and overlap-add method
434 for(size_t j = 0; j < u->window_size; j += v_size){
435 //dst[j] = W[j] * src[j];
436 float_vector_t *d = (float_vector_t*) (dst + j);
437 float_vector_t *w = (float_vector_t*) (W + j);
438 float_vector_t *s = (float_vector_t*) (src + j);
440 d->m = _mm_mul_ps(x.m, _mm_mul_ps(w->m, s->m));
441 // d->v = x->v * w->v * s->v;
444 //zero pad the remaining fft window
445 memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float));
447 //Processing is done here!
449 fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
450 //perform filtering - purely magnitude based
451 for(size_t j = 0; j < FILTER_SIZE; j += v_size / 2){
452 //output_window[j][0]*=H[j];
453 //output_window[j][1]*=H[j];
454 float_vector_t *d = (float_vector_t*)( ((float *) output_window) + 2 * j);
456 h.f[0] = h.f[1] = H[j];
457 h.f[2] = h.f[3] = H[j + 1];
459 d->m = _mm_mul_ps(d->m, h.m);
461 // d->v = d->v * h.v;
466 fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
468 ////debug: tests overlapping add
469 ////and negates ALL PREVIOUS processing
470 ////yields a perfect reconstruction if COLA is held
471 //for(size_t j = 0; j < u->window_size; ++j){
472 // dst[j] = W[j] * src[j];
475 //overlap add and preserve overlap component from this window (linear phase)
476 for(size_t j = 0; j < overlap_size; j += v_size){
477 //dst[j]+=overlap[j];
478 //overlap[j]+=dst[j+R];
479 float_vector_t *d = (float_vector_t*)(dst + j);
480 float_vector_t *o = (float_vector_t*)(overlap + j);
482 d->m = _mm_add_ps(d->m, o->m);
483 o->m = ((float_vector_t*)(dst + u->R + j))->m;
485 // d->v = d->v + o->v;
486 // o->v = ((float_vector_t*)(dst + u->R + j))->v;
489 //memcpy(overlap, dst+u->R, u->overlap_size * sizeof(float)); //overlap preserve (debug)
490 //zero out the bit beyond the real overlap so we don't add garbage next iteration
491 memset(overlap + u->overlap_size, 0, overlap_size - u->overlap_size);
493 ////debug: tests if basic buffering works
494 ////shouldn't modify the signal AT ALL (beyond roundoff)
495 //for(size_t j = 0; j < u->window_size; ++j){
499 //preserve the needed input for the next window's overlap
500 memmove(src, src + u->R,
501 (u->samples_gathered - u->R) * sizeof(float)
506 static void flatten_to_memblockq(struct userdata *u){
507 size_t mbs = pa_mempool_block_size_max(u->sink->core->mempool);
511 while(i < u->output_buffer_length){
513 tchunk.length = PA_MIN((u->output_buffer_length - i), mbs);
514 tchunk.memblock = pa_memblock_new(u->sink->core->mempool, tchunk.length);
515 //pa_log_debug("pushing %ld into the q", tchunk.length);
516 dst = pa_memblock_acquire(tchunk.memblock);
517 memcpy(dst, u->output_buffer + i, tchunk.length);
518 pa_memblock_release(tchunk.memblock);
519 pa_memblockq_push(u->output_q, &tchunk);
520 pa_memblock_unref(tchunk.memblock);
525 static void process_samples(struct userdata *u){
526 size_t fs = pa_frame_size(&(u->sink->sample_spec));
529 size_t iterations, offset;
530 pa_assert(u->samples_gathered >= u->window_size);
531 iterations = (u->samples_gathered - u->overlap_size) / u->R;
532 //make sure there is enough buffer memory allocated
533 if(iterations * u->R * fs > u->output_buffer_max_length){
534 u->output_buffer_max_length = iterations * u->R * fs;
535 pa_xfree(u->output_buffer);
536 u->output_buffer = pa_xmalloc(u->output_buffer_max_length);
538 u->output_buffer_length = iterations * u->R * fs;
540 for(size_t iter = 0; iter < iterations; ++iter){
541 offset = iter * u->R * fs;
542 for(size_t c = 0;c < u->channels; c++) {
543 a_i = pa_aupdate_read_begin(u->a_H[c]);
556 pa_aupdate_read_end(u->a_H[c]);
557 if(u->first_iteration){
558 /* The windowing function will make the audio ramped in, as a cheap fix we can
559 * undo the windowing (for non-zero window values)
561 for(size_t i = 0; i < u->overlap_size; ++i){
562 u->work_buffer[i] = u->W[i] <= FLT_EPSILON ? u->work_buffer[i] : u->work_buffer[i] / u->W[i];
565 pa_sample_clamp(PA_SAMPLE_FLOAT32NE, (uint8_t *) (((float *)u->output_buffer) + c) + offset, fs, u->work_buffer, sizeof(float), u->R);
567 if(u->first_iteration){
568 u->first_iteration = FALSE;
570 u->samples_gathered -= u->R;
572 flatten_to_memblockq(u);
575 static void input_buffer(struct userdata *u, pa_memchunk *in){
576 size_t fs = pa_frame_size(&(u->sink->sample_spec));
577 size_t samples = in->length/fs;
578 float *src = pa_memblock_acquire_chunk(in);
579 pa_assert(u->samples_gathered + samples <= u->input_buffer_max);
580 for(size_t c = 0; c < u->channels; c++) {
581 //buffer with an offset after the overlap from previous
584 u->input[c] + u->samples_gathered + samples <= u->input[c] + u->input_buffer_max
586 pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input[c] + u->samples_gathered, sizeof(float), src + c, fs, samples);
588 u->samples_gathered += samples;
589 pa_memblock_release(in->memblock);
592 /* Called from I/O thread context */
593 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
595 size_t fs, target_samples;
597 //struct timeval start, end;
600 pa_sink_input_assert_ref(i);
601 pa_assert_se(u = i->userdata);
605 /* FIXME: Please clean this up. I see more commented code lines
606 * than uncommented code lines. I am sorry, but I am too dumb to
607 * understand this. */
609 fs = pa_frame_size(&(u->sink->sample_spec));
610 mbs = pa_mempool_block_size_max(u->sink->core->mempool);
611 if(pa_memblockq_get_length(u->output_q) > 0){
612 //pa_log_debug("qsize is %ld", pa_memblockq_get_length(u->output_q));
615 //nbytes = PA_MIN(nbytes, pa_mempool_block_size_max(u->sink->core->mempool));
616 target_samples = PA_ROUND_UP(nbytes / fs, u->R);
617 ////pa_log_debug("vanilla mbs = %ld",mbs);
618 //mbs = PA_ROUND_DOWN(mbs / fs, u->R);
619 //mbs = PA_MAX(mbs, u->R);
620 //target_samples = PA_MAX(target_samples, mbs);
621 //pa_log_debug("target samples: %ld", target_samples);
622 if(u->first_iteration){
623 //allocate request_size
624 target_samples = PA_MAX(target_samples, u->window_size);
626 //allocate request_size + overlap
627 target_samples += u->overlap_size;
629 alloc_input_buffers(u, target_samples);
630 //pa_log_debug("post target samples: %ld", target_samples);
631 chunk->memblock = NULL;
633 /* Hmm, process any rewind request that might be queued up */
634 pa_sink_process_rewind(u->sink, 0);
636 //pa_log_debug("start output-buffered %ld, input-buffered %ld, requested %ld",buffered_samples,u->samples_gathered,samples_requested);
637 //pa_rtclock_get(&start);
639 size_t input_remaining = target_samples - u->samples_gathered;
640 // pa_log_debug("input remaining %ld samples", input_remaining);
641 pa_assert(input_remaining > 0);
642 while (pa_memblockq_peek(u->input_q, &tchunk) < 0) {
643 //pa_sink_render(u->sink, input_remaining * fs, &tchunk);
644 pa_sink_render_full(u->sink, PA_MIN(input_remaining * fs, mbs), &tchunk);
645 pa_memblockq_push(u->input_q, &tchunk);
646 pa_memblock_unref(tchunk.memblock);
648 pa_assert(tchunk.memblock);
650 tchunk.length = PA_MIN(input_remaining * fs, tchunk.length);
652 pa_memblockq_drop(u->input_q, tchunk.length);
653 //pa_log_debug("asked for %ld input samples, got %ld samples",input_remaining,buffer->length/fs);
655 //pa_rtclock_get(start);
656 // pa_log_debug("buffering %ld bytes", tchunk.length);
657 input_buffer(u, &tchunk);
658 //pa_rtclock_get(&end);
659 //pa_log_debug("Took %0.5f seconds to setup", pa_timeval_diff(end, start) / (double) PA_USEC_PER_SEC);
660 pa_memblock_unref(tchunk.memblock);
661 } while(u->samples_gathered < target_samples);
663 //pa_rtclock_get(&end);
664 //pa_log_debug("Took %0.6f seconds to get data", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC);
666 pa_assert(u->fft_size >= u->window_size);
667 pa_assert(u->R < u->window_size);
668 //pa_rtclock_get(&start);
669 /* process a block */
671 //pa_rtclock_get(&end);
672 //pa_log_debug("Took %0.6f seconds to process", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC);
674 pa_assert_se(pa_memblockq_peek(u->output_q, chunk) >= 0);
675 pa_assert(chunk->memblock);
676 pa_memblockq_drop(u->output_q, chunk->length);
678 /** FIXME: Uh? you need to unref the chunk here! */
680 //pa_log_debug("gave %ld", chunk->length/fs);
681 //pa_log_debug("end pop");
685 /* Called from main context */
686 static void sink_input_volume_changed_cb(pa_sink_input *i) {
689 pa_sink_input_assert_ref(i);
690 pa_assert_se(u = i->userdata);
692 pa_sink_volume_changed(u->sink, &i->volume);
695 /* Called from main context */
696 static void sink_input_mute_changed_cb(pa_sink_input *i) {
699 pa_sink_input_assert_ref(i);
700 pa_assert_se(u = i->userdata);
702 pa_sink_mute_changed(u->sink, i->muted);
706 static void reset_filter(struct userdata *u){
707 size_t fs = pa_frame_size(&u->sink->sample_spec);
710 u->samples_gathered = 0;
712 for(size_t i = 0; i < u->channels; ++i)
713 pa_memzero(u->overlap_accum[i], u->overlap_size * sizeof(float));
715 u->first_iteration = TRUE;
716 //set buffer size to max request, no overlap copy
717 max_request = PA_ROUND_UP(pa_sink_input_get_max_request(u->sink_input) / fs , u->R);
718 max_request = PA_MAX(max_request, u->window_size);
719 pa_sink_set_max_request_within_thread(u->sink, max_request * fs);
723 /* Called from I/O thread context */
724 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
728 pa_log_debug("Rewind callback!");
729 pa_sink_input_assert_ref(i);
730 pa_assert_se(u = i->userdata);
732 if (u->sink->thread_info.rewind_nbytes > 0) {
735 //max_rewrite = nbytes;
736 max_rewrite = nbytes + pa_memblockq_get_length(u->input_q);
737 //PA_MIN(pa_memblockq_get_length(u->input_q), nbytes);
738 amount = PA_MIN(u->sink->thread_info.rewind_nbytes, max_rewrite);
739 u->sink->thread_info.rewind_nbytes = 0;
742 //invalidate the output q
743 pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
744 pa_log("Resetting filter");
745 //reset_filter(u); //this is the "proper" thing to do...
749 pa_sink_process_rewind(u->sink, amount);
750 pa_memblockq_rewind(u->input_q, nbytes);
753 /* Called from I/O thread context */
754 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
757 pa_sink_input_assert_ref(i);
758 pa_assert_se(u = i->userdata);
760 /* FIXME: Too small max_rewind:
761 * https://bugs.freedesktop.org/show_bug.cgi?id=53709 */
762 pa_memblockq_set_maxrewind(u->input_q, nbytes);
763 pa_sink_set_max_rewind_within_thread(u->sink, nbytes);
766 /* Called from I/O thread context */
767 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
771 pa_sink_input_assert_ref(i);
772 pa_assert_se(u = i->userdata);
774 fs = pa_frame_size(&u->sink_input->sample_spec);
775 pa_sink_set_max_request_within_thread(u->sink, PA_ROUND_UP(nbytes / fs, u->R) * fs);
778 /* Called from I/O thread context */
779 static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
782 pa_sink_input_assert_ref(i);
783 pa_assert_se(u = i->userdata);
785 pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
788 /* Called from I/O thread context */
789 static void sink_input_update_sink_fixed_latency_cb(pa_sink_input *i) {
792 pa_sink_input_assert_ref(i);
793 pa_assert_se(u = i->userdata);
795 pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
798 /* Called from I/O thread context */
799 static void sink_input_detach_cb(pa_sink_input *i) {
802 pa_sink_input_assert_ref(i);
803 pa_assert_se(u = i->userdata);
805 pa_sink_detach_within_thread(u->sink);
807 pa_sink_set_rtpoll(u->sink, NULL);
810 /* Called from I/O thread context */
811 static void sink_input_attach_cb(pa_sink_input *i) {
813 size_t fs, max_request;
815 pa_sink_input_assert_ref(i);
816 pa_assert_se(u = i->userdata);
818 pa_sink_set_rtpoll(u->sink, i->sink->thread_info.rtpoll);
819 pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
820 pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
822 fs = pa_frame_size(&u->sink_input->sample_spec);
823 /* set buffer size to max request, no overlap copy */
824 max_request = PA_ROUND_UP(pa_sink_input_get_max_request(u->sink_input) / fs, u->R);
825 max_request = PA_MAX(max_request, u->window_size);
827 pa_sink_set_max_request_within_thread(u->sink, max_request * fs);
829 /* FIXME: Too small max_rewind:
830 * https://bugs.freedesktop.org/show_bug.cgi?id=53709 */
831 pa_sink_set_max_rewind_within_thread(u->sink, pa_sink_input_get_max_rewind(i));
833 pa_sink_attach_within_thread(u->sink);
836 /* Called from main context */
837 static void sink_input_kill_cb(pa_sink_input *i) {
840 pa_sink_input_assert_ref(i);
841 pa_assert_se(u = i->userdata);
843 /* The order here matters! We first kill the sink input, followed
844 * by the sink. That means the sink callbacks must be protected
845 * against an unconnected sink input! */
846 pa_sink_input_unlink(u->sink_input);
847 pa_sink_unlink(u->sink);
849 pa_sink_input_unref(u->sink_input);
850 u->sink_input = NULL;
852 /* Leave u->sink alone for now, it will be cleaned up on module
853 * unload (and it is needed during unload as well). */
855 pa_module_unload_request(u->module, TRUE);
858 /* Called from IO thread context */
859 static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t state) {
862 pa_sink_input_assert_ref(i);
863 pa_assert_se(u = i->userdata);
865 /* If we are added for the first time, ask for a rewinding so that
866 * we are heard right-away. */
867 if (PA_SINK_INPUT_IS_LINKED(state) &&
868 i->thread_info.state == PA_SINK_INPUT_INIT) {
869 pa_log_debug("Requesting rewind due to state change.");
870 pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
874 static void pack(char **strs, size_t len, char **packed, size_t *length){
876 size_t headers = (1+len) * sizeof(uint16_t);
878 for(size_t i = 0; i < len; ++i){
879 t_len += strlen(strs[i]);
881 *length = headers + t_len;
882 p = *packed = pa_xmalloc0(*length);
883 *((uint16_t *) p) = (uint16_t) len;
884 p += sizeof(uint16_t);
885 for(size_t i = 0; i < len; ++i){
886 uint16_t l = strlen(strs[i]);
887 *((uint16_t *) p) = (uint16_t) l;
888 p += sizeof(uint16_t);
889 memcpy(p, strs[i], l);
893 static void unpack(char *str, size_t length, char ***strs, size_t *len){
895 *len = *((uint16_t *) p);
896 p += sizeof(uint16_t);
897 *strs = pa_xnew(char *, *len);
899 for(size_t i = 0; i < *len; ++i){
900 size_t l = *((uint16_t *) p);
901 p += sizeof(uint16_t);
902 (*strs)[i] = pa_xnew(char, l + 1);
903 memcpy((*strs)[i], p, l);
904 (*strs)[i][l] = '\0';
908 static void save_profile(struct userdata *u, size_t channel, char *name){
910 const size_t profile_size = CHANNEL_PROFILE_SIZE(u) * sizeof(float);
911 float *H_n, *profile;
914 profile = pa_xnew0(float, profile_size);
915 a_i = pa_aupdate_read_begin(u->a_H[channel]);
916 profile[0] = u->Xs[a_i][channel];
917 H = u->Hs[channel][a_i];
919 for(size_t i = 0 ; i < FILTER_SIZE(u); ++i){
920 H_n[i] = H[i] * u->fft_size;
923 pa_aupdate_read_end(u->a_H[channel]);
925 key.size = strlen(key.data);
927 data.size = profile_size;
928 pa_database_set(u->database, &key, &data, TRUE);
929 pa_database_sync(u->database);
930 if(u->base_profiles[channel]){
931 pa_xfree(u->base_profiles[channel]);
933 u->base_profiles[channel] = pa_xstrdup(name);
936 static void save_state(struct userdata *u){
938 const size_t filter_state_size = FILTER_STATE_SIZE(u) * sizeof(float);
942 pa_database *database;
945 size_t packed_length;
947 pack(u->base_profiles, u->channels, &packed, &packed_length);
948 state = (float *) pa_xmalloc0(filter_state_size + packed_length);
949 memcpy(state + FILTER_STATE_SIZE(u), packed, packed_length);
952 for(size_t c = 0; c < u->channels; ++c){
953 a_i = pa_aupdate_read_begin(u->a_H[c]);
954 state[c * CHANNEL_PROFILE_SIZE(u)] = u->Xs[c][a_i];
956 H_n = &state[c * CHANNEL_PROFILE_SIZE(u) + 1];
957 memcpy(H_n, H, FILTER_SIZE(u) * sizeof(float));
958 pa_aupdate_read_end(u->a_H[c]);
961 key.data = u->sink->name;
962 key.size = strlen(key.data);
964 data.size = filter_state_size + packed_length;
965 //thread safety for 0.9.17?
966 pa_assert_se(dbname = pa_state_path(EQ_STATE_DB, FALSE));
967 pa_assert_se(database = pa_database_open(dbname, TRUE));
970 pa_database_set(database, &key, &data, TRUE);
971 pa_database_sync(database);
972 pa_database_close(database);
976 static void remove_profile(pa_core *c, char *name){
978 pa_database *database;
980 key.size = strlen(key.data);
981 pa_assert_se(database = pa_shared_get(c, EQDB));
982 pa_database_unset(database, &key);
983 pa_database_sync(database);
986 static const char* load_profile(struct userdata *u, size_t channel, char *name){
989 const size_t profile_size = CHANNEL_PROFILE_SIZE(u) * sizeof(float);
991 key.size = strlen(key.data);
992 if(pa_database_get(u->database, &key, &value) != NULL){
993 if(value.size == profile_size){
994 float *profile = (float *) value.data;
995 a_i = pa_aupdate_write_begin(u->a_H[channel]);
996 u->Xs[channel][a_i] = profile[0];
997 memcpy(u->Hs[channel][a_i], profile + 1, FILTER_SIZE(u) * sizeof(float));
998 fix_filter(u->Hs[channel][a_i], u->fft_size);
999 pa_aupdate_write_end(u->a_H[channel]);
1000 pa_xfree(u->base_profiles[channel]);
1001 u->base_profiles[channel] = pa_xstrdup(name);
1003 return "incompatible size";
1005 pa_datum_free(&value);
1007 return "profile doesn't exist";
1012 static void load_state(struct userdata *u){
1015 pa_datum key, value;
1016 pa_database *database;
1018 pa_assert_se(dbname = pa_state_path(EQ_STATE_DB, FALSE));
1019 database = pa_database_open(dbname, FALSE);
1022 pa_log("No resume state");
1026 key.data = u->sink->name;
1027 key.size = strlen(key.data);
1029 if(pa_database_get(database, &key, &value) != NULL){
1030 if(value.size > FILTER_STATE_SIZE(u) * sizeof(float) + sizeof(uint16_t)){
1031 float *state = (float *) value.data;
1034 for(size_t c = 0; c < u->channels; ++c){
1035 a_i = pa_aupdate_write_begin(u->a_H[c]);
1036 H = state + c * CHANNEL_PROFILE_SIZE(u) + 1;
1037 u->Xs[c][a_i] = state[c * CHANNEL_PROFILE_SIZE(u)];
1038 memcpy(u->Hs[c][a_i], H, FILTER_SIZE(u) * sizeof(float));
1039 pa_aupdate_write_end(u->a_H[c]);
1041 unpack(((char *)value.data) + FILTER_STATE_SIZE(u) * sizeof(float), value.size - FILTER_STATE_SIZE(u) * sizeof(float), &names, &n_profs);
1042 n_profs = PA_MIN(n_profs, u->channels);
1043 for(size_t c = 0; c < n_profs; ++c){
1044 pa_xfree(u->base_profiles[c]);
1045 u->base_profiles[c] = names[c];
1049 pa_datum_free(&value);
1051 pa_log("resume state exists but is wrong size!");
1053 pa_database_close(database);
1056 /* Called from main context */
1057 static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
1060 pa_sink_input_assert_ref(i);
1061 pa_assert_se(u = i->userdata);
1066 return u->sink != dest;
1069 /* Called from main context */
1070 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1073 pa_sink_input_assert_ref(i);
1074 pa_assert_se(u = i->userdata);
1077 pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq);
1078 pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags);
1080 pa_sink_set_asyncmsgq(u->sink, NULL);
1083 int pa__init(pa_module*m) {
1090 pa_sink_input_new_data sink_input_data;
1091 pa_sink_new_data sink_data;
1096 pa_bool_t use_volume_sharing = TRUE;
1100 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1101 pa_log("Failed to parse module arguments.");
1105 if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink_master", NULL), PA_NAMEREG_SINK))) {
1106 pa_log("Master sink not found");
1110 ss = master->sample_spec;
1111 ss.format = PA_SAMPLE_FLOAT32;
1112 map = master->channel_map;
1113 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
1114 pa_log("Invalid sample format specification or channel map");
1118 //fs = pa_frame_size(&ss);
1120 if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) {
1121 pa_log("use_volume_sharing= expects a boolean argument");
1125 u = pa_xnew0(struct userdata, 1);
1129 u->channels = ss.channels;
1130 u->fft_size = pow(2, ceil(log(ss.rate) / log(2)));//probably unstable near corner cases of powers of 2
1131 pa_log_debug("fft size: %zd", u->fft_size);
1132 u->window_size = 15999;
1133 if (u->window_size % 2 == 0)
1135 u->R = (u->window_size + 1) / 2;
1136 u->overlap_size = u->window_size - u->R;
1137 u->samples_gathered = 0;
1138 u->input_buffer_max = 0;
1140 u->a_H = pa_xnew0(pa_aupdate *, u->channels);
1141 u->Xs = pa_xnew0(float *, u->channels);
1142 u->Hs = pa_xnew0(float **, u->channels);
1144 for (c = 0; c < u->channels; ++c) {
1145 u->Xs[c] = pa_xnew0(float, 2);
1146 u->Hs[c] = pa_xnew0(float *, 2);
1147 for (i = 0; i < 2; ++i)
1148 u->Hs[c][i] = alloc(FILTER_SIZE(u), sizeof(float));
1151 u->W = alloc(u->window_size, sizeof(float));
1152 u->work_buffer = alloc(u->fft_size, sizeof(float));
1153 u->input = pa_xnew0(float *, u->channels);
1154 u->overlap_accum = pa_xnew0(float *, u->channels);
1155 for (c = 0; c < u->channels; ++c) {
1156 u->a_H[c] = pa_aupdate_new();
1158 u->overlap_accum[c] = alloc(u->overlap_size, sizeof(float));
1160 u->output_window = alloc(FILTER_SIZE(u), sizeof(fftwf_complex));
1161 u->forward_plan = fftwf_plan_dft_r2c_1d(u->fft_size, u->work_buffer, u->output_window, FFTW_ESTIMATE);
1162 u->inverse_plan = fftwf_plan_dft_c2r_1d(u->fft_size, u->output_window, u->work_buffer, FFTW_ESTIMATE);
1164 hanning_window(u->W, u->window_size);
1165 u->first_iteration = TRUE;
1167 u->base_profiles = pa_xnew0(char *, u->channels);
1168 for (c = 0; c < u->channels; ++c)
1169 u->base_profiles[c] = pa_xstrdup("default");
1172 pa_sink_new_data_init(&sink_data);
1173 sink_data.driver = __FILE__;
1174 sink_data.module = m;
1175 if (!(sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL))))
1176 sink_data.name = pa_sprintf_malloc("%s.equalizer", master->name);
1177 pa_sink_new_data_set_sample_spec(&sink_data, &ss);
1178 pa_sink_new_data_set_channel_map(&sink_data, &map);
1180 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
1181 pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "FFT based equalizer on %s", z ? z : master->name);
1183 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
1184 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
1186 if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) {
1187 pa_log("Invalid properties");
1188 pa_sink_new_data_done(&sink_data);
1192 u->autoloaded = DEFAULT_AUTOLOADED;
1193 if (pa_modargs_get_value_boolean(ma, "autoloaded", &u->autoloaded) < 0) {
1194 pa_log("Failed to parse autoloaded value");
1198 u->sink = pa_sink_new(m->core, &sink_data, (master->flags & (PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY))
1199 | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0));
1200 pa_sink_new_data_done(&sink_data);
1203 pa_log("Failed to create sink.");
1207 u->sink->parent.process_msg = sink_process_msg_cb;
1208 u->sink->set_state = sink_set_state_cb;
1209 u->sink->update_requested_latency = sink_update_requested_latency_cb;
1210 u->sink->request_rewind = sink_request_rewind_cb;
1211 pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb);
1212 if (!use_volume_sharing) {
1213 pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
1214 pa_sink_enable_decibel_volume(u->sink, TRUE);
1216 u->sink->userdata = u;
1218 u->input_q = pa_memblockq_new("module-equalizer-sink input_q", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &u->sink->silence);
1219 u->output_q = pa_memblockq_new("module-equalizer-sink output_q", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
1220 u->output_buffer = NULL;
1221 u->output_buffer_length = 0;
1222 u->output_buffer_max_length = 0;
1224 pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);
1225 //pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->R*fs, &ss));
1227 /* Create sink input */
1228 pa_sink_input_new_data_init(&sink_input_data);
1229 sink_input_data.driver = __FILE__;
1230 sink_input_data.module = m;
1231 pa_sink_input_new_data_set_sink(&sink_input_data, master, FALSE);
1232 sink_input_data.origin_sink = u->sink;
1233 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Equalized Stream");
1234 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
1235 pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
1236 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
1238 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
1239 pa_sink_input_new_data_done(&sink_input_data);
1244 u->sink_input->pop = sink_input_pop_cb;
1245 u->sink_input->process_rewind = sink_input_process_rewind_cb;
1246 u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1247 u->sink_input->update_max_request = sink_input_update_max_request_cb;
1248 u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb;
1249 u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb;
1250 u->sink_input->kill = sink_input_kill_cb;
1251 u->sink_input->attach = sink_input_attach_cb;
1252 u->sink_input->detach = sink_input_detach_cb;
1253 u->sink_input->state_change = sink_input_state_change_cb;
1254 u->sink_input->may_move_to = sink_input_may_move_to_cb;
1255 u->sink_input->moving = sink_input_moving_cb;
1256 if (!use_volume_sharing)
1257 u->sink_input->volume_changed = sink_input_volume_changed_cb;
1258 u->sink_input->mute_changed = sink_input_mute_changed_cb;
1259 u->sink_input->userdata = u;
1261 u->sink->input_to_master = u->sink_input;
1265 /* default filter to these */
1266 for (c = 0; c< u->channels; ++c) {
1267 a_i = pa_aupdate_write_begin(u->a_H[c]);
1269 u->Xs[c][a_i] = 1.0f;
1271 for(i = 0; i < FILTER_SIZE(u); ++i)
1272 H[i] = 1.0 / sqrtf(2.0f);
1274 fix_filter(H, u->fft_size);
1275 pa_aupdate_write_end(u->a_H[c]);
1278 /* load old parameters */
1281 pa_sink_put(u->sink);
1282 pa_sink_input_put(u->sink_input);
1284 pa_modargs_free(ma);
1290 pa_modargs_free(ma);
1297 int pa__get_n_used(pa_module *m) {
1301 pa_assert_se(u = m->userdata);
1303 return pa_sink_linked_by(u->sink);
1306 void pa__done(pa_module*m) {
1312 if (!(u = m->userdata))
1319 for(c = 0; c < u->channels; ++c)
1320 pa_xfree(u->base_profiles[c]);
1321 pa_xfree(u->base_profiles);
1323 /* See comments in sink_input_kill_cb() above regarding
1324 * destruction order! */
1327 pa_sink_input_unlink(u->sink_input);
1330 pa_sink_unlink(u->sink);
1333 pa_sink_input_unref(u->sink_input);
1336 pa_sink_unref(u->sink);
1338 pa_xfree(u->output_buffer);
1339 pa_memblockq_free(u->output_q);
1340 pa_memblockq_free(u->input_q);
1342 fftwf_destroy_plan(u->inverse_plan);
1343 fftwf_destroy_plan(u->forward_plan);
1344 pa_xfree(u->output_window);
1345 for (c = 0; c < u->channels; ++c) {
1346 pa_aupdate_free(u->a_H[c]);
1347 pa_xfree(u->overlap_accum[c]);
1348 pa_xfree(u->input[c]);
1351 pa_xfree(u->overlap_accum);
1353 pa_xfree(u->work_buffer);
1355 for (c = 0; c < u->channels; ++c) {
1357 for (size_t i = 0; i < 2; ++i)
1358 pa_xfree(u->Hs[c][i]);
1368 * DBus Routines and Callbacks
1370 #define EXTNAME "org.PulseAudio.Ext.Equalizing1"
1371 #define MANAGER_PATH "/org/pulseaudio/equalizing1"
1372 #define MANAGER_IFACE EXTNAME ".Manager"
1373 #define EQUALIZER_IFACE EXTNAME ".Equalizer"
1374 static void manager_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u);
1375 static void manager_get_sinks(DBusConnection *conn, DBusMessage *msg, void *_u);
1376 static void manager_get_profiles(DBusConnection *conn, DBusMessage *msg, void *_u);
1377 static void manager_get_all(DBusConnection *conn, DBusMessage *msg, void *_u);
1378 static void manager_handle_remove_profile(DBusConnection *conn, DBusMessage *msg, void *_u);
1379 static void equalizer_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u);
1380 static void equalizer_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *_u);
1381 static void equalizer_get_filter_rate(DBusConnection *conn, DBusMessage *msg, void *_u);
1382 static void equalizer_get_n_coefs(DBusConnection *conn, DBusMessage *msg, void *_u);
1383 static void equalizer_get_n_channels(DBusConnection *conn, DBusMessage *msg, void *_u);
1384 static void equalizer_get_all(DBusConnection *conn, DBusMessage *msg, void *_u);
1385 static void equalizer_handle_seed_filter(DBusConnection *conn, DBusMessage *msg, void *_u);
1386 static void equalizer_handle_get_filter_points(DBusConnection *conn, DBusMessage *msg, void *_u);
1387 static void equalizer_handle_get_filter(DBusConnection *conn, DBusMessage *msg, void *_u);
1388 static void equalizer_handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *_u);
1389 static void equalizer_handle_save_profile(DBusConnection *conn, DBusMessage *msg, void *_u);
1390 static void equalizer_handle_load_profile(DBusConnection *conn, DBusMessage *msg, void *_u);
1391 static void equalizer_handle_save_state(DBusConnection *conn, DBusMessage *msg, void *_u);
1392 static void equalizer_handle_get_profile_name(DBusConnection *conn, DBusMessage *msg, void *_u);
1393 enum manager_method_index {
1394 MANAGER_METHOD_REMOVE_PROFILE,
1398 pa_dbus_arg_info remove_profile_args[]={
1402 static pa_dbus_method_handler manager_methods[MANAGER_METHOD_MAX]={
1403 [MANAGER_METHOD_REMOVE_PROFILE]={
1404 .method_name="RemoveProfile",
1405 .arguments=remove_profile_args,
1406 .n_arguments=sizeof(remove_profile_args)/sizeof(pa_dbus_arg_info),
1407 .receive_cb=manager_handle_remove_profile}
1410 enum manager_handler_index {
1411 MANAGER_HANDLER_REVISION,
1412 MANAGER_HANDLER_EQUALIZED_SINKS,
1413 MANAGER_HANDLER_PROFILES,
1417 static pa_dbus_property_handler manager_handlers[MANAGER_HANDLER_MAX]={
1418 [MANAGER_HANDLER_REVISION]={.property_name="InterfaceRevision",.type="u",.get_cb=manager_get_revision,.set_cb=NULL},
1419 [MANAGER_HANDLER_EQUALIZED_SINKS]={.property_name="EqualizedSinks",.type="ao",.get_cb=manager_get_sinks,.set_cb=NULL},
1420 [MANAGER_HANDLER_PROFILES]={.property_name="Profiles",.type="as",.get_cb=manager_get_profiles,.set_cb=NULL}
1423 pa_dbus_arg_info sink_args[]={
1427 enum manager_signal_index{
1428 MANAGER_SIGNAL_SINK_ADDED,
1429 MANAGER_SIGNAL_SINK_REMOVED,
1430 MANAGER_SIGNAL_PROFILES_CHANGED,
1434 static pa_dbus_signal_info manager_signals[MANAGER_SIGNAL_MAX]={
1435 [MANAGER_SIGNAL_SINK_ADDED]={.name="SinkAdded", .arguments=sink_args, .n_arguments=sizeof(sink_args)/sizeof(pa_dbus_arg_info)},
1436 [MANAGER_SIGNAL_SINK_REMOVED]={.name="SinkRemoved", .arguments=sink_args, .n_arguments=sizeof(sink_args)/sizeof(pa_dbus_arg_info)},
1437 [MANAGER_SIGNAL_PROFILES_CHANGED]={.name="ProfilesChanged", .arguments=NULL, .n_arguments=0}
1440 static pa_dbus_interface_info manager_info={
1441 .name=MANAGER_IFACE,
1442 .method_handlers=manager_methods,
1443 .n_method_handlers=MANAGER_METHOD_MAX,
1444 .property_handlers=manager_handlers,
1445 .n_property_handlers=MANAGER_HANDLER_MAX,
1446 .get_all_properties_cb=manager_get_all,
1447 .signals=manager_signals,
1448 .n_signals=MANAGER_SIGNAL_MAX
1451 enum equalizer_method_index {
1452 EQUALIZER_METHOD_FILTER_POINTS,
1453 EQUALIZER_METHOD_SEED_FILTER,
1454 EQUALIZER_METHOD_SAVE_PROFILE,
1455 EQUALIZER_METHOD_LOAD_PROFILE,
1456 EQUALIZER_METHOD_SET_FILTER,
1457 EQUALIZER_METHOD_GET_FILTER,
1458 EQUALIZER_METHOD_SAVE_STATE,
1459 EQUALIZER_METHOD_GET_PROFILE_NAME,
1460 EQUALIZER_METHOD_MAX
1463 enum equalizer_handler_index {
1464 EQUALIZER_HANDLER_REVISION,
1465 EQUALIZER_HANDLER_SAMPLERATE,
1466 EQUALIZER_HANDLER_FILTERSAMPLERATE,
1467 EQUALIZER_HANDLER_N_COEFS,
1468 EQUALIZER_HANDLER_N_CHANNELS,
1469 EQUALIZER_HANDLER_MAX
1472 pa_dbus_arg_info filter_points_args[]={
1473 {"channel", "u","in"},
1476 {"preamp", "d","out"}
1478 pa_dbus_arg_info seed_filter_args[]={
1479 {"channel", "u","in"},
1482 {"preamp", "d","in"}
1485 pa_dbus_arg_info set_filter_args[]={
1486 {"channel", "u","in"},
1488 {"preamp", "d","in"}
1490 pa_dbus_arg_info get_filter_args[]={
1491 {"channel", "u","in"},
1493 {"preamp", "d","out"}
1496 pa_dbus_arg_info save_profile_args[]={
1497 {"channel", "u","in"},
1500 pa_dbus_arg_info load_profile_args[]={
1501 {"channel", "u","in"},
1504 pa_dbus_arg_info base_profile_name_args[]={
1505 {"channel", "u","in"},
1509 static pa_dbus_method_handler equalizer_methods[EQUALIZER_METHOD_MAX]={
1510 [EQUALIZER_METHOD_SEED_FILTER]={
1511 .method_name="SeedFilter",
1512 .arguments=seed_filter_args,
1513 .n_arguments=sizeof(seed_filter_args)/sizeof(pa_dbus_arg_info),
1514 .receive_cb=equalizer_handle_seed_filter},
1515 [EQUALIZER_METHOD_FILTER_POINTS]={
1516 .method_name="FilterAtPoints",
1517 .arguments=filter_points_args,
1518 .n_arguments=sizeof(filter_points_args)/sizeof(pa_dbus_arg_info),
1519 .receive_cb=equalizer_handle_get_filter_points},
1520 [EQUALIZER_METHOD_SET_FILTER]={
1521 .method_name="SetFilter",
1522 .arguments=set_filter_args,
1523 .n_arguments=sizeof(set_filter_args)/sizeof(pa_dbus_arg_info),
1524 .receive_cb=equalizer_handle_set_filter},
1525 [EQUALIZER_METHOD_GET_FILTER]={
1526 .method_name="GetFilter",
1527 .arguments=get_filter_args,
1528 .n_arguments=sizeof(get_filter_args)/sizeof(pa_dbus_arg_info),
1529 .receive_cb=equalizer_handle_get_filter},
1530 [EQUALIZER_METHOD_SAVE_PROFILE]={
1531 .method_name="SaveProfile",
1532 .arguments=save_profile_args,
1533 .n_arguments=sizeof(save_profile_args)/sizeof(pa_dbus_arg_info),
1534 .receive_cb=equalizer_handle_save_profile},
1535 [EQUALIZER_METHOD_LOAD_PROFILE]={
1536 .method_name="LoadProfile",
1537 .arguments=load_profile_args,
1538 .n_arguments=sizeof(load_profile_args)/sizeof(pa_dbus_arg_info),
1539 .receive_cb=equalizer_handle_load_profile},
1540 [EQUALIZER_METHOD_SAVE_STATE]={
1541 .method_name="SaveState",
1544 .receive_cb=equalizer_handle_save_state},
1545 [EQUALIZER_METHOD_GET_PROFILE_NAME]={
1546 .method_name="BaseProfile",
1547 .arguments=base_profile_name_args,
1548 .n_arguments=sizeof(base_profile_name_args)/sizeof(pa_dbus_arg_info),
1549 .receive_cb=equalizer_handle_get_profile_name}
1552 static pa_dbus_property_handler equalizer_handlers[EQUALIZER_HANDLER_MAX]={
1553 [EQUALIZER_HANDLER_REVISION]={.property_name="InterfaceRevision",.type="u",.get_cb=equalizer_get_revision,.set_cb=NULL},
1554 [EQUALIZER_HANDLER_SAMPLERATE]={.property_name="SampleRate",.type="u",.get_cb=equalizer_get_sample_rate,.set_cb=NULL},
1555 [EQUALIZER_HANDLER_FILTERSAMPLERATE]={.property_name="FilterSampleRate",.type="u",.get_cb=equalizer_get_filter_rate,.set_cb=NULL},
1556 [EQUALIZER_HANDLER_N_COEFS]={.property_name="NFilterCoefficients",.type="u",.get_cb=equalizer_get_n_coefs,.set_cb=NULL},
1557 [EQUALIZER_HANDLER_N_CHANNELS]={.property_name="NChannels",.type="u",.get_cb=equalizer_get_n_channels,.set_cb=NULL},
1560 enum equalizer_signal_index{
1561 EQUALIZER_SIGNAL_FILTER_CHANGED,
1562 EQUALIZER_SIGNAL_SINK_RECONFIGURED,
1563 EQUALIZER_SIGNAL_MAX
1566 static pa_dbus_signal_info equalizer_signals[EQUALIZER_SIGNAL_MAX]={
1567 [EQUALIZER_SIGNAL_FILTER_CHANGED]={.name="FilterChanged", .arguments=NULL, .n_arguments=0},
1568 [EQUALIZER_SIGNAL_SINK_RECONFIGURED]={.name="SinkReconfigured", .arguments=NULL, .n_arguments=0},
1571 static pa_dbus_interface_info equalizer_info={
1572 .name=EQUALIZER_IFACE,
1573 .method_handlers=equalizer_methods,
1574 .n_method_handlers=EQUALIZER_METHOD_MAX,
1575 .property_handlers=equalizer_handlers,
1576 .n_property_handlers=EQUALIZER_HANDLER_MAX,
1577 .get_all_properties_cb=equalizer_get_all,
1578 .signals=equalizer_signals,
1579 .n_signals=EQUALIZER_SIGNAL_MAX
1582 void dbus_init(struct userdata *u){
1584 DBusMessage *signal = NULL;
1585 pa_idxset *sink_list = NULL;
1586 u->dbus_protocol=pa_dbus_protocol_get(u->sink->core);
1587 u->dbus_path=pa_sprintf_malloc("/org/pulseaudio/core1/sink%d", u->sink->index);
1589 pa_dbus_protocol_add_interface(u->dbus_protocol, u->dbus_path, &equalizer_info, u);
1590 sink_list = pa_shared_get(u->sink->core, SINKLIST);
1591 u->database = pa_shared_get(u->sink->core, EQDB);
1592 if(sink_list == NULL){
1594 sink_list=pa_idxset_new(&pa_idxset_trivial_hash_func, &pa_idxset_trivial_compare_func);
1595 pa_shared_set(u->sink->core, SINKLIST, sink_list);
1596 pa_assert_se(dbname = pa_state_path("equalizer-presets", FALSE));
1597 pa_assert_se(u->database = pa_database_open(dbname, TRUE));
1599 pa_shared_set(u->sink->core, EQDB, u->database);
1600 pa_dbus_protocol_add_interface(u->dbus_protocol, MANAGER_PATH, &manager_info, u->sink->core);
1601 pa_dbus_protocol_register_extension(u->dbus_protocol, EXTNAME);
1603 pa_idxset_put(sink_list, u, &dummy);
1605 pa_assert_se((signal = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_SINK_ADDED].name)));
1606 dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &u->dbus_path, DBUS_TYPE_INVALID);
1607 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
1608 dbus_message_unref(signal);
1611 void dbus_done(struct userdata *u){
1612 pa_idxset *sink_list;
1615 DBusMessage *signal = NULL;
1616 pa_assert_se((signal = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_SINK_REMOVED].name)));
1617 dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &u->dbus_path, DBUS_TYPE_INVALID);
1618 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
1619 dbus_message_unref(signal);
1621 pa_assert_se(sink_list=pa_shared_get(u->sink->core,SINKLIST));
1622 pa_idxset_remove_by_data(sink_list,u,&dummy);
1623 if(pa_idxset_size(sink_list)==0){
1624 pa_dbus_protocol_unregister_extension(u->dbus_protocol, EXTNAME);
1625 pa_dbus_protocol_remove_interface(u->dbus_protocol, MANAGER_PATH, manager_info.name);
1626 pa_shared_remove(u->sink->core, EQDB);
1627 pa_database_close(u->database);
1628 pa_shared_remove(u->sink->core, SINKLIST);
1629 pa_xfree(sink_list);
1631 pa_dbus_protocol_remove_interface(u->dbus_protocol, u->dbus_path, equalizer_info.name);
1632 pa_xfree(u->dbus_path);
1633 pa_dbus_protocol_unref(u->dbus_protocol);
1636 void manager_handle_remove_profile(DBusConnection *conn, DBusMessage *msg, void *_u) {
1638 pa_core *c = (pa_core *)_u;
1639 DBusMessage *signal = NULL;
1640 pa_dbus_protocol *dbus_protocol;
1645 dbus_error_init(&error);
1646 if(!dbus_message_get_args(msg, &error,
1647 DBUS_TYPE_STRING, &name,
1648 DBUS_TYPE_INVALID)){
1649 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1650 dbus_error_free(&error);
1653 remove_profile(c,name);
1654 pa_dbus_send_empty_reply(conn, msg);
1656 pa_assert_se((signal = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_PROFILES_CHANGED].name)));
1657 dbus_protocol = pa_dbus_protocol_get(c);
1658 pa_dbus_protocol_send_signal(dbus_protocol, signal);
1659 pa_dbus_protocol_unref(dbus_protocol);
1660 dbus_message_unref(signal);
1663 void manager_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u){
1665 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &rev);
1668 static void get_sinks(pa_core *u, char ***names, unsigned *n_sinks){
1670 struct userdata *sink_u = NULL;
1672 pa_idxset *sink_list;
1677 pa_assert_se(sink_list = pa_shared_get(u, SINKLIST));
1678 *n_sinks = (unsigned) pa_idxset_size(sink_list);
1679 *names = *n_sinks > 0 ? pa_xnew0(char *,*n_sinks) : NULL;
1680 for(uint32_t i = 0; i < *n_sinks; ++i){
1681 sink_u = (struct userdata *) pa_idxset_iterate(sink_list, &iter, &dummy);
1682 (*names)[i] = pa_xstrdup(sink_u->dbus_path);
1686 void manager_get_sinks(DBusConnection *conn, DBusMessage *msg, void *_u){
1688 char **names = NULL;
1693 get_sinks((pa_core *) _u, &names, &n);
1694 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, names, n);
1695 for(unsigned i = 0; i < n; ++i){
1701 static void get_profiles(pa_core *c, char ***names, unsigned *n){
1703 pa_database *database;
1704 pa_datum key, next_key;
1705 pa_strlist *head=NULL, *iter;
1707 pa_assert_se(database = pa_shared_get(c, EQDB));
1712 done = !pa_database_first(database, &key, NULL);
1715 done = !pa_database_next(database, &key, &next_key, NULL);
1716 name=pa_xmalloc(key.size + 1);
1717 memcpy(name, key.data, key.size);
1718 name[key.size] = '\0';
1719 pa_datum_free(&key);
1720 head = pa_strlist_prepend(head, name);
1725 (*names) = *n > 0 ? pa_xnew0(char *, *n) : NULL;
1727 for(unsigned i = 0; i < *n; ++i){
1728 (*names)[*n - 1 - i] = pa_xstrdup(pa_strlist_data(iter));
1729 iter = pa_strlist_next(iter);
1731 pa_strlist_free(head);
1734 void manager_get_profiles(DBusConnection *conn, DBusMessage *msg, void *_u){
1741 get_profiles((pa_core *)_u, &names, &n);
1742 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_STRING, names, n);
1743 for(unsigned i = 0; i < n; ++i){
1749 void manager_get_all(DBusConnection *conn, DBusMessage *msg, void *_u){
1751 char **names = NULL;
1753 DBusMessage *reply = NULL;
1754 DBusMessageIter msg_iter, dict_iter;
1758 pa_assert_se(c = _u);
1760 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1761 dbus_message_iter_init_append(reply, &msg_iter);
1762 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
1765 pa_dbus_append_basic_variant_dict_entry(&dict_iter, manager_handlers[MANAGER_HANDLER_REVISION].property_name, DBUS_TYPE_UINT32, &rev);
1767 get_sinks(c, &names, &n);
1768 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter,manager_handlers[MANAGER_HANDLER_EQUALIZED_SINKS].property_name, DBUS_TYPE_OBJECT_PATH, names, n);
1769 for(unsigned i = 0; i < n; ++i){
1774 get_profiles(c, &names, &n);
1775 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, manager_handlers[MANAGER_HANDLER_PROFILES].property_name, DBUS_TYPE_STRING, names, n);
1776 for(unsigned i = 0; i < n; ++i){
1780 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
1781 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1782 dbus_message_unref(reply);
1785 void equalizer_handle_seed_filter(DBusConnection *conn, DBusMessage *msg, void *_u) {
1786 struct userdata *u = _u;
1788 DBusMessage *signal = NULL;
1790 uint32_t *xs, channel, r_channel;
1791 double *_ys, preamp;
1792 unsigned x_npoints, y_npoints, a_i;
1794 pa_bool_t points_good = TRUE;
1800 dbus_error_init(&error);
1802 if(!dbus_message_get_args(msg, &error,
1803 DBUS_TYPE_UINT32, &channel,
1804 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &xs, &x_npoints,
1805 DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &_ys, &y_npoints,
1806 DBUS_TYPE_DOUBLE, &preamp,
1807 DBUS_TYPE_INVALID)){
1808 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1809 dbus_error_free(&error);
1812 if(channel > u->channels){
1813 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
1814 dbus_error_free(&error);
1817 for(size_t i = 0; i < x_npoints; ++i){
1818 if(xs[i] >= FILTER_SIZE(u)){
1819 points_good = FALSE;
1823 if(!is_monotonic(xs, x_npoints) || !points_good){
1824 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs must be monotonic and 0<=x<=%zd", u->fft_size / 2);
1825 dbus_error_free(&error);
1827 }else if(x_npoints != y_npoints || x_npoints < 2 || x_npoints > FILTER_SIZE(u)){
1828 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs and ys must be the same length and 2<=l<=%zd!", FILTER_SIZE(u));
1829 dbus_error_free(&error);
1831 }else if(xs[0] != 0 || xs[x_npoints - 1] != u->fft_size / 2){
1832 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs[0] must be 0 and xs[-1]=fft_size/2");
1833 dbus_error_free(&error);
1837 ys = pa_xmalloc(x_npoints * sizeof(float));
1838 for(uint32_t i = 0; i < x_npoints; ++i){
1839 ys[i] = (float) _ys[i];
1841 r_channel = channel == u->channels ? 0 : channel;
1842 a_i = pa_aupdate_write_begin(u->a_H[r_channel]);
1843 H = u->Hs[r_channel][a_i];
1844 u->Xs[r_channel][a_i] = preamp;
1845 interpolate(H, FILTER_SIZE(u), xs, ys, x_npoints);
1846 fix_filter(H, u->fft_size);
1847 if(channel == u->channels){
1848 for(size_t c = 1; c < u->channels; ++c){
1849 unsigned b_i = pa_aupdate_write_begin(u->a_H[c]);
1850 float *H_p = u->Hs[c][b_i];
1851 u->Xs[c][b_i] = preamp;
1852 memcpy(H_p, H, FILTER_SIZE(u) * sizeof(float));
1853 pa_aupdate_write_end(u->a_H[c]);
1856 pa_aupdate_write_end(u->a_H[r_channel]);
1860 pa_dbus_send_empty_reply(conn, msg);
1862 pa_assert_se((signal = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name)));
1863 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
1864 dbus_message_unref(signal);
1867 void equalizer_handle_get_filter_points(DBusConnection *conn, DBusMessage *msg, void *_u) {
1868 struct userdata *u = (struct userdata *) _u;
1869 uint32_t *xs, channel, r_channel;
1871 unsigned x_npoints, a_i;
1873 pa_bool_t points_good=TRUE;
1874 DBusMessage *reply = NULL;
1875 DBusMessageIter msg_iter;
1882 dbus_error_init(&error);
1883 if(!dbus_message_get_args(msg, &error,
1884 DBUS_TYPE_UINT32, &channel,
1885 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &xs, &x_npoints,
1886 DBUS_TYPE_INVALID)){
1887 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1888 dbus_error_free(&error);
1891 if(channel > u->channels){
1892 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
1893 dbus_error_free(&error);
1897 for(size_t i = 0; i < x_npoints; ++i){
1898 if(xs[i] >= FILTER_SIZE(u)){
1904 if(x_npoints > FILTER_SIZE(u) || !points_good){
1905 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs indices/length must be <= %zd!", FILTER_SIZE(u));
1906 dbus_error_free(&error);
1910 r_channel = channel == u->channels ? 0 : channel;
1911 ys = pa_xmalloc(x_npoints * sizeof(double));
1912 a_i = pa_aupdate_read_begin(u->a_H[r_channel]);
1913 H = u->Hs[r_channel][a_i];
1914 preamp = u->Xs[r_channel][a_i];
1915 for(uint32_t i = 0; i < x_npoints; ++i){
1916 ys[i] = H[xs[i]] * u->fft_size;
1918 pa_aupdate_read_end(u->a_H[r_channel]);
1920 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1921 dbus_message_iter_init_append(reply, &msg_iter);
1923 pa_dbus_append_basic_array(&msg_iter, DBUS_TYPE_DOUBLE, ys, x_npoints);
1924 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_DOUBLE, &preamp);
1926 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1927 dbus_message_unref(reply);
1931 static void get_filter(struct userdata *u, size_t channel, double **H_, double *preamp){
1934 size_t r_channel = channel == u->channels ? 0 : channel;
1935 *H_ = pa_xnew0(double, FILTER_SIZE(u));
1936 a_i = pa_aupdate_read_begin(u->a_H[r_channel]);
1937 H = u->Hs[r_channel][a_i];
1938 for(size_t i = 0;i < FILTER_SIZE(u); ++i){
1939 (*H_)[i] = H[i] * u->fft_size;
1941 *preamp = u->Xs[r_channel][a_i];
1943 pa_aupdate_read_end(u->a_H[r_channel]);
1946 void equalizer_handle_get_filter(DBusConnection *conn, DBusMessage *msg, void *_u){
1951 DBusMessage *reply = NULL;
1952 DBusMessageIter msg_iter;
1954 pa_assert_se(u = (struct userdata *) _u);
1958 dbus_error_init(&error);
1959 if(!dbus_message_get_args(msg, &error,
1960 DBUS_TYPE_UINT32, &channel,
1961 DBUS_TYPE_INVALID)){
1962 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1963 dbus_error_free(&error);
1966 if(channel > u->channels){
1967 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
1968 dbus_error_free(&error);
1972 n_coefs = CHANNEL_PROFILE_SIZE(u);
1975 get_filter(u, channel, &H_, &preamp);
1976 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1977 dbus_message_iter_init_append(reply, &msg_iter);
1979 pa_dbus_append_basic_array(&msg_iter, DBUS_TYPE_DOUBLE, H_, n_coefs);
1980 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_DOUBLE, &preamp);
1982 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1983 dbus_message_unref(reply);
1987 static void set_filter(struct userdata *u, size_t channel, double *H_, double preamp){
1989 size_t r_channel = channel == u->channels ? 0 : channel;
1992 a_i = pa_aupdate_write_begin(u->a_H[r_channel]);
1993 u->Xs[r_channel][a_i] = (float) preamp;
1994 H = u->Hs[r_channel][a_i];
1995 for(size_t i = 0; i < FILTER_SIZE(u); ++i){
1996 H[i] = (float) H_[i];
1998 fix_filter(H, u->fft_size);
1999 if(channel == u->channels){
2000 for(size_t c = 1; c < u->channels; ++c){
2001 unsigned b_i = pa_aupdate_write_begin(u->a_H[c]);
2002 u->Xs[c][b_i] = u->Xs[r_channel][a_i];
2003 memcpy(u->Hs[c][b_i], u->Hs[r_channel][a_i], FILTER_SIZE(u) * sizeof(float));
2004 pa_aupdate_write_end(u->a_H[c]);
2007 pa_aupdate_write_end(u->a_H[r_channel]);
2010 void equalizer_handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *_u){
2015 DBusMessage *signal = NULL;
2017 pa_assert_se(u = (struct userdata *) _u);
2021 dbus_error_init(&error);
2022 if(!dbus_message_get_args(msg, &error,
2023 DBUS_TYPE_UINT32, &channel,
2024 DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &H, &_n_coefs,
2025 DBUS_TYPE_DOUBLE, &preamp,
2026 DBUS_TYPE_INVALID)){
2027 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
2028 dbus_error_free(&error);
2031 if(channel > u->channels){
2032 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
2033 dbus_error_free(&error);
2036 if(_n_coefs != FILTER_SIZE(u)){
2037 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "This filter takes exactly %zd coefficients, you gave %d", FILTER_SIZE(u), _n_coefs);
2040 set_filter(u, channel, H, preamp);
2042 pa_dbus_send_empty_reply(conn, msg);
2044 pa_assert_se((signal = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name)));
2045 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
2046 dbus_message_unref(signal);
2049 void equalizer_handle_save_profile(DBusConnection *conn, DBusMessage *msg, void *_u) {
2050 struct userdata *u = (struct userdata *) _u;
2052 uint32_t channel, r_channel;
2053 DBusMessage *signal = NULL;
2058 dbus_error_init(&error);
2060 if(!dbus_message_get_args(msg, &error,
2061 DBUS_TYPE_UINT32, &channel,
2062 DBUS_TYPE_STRING, &name,
2063 DBUS_TYPE_INVALID)){
2064 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
2065 dbus_error_free(&error);
2068 if(channel > u->channels){
2069 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
2070 dbus_error_free(&error);
2073 r_channel = channel == u->channels ? 0 : channel;
2074 save_profile(u, r_channel, name);
2075 pa_dbus_send_empty_reply(conn, msg);
2077 pa_assert_se((signal = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_PROFILES_CHANGED].name)));
2078 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
2079 dbus_message_unref(signal);
2082 void equalizer_handle_load_profile(DBusConnection *conn, DBusMessage *msg, void *_u) {
2083 struct userdata *u = (struct userdata *) _u;
2086 uint32_t channel, r_channel;
2087 const char *err_msg = NULL;
2088 DBusMessage *signal = NULL;
2093 dbus_error_init(&error);
2095 if(!dbus_message_get_args(msg, &error,
2096 DBUS_TYPE_UINT32, &channel,
2097 DBUS_TYPE_STRING, &name,
2098 DBUS_TYPE_INVALID)){
2099 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
2100 dbus_error_free(&error);
2103 if(channel > u->channels){
2104 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
2105 dbus_error_free(&error);
2108 r_channel = channel == u->channels ? 0 : channel;
2110 err_msg = load_profile(u, r_channel, name);
2111 if(err_msg != NULL){
2112 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "error loading profile %s: %s", name, err_msg);
2113 dbus_error_free(&error);
2116 if(channel == u->channels){
2117 for(uint32_t c = 1; c < u->channels; ++c){
2118 load_profile(u, c, name);
2121 pa_dbus_send_empty_reply(conn, msg);
2123 pa_assert_se((signal = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name)));
2124 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
2125 dbus_message_unref(signal);
2128 void equalizer_handle_save_state(DBusConnection *conn, DBusMessage *msg, void *_u) {
2129 struct userdata *u = (struct userdata *) _u;
2135 pa_dbus_send_empty_reply(conn, msg);
2138 void equalizer_handle_get_profile_name(DBusConnection *conn, DBusMessage *msg, void *_u){
2139 struct userdata *u = (struct userdata *) _u;
2141 uint32_t channel, r_channel;
2146 dbus_error_init(&error);
2148 if(!dbus_message_get_args(msg, &error,
2149 DBUS_TYPE_UINT32, &channel,
2150 DBUS_TYPE_INVALID)){
2151 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
2152 dbus_error_free(&error);
2155 if(channel > u->channels){
2156 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
2157 dbus_error_free(&error);
2160 r_channel = channel == u->channels ? 0 : channel;
2161 pa_assert(u->base_profiles[r_channel]);
2162 pa_dbus_send_basic_value_reply(conn,msg, DBUS_TYPE_STRING, &u->base_profiles[r_channel]);
2165 void equalizer_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u){
2167 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &rev);
2170 void equalizer_get_n_channels(DBusConnection *conn, DBusMessage *msg, void *_u){
2173 pa_assert_se(u = (struct userdata *) _u);
2177 channels = (uint32_t) u->channels;
2178 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &channels);
2181 void equalizer_get_n_coefs(DBusConnection *conn, DBusMessage *msg, void *_u){
2184 pa_assert_se(u = (struct userdata *) _u);
2188 n_coefs = (uint32_t) CHANNEL_PROFILE_SIZE(u);
2189 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &n_coefs);
2192 void equalizer_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *_u){
2195 pa_assert_se(u = (struct userdata *) _u);
2199 rate = (uint32_t) u->sink->sample_spec.rate;
2200 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &rate);
2203 void equalizer_get_filter_rate(DBusConnection *conn, DBusMessage *msg, void *_u){
2206 pa_assert_se(u = (struct userdata *) _u);
2210 fft_size = (uint32_t) u->fft_size;
2211 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &fft_size);
2214 void equalizer_get_all(DBusConnection *conn, DBusMessage *msg, void *_u){
2216 DBusMessage *reply = NULL;
2217 DBusMessageIter msg_iter, dict_iter;
2218 uint32_t rev, n_coefs, rate, fft_size, channels;
2220 pa_assert_se(u = _u);
2224 n_coefs = (uint32_t) CHANNEL_PROFILE_SIZE(u);
2225 rate = (uint32_t) u->sink->sample_spec.rate;
2226 fft_size = (uint32_t) u->fft_size;
2227 channels = (uint32_t) u->channels;
2229 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2230 dbus_message_iter_init_append(reply, &msg_iter);
2231 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
2233 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_REVISION].property_name, DBUS_TYPE_UINT32, &rev);
2234 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_SAMPLERATE].property_name, DBUS_TYPE_UINT32, &rate);
2235 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_FILTERSAMPLERATE].property_name, DBUS_TYPE_UINT32, &fft_size);
2236 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_N_COEFS].property_name, DBUS_TYPE_UINT32, &n_coefs);
2237 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_N_CHANNELS].property_name, DBUS_TYPE_UINT32, &channels);
2239 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
2240 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2241 dbus_message_unref(reply);