wmail: change "!stat(...) == 0" to "stat(...) == -1"
[dockapps.git] / ascd / libworkman / plat_sun_cdda.c
blob90c57594c14d6fa8d366cfcfc0362d3e48885532
1 /*
2 * $Id: plat_sun_cdda.c,v 1.3 1999/03/07 08:36:41 dirk Exp $
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
25 * Sun (really Solaris) CDDA functions.
28 #include "include/wm_config.h"
29 #if defined(sun) && defined(SYSV) && defined(BUILD_CDDA) /* { */
31 static char plat_sun_cdda_id[] = "$Id: plat_sun_cdda.c,v 1.3 1999/03/07 08:36:41 dirk Exp $";
34 #include "include/wm_cdda.h"
35 /* types.h and cdio.h are included by wmcdda.h */
37 #include <stdio.h>
38 #include <math.h>
39 #include <sys/ioctl.h>
40 #include <malloc.h>
41 #include <errno.h>
43 #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM
45 #define CDDABLKSIZE 2368
46 #define SAMPLES_PER_BLK 588
48 /* Address of next block to read. */
49 int current_position = 0;
51 /* Address of first and last blocks to read. */
52 int starting_position = 0;
53 int ending_position = 0;
55 /* Playback direction. */
56 int direction = 1;
58 /* Number of blocks to read at once; initialize to the maximum. */
59 /* (was 30. Set to 15 for INTeL. Maybe config option? */
60 int numblocks = 15;
63 * This is the fastest way to convert from BCD to 8-bit.
65 unsigned char unbcd[256] = {
66 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,0,0,0,0,0,
67 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0,0,0,0,0,0,
68 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0,0,0,0,0,0,
69 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0,0,0,0,0,0,
70 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0,0,0,0,0,0,
71 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0,0,0,0,0,0,
72 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0,0,0,0,0,0,
73 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0,0,0,0,0,0,
74 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0,0,0,0,0,0,
75 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0,0,0,0,0,0,
76 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
77 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
78 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
79 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
80 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
81 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
85 * Initialize the CDDA data buffer and open the appropriate device.
87 * NOTE: We allocate twice as much space as we need to actually read a block;
88 * this lets us do audio manipulations without bothering to malloc a second
89 * buffer.
91 * Also, test to see if we can actually *do* CDDA on this drive; if not, we
92 * need to exit right away so the UI doesn't show the user any CDDA controls.
94 int
95 wmcdda_init(char **bufadr, long *buflenadr, int init_fd, char *devname)
97 struct cdrom_cdda cdda;
99 *bufadr = malloc(numblocks * CDDABLKSIZE * 2);
100 if (*bufadr == NULL)
101 return (-1);
103 *buflenadr = numblocks * CDDABLKSIZE;
105 /*init_fd = open(devname, 0);
106 if (init_fd == -1)
107 init_fd = open("/dev/rdsk/c0t6d0s2", 0);
109 init_fd = wmcdda_open(devname);
111 if (init_fd > -1)
113 cdda.cdda_addr = 200;
114 cdda.cdda_length = 1;
115 cdda.cdda_data = *bufadr;
116 cdda.cdda_subcode = CDROM_DA_SUBQ;
118 if (ioctl(init_fd, CDROMCDDA, &cdda) < 0)
120 close(init_fd);
121 init_fd = -1;
125 return (init_fd);
129 * Try to open the CD device
132 wmcdda_open(char *devname)
134 int fd;
136 fd = open(devname, 0);
137 if (fd == -1)
138 fd = open("/dev/rdsk/c0t6d0s2", 0);
140 return(fd);
145 * Close the CD-ROM device in preparation for exiting.
147 void
148 wmcdda_close(int fd)
150 close(fd);
154 * Set up for playing the CD. Actually this doesn't play a thing, just sets a
155 * couple variables so we'll know what to do when we're called.
157 void
158 wmcdda_setup(int start, int end, int realstart)
160 current_position = start - 150;
161 ending_position = end - 150;
162 starting_position = realstart - 150;
165 * Special case: don't start at the "end" of a track if we're
166 * playing backwards!
168 if (direction == -1 && start == realstart)
169 current_position = ending_position - numblocks;
173 * Read some blocks from the CD. Stop if we hit the end of the current region.
175 * Returns number of bytes read, -1 on error, 0 if stopped for a benign reason.
177 long
178 wmcdda_read(int fd, unsigned char *rawbuf, long buflen,
179 struct cdda_block *block)
181 struct cdrom_cdda cdda;
182 int blk;
183 unsigned char *q;
184 extern int speed;
186 if ((direction > 0 && current_position >= ending_position) ||
187 (direction < 0 && current_position < starting_position))
189 block->status = WMCDDA_DONE;
190 return (0);
193 cdda.cdda_addr = current_position;
194 if (ending_position && current_position + numblocks > ending_position)
195 cdda.cdda_length = ending_position - current_position;
196 else
197 cdda.cdda_length = numblocks;
198 cdda.cdda_data = rawbuf;
199 cdda.cdda_subcode = CDROM_DA_SUBQ;
201 if (ioctl(fd, CDROMCDDA, &cdda) < 0)
203 if (errno == ENXIO) /* CD ejected! */
205 block->status = WMCDDA_EJECTED;
206 return (-1);
209 if (current_position + numblocks > ending_position)
212 * Hit the end of the CD, probably.
214 block->status = WMCDDA_DONE;
215 return (0);
218 /* Sometimes it fails once, dunno why */
219 if (ioctl(fd, CDROMCDDA, &cdda) < 0)
221 if (ioctl(fd, CDROMCDDA, &cdda) < 0)
223 if (ioctl(fd, CDROMCDDA, &cdda) < 0)
225 perror("CDROMCDDA");
226 block->status = WMCDDA_ERROR;
227 return (-1);
233 if (speed > 148)
236 * We want speed=148 to advance by cdda_length, but
237 * speed=256 to advance cdda_length * 4.
239 current_position = current_position +
240 (cdda.cdda_length * direction * (speed - 112)) / 36;
242 else
243 current_position = current_position +
244 cdda.cdda_length * direction;
246 for (blk = 0; blk < numblocks; blk++)
249 * New valid Q-subchannel information? Update the block
250 * status.
252 q = &rawbuf[blk * CDDABLKSIZE + SAMPLES_PER_BLK * 4];
253 if (*q == 1)
255 block->status = WMCDDA_OK;
256 block->track = unbcd[q[1]];
257 block->index = unbcd[q[2]];
258 block->minute = unbcd[q[7]];
259 block->second = unbcd[q[8]];
260 block->frame = unbcd[q[9]];
264 return (cdda.cdda_length * CDDABLKSIZE);
268 * Normalize a bunch of CDDA data. Basically this means ripping out the
269 * Q subchannel data and doing byte-swapping, since the CD audio is in
270 * littleendian format.
272 * Scanning is handled here too.
274 * XXX - do byte swapping on Intel boxes?
276 long
277 wmcdda_normalize(unsigned char *rawbuf, long buflen, struct cdda_block *block)
279 int i, nextq;
280 int blocks = buflen / CDDABLKSIZE;
281 unsigned char *dest = rawbuf;
282 unsigned char tmp;
283 long *buf32 = (long *)rawbuf, tmp32;
286 * this was #ifndef LITTLEENDIAN
287 * in wmcdda it was called LITTLE_ENDIAN. Was this a flaw?
289 #if WM_BIG_ENDIAN
290 if (blocks--)
291 for (i = 0; i < SAMPLES_PER_BLK * 2; i++)
293 /* Only need to use temp buffer on first block. */
294 tmp = *rawbuf++;
295 *dest++ = *rawbuf++;
296 *dest++ = tmp;
298 #endif
300 while (blocks--)
302 /* Skip over Q data. */
303 rawbuf += 16;
305 for (i = 0; i < SAMPLES_PER_BLK * 2; i++)
307 #if WM_LITTLE_ENDIAN
308 *dest++ = *rawbuf++;
309 *dest++ = *rawbuf++;
310 #else
311 *dest++ = rawbuf[1];
312 *dest++ = rawbuf[0];
313 rawbuf += 2;
314 #endif
318 buflen -= ((buflen / CDDABLKSIZE) * 16);
321 * Reverse the data here if we're playing backwards.
322 * XXX - ideally this should be done above.
324 if (direction < 0)
326 buflen /= 4; /* we can move 32 bits at a time. */
328 for (i = 0; i < buflen / 2; i++)
330 tmp32 = buf32[i];
331 buf32[i] = buf32[buflen - i - 1];
332 buf32[buflen - i - 1] = tmp32;
335 buflen *= 4;
338 return (buflen);
342 * Set the playback direction.
344 void
345 wmcdda_direction(int newdir)
347 if (newdir == 0)
349 numblocks = 20;
350 direction = 1;
352 else
354 numblocks = 30;
355 direction = -1;
360 * Do system-specific stuff to get ready to play at a particular speed.
362 void
363 wmcdda_speed(int speed)
365 if (speed > 128)
366 numblocks = 12;
367 else
368 numblocks = direction > 0 ? 20 : 30;
371 #endif /* } */