~ubuntu-branches/ubuntu/saucy/mpd/saucy

« back to all changes in this revision

Viewing changes to src/compress.c

  • Committer: Bazaar Package Importer
  • Author(s): Angel Abad
  • Date: 2011-02-02 12:26:30 UTC
  • mfrom: (1.5.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20110202122630-bdyx8w4k94doz4fs
Tags: 0.16.1-1ubuntu1
* Merge from debian unstable. Remaining changes:
  - debian/control:
    + Don't build-depend on libmikmod2-dev (Debian bug #510675).
    + Move avahi-daemon from Suggests field to Recommends field.
  - debian/mpd.init.d:
    + Read mpd user from mpd.conf.
  - debian/control, debian/rules:
    + Add libmp3lame-dev to the build dependencies and enable lame.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2003-2009 The Music Player Daemon Project
3
 
 * http://www.musicpd.org
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License as published by
7
 
 * the Free Software Foundation; either version 2 of the License, or
8
 
 * (at your option) any later version.
9
 
 *
10
 
 * This program is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 * GNU General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License along
16
 
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
 
 */
19
 
 
20
 
/*
21
 
 * Imported from AudioCompress by J. Shagam <fluffy@beesbuzz.biz>
22
 
 */
23
 
 
24
 
#include "compress.h"
25
 
 
26
 
#include <glib.h>
27
 
 
28
 
#include <stdint.h>
29
 
#include <string.h>
30
 
 
31
 
#ifdef USE_X
32
 
#include <X11/Xlib.h>
33
 
#include <X11/Xutil.h>
34
 
 
35
 
static Display *display;
36
 
static Window window;
37
 
static Visual *visual;
38
 
static int screen;
39
 
static GC blackGC, whiteGC, blueGC, yellowGC, dkyellowGC, redGC;
40
 
#endif
41
 
 
42
 
static int *peaks;
43
 
static int gainCurrent, gainTarget;
44
 
 
45
 
static struct {
46
 
        int show_mon;
47
 
        int anticlip;
48
 
        int target;
49
 
        int gainmax;
50
 
        int gainsmooth;
51
 
        unsigned buckets;
52
 
} prefs;
53
 
 
54
 
#ifdef USE_X
55
 
static int mon_init;
56
 
#endif
57
 
 
58
 
void CompressCfg(int show_mon, int anticlip, int target, int gainmax,
59
 
                 int gainsmooth, unsigned buckets)
60
 
{
61
 
        static unsigned lastsize;
62
 
 
63
 
        prefs.show_mon = show_mon;
64
 
        prefs.anticlip = anticlip;
65
 
        prefs.target = target;
66
 
        prefs.gainmax = gainmax;
67
 
        prefs.gainsmooth = gainsmooth;
68
 
        prefs.buckets = buckets;
69
 
 
70
 
        /* Allocate the peak structure */
71
 
        peaks = g_realloc(peaks, sizeof(int)*prefs.buckets);
72
 
 
73
 
        if (prefs.buckets > lastsize)
74
 
                memset(peaks + lastsize, 0, sizeof(int)*(prefs.buckets
75
 
                                                         - lastsize));
76
 
        lastsize = prefs.buckets;
77
 
 
78
 
#ifdef USE_X
79
 
        /* Configure the monitor window if needed */
80
 
        if (show_mon && !mon_init)
81
 
        {
82
 
                display = XOpenDisplay(getenv("DISPLAY"));
83
 
 
84
 
                /* We really shouldn't try to init X if there's no X */
85
 
                if (!display)
86
 
                {
87
 
                        fprintf(stderr,
88
 
                                "X not detected; disabling monitor window\n");
89
 
                        show_mon = prefs.show_mon = 0;
90
 
                }
91
 
        }
92
 
 
93
 
        if (show_mon && !mon_init)
94
 
        {
95
 
                XGCValues gcv;
96
 
                XColor col;
97
 
        
98
 
                gainCurrent = gainTarget = (1 << GAINSHIFT);
99
 
 
100
 
 
101
 
 
102
 
                screen = DefaultScreen(display);
103
 
                visual = DefaultVisual(display, screen);
104
 
                window = XCreateSimpleWindow(display,
105
 
                                             RootWindow(display, screen),
106
 
                                             0, 0, prefs.buckets, 128 + 8, 0,
107
 
                                             BlackPixel(display, screen),
108
 
                                             WhitePixel(display, screen));
109
 
                XStoreName(display, window, "AudioCompress monitor");
110
 
        
111
 
                gcv.foreground = BlackPixel(display, screen);
112
 
                blackGC = XCreateGC(display, window, GCForeground, &gcv);
113
 
                gcv.foreground = WhitePixel(display, screen);
114
 
                whiteGC = XCreateGC(display, window, GCForeground, &gcv);
115
 
                col.red = 0;
116
 
                col.green = 0;
117
 
                col.blue = 65535;
118
 
                XAllocColor(display, DefaultColormap(display, screen), &col);
119
 
                gcv.foreground = col.pixel;
120
 
                blueGC = XCreateGC(display, window, GCForeground, &gcv);
121
 
                col.red = 65535;
122
 
                col.green = 65535;
123
 
                col.blue = 0;
124
 
                XAllocColor(display, DefaultColormap(display, screen), &col);
125
 
                gcv.foreground = col.pixel;
126
 
                yellowGC = XCreateGC(display, window, GCForeground, &gcv);
127
 
                col.red = 32767;
128
 
                col.green = 32767;
129
 
                col.blue = 0;
130
 
                XAllocColor(display, DefaultColormap(display, screen), &col);
131
 
                gcv.foreground = col.pixel;
132
 
                dkyellowGC = XCreateGC(display, window, GCForeground, &gcv);
133
 
                col.red = 65535;
134
 
                col.green = 0;
135
 
                col.blue = 0;
136
 
                XAllocColor(display, DefaultColormap(display, screen), &col);
137
 
                gcv.foreground = col.pixel;
138
 
                redGC = XCreateGC(display, window, GCForeground, &gcv);
139
 
                mon_init = 1;
140
 
        }
141
 
 
142
 
        if (mon_init)
143
 
        {
144
 
                if (show_mon)
145
 
                        XMapWindow(display, window);
146
 
                else
147
 
                        XUnmapWindow(display, window);
148
 
                XResizeWindow(display, window, prefs.buckets, 128 + 8);
149
 
                XFlush(display);
150
 
        }
151
 
#endif
152
 
}
153
 
 
154
 
void CompressFree(void)
155
 
{
156
 
#ifdef USE_X
157
 
        if (mon_init)
158
 
        {
159
 
                XFreeGC(display, blackGC);
160
 
                XFreeGC(display, whiteGC);
161
 
                XFreeGC(display, blueGC);
162
 
                XFreeGC(display, yellowGC);
163
 
                XFreeGC(display, dkyellowGC);
164
 
                XFreeGC(display, redGC);
165
 
                XDestroyWindow(display, window);
166
 
                XCloseDisplay(display);
167
 
        }
168
 
#endif
169
 
 
170
 
        g_free(peaks);
171
 
}
172
 
 
173
 
void CompressDo(void *data, unsigned int length)
174
 
{
175
 
        int16_t *audio = (int16_t *)data, *ap;
176
 
        int peak;
177
 
        unsigned int i, pos;
178
 
        int gr, gf, gn;
179
 
        static int pn = -1;
180
 
#ifdef STATS
181
 
        static int clip;
182
 
#endif
183
 
        static int clipped;
184
 
 
185
 
        if (!peaks)
186
 
                return;
187
 
 
188
 
        if (pn == -1)
189
 
        {
190
 
                for (i = 0; i < prefs.buckets; i++)
191
 
                        peaks[i] = 0;
192
 
        }
193
 
        pn = (pn + 1)%prefs.buckets;
194
 
 
195
 
#ifdef DEBUG
196
 
        fprintf(stderr, "modifyNative16(0x%08x, %d)\n",(unsigned int)data,
197
 
                length);
198
 
#endif
199
 
 
200
 
        /* Determine peak's value and position */
201
 
        peak = 1;
202
 
        pos = 0;
203
 
 
204
 
#ifdef DEBUG
205
 
        fprintf(stderr, "finding peak(b=%d)\n", pn);
206
 
#endif
207
 
 
208
 
        ap = audio;
209
 
        for (i = 0; i < length/2; i++)
210
 
        {
211
 
                int val = *ap;
212
 
                if (val > peak)
213
 
                {
214
 
                        peak = val;
215
 
                        pos = i;
216
 
                } else if (-val > peak)
217
 
                {
218
 
                        peak = -val;
219
 
                        pos = i;
220
 
                }
221
 
                ap++;
222
 
        }
223
 
        peaks[pn] = peak;
224
 
 
225
 
        /* Only draw if needed, of course */
226
 
#ifdef USE_X
227
 
        if (prefs.show_mon)
228
 
        {
229
 
                /* current amplitude */
230
 
                XDrawLine(display, window, whiteGC,
231
 
                          pn, 0,
232
 
                          pn,
233
 
                          127 -
234
 
                          (peaks[pn]*gainCurrent >> (GAINSHIFT + 8)));
235
 
 
236
 
                /* amplification */
237
 
                XDrawLine(display, window, yellowGC,
238
 
                          pn,
239
 
                          127 - (peaks[pn]*gainCurrent
240
 
                                 >> (GAINSHIFT + 8)),
241
 
                          pn, 127);
242
 
 
243
 
                /* peak */
244
 
                XDrawLine(display, window, blackGC,
245
 
                          pn, 127 - (peaks[pn] >> 8), pn, 127);
246
 
 
247
 
                /* clip indicator */
248
 
                if (clipped)
249
 
                        XDrawLine(display, window, redGC,
250
 
                                  (pn + prefs.buckets - 1)%prefs.buckets,
251
 
                                  126 - clipped/(length*512),
252
 
                                  (pn + prefs.buckets - 1)%prefs.buckets,
253
 
                                  127);
254
 
                clipped = 0;
255
 
 
256
 
                /* target line */
257
 
                /* XDrawPoint(display, window, redGC, */
258
 
                /*         pn, 127 - TARGET/256); */
259
 
                /* amplification edge */
260
 
                XDrawLine(display, window, dkyellowGC,
261
 
                          pn,
262
 
                          127 - (peaks[pn]*gainCurrent
263
 
                                 >> (GAINSHIFT + 8)),
264
 
                          pn - 1,
265
 
                          127 -
266
 
                          (peaks[(pn + prefs.buckets
267
 
                                  - 1)%prefs.buckets]*gainCurrent
268
 
                           >> (GAINSHIFT + 8)));
269
 
        }
270
 
#endif
271
 
 
272
 
        for (i = 0; i < prefs.buckets; i++)
273
 
        {
274
 
                if (peaks[i] > peak)
275
 
                {
276
 
                        peak = peaks[i];
277
 
                        pos = 0;
278
 
                }
279
 
        }
280
 
 
281
 
        /* Determine target gain */
282
 
        gn = (1 << GAINSHIFT)*prefs.target/peak;
283
 
 
284
 
        if (gn <(1 << GAINSHIFT))
285
 
                gn = 1 << GAINSHIFT;
286
 
 
287
 
        gainTarget = (gainTarget *((1 << prefs.gainsmooth) - 1) + gn)
288
 
                                      >> prefs.gainsmooth;
289
 
 
290
 
        /* Give it an extra insignifigant nudge to counteract possible
291
 
        ** rounding error
292
 
        */
293
 
 
294
 
        if (gn < gainTarget)
295
 
                gainTarget--;
296
 
        else if (gn > gainTarget)
297
 
                gainTarget++;
298
 
 
299
 
        if (gainTarget > prefs.gainmax << GAINSHIFT)
300
 
                gainTarget = prefs.gainmax << GAINSHIFT;
301
 
 
302
 
 
303
 
#ifdef USE_X
304
 
        if (prefs.show_mon)
305
 
        {
306
 
                int x;
307
 
 
308
 
                /* peak*gain */
309
 
                XDrawPoint(display, window, redGC,
310
 
                           pn,
311
 
                           127 - (peak*gainCurrent
312
 
                                  >> (GAINSHIFT + 8)));
313
 
 
314
 
                /* gain indicator */
315
 
                XFillRectangle(display, window, whiteGC, 0, 128,
316
 
                               prefs.buckets, 8);
317
 
                x = (gainTarget - (1 << GAINSHIFT))*prefs.buckets
318
 
                        / ((prefs.gainmax - 1) << GAINSHIFT);
319
 
                XDrawLine(display, window, redGC, x,
320
 
                          128, x, 128 + 8);
321
 
 
322
 
                x = (gn - (1 << GAINSHIFT))*prefs.buckets
323
 
                        / ((prefs.gainmax - 1) << GAINSHIFT);
324
 
 
325
 
                XDrawLine(display, window, blackGC,
326
 
                          x, 132 - 1,
327
 
                          x, 132 + 1);
328
 
 
329
 
                /* blue peak line */
330
 
                XDrawLine(display, window, blueGC,
331
 
                          0, 127 - (peak >> 8), prefs.buckets,
332
 
                          127 - (peak >> 8));
333
 
                XFlush(display);
334
 
                XDrawLine(display, window, whiteGC,
335
 
                          0, 127 - (peak >> 8), prefs.buckets,
336
 
                          127 - (peak >> 8));
337
 
        }
338
 
#endif
339
 
 
340
 
        /* See if a peak is going to clip */
341
 
        gn = (1 << GAINSHIFT)*32768/peak;
342
 
 
343
 
        if (gn < gainTarget)
344
 
        {
345
 
                gainTarget = gn;
346
 
 
347
 
                if (prefs.anticlip)
348
 
                        pos = 0;
349
 
 
350
 
        } else
351
 
        {
352
 
                /* We're ramping up, so draw it out over the whole frame */
353
 
                pos = length;
354
 
        }
355
 
 
356
 
        /* Determine gain rate necessary to make target */
357
 
        if (!pos)
358
 
                pos = 1;
359
 
 
360
 
        gr = ((gainTarget - gainCurrent) << 16)/(int)pos;
361
 
 
362
 
        /* Do the shiznit */
363
 
        gf = gainCurrent << 16;
364
 
 
365
 
#ifdef STATS
366
 
        fprintf(stderr, "\rgain = %2.2f%+.2e ",
367
 
                gainCurrent*1.0/(1 << GAINSHIFT),
368
 
                (gainTarget - gainCurrent)*1.0/(1 << GAINSHIFT));
369
 
#endif
370
 
 
371
 
        ap = audio;
372
 
        for (i = 0; i < length/2; i++)
373
 
        {
374
 
                int sample;
375
 
 
376
 
                /* Interpolate the gain */
377
 
                gainCurrent = gf >> 16;
378
 
                if (i < pos)
379
 
                        gf += gr;
380
 
                else if (i == pos)
381
 
                        gf = gainTarget << 16;
382
 
 
383
 
                /* Amplify */
384
 
                sample = (*ap)*gainCurrent >> GAINSHIFT;
385
 
                if (sample < -32768)
386
 
                {
387
 
#ifdef STATS
388
 
                        clip++;
389
 
#endif
390
 
                        clipped += -32768 - sample;
391
 
                        sample = -32768;
392
 
                } else if (sample > 32767)
393
 
                {
394
 
#ifdef STATS
395
 
                        clip++;
396
 
#endif
397
 
                        clipped += sample - 32767;
398
 
                        sample = 32767;
399
 
                }
400
 
                *ap++ = sample;
401
 
        }
402
 
#ifdef STATS
403
 
        fprintf(stderr, "clip %d b%-3d ", clip, pn);
404
 
#endif
405
 
 
406
 
#ifdef DEBUG
407
 
        fprintf(stderr, "\ndone\n");
408
 
#endif
409
 
}
410