1 /* the Music Player Daemon (MPD)
2 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3 * This project's homepage is: http://www.musicpd.org
6 * (c)2003-6 fluffy@beesbuzz.biz
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <sys/types.h>
33 #include <X11/Xutil.h>
35 static Display *display;
37 static Visual *visual;
39 static GC blackGC, whiteGC, blueGC, yellowGC, dkyellowGC, redGC;
43 static int gainCurrent, gainTarget;
58 void CompressCfg(int show_mon, int anticlip, int target, int gainmax,
59 int gainsmooth, int buckets)
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;
70 /* Allocate the peak structure */
71 peaks = xrealloc(peaks, sizeof(int)*prefs.buckets);
73 if (prefs.buckets > lastsize)
74 memset(peaks + lastsize, 0, sizeof(int)*(prefs.buckets
76 lastsize = prefs.buckets;
79 /* Configure the monitor window if needed */
80 if (show_mon && !mon_init)
82 display = XOpenDisplay(getenv("DISPLAY"));
84 /* We really shouldn't try to init X if there's no X */
88 "X not detected; disabling monitor window\n");
89 show_mon = prefs.show_mon = 0;
93 if (show_mon && !mon_init)
98 gainCurrent = gainTarget = (1 << GAINSHIFT);
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");
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);
118 XAllocColor(display, DefaultColormap(display, screen), &col);
119 gcv.foreground = col.pixel;
120 blueGC = XCreateGC(display, window, GCForeground, &gcv);
124 XAllocColor(display, DefaultColormap(display, screen), &col);
125 gcv.foreground = col.pixel;
126 yellowGC = XCreateGC(display, window, GCForeground, &gcv);
130 XAllocColor(display, DefaultColormap(display, screen), &col);
131 gcv.foreground = col.pixel;
132 dkyellowGC = XCreateGC(display, window, GCForeground, &gcv);
136 XAllocColor(display, DefaultColormap(display, screen), &col);
137 gcv.foreground = col.pixel;
138 redGC = XCreateGC(display, window, GCForeground, &gcv);
145 XMapWindow(display, window);
147 XUnmapWindow(display, window);
148 XResizeWindow(display, window, prefs.buckets, 128 + 8);
154 void CompressFree(void)
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);
174 void CompressDo(void *data, unsigned int length)
176 int16_t *audio = (int16_t *)data, *ap;
191 for (i = 0; i < prefs.buckets; i++)
194 pn = (pn + 1)%prefs.buckets;
197 fprintf(stderr, "modifyNative16(0x%08x, %d)\n",(unsigned int)data,
201 /* Determine peak's value and position */
206 fprintf(stderr, "finding peak(b=%d)\n", pn);
210 for (i = 0; i < length/2; i++)
217 } else if (-val > peak)
226 /* Only draw if needed, of course */
230 /* current amplitude */
231 XDrawLine(display, window, whiteGC,
235 (peaks[pn]*gainCurrent >> (GAINSHIFT + 8)));
238 XDrawLine(display, window, yellowGC,
240 127 - (peaks[pn]*gainCurrent
245 XDrawLine(display, window, blackGC,
246 pn, 127 - (peaks[pn] >> 8), pn, 127);
250 XDrawLine(display, window, redGC,
251 (pn + prefs.buckets - 1)%prefs.buckets,
252 126 - clipped/(length*512),
253 (pn + prefs.buckets - 1)%prefs.buckets,
258 /* XDrawPoint(display, window, redGC, */
259 /* pn, 127 - TARGET/256); */
260 /* amplification edge */
261 XDrawLine(display, window, dkyellowGC,
263 127 - (peaks[pn]*gainCurrent
267 (peaks[(pn + prefs.buckets
268 - 1)%prefs.buckets]*gainCurrent
269 >> (GAINSHIFT + 8)));
273 for (i = 0; i < prefs.buckets; i++)
282 /* Determine target gain */
283 gn = (1 << GAINSHIFT)*prefs.target/peak;
285 if (gn <(1 << GAINSHIFT))
288 gainTarget = (gainTarget *((1 << prefs.gainsmooth) - 1) + gn)
291 /* Give it an extra insignifigant nudge to counteract possible
297 else if (gn > gainTarget)
300 if (gainTarget > prefs.gainmax << GAINSHIFT)
301 gainTarget = prefs.gainmax << GAINSHIFT;
310 XDrawPoint(display, window, redGC,
312 127 - (peak*gainCurrent
313 >> (GAINSHIFT + 8)));
316 XFillRectangle(display, window, whiteGC, 0, 128,
318 x = (gainTarget - (1 << GAINSHIFT))*prefs.buckets
319 / ((prefs.gainmax - 1) << GAINSHIFT);
320 XDrawLine(display, window, redGC, x,
323 x = (gn - (1 << GAINSHIFT))*prefs.buckets
324 / ((prefs.gainmax - 1) << GAINSHIFT);
326 XDrawLine(display, window, blackGC,
331 XDrawLine(display, window, blueGC,
332 0, 127 - (peak >> 8), prefs.buckets,
335 XDrawLine(display, window, whiteGC,
336 0, 127 - (peak >> 8), prefs.buckets,
341 /* See if a peak is going to clip */
342 gn = (1 << GAINSHIFT)*32768/peak;
353 /* We're ramping up, so draw it out over the whole frame */
357 /* Determine gain rate necessary to make target */
361 gr = ((gainTarget - gainCurrent) << 16)/pos;
364 gf = gainCurrent << 16;
367 fprintf(stderr, "\rgain = %2.2f%+.2e ",
368 gainCurrent*1.0/(1 << GAINSHIFT),
369 (gainTarget - gainCurrent)*1.0/(1 << GAINSHIFT));
373 for (i = 0; i < length/2; i++)
377 /* Interpolate the gain */
378 gainCurrent = gf >> 16;
382 gf = gainTarget << 16;
385 sample = (*ap)*gainCurrent >> GAINSHIFT;
391 clipped += -32768 - sample;
393 } else if (sample > 32767)
398 clipped += sample - 32767;
404 fprintf(stderr, "clip %d b%-3d ", clip, pn);
408 fprintf(stderr, "\ndone\n");