2 * $Id: plat_linux_cdda.c,v 1.3 1999/03/07 08:36:40 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 * Linux CDDA functions. Derived from the SUN module.
28 #include "include/wm_config.h"
30 #if defined(linux) && defined(BUILD_CDDA) /* { */
32 static char plat_linux_cdda_id
[] = "$Id: plat_linux_cdda.c,v 1.3 1999/03/07 08:36:40 dirk Exp $";
35 #include "include/wm_cdda.h"
36 /* types.h and cdio.h are included by wmcdda.h */
40 #include <sys/ioctl.h>
44 #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM
46 #define CDDABLKSIZE 2368
47 #define SAMPLES_PER_BLK 588
49 /* Address of next block to read. */
50 int current_position
= 0;
52 /* Address of first and last blocks to read. */
53 int starting_position
= 0;
54 int ending_position
= 0;
56 /* Playback direction. */
59 /* Number of blocks to read at once; initialize to the maximum. */
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
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.
95 wmcdda_init(char **bufadr
, long *buflenadr
, int init_fd
, char *devname
)
97 struct cdrom_cdda cdda
;
99 *bufadr
= malloc(numblocks
* CDDABLKSIZE
* 2);
103 *buflenadr
= numblocks
* CDDABLKSIZE
;
105 /*init_fd = open(devname, 0);
107 init_fd = open("/dev/rdsk/c0t6d0s2", 0);
109 init_fd
= wmcdda_open(devname
);
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)
129 * Try to open the CD device
132 wmcdda_open(char *devname
)
136 fd
= open(devname
, 0);
138 fd
= open("/dev/rdsk/c0t6d0s2", 0);
145 * Close the CD-ROM device in preparation for exiting.
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.
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
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.
178 wmcdda_read(int fd
, unsigned char *rawbuf
, long buflen
,
179 struct cdda_block
*block
)
181 struct cdrom_cdda cdda
;
186 if ((direction
> 0 && current_position
>= ending_position
) ||
187 (direction
< 0 && current_position
< starting_position
))
189 block
->status
= WMCDDA_DONE
;
193 cdda
.cdda_addr
= current_position
;
194 if (ending_position
&& current_position
+ numblocks
> ending_position
)
195 cdda
.cdda_length
= ending_position
- current_position
;
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
;
209 if (current_position
+ numblocks
> ending_position
)
212 * Hit the end of the CD, probably.
214 block
->status
= WMCDDA_DONE
;
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)
226 block
->status
= WMCDDA_ERROR
;
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;
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
252 q
= &rawbuf
[blk
* CDDABLKSIZE
+ SAMPLES_PER_BLK
* 4];
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?
277 wmcdda_normalize(unsigned char *rawbuf
, long buflen
, struct cdda_block
*block
)
280 int blocks
= buflen
/ CDDABLKSIZE
;
281 unsigned char *dest
= rawbuf
;
283 long *buf32
= (long *)rawbuf
, tmp32
;
286 * this was #ifndef LITTLEENDIAN
287 * in wmcdda it was called LITTLE_ENDIAN. Was this a flaw?
291 for (i
= 0; i
< SAMPLES_PER_BLK
* 2; i
++)
293 /* Only need to use temp buffer on first block. */
302 /* Skip over Q data. */
305 for (i
= 0; i
< SAMPLES_PER_BLK
* 2; i
++)
318 buflen
-= ((buflen
/ CDDABLKSIZE
) * 16);
321 * Reverse the data here if we're playing backwards.
322 * XXX - ideally this should be done above.
326 buflen
/= 4; /* we can move 32 bits at a time. */
328 for (i
= 0; i
< buflen
/ 2; i
++)
331 buf32
[i
] = buf32
[buflen
- i
- 1];
332 buf32
[buflen
- i
- 1] = tmp32
;
342 * Set the playback direction.
345 wmcdda_direction(int newdir
)
360 * Do system-specific stuff to get ready to play at a particular speed.
363 wmcdda_speed(int speed
)
368 numblocks
= direction
> 0 ? 20 : 30;