4 * This file is part of WorkMan, the civilized CD player library
5 * (c) 1991-1997 by Steven Grimm (original author)
6 * (c) by Dirk Försterling (current 'author' = maintainer)
7 * The maintainer can be contacted by his e-mail address:
8 * milliByte@DeathsDoor.com
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the Free
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 ******************************************************************
26 * Digital audio manipulator for WorkMan.
28 * The CDDA architecture looks like this:
30 * WorkMan (or another UI!)
32 * ||| (separate processes connected by pipe)
34 * +------------- cddaslave -------------+
36 * command module CDDA reader audio output
37 * (portable) (per platform) (per platform)
39 * This source file has the command module and some of the scaffolding
40 * to hold cddaslave together, plus some non-system-dependent audio
41 * processing code. Look in plat_*_cdda.c for system-specific stuff.
49 static char cddaslave_id
[] = "$Id: cddaslave.c,v 1.3 1999/02/14 22:10:24 dirk Exp $";
52 #include <sys/types.h>
54 #include "include/wm_cdda.h"
55 #include "include/wm_platform.h"
58 int playing
= 0; /* Should the CD be playing now? */
61 * Loudness setting, plus the floating volume multiplier and decaying-average
65 unsigned int volume
= 32768;
69 * Playback speed (0 = slow)
74 * This is non-null if we're saving audio to a file.
79 * Audio file header format.
81 typedef unsigned long u_32
;
91 /* had to change #ifdef to #if -> see wm_cdda.h */
97 extern unsigned long htonl(x
);
101 long cdda_transform();
104 * Send status information upstream.
108 struct cdda_block
*blk
;
110 write(1, blk
, sizeof(*blk
));
114 * Accept a command from our master.
116 * The protocol is byte-oriented:
117 * PmsfMSFxyz Play from msf to MSF (MSF can be 0,0,0 to play to end)
118 * xyz is the msf of the start of this chunk, i.e., the
119 * ending boundary for reverse play.
121 * E Eject. This means we just close the CD device and
122 * open it again later.
124 * Vn Set volume level (0-255).
125 * Bn Set balance level (0-255).
126 * EnL Set an equalizer level (n = 0 for bass, 255 for treble)
127 * G Get current status.
128 * sn Set speed multiplier to n.
129 * dn Set direction to forward (n = 0) or reverse.
130 * Fllllx... Start saving to a file (length = l, followed by name)
132 * Ln Set loudness level (0-255).
137 struct cdda_block
*blk
;
139 unsigned char inbuf
[10];
144 if (read(0, inbuf
, 1) <= 0) /* Parent died. */
157 blk
->status
= WMCDDA_ACK
;
166 wmcdda_setup(inbuf
[0] * 60 * 75 + inbuf
[1] * 75 + inbuf
[2],
167 inbuf
[3] * 60 * 75 + inbuf
[4] * 75 + inbuf
[5],
168 inbuf
[6] * 60 * 75 + inbuf
[7] * 75 + inbuf
[8]);
175 blk
->status
= WMCDDA_ACK
;
182 blk
->status
= WMCDDA_ACK
;
184 blk
->status
= WMCDDA_STOPPED
;
190 wmaudio_balance(inbuf
[0]);
191 blk
->status
= WMCDDA_ACK
;
197 wmaudio_volume(inbuf
[0]);
198 blk
->status
= WMCDDA_ACK
;
203 blk
->status
= WMCDDA_ACK
;
207 blk
->status
= WMCDDA_PLAYED
;
209 blk
->status
= WMCDDA_STOPPED
;
215 blk
->status
= WMCDDA_ACK
;
225 blk
->status
= WMCDDA_ACK
;
231 wmcdda_direction(inbuf
[0]);
232 blk
->status
= WMCDDA_ACK
;
239 blk
->status
= WMCDDA_ACK
;
244 read(0, &namelen
, sizeof(namelen
));
252 filename
= malloc(namelen
+ 1);
253 if (filename
== NULL
)
261 read(0, filename
, namelen
);
262 filename
[namelen
] = '\0';
263 output
= fopen(filename
, "w");
268 /* Write an .au file header. */
269 hdr
.magic
= htonl(0x2e736e64);
270 hdr
.hdr_size
= htonl(sizeof(hdr
) + 28);
271 hdr
.data_size
= htonl(~0);
272 hdr
.encoding
= htonl(3); /* linear-16 */
273 hdr
.sample_rate
= htonl(44100);
274 hdr
.channels
= htonl(2);
276 fwrite(&hdr
, sizeof(hdr
), 1, output
);
277 fwrite("Recorded from CD by WorkMan", 28, 1,
284 blk
->status
= WMCDDA_ACK
;
291 * Transform some CDDA data.
294 wmcdda_transform(unsigned char *rawbuf
, long buflen
, struct cdda_block
*block
)
297 long *buf32
= (long *)rawbuf
;
298 register short *buf16
= (short *)rawbuf
;
302 * Loudness transformation. Basically this is a self-adjusting
303 * volume control; our goal is to keep the average output level
304 * around a certain value (2500 seems to be pleasing.) We do this
305 * by maintaining a decaying average of the recent output levels
306 * (where "recent" is some fraction of a second.) All output levels
307 * are multiplied by the inverse of the decaying average; this has
308 * the volume-leveling effect we desire, and isn't too CPU-intensive.
310 * This is done by modifying the digital data, rather than adjusting
311 * the system volume control, because (at least on some systems)
312 * tweaking the system volume can generate little pops and clicks.
314 * There's probably a more elegant way to achieve this effect, but
315 * what the heck, I never took a DSP class and am making this up as
316 * I go along, with a little help from some friends.
318 * This is all done with fixed-point math, oriented around powers
319 * of two, which with luck will keep the CPU usage to a minimum.
320 * More could probably be done, for example using lookup tables to
321 * replace multiplies and divides; whether the memory hit (128K
322 * for each table) is worthwhile is unclear.
326 /* We aren't really going backwards, but i > 0 is fast */
327 for (i
= buflen
/ 2; i
> 0; i
--)
330 * Adjust this sample to the current level.
332 aval
= (*buf16
= (((long)*buf16
) * volume
) >> 15);
336 * Don't adjust the decaying average for each sample;
337 * that just spends CPU time for very little benefit.
343 * We want to use absolute values to compute the
344 * decaying average; otherwise it'd sit around 0.
350 * Adjust more quickly when we start hitting peaks,
351 * or we'll get clipping when there's a sudden loud
352 * section after lots of quiet.
358 * Adjust the decaying average.
360 level
= ((level
<< 11) - level
+ aval
) >> 11;
363 * Let *really* quiet sounds play softly, or we'll
364 * amplify background hiss to full volume and blast
365 * the user's speakers when real sound starts up.
367 if (! (level
& ~511))
371 * And adjust the volume setting using the inverse
372 * of the decaying average.
374 volume
= (2500 << 15) / level
;
382 * Half-speed play. Stretch things out.
386 buflen
/= 2; /* Since we're moving 32 bits at a time */
388 for (i
= buflen
- 1; i
> 0; i
--)
390 buf32
[i
] = buf32
[i
/ 2];
393 buflen
*= 4; /* 2 for doubling the buffer, 2 from above */
397 * Slow play; can't optimize it as well as half-speed.
399 if (speed
&& speed
< 128)
401 int multiplier
= ((speed
+ 128) * 128) / 256;
405 buflen
/= 4; /* Get the number of 32-bit values */
408 * Buffer length doubles when speed is 0, stays the same
411 newlen
= (buflen
* 128) / multiplier
;
414 for (i
= newlen
- 1; i
> 0; i
--)
416 buf32
[i
] = buf32
[pos
];
436 fd_set readfd
, dummyfd
;
437 struct timeval timeout
;
440 struct cdda_block blockinfo
;
446 * Device name should be the command-line argument.
454 * If we're running setuid root, bump up our priority then lose
463 timerclear(&timeout
);
465 cd_fd
= wmcdda_init(&cddabuf
, &cddabuflen
, cd_fd
, devname
);
470 blockinfo
.status
= WMCDDA_ACK
;
471 send_status(&blockinfo
);
472 blockinfo
.status
= WMCDDA_STOPPED
;
475 * Accept commands as they come in, and play some sound if we're
476 * supposed to be doing that.
483 * If we're playing, we don't want select to block. Otherwise,
484 * wait a little while for the next command.
489 timeout
.tv_usec
= 500000;
491 nfds
= select(1, &readfd
, &dummyfd
, &dummyfd
, &timeout
);
493 if (nfds
< 0) /* Broken pipe; our GUI exited. */
500 if (FD_ISSET(0, &readfd
))
502 /* If this doesn't work, just hope for the best */
504 cd_fd
= wmcdda_open(devname
);
505 cd_fd
= command(cd_fd
, &blockinfo
);
507 * Process all commands in rapid succession, rather
508 * than possibly waiting for a CDDA read.
515 result
= wmcdda_read(cd_fd
, cddabuf
, cddabuflen
,
519 /* Let the output queue drain. */
520 if (blockinfo
.status
== WMCDDA_DONE
)
523 if (wmaudio_send_status())
525 /* queue drained, stop polling*/
532 send_status(&blockinfo
);
537 result
= wmcdda_normalize(cddabuf
, result
,
539 result
= wmcdda_transform(cddabuf
, result
,
542 fwrite(cddabuf
, result
, 1, output
);
543 result
= wmaudio_convert(cddabuf
, result
,
545 if (wmaudio_play(cddabuf
, result
, &blockinfo
))
549 send_status(&blockinfo
);
554 send_status(&blockinfo
);
558 #else /* BUILD_CDDA */
565 #endif /* BUILD_CDDA */