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");