~ubuntu-branches/ubuntu/hoary/kdemultimedia/hoary

« back to all changes in this revision

Viewing changes to kscd/libwm/plat_linux_cdda.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2003-01-22 15:00:51 UTC
  • Revision ID: james.westby@ubuntu.com-20030122150051-uihwkdoxf15mi1tn
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: plat_linux_cdda.c,v 1.4 2000/08/30 04:40:36 dfoerste Exp $
 
3
 *
 
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 
 
9
 *
 
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.
 
14
 *
 
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.
 
19
 *
 
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
 
23
 *
 
24
 *
 
25
 * Linux CDDA functions. Derived from the SUN module.
 
26
 */
 
27
 
 
28
#include "include/wm_config.h"
 
29
 
 
30
static char plat_linux_cdda_id[] = "$Id: plat_linux_cdda.c,v 1.4 2000/08/30 04:40:36 dfoerste Exp $";
 
31
 
 
32
#if defined(__linux__) && defined(BUILD_CDDA) /* { */
 
33
 
 
34
#include "include/wm_cdda.h"
 
35
/* types.h and cdio.h are included by wmcdda.h */
 
36
 
 
37
#include <stdio.h>
 
38
#include <math.h>
 
39
#include <sys/ioctl.h>
 
40
#include <malloc.h>
 
41
#include <errno.h>
 
42
 
 
43
#define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM
 
44
 
 
45
#define CDDABLKSIZE 2368
 
46
#define SAMPLES_PER_BLK 588
 
47
 
 
48
/* Address of next block to read. */
 
49
int     current_position = 0;
 
50
 
 
51
/* Address of first and last blocks to read. */
 
52
int     starting_position = 0;
 
53
int     ending_position = 0;
 
54
 
 
55
/* Playback direction. */
 
56
int     direction = 1;
 
57
 
 
58
/* Number of blocks to read at once; initialize to the maximum. */
 
59
int     numblocks = 30;
 
60
 
 
61
/*
 
62
 * This is the fastest way to convert from BCD to 8-bit.
 
63
 */
 
64
unsigned char unbcd[256] = {
 
65
  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  0,0,0,0,0,0,
 
66
 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  0,0,0,0,0,0,
 
67
 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,  0,0,0,0,0,0,
 
68
 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,  0,0,0,0,0,0,
 
69
 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,  0,0,0,0,0,0,
 
70
 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,  0,0,0,0,0,0,
 
71
 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,  0,0,0,0,0,0,
 
72
 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,  0,0,0,0,0,0,
 
73
 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,  0,0,0,0,0,0,
 
74
 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,  0,0,0,0,0,0,
 
75
 0,0,0,0,0,0,0,0,0,0,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
};
 
82
 
 
83
/*
 
84
 * Initialize the CDDA data buffer and open the appropriate device.
 
85
 *
 
86
 * NOTE: We allocate twice as much space as we need to actually read a block;
 
87
 * this lets us do audio manipulations without bothering to malloc a second
 
88
 * buffer.
 
89
 *
 
90
 * Also, test to see if we can actually *do* CDDA on this drive; if not, we
 
91
 * need to exit right away so the UI doesn't show the user any CDDA controls.
 
92
 */
 
93
int
 
94
wmcdda_init(char **bufadr, long *buflenadr, int init_fd, char *devname)
 
95
{
 
96
        struct cdrom_cdda       cdda;
 
97
 
 
98
        *bufadr = malloc(numblocks * CDDABLKSIZE * 2);
 
99
        if (*bufadr == NULL)
 
100
                return (-1);
 
101
 
 
102
        *buflenadr = numblocks * CDDABLKSIZE;
 
103
 
 
104
        /*init_fd = open(devname, 0);
 
105
        if (init_fd == -1)
 
106
                init_fd = open("/dev/rdsk/c0t6d0s2", 0);
 
107
        */
 
108
        init_fd = wmcdda_open(devname);
 
109
 
 
110
        if (init_fd > -1)
 
111
        {
 
112
                cdda.cdda_addr = 200;
 
113
                cdda.cdda_length = 1;
 
114
                cdda.cdda_data = *bufadr;
 
115
                cdda.cdda_subcode = CDROM_DA_SUBQ;
 
116
 
 
117
                if (ioctl(init_fd, CDROMCDDA, &cdda) < 0)
 
118
                {
 
119
                        close(init_fd);
 
120
                        init_fd = -1;
 
121
                }
 
122
        }
 
123
 
 
124
        return (init_fd);
 
125
}
 
126
 
 
127
/*
 
128
 * Try to open the CD device
 
129
 */
 
130
int
 
131
wmcdda_open(char *devname)
 
132
{
 
133
    int fd;
 
134
 
 
135
    fd = open(devname, 0); 
 
136
    if (fd == -1)
 
137
        fd = open("/dev/rdsk/c0t6d0s2", 0);
 
138
 
 
139
    return(fd);
 
140
}
 
141
 
 
142
 
 
143
/*
 
144
 * Close the CD-ROM device in preparation for exiting.
 
145
 */
 
146
void
 
147
wmcdda_close(int fd)
 
148
{
 
149
        close(fd);
 
150
}
 
151
 
 
152
/*
 
153
 * Set up for playing the CD.  Actually this doesn't play a thing, just sets a
 
154
 * couple variables so we'll know what to do when we're called.
 
155
 */
 
156
void
 
157
wmcdda_setup(int start, int end, int realstart)
 
158
{
 
159
        current_position = start - 150;
 
160
        ending_position = end - 150;
 
161
        starting_position = realstart - 150;
 
162
 
 
163
        /*
 
164
         * Special case: don't start at the "end" of a track if we're
 
165
         * playing backwards!
 
166
         */
 
167
        if (direction == -1 && start == realstart)
 
168
                current_position = ending_position - numblocks;
 
169
}
 
170
 
 
171
/*
 
172
 * Read some blocks from the CD.  Stop if we hit the end of the current region.
 
173
 *
 
174
 * Returns number of bytes read, -1 on error, 0 if stopped for a benign reason.
 
175
 */
 
176
long
 
177
wmcdda_read(int fd, unsigned char *rawbuf, long buflen,
 
178
        struct cdda_block *block)
 
179
{
 
180
        struct cdrom_cdda       cdda;
 
181
        int                     blk;
 
182
        unsigned char           *q;
 
183
        extern int              speed;
 
184
 
 
185
        if ((direction > 0 && current_position >= ending_position) ||
 
186
            (direction < 0 && current_position < starting_position))
 
187
        {
 
188
                block->status = WMCDDA_DONE;
 
189
                return (0);
 
190
        }
 
191
 
 
192
        cdda.cdda_addr = current_position;
 
193
        if (ending_position && current_position + numblocks > ending_position)
 
194
                cdda.cdda_length = ending_position - current_position;
 
195
        else
 
196
                cdda.cdda_length = numblocks;
 
197
        cdda.cdda_data = rawbuf;
 
198
        cdda.cdda_subcode = CDROM_DA_SUBQ;
 
199
 
 
200
        if (ioctl(fd, CDROMCDDA, &cdda) < 0)
 
201
        {
 
202
                if (errno == ENXIO)     /* CD ejected! */
 
203
                {
 
204
                        block->status = WMCDDA_EJECTED;
 
205
                        return (-1);
 
206
                }
 
207
 
 
208
                if (current_position + numblocks > ending_position)
 
209
                {
 
210
                        /*
 
211
                         * Hit the end of the CD, probably.
 
212
                         */
 
213
                        block->status = WMCDDA_DONE;
 
214
                        return (0);
 
215
                }
 
216
 
 
217
                /* Sometimes it fails once, dunno why */
 
218
                if (ioctl(fd, CDROMCDDA, &cdda) < 0)
 
219
                {
 
220
                        if (ioctl(fd, CDROMCDDA, &cdda) < 0)
 
221
                        {
 
222
                                if (ioctl(fd, CDROMCDDA, &cdda) < 0)
 
223
                                {
 
224
                                        perror("CDROMCDDA");
 
225
                                        block->status = WMCDDA_ERROR;
 
226
                                        return (-1);
 
227
                                }
 
228
                        }
 
229
                }
 
230
        }
 
231
 
 
232
        if (speed > 148)
 
233
        {
 
234
                /*
 
235
                 * We want speed=148 to advance by cdda_length, but
 
236
                 * speed=256 to advance cdda_length * 4.
 
237
                 */
 
238
                current_position = current_position +
 
239
                        (cdda.cdda_length * direction * (speed - 112)) / 36;
 
240
        }
 
241
        else
 
242
                current_position = current_position +
 
243
                        cdda.cdda_length * direction;
 
244
 
 
245
        for (blk = 0; blk < numblocks; blk++)
 
246
        {
 
247
                /*
 
248
                 * New valid Q-subchannel information?  Update the block
 
249
                 * status.
 
250
                 */
 
251
                q = &rawbuf[blk * CDDABLKSIZE + SAMPLES_PER_BLK * 4];
 
252
                if (*q == 1)
 
253
                {
 
254
                        block->status = WMCDDA_OK;
 
255
                        block->track =  unbcd[q[1]];
 
256
                        block->index =  unbcd[q[2]];
 
257
                        block->minute = unbcd[q[7]];
 
258
                        block->second = unbcd[q[8]];
 
259
                        block->frame =  unbcd[q[9]];
 
260
                }
 
261
        }
 
262
 
 
263
        return (cdda.cdda_length * CDDABLKSIZE);
 
264
}
 
265
 
 
266
/*
 
267
 * Normalize a bunch of CDDA data.  Basically this means ripping out the
 
268
 * Q subchannel data and doing byte-swapping, since the CD audio is in
 
269
 * littleendian format.
 
270
 *
 
271
 * Scanning is handled here too.
 
272
 *
 
273
 * XXX - do byte swapping on Intel boxes?
 
274
 */
 
275
long
 
276
wmcdda_normalize(unsigned char *rawbuf, long buflen, struct cdda_block *block)
 
277
{
 
278
        int             i, nextq;
 
279
        int             blocks = buflen / CDDABLKSIZE;
 
280
        unsigned char   *dest = rawbuf;
 
281
        unsigned char   tmp;
 
282
        long            *buf32 = (long *)rawbuf, tmp32;
 
283
 
 
284
/*
 
285
 * this was #ifndef LITTLEENDIAN
 
286
 * in wmcdda it was called LITTLE_ENDIAN. Was this a flaw?
 
287
 */
 
288
#if WM_BIG_ENDIAN
 
289
        if (blocks--)
 
290
                for (i = 0; i < SAMPLES_PER_BLK * 2; i++)
 
291
                {
 
292
                        /* Only need to use temp buffer on first block. */
 
293
                        tmp = *rawbuf++;
 
294
                        *dest++ = *rawbuf++;
 
295
                        *dest++ = tmp;
 
296
                }
 
297
#endif
 
298
 
 
299
        while (blocks--)
 
300
        {
 
301
                /* Skip over Q data. */
 
302
                rawbuf += 16;
 
303
 
 
304
                for (i = 0; i < SAMPLES_PER_BLK * 2; i++)
 
305
                {
 
306
#if WM_LITTLE_ENDIAN
 
307
                        *dest++ = *rawbuf++;
 
308
                        *dest++ = *rawbuf++;
 
309
#else
 
310
                        *dest++ = rawbuf[1];
 
311
                        *dest++ = rawbuf[0];
 
312
                        rawbuf += 2;
 
313
#endif
 
314
                }
 
315
        }
 
316
 
 
317
        buflen -= ((buflen / CDDABLKSIZE) * 16);
 
318
 
 
319
        /*
 
320
         * Reverse the data here if we're playing backwards.
 
321
         * XXX - ideally this should be done above.
 
322
         */
 
323
        if (direction < 0)
 
324
        {
 
325
                buflen /= 4;    /* we can move 32 bits at a time. */
 
326
 
 
327
                for (i = 0; i < buflen / 2; i++)
 
328
                {
 
329
                        tmp32 = buf32[i];
 
330
                        buf32[i] = buf32[buflen - i - 1];
 
331
                        buf32[buflen - i - 1] = tmp32;
 
332
                }
 
333
 
 
334
                buflen *= 4;
 
335
        }
 
336
 
 
337
        return (buflen);
 
338
}
 
339
 
 
340
/*
 
341
 * Set the playback direction.
 
342
 */
 
343
void
 
344
wmcdda_direction(int newdir)
 
345
{
 
346
        if (newdir == 0)
 
347
        {
 
348
                numblocks = 20;
 
349
                direction = 1;
 
350
        }
 
351
        else
 
352
        {
 
353
                numblocks = 30;
 
354
                direction = -1;
 
355
        }
 
356
}
 
357
 
 
358
/*
 
359
 * Do system-specific stuff to get ready to play at a particular speed.
 
360
 */
 
361
void
 
362
wmcdda_speed(int speed)
 
363
{
 
364
        if (speed > 128)
 
365
                numblocks = 12;
 
366
        else
 
367
                numblocks = direction > 0 ? 20 : 30;
 
368
}
 
369
 
 
370
#endif /* } */