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

« back to all changes in this revision

Viewing changes to kscd/libwm/plat_sun_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_sun_cdda.c,v 1.4 2000/10/16 08:01:08 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
 * Sun (really Solaris) CDDA functions.
 
26
 */
 
27
 
 
28
#include "include/wm_config.h"
 
29
 
 
30
static char plat_sun_cdda_id[] = "$Id: plat_sun_cdda.c,v 1.4 2000/10/16 08:01:08 dfoerste Exp $";
 
31
#if defined(sun) || defined(__sun__) && defined(SYSV) && defined(BUILD_CDDA) && defined(WMCDDA_DONE) /* { */
 
32
 
 
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
/* (was 30. Set to 15 for INTeL. Maybe config option? */
 
60
int     numblocks = 15;
 
61
 
 
62
/*
 
63
 * This is the fastest way to convert from BCD to 8-bit.
 
64
 */
 
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
 
82
};
 
83
 
 
84
/*
 
85
 * Initialize the CDDA data buffer and open the appropriate device.
 
86
 *
 
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.
 
90
 *
 
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.
 
93
 */
 
94
int
 
95
wmcdda_init(char **bufadr, long *buflenadr, int init_fd, char *devname)
 
96
{
 
97
        struct cdrom_cdda       cdda;
 
98
 
 
99
        *bufadr = malloc(numblocks * CDDABLKSIZE * 2);
 
100
        if (*bufadr == NULL)
 
101
                return (-1);
 
102
 
 
103
        *buflenadr = numblocks * CDDABLKSIZE;
 
104
 
 
105
        /*init_fd = open(devname, 0);
 
106
        if (init_fd == -1)
 
107
                init_fd = open("/dev/rdsk/c0t6d0s2", 0);
 
108
        */
 
109
        init_fd = wmcdda_open(devname);
 
110
 
 
111
        if (init_fd > -1)
 
112
        {
 
113
                cdda.cdda_addr = 200;
 
114
                cdda.cdda_length = 1;
 
115
                cdda.cdda_data = *bufadr;
 
116
                cdda.cdda_subcode = CDROM_DA_SUBQ;
 
117
 
 
118
                if (ioctl(init_fd, CDROMCDDA, &cdda) < 0)
 
119
                {
 
120
                        close(init_fd);
 
121
                        init_fd = -1;
 
122
                }
 
123
        }
 
124
 
 
125
        return (init_fd);
 
126
}
 
127
 
 
128
/*
 
129
 * Try to open the CD device
 
130
 */
 
131
int
 
132
wmcdda_open(char *devname)
 
133
{
 
134
    int fd;
 
135
 
 
136
    fd = open(devname, 0); 
 
137
    if (fd == -1)
 
138
        fd = open("/dev/rdsk/c0t6d0s2", 0);
 
139
 
 
140
    return(fd);
 
141
}
 
142
 
 
143
 
 
144
/*
 
145
 * Close the CD-ROM device in preparation for exiting.
 
146
 */
 
147
void
 
148
wmcdda_close(int fd)
 
149
{
 
150
        close(fd);
 
151
}
 
152
 
 
153
/*
 
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.
 
156
 */
 
157
void
 
158
wmcdda_setup(int start, int end, int realstart)
 
159
{
 
160
        current_position = start - 150;
 
161
        ending_position = end - 150;
 
162
        starting_position = realstart - 150;
 
163
 
 
164
        /*
 
165
         * Special case: don't start at the "end" of a track if we're
 
166
         * playing backwards!
 
167
         */
 
168
        if (direction == -1 && start == realstart)
 
169
                current_position = ending_position - numblocks;
 
170
}
 
171
 
 
172
/*
 
173
 * Read some blocks from the CD.  Stop if we hit the end of the current region.
 
174
 *
 
175
 * Returns number of bytes read, -1 on error, 0 if stopped for a benign reason.
 
176
 */
 
177
long
 
178
wmcdda_read(int fd, unsigned char *rawbuf, long buflen,
 
179
        struct cdda_block *block)
 
180
{
 
181
        struct cdrom_cdda       cdda;
 
182
        int                     blk;
 
183
        unsigned char           *q;
 
184
        extern int              speed;
 
185
 
 
186
        if ((direction > 0 && current_position >= ending_position) ||
 
187
            (direction < 0 && current_position < starting_position))
 
188
        {
 
189
                block->status = WMCDDA_DONE;
 
190
                return (0);
 
191
        }
 
192
 
 
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;
 
200
 
 
201
        if (ioctl(fd, CDROMCDDA, &cdda) < 0)
 
202
        {
 
203
                if (errno == ENXIO)     /* CD ejected! */
 
204
                {
 
205
                        block->status = WMCDDA_EJECTED;
 
206
                        return (-1);
 
207
                }
 
208
 
 
209
                if (current_position + numblocks > ending_position)
 
210
                {
 
211
                        /*
 
212
                         * Hit the end of the CD, probably.
 
213
                         */
 
214
                        block->status = WMCDDA_DONE;
 
215
                        return (0);
 
216
                }
 
217
 
 
218
                /* Sometimes it fails once, dunno why */
 
219
                if (ioctl(fd, CDROMCDDA, &cdda) < 0)
 
220
                {
 
221
                        if (ioctl(fd, CDROMCDDA, &cdda) < 0)
 
222
                        {
 
223
                                if (ioctl(fd, CDROMCDDA, &cdda) < 0)
 
224
                                {
 
225
                                        perror("CDROMCDDA");
 
226
                                        block->status = WMCDDA_ERROR;
 
227
                                        return (-1);
 
228
                                }
 
229
                        }
 
230
                }
 
231
        }
 
232
 
 
233
        if (speed > 148)
 
234
        {
 
235
                /*
 
236
                 * We want speed=148 to advance by cdda_length, but
 
237
                 * speed=256 to advance cdda_length * 4.
 
238
                 */
 
239
                current_position = current_position +
 
240
                        (cdda.cdda_length * direction * (speed - 112)) / 36;
 
241
        }
 
242
        else
 
243
                current_position = current_position +
 
244
                        cdda.cdda_length * direction;
 
245
 
 
246
        for (blk = 0; blk < numblocks; blk++)
 
247
        {
 
248
                /*
 
249
                 * New valid Q-subchannel information?  Update the block
 
250
                 * status.
 
251
                 */
 
252
                q = &rawbuf[blk * CDDABLKSIZE + SAMPLES_PER_BLK * 4];
 
253
                if (*q == 1)
 
254
                {
 
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]];
 
261
                }
 
262
        }
 
263
 
 
264
        return (cdda.cdda_length * CDDABLKSIZE);
 
265
}
 
266
 
 
267
/*
 
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.
 
271
 *
 
272
 * Scanning is handled here too.
 
273
 *
 
274
 * XXX - do byte swapping on Intel boxes?
 
275
 */
 
276
long
 
277
wmcdda_normalize(unsigned char *rawbuf, long buflen, struct cdda_block *block)
 
278
{
 
279
        int             i, nextq;
 
280
        int             blocks = buflen / CDDABLKSIZE;
 
281
        unsigned char   *dest = rawbuf;
 
282
        unsigned char   tmp;
 
283
        long            *buf32 = (long *)rawbuf, tmp32;
 
284
 
 
285
/*
 
286
 * this was #ifndef LITTLEENDIAN
 
287
 * in wmcdda it was called LITTLE_ENDIAN. Was this a flaw?
 
288
 */
 
289
#if WM_BIG_ENDIAN
 
290
        if (blocks--)
 
291
                for (i = 0; i < SAMPLES_PER_BLK * 2; i++)
 
292
                {
 
293
                        /* Only need to use temp buffer on first block. */
 
294
                        tmp = *rawbuf++;
 
295
                        *dest++ = *rawbuf++;
 
296
                        *dest++ = tmp;
 
297
                }
 
298
#endif
 
299
 
 
300
        while (blocks--)
 
301
        {
 
302
                /* Skip over Q data. */
 
303
                rawbuf += 16;
 
304
 
 
305
                for (i = 0; i < SAMPLES_PER_BLK * 2; i++)
 
306
                {
 
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
 
315
                }
 
316
        }
 
317
 
 
318
        buflen -= ((buflen / CDDABLKSIZE) * 16);
 
319
 
 
320
        /*
 
321
         * Reverse the data here if we're playing backwards.
 
322
         * XXX - ideally this should be done above.
 
323
         */
 
324
        if (direction < 0)
 
325
        {
 
326
                buflen /= 4;    /* we can move 32 bits at a time. */
 
327
 
 
328
                for (i = 0; i < buflen / 2; i++)
 
329
                {
 
330
                        tmp32 = buf32[i];
 
331
                        buf32[i] = buf32[buflen - i - 1];
 
332
                        buf32[buflen - i - 1] = tmp32;
 
333
                }
 
334
 
 
335
                buflen *= 4;
 
336
        }
 
337
 
 
338
        return (buflen);
 
339
}
 
340
 
 
341
/*
 
342
 * Set the playback direction.
 
343
 */
 
344
void
 
345
wmcdda_direction(int newdir)
 
346
{
 
347
        if (newdir == 0)
 
348
        {
 
349
                numblocks = 20;
 
350
                direction = 1;
 
351
        }
 
352
        else
 
353
        {
 
354
                numblocks = 30;
 
355
                direction = -1;
 
356
        }
 
357
}
 
358
 
 
359
/*
 
360
 * Do system-specific stuff to get ready to play at a particular speed.
 
361
 */
 
362
void
 
363
wmcdda_speed(int speed)
 
364
{
 
365
        if (speed > 128)
 
366
                numblocks = 12;
 
367
        else
 
368
                numblocks = direction > 0 ? 20 : 30;
 
369
}
 
370
 
 
371
#endif /* } */