2 * Copyright (C) 2005-2011 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>
17 #include "compress_filter.cmdline.h"
21 #include "buffer_tree.h"
26 /** Data specific to the compress filter. */
27 struct private_compress_data
{
28 /** The current multiplier. */
29 unsigned current_gain
;
30 /** Points to the configuration data for this instance of the compress filter. */
31 struct compress_filter_args_info
*conf
;
32 /** Maximal admissible gain. */
34 /** Number of samples already seen. */
36 /** Absolute value of the maximal sample in the current block. */
40 static void compress_close(struct filter_node
*fn
)
42 free(fn
->private_data
);
45 static void compress_post_select(__a_unused
struct sched
*s
, struct task
*t
)
47 struct filter_node
*fn
= container_of(t
, struct filter_node
, task
);
48 struct private_compress_data
*pcd
= fn
->private_data
;
49 struct btr_node
*btrn
= fn
->btrn
;
50 bool inplace
= btr_inplace_ok(btrn
);
55 unsigned gain_shift
= pcd
->conf
->inertia_arg
+ pcd
->conf
->damp_arg
,
56 mask
= (1 << pcd
->conf
->blocksize_arg
) - 1;
61 ret
= btr_node_status(btrn
, fn
->min_iqs
, BTR_NT_INTERNAL
);
66 btr_merge(btrn
, fn
->min_iqs
);
67 length
= btr_next_buffer(btrn
, &inbuf
) & ~(size_t)1;
68 if (length
== 0) { /* eof and 1 byte available */
69 ret
= -E_COMPRESS_EOF
;
72 ip
= (int16_t *)inbuf
;
76 op
= para_malloc(length
);
77 for (i
= 0; i
< length
/ 2; i
++) {
78 /* be careful in that heat, my dear */
79 int sample
= *ip
++, adjusted_sample
= (PARA_ABS(sample
) *
80 pcd
->current_gain
) >> gain_shift
;
81 if (adjusted_sample
> 32767) { /* clip */
82 PARA_NOTICE_LOG("clip: sample: %d, adjusted sample: %d\n",
83 sample
, adjusted_sample
);
84 adjusted_sample
= 32767;
85 pcd
->current_gain
= (3 * pcd
->current_gain
+
86 (1 << pcd
->conf
->inertia_arg
)) / 4;
89 pcd
->peak
= PARA_MAX(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(btrn
);
116 /** TODO: Add sanity checks */
117 static int compress_parse_config(int argc
, char **argv
, void **config
)
120 struct compress_filter_args_info
*compress_conf
121 = para_calloc(sizeof(*compress_conf
));
123 ret
= -E_COMPRESS_SYNTAX
;
124 if (compress_cmdline_parser(argc
, argv
, compress_conf
))
126 *config
= compress_conf
;
133 static void compress_open(struct filter_node
*fn
)
135 struct private_compress_data
*pcd
= para_calloc(
136 sizeof(struct private_compress_data
));
137 pcd
->conf
= fn
->conf
;
138 fn
->private_data
= pcd
;
139 fn
->min_iqs
= 2; /* 16 bit audio */
140 pcd
->current_gain
= 1 << pcd
->conf
->inertia_arg
;
141 pcd
->max_gain
= 1 << (pcd
->conf
->inertia_arg
+ pcd
->conf
->aggressiveness_arg
);
144 static void compress_free_config(void *conf
)
146 compress_cmdline_parser_free(conf
);
150 * The init function of the compress filter.
152 * \param f Pointer to the struct to initialize.
154 void compress_filter_init(struct filter
*f
)
156 struct compress_filter_args_info dummy
;
158 compress_cmdline_parser_init(&dummy
);
159 f
->open
= compress_open
;
160 f
->close
= compress_close
;
161 f
->pre_select
= generic_filter_pre_select
;
162 f
->post_select
= compress_post_select
;
163 f
->parse_config
= compress_parse_config
;
164 f
->free_config
= compress_free_config
;
165 f
->help
= (struct ggo_help
) {
166 .short_help
= compress_filter_args_info_help
,
167 .detailed_help
= compress_filter_args_info_detailed_help