2 * Copyright (C) 2005-2013 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file compress_filter.c Paraslash's dynamic audio range compressor. */
10 * Uses ideas of AudioCompress, (C) 2002-2004 M. Hari Nezumi <magenta@trikuare.cx>
16 #include "compress_filter.cmdline.h"
20 #include "buffer_tree.h"
25 /** Data specific to the compress filter. */
26 struct private_compress_data
{
27 /** The current multiplier. */
28 unsigned current_gain
;
29 /** Points to the configuration data for this instance of the compress filter. */
30 struct compress_filter_args_info
*conf
;
31 /** Maximal admissible gain. */
33 /** Number of samples already seen. */
35 /** Absolute value of the maximal sample in the current block. */
39 static void compress_close(struct filter_node
*fn
)
41 free(fn
->private_data
);
44 static void compress_post_select(__a_unused
struct sched
*s
, struct task
*t
)
46 struct filter_node
*fn
= container_of(t
, struct filter_node
, task
);
47 struct private_compress_data
*pcd
= fn
->private_data
;
48 struct btr_node
*btrn
= fn
->btrn
;
49 bool inplace
= btr_inplace_ok(btrn
);
54 unsigned gain_shift
= pcd
->conf
->inertia_arg
+ pcd
->conf
->damp_arg
,
55 mask
= (1 << pcd
->conf
->blocksize_arg
) - 1;
60 ret
= btr_node_status(btrn
, fn
->min_iqs
, BTR_NT_INTERNAL
);
65 btr_merge(btrn
, fn
->min_iqs
);
66 length
= btr_next_buffer(btrn
, &inbuf
) & ~(size_t)1;
67 if (length
== 0) { /* eof and 1 byte available */
68 ret
= -E_COMPRESS_EOF
;
71 ip
= (int16_t *)inbuf
;
75 op
= para_malloc(length
);
76 for (i
= 0; i
< length
/ 2; i
++) {
77 /* be careful in that heat, my dear */
78 int sample
= *ip
++, adjusted_sample
;
80 adjusted_sample
= sample
> 0? sample
: -sample
;
81 adjusted_sample
*= pcd
->current_gain
;
82 adjusted_sample
>>= gain_shift
;
83 if (adjusted_sample
> 32767) { /* clip */
84 adjusted_sample
= 32767;
85 pcd
->current_gain
= (3 * pcd
->current_gain
+
86 (1 << pcd
->conf
->inertia_arg
)) / 4;
88 } else if (adjusted_sample
> pcd
->peak
)
89 pcd
->peak
= adjusted_sample
;
90 op
[i
] = sample
>= 0? adjusted_sample
: -adjusted_sample
;
91 if (++pcd
->num_samples
& mask
)
93 // PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain,
95 if (pcd
->peak
< pcd
->conf
->target_level_arg
) {
96 if (pcd
->current_gain
< pcd
->max_gain
)
99 pcd
->current_gain
= PARA_MAX(pcd
->current_gain
- 2,
100 1U << pcd
->conf
->inertia_arg
);
104 btr_pushdown_one(btrn
);
106 btr_consume(btrn
, length
);
107 btr_add_output((char *)op
, length
, btrn
);
113 btr_remove_node(&fn
->btrn
);
116 /** TODO: Add sanity checks */
117 static int compress_parse_config(int argc
, char **argv
, void **config
)
119 struct compress_filter_args_info
*conf
= para_calloc(sizeof(*conf
));
121 compress_filter_cmdline_parser(argc
, argv
, conf
);
126 static void compress_open(struct filter_node
*fn
)
128 struct private_compress_data
*pcd
= para_calloc(
129 sizeof(struct private_compress_data
));
130 pcd
->conf
= fn
->conf
;
131 fn
->private_data
= pcd
;
132 fn
->min_iqs
= 2; /* 16 bit audio */
133 pcd
->current_gain
= 1 << pcd
->conf
->inertia_arg
;
134 pcd
->max_gain
= 1 << (pcd
->conf
->inertia_arg
+ pcd
->conf
->aggressiveness_arg
);
137 static void compress_free_config(void *conf
)
139 compress_filter_cmdline_parser_free(conf
);
143 * The init function of the compress filter.
145 * \param f Pointer to the struct to initialize.
147 void compress_filter_init(struct filter
*f
)
149 struct compress_filter_args_info dummy
;
151 compress_filter_cmdline_parser_init(&dummy
);
152 f
->open
= compress_open
;
153 f
->close
= compress_close
;
154 f
->pre_select
= generic_filter_pre_select
;
155 f
->post_select
= compress_post_select
;
156 f
->parse_config
= compress_parse_config
;
157 f
->free_config
= compress_free_config
;
158 f
->help
= (struct ggo_help
) {
159 .short_help
= compress_filter_args_info_help
,
160 .detailed_help
= compress_filter_args_info_detailed_help