comparison src/audiocompress/compress.c @ 12:3da1b8942b8b trunk

[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author nenolod
date Mon, 18 Sep 2006 03:14:20 -0700
parents src/Effect/audiocompress/compress.c@13389e613d67
children da7a68f68116
comparison
equal deleted inserted replaced
11:cff1d04026ae 12:3da1b8942b8b
1 /* compress.c
2 ** Compressor logic
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/types.h>
9
10 #include "config.h"
11 #include "compress.h"
12
13 static int *peaks = NULL;
14 static int gainCurrent, gainTarget;
15
16 static struct {
17 int anticlip;
18 int target;
19 int gainmax;
20 int gainsmooth;
21 int buckets;
22 } prefs;
23
24 void CompressCfg(int anticlip, int target, int gainmax,
25 int gainsmooth, int buckets)
26 {
27 static int lastsize = 0;
28
29 prefs.anticlip = anticlip;
30 prefs.target = target;
31 prefs.gainmax = gainmax;
32 prefs.gainsmooth = gainsmooth;
33 prefs.buckets = buckets;
34
35 /* Allocate the peak structure */
36 peaks = realloc(peaks, sizeof(int)*prefs.buckets);
37
38 if (prefs.buckets > lastsize)
39 memset(peaks + lastsize, 0, sizeof(int)*(prefs.buckets
40 - lastsize));
41 lastsize = prefs.buckets;
42 }
43
44 void CompressFree(void)
45 {
46 if (peaks)
47 {
48 free(peaks);
49 peaks = NULL;
50 }
51 }
52
53 void CompressDo(void *data, unsigned int length)
54 {
55 int16_t *audio = (int16_t *)data, *ap;
56 int peak, pos;
57 int i;
58 int gr, gf, gn;
59 static int pn = -1;
60 #ifdef STATS
61 static int clip = 0;
62 #endif
63 static int clipped = 0;
64
65 if (!peaks)
66 return;
67
68 if (pn == -1)
69 {
70 for (i = 0; i < prefs.buckets; i++)
71 peaks[i] = 0;
72 }
73 pn = (pn + 1)%prefs.buckets;
74
75 #ifdef DEBUG
76 fprintf(stderr, "modifyNative16(0x%08x, %d)\n",(unsigned int)data,
77 length);
78 #endif
79
80 /* Determine peak's value and position */
81 peak = 1;
82 pos = 0;
83
84 #ifdef DEBUG
85 fprintf(stderr, "finding peak(b=%d)\n", pn);
86 #endif
87
88 ap = audio;
89 for (i = 0; i < length/2; i++)
90 {
91 int val = *ap;
92 if (val > peak)
93 {
94 peak = val;
95 pos = i;
96 } else if (-val > peak)
97 {
98 peak = -val;
99 pos = i;
100 }
101 ap++;
102 }
103 peaks[pn] = peak;
104
105 for (i = 0; i < prefs.buckets; i++)
106 {
107 if (peaks[i] > peak)
108 {
109 peak = peaks[i];
110 pos = 0;
111 }
112 }
113
114 /* Determine target gain */
115 gn = (1 << GAINSHIFT)*prefs.target/peak;
116
117 if (gn <(1 << GAINSHIFT))
118 gn = 1 << GAINSHIFT;
119
120 gainTarget = (gainTarget *((1 << prefs.gainsmooth) - 1) + gn)
121 >> prefs.gainsmooth;
122
123 /* Give it an extra insignifigant nudge to counteract possible
124 ** rounding error
125 */
126
127 if (gn < gainTarget)
128 gainTarget--;
129 else if (gn > gainTarget)
130 gainTarget++;
131
132 if (gainTarget > prefs.gainmax << GAINSHIFT)
133 gainTarget = prefs.gainmax << GAINSHIFT;
134
135
136 /* See if a peak is going to clip */
137 gn = (1 << GAINSHIFT)*32768/peak;
138
139 if (gn < gainTarget)
140 {
141 gainTarget = gn;
142
143 if (prefs.anticlip)
144 pos = 0;
145
146 } else
147 {
148 /* We're ramping up, so draw it out over the whole frame */
149 pos = length;
150 }
151
152 /* Determine gain rate necessary to make target */
153 if (!pos)
154 pos = 1;
155
156 gr = ((gainTarget - gainCurrent) << 16)/pos;
157
158 /* Do the shiznit */
159 gf = gainCurrent << 16;
160
161 #ifdef STATS
162 fprintf(stderr, "\rgain = %2.2f%+.2e ",
163 gainCurrent*1.0/(1 << GAINSHIFT),
164 (gainTarget - gainCurrent)*1.0/(1 << GAINSHIFT));
165 #endif
166
167 ap = audio;
168 for (i = 0; i < length/2; i++)
169 {
170 int sample;
171
172 /* Interpolate the gain */
173 gainCurrent = gf >> 16;
174 if (i < pos)
175 gf += gr;
176 else if (i == pos)
177 gf = gainTarget << 16;
178
179 /* Amplify */
180 sample = (*ap)*gainCurrent >> GAINSHIFT;
181 if (sample < -32768)
182 {
183 #ifdef STATS
184 clip++;
185 #endif
186 clipped += -32768 - sample;
187 sample = -32768;
188 } else if (sample > 32767)
189 {
190 #ifdef STATS
191 clip++;
192 #endif
193 clipped += sample - 32767;
194 sample = 32767;
195 }
196 *ap++ = sample;
197 }
198 #ifdef STATS
199 fprintf(stderr, "clip %d b%-3d ", clip, pn);
200 #endif
201
202 #ifdef DEBUG
203 fprintf(stderr, "\ndone\n");
204 #endif
205 }
206