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 int 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;
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 */
77 int sample
= *ip
++, adjusted_sample
= (PARA_ABS(sample
) *
78 pcd
->current_gain
) >> gain_shift
;
79 if (adjusted_sample
> 32767) { /* clip */
80 PARA_NOTICE_LOG("clip: sample: %d, adjusted sample: %d\n",
81 sample
, adjusted_sample
);
82 adjusted_sample
= 32767;
83 pcd
->current_gain
= (3 * pcd
->current_gain
+
84 (1 << pcd
->conf
->inertia_arg
)) / 4;
87 pcd
->peak
= PARA_MAX(pcd
->peak
, adjusted_sample
);
88 op
[i
] = sample
>= 0? adjusted_sample
: -adjusted_sample
;
89 if (++pcd
->num_samples
& mask
)
91 // PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain,
93 if (pcd
->peak
< pcd
->conf
->target_level_arg
) {
94 if (pcd
->current_gain
< pcd
->max_gain
)
97 pcd
->current_gain
= PARA_MAX(pcd
->current_gain
- 2,
98 1U << pcd
->conf
->inertia_arg
);
102 btr_pushdown_one(btrn
);
104 btr_consume(btrn
, length
);
105 btr_add_output((char *)op
, length
, btrn
);
110 btr_remove_node(&fn
->btrn
);
114 /** TODO: Add sanity checks */
115 static int compress_parse_config(int argc
, char **argv
, void **config
)
117 struct compress_filter_args_info
*conf
= para_calloc(sizeof(*conf
));
119 compress_filter_cmdline_parser(argc
, argv
, conf
);
124 static void compress_open(struct filter_node
*fn
)
126 struct private_compress_data
*pcd
= para_calloc(
127 sizeof(struct private_compress_data
));
128 pcd
->conf
= fn
->conf
;
129 fn
->private_data
= pcd
;
130 fn
->min_iqs
= 2; /* 16 bit audio */
131 pcd
->current_gain
= 1 << pcd
->conf
->inertia_arg
;
132 pcd
->max_gain
= 1 << (pcd
->conf
->inertia_arg
+ pcd
->conf
->aggressiveness_arg
);
135 static void compress_free_config(void *conf
)
137 compress_filter_cmdline_parser_free(conf
);
141 * The init function of the compress filter.
143 * \param f Pointer to the struct to initialize.
145 void compress_filter_init(struct filter
*f
)
147 struct compress_filter_args_info dummy
;
149 compress_filter_cmdline_parser_init(&dummy
);
150 f
->open
= compress_open
;
151 f
->close
= compress_close
;
152 f
->pre_select
= generic_filter_pre_select
;
153 f
->new_post_select
= compress_post_select
;
154 f
->parse_config
= compress_parse_config
;
155 f
->free_config
= compress_free_config
;
156 f
->help
= (struct ggo_help
) {
157 .short_help
= compress_filter_args_info_help
,
158 .detailed_help
= compress_filter_args_info_detailed_help