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.
45
#include "include/wm_config.h"
49
static char cddaslave_id[] = "$Id: cddaslave.c,v 1.2 2001/06/05 05:37:25 dfoerste 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 */