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>
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
= (PARA_ABS(sample
) *
79 pcd
->current_gain
) >> gain_shift
;
80 if (adjusted_sample
> 32767) { /* clip */
81 PARA_NOTICE_LOG("clip: sample: %d, adjusted sample: %d\n",
82 sample
, adjusted_sample
);
83 adjusted_sample
= 32767;
84 pcd
->current_gain
= (3 * pcd
->current_gain
+
85 (1 << pcd
->conf
->inertia_arg
)) / 4;
88 pcd
->peak
= PARA_MAX(pcd
->peak
, adjusted_sample
);
89 op
[i
] = sample
>= 0? adjusted_sample
: -adjusted_sample
;
90 if (++pcd
->num_samples
& mask
)
92 // PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain,
94 if (pcd
->peak
< pcd
->conf
->target_level_arg
) {
95 if (pcd
->current_gain
< pcd
->max_gain
)
98 pcd
->current_gain
= PARA_MAX(pcd
->current_gain
- 2,
99 1U << pcd
->conf
->inertia_arg
);
103 btr_pushdown_one(btrn
);
105 btr_consume(btrn
, length
);
106 btr_add_output((char *)op
, length
, btrn
);
112 btr_remove_node(btrn
);
115 /** TODO: Add sanity checks */
116 static int compress_parse_config(int argc
, char **argv
, void **config
)
119 struct compress_filter_args_info
*compress_conf
120 = para_calloc(sizeof(*compress_conf
));
122 ret
= -E_COMPRESS_SYNTAX
;
123 if (compress_cmdline_parser(argc
, argv
, compress_conf
))
125 *config
= compress_conf
;
132 static void compress_open(struct filter_node
*fn
)
134 struct private_compress_data
*pcd
= para_calloc(
135 sizeof(struct private_compress_data
));
136 pcd
->conf
= fn
->conf
;
137 fn
->private_data
= pcd
;
138 fn
->min_iqs
= 2; /* 16 bit audio */
139 pcd
->current_gain
= 1 << pcd
->conf
->inertia_arg
;
140 pcd
->max_gain
= 1 << (pcd
->conf
->inertia_arg
+ pcd
->conf
->aggressiveness_arg
);
143 static void compress_free_config(void *conf
)
145 compress_cmdline_parser_free(conf
);
149 * The init function of the compress filter.
151 * \param f Pointer to the struct to initialize.
153 void compress_filter_init(struct filter
*f
)
155 struct compress_filter_args_info dummy
;
157 compress_cmdline_parser_init(&dummy
);
158 f
->open
= compress_open
;
159 f
->close
= compress_close
;
160 f
->pre_select
= generic_filter_pre_select
;
161 f
->post_select
= compress_post_select
;
162 f
->parse_config
= compress_parse_config
;
163 f
->free_config
= compress_free_config
;
164 f
->help
= (struct ggo_help
) {
165 .short_help
= compress_filter_args_info_help
,
166 .detailed_help
= compress_filter_args_info_detailed_help