2 * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file compress.c Paraslash's dynamic audio range compressor. */
10 * Uses ideas of AudioCompress, (C) 2002-2004 M. Hari Nezumi <magenta@trikuare.cx>
14 #include "compress_filter.cmdline.h"
21 /** The size of the output data buffer. */
22 #define COMPRESS_CHUNK_SIZE 40960
24 extern char *stat_item_values
[NUM_STAT_ITEMS
];
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. */
38 /** Amplification factor. */
42 static ssize_t
compress(char *inbuf
, size_t inbuf_len
, struct filter_node
*fn
)
44 size_t i
, length
= PARA_MIN((inbuf_len
/ 2) * 2,
45 (fn
->bufsize
- fn
->loaded
) / 2 * 2);
46 struct private_compress_data
*pcd
= fn
->private_data
;
47 int16_t *ip
= (int16_t *)inbuf
, *op
= (int16_t *)(fn
->buf
+ fn
->loaded
);
48 unsigned gain_shift
= pcd
->conf
->inertia_arg
+ pcd
->conf
->damp_arg
,
49 mask
= (1 << pcd
->conf
->blocksize_arg
) - 1;
53 for (i
= 0; i
< length
/ 2; i
++) {
54 /* be careful in that heat, my dear */
55 int sample
= *ip
++, adjusted_sample
= (PARA_ABS(sample
) * (64 + pcd
->amp
)) >> 6;
57 adjusted_sample
= (adjusted_sample
* pcd
->current_gain
) >> gain_shift
;
58 if (unlikely(adjusted_sample
> 32767)) { /* clip */
59 PARA_NOTICE_LOG("clip: sample: %d, adjusted sample: %d\n",
60 sample
, adjusted_sample
);
61 adjusted_sample
= 32767;
62 pcd
->current_gain
= (3 * pcd
->current_gain
+
63 (1 << pcd
->conf
->inertia_arg
)) / 4;
66 pcd
->peak
= PARA_MAX(pcd
->peak
, adjusted_sample
);
67 *op
++ = sample
>= 0? adjusted_sample
: -adjusted_sample
;
68 if (likely(++pcd
->num_samples
& mask
))
70 // PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain,
72 if (pcd
->peak
< pcd
->conf
->target_level_arg
) {
73 if (pcd
->current_gain
< pcd
->max_gain
)
76 pcd
->current_gain
= PARA_MAX(pcd
->current_gain
- 2,
77 1 << pcd
->conf
->inertia_arg
);
84 static void close_compress(struct filter_node
*fn
)
86 free(fn
->private_data
);
90 static void *compress_parse_config(int argc
, char **argv
)
92 struct compress_filter_args_info
*ret
= para_calloc(sizeof(struct compress_filter_args_info
));
93 if (!compress_cmdline_parser(argc
, argv
, ret
))
99 static void open_compress(struct filter_node
*fn
)
101 struct private_compress_data
*pcd
= para_calloc(
102 sizeof(struct private_compress_data
));
103 pcd
->conf
= fn
->conf
;
104 fn
->private_data
= pcd
;
105 fn
->bufsize
= COMPRESS_CHUNK_SIZE
;
106 fn
->buf
= para_malloc(fn
->bufsize
);
107 pcd
->current_gain
= 1 << pcd
->conf
->inertia_arg
;
108 pcd
->max_gain
= 1 << (pcd
->conf
->inertia_arg
+ pcd
->conf
->aggressiveness_arg
);
109 if (stat_item_values
[SI_AMPLIFICATION
])
110 sscanf(stat_item_values
[SI_AMPLIFICATION
], "%u", &pcd
->amp
);
111 PARA_NOTICE_LOG("amplification: %u (scaling factor: %1.2f)\n", pcd
->amp
,
112 pcd
->amp
/ 64.0 + 1.0);
116 * The init function of the compress filter.
118 * \param f Pointer to the struct to initialize.
120 void compress_init(struct filter
*f
)
122 f
->open
= open_compress
;
123 f
->close
= close_compress
;
124 f
->convert
= compress
;
125 f
->print_help
= compress_cmdline_parser_print_help
;
126 f
->parse_config
= compress_parse_config
;