2 * Copyright (C) 2005-2014 Andre Noll <maan@tuebingen.mpg.de>
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 int compress_post_select(__a_unused
struct sched
*s
, void *context
)
46 struct filter_node
*fn
= context
;
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;
59 ret
= btr_node_status(btrn
, fn
->min_iqs
, BTR_NT_INTERNAL
);
64 btr_merge(btrn
, fn
->min_iqs
);
65 length
= btr_next_buffer(btrn
, &inbuf
) & ~(size_t)1;
66 if (length
== 0) { /* eof and 1 byte available */
67 ret
= -E_COMPRESS_EOF
;
70 ip
= (int16_t *)inbuf
;
74 op
= para_malloc(length
);
75 for (i
= 0; i
< length
/ 2; i
++) {
76 /* be careful in that heat, my dear */
84 sample
*= pcd
->current_gain
;
85 sample
>>= gain_shift
;
86 if (sample
> 32767) { /* clip */
88 pcd
->current_gain
= (3 * pcd
->current_gain
+
89 (1 << pcd
->conf
->inertia_arg
)) / 4;
91 } else if (sample
> pcd
->peak
)
93 op
[i
] = neg
? -sample
: sample
;
94 if (++pcd
->num_samples
& mask
)
96 // PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain,
98 if (pcd
->peak
< pcd
->conf
->target_level_arg
) {
99 if (pcd
->current_gain
< pcd
->max_gain
)
102 pcd
->current_gain
= PARA_MAX(pcd
->current_gain
- 2,
103 1U << pcd
->conf
->inertia_arg
);
107 btr_pushdown_one(btrn
);
109 btr_consume(btrn
, length
);
110 btr_add_output((char *)op
, length
, btrn
);
115 btr_remove_node(&fn
->btrn
);
119 /** TODO: Add sanity checks */
120 static int compress_parse_config(int argc
, char **argv
, void **config
)
122 struct compress_filter_args_info
*conf
= para_calloc(sizeof(*conf
));
124 compress_filter_cmdline_parser(argc
, argv
, conf
);
129 static void compress_open(struct filter_node
*fn
)
131 struct private_compress_data
*pcd
= para_calloc(
132 sizeof(struct private_compress_data
));
133 pcd
->conf
= fn
->conf
;
134 fn
->private_data
= pcd
;
135 fn
->min_iqs
= 2; /* 16 bit audio */
136 pcd
->current_gain
= 1 << pcd
->conf
->inertia_arg
;
137 pcd
->max_gain
= 1 << (pcd
->conf
->inertia_arg
+ pcd
->conf
->aggressiveness_arg
);
140 static void compress_free_config(void *conf
)
142 compress_filter_cmdline_parser_free(conf
);
146 * The init function of the compress filter.
148 * \param f Pointer to the struct to initialize.
150 void compress_filter_init(struct filter
*f
)
152 struct compress_filter_args_info dummy
;
154 compress_filter_cmdline_parser_init(&dummy
);
155 f
->open
= compress_open
;
156 f
->close
= compress_close
;
157 f
->pre_select
= generic_filter_pre_select
;
158 f
->post_select
= compress_post_select
;
159 f
->parse_config
= compress_parse_config
;
160 f
->free_config
= compress_free_config
;
161 f
->help
= (struct ggo_help
)DEFINE_GGO_HELP(compress_filter
);