~ubuntu-branches/ubuntu/vivid/basilisk2/vivid

« back to all changes in this revision

Viewing changes to src/Unix/bincue_unix.cpp

  • Committer: Package Import Robot
  • Author(s): Jonas Smedegaard, Jonas Smedegaard, Jérémy Lal, Giulio Paci
  • Date: 2012-05-19 02:08:30 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20120519020830-o59ui1wsfftg55m6
Tags: 0.9.20120331-1
* Upstream update

[ Jonas Smedegaard ]
* Drop local CDBS snippets: All included in main cdbs now.
* Use source format 3.0 (quilt), and stop including patchsys-quilt.mk.
  Stop build-depending on quilt, patchutils.
* Add full licensing header to debian/rules, and update copyright
  years.
* Add README.source (and drop outdated README.cdbs-tweaks).
* Refresh patches with shortening quilt options --no-index
  --no-timestamps -pab, and fix their path prefix.
* Rewrite copyright file using draft DEP-5 format.
* Update control file Vcs-* fields: Packaging moved to Git.
* Ease building with git-buildpackage:
  + Add gbp.conf, enabling pristine-tar and tag signing.
  + Git-ignore quilt .pc dir.
* Bump debhelper compat level to 7.
* Update Vcs-Browser field to use anonscm.debian.org.
* Add Giulio Paci and Jérémy Lal as uploaders, and permit Debian
  Maintainers to upload.

[ Jérémy Lal ]
* Drop patch 1002 to fix capitalized flag: corrected upstream.

[ Giulio Paci ]
* Restart package development.
  Closes: #662175.
* Add patches to fix compilation and documentation.
* Provide JIT flavor on supported architectures (i386 and amd64).
* Bump standards-version to 3.9.3.
* Update copyright file:
  + Adjust licenses now clarified/improved upstream.
* Update ChangeLog.cvs.
* Enable CDBS autogeneration of autotools files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2002-2010  The DOSBox Team
 
3
 *
 
4
 *  This program is free software; you can redistribute it and/or modify
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License, or
 
7
 *  (at your option) any later version.
 
8
 *
 
9
 *  This program is distributed in the hope that it will be useful,
 
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 *  GNU General Public License for more details.
 
13
 *
 
14
 *  You should have received a copy of the GNU General Public License
 
15
 *  along with this program; if not, write to the Free Software
 
16
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
17
 */
 
18
 
 
19
/* Geoffrey Brown 2010
 
20
 * Includes ideas from dosbox src/dos/cdrom_image.cpp 
 
21
 *
 
22
 * Limitations: 1) cue files must reference single bin file
 
23
 *              2) only supports raw mode1 data and audio
 
24
 *              3) no support for audio flags
 
25
 *              4) requires SDL audio or OS X core audio
 
26
 *              5) limited cue file keyword support
 
27
 *
 
28
 * Creating cue/bin files:
 
29
 *      cdrdao read-cd --read-raw --paranoia 3 foo.toc
 
30
 *  toc2cue foo.toc
 
31
 */
 
32
 
 
33
#include "sysdeps.h"
 
34
#include <stdio.h>
 
35
#include <stdlib.h>
 
36
#include <ctype.h>
 
37
#include <libgen.h>
 
38
#include <string.h>
 
39
#include <fcntl.h>
 
40
#include <unistd.h>
 
41
#include <sys/stat.h>
 
42
#include <errno.h>
 
43
 
 
44
#ifdef OSX_CORE_AUDIO
 
45
#include "../MacOSX/MacOSX_sound_if.h"
 
46
static int bincue_core_audio_callback(void);
 
47
#endif
 
48
 
 
49
#ifdef USE_SDL_AUDIO
 
50
#include <SDL.h>
 
51
#include <SDL_audio.h>
 
52
#endif
 
53
 
 
54
#include "bincue_unix.h"
 
55
#define DEBUG 0
 
56
#include "debug.h"
 
57
 
 
58
#define MAXTRACK 100
 
59
#define MAXLINE 512
 
60
#define CD_FRAMES 75
 
61
#define RAW_SECTOR_SIZE         2352
 
62
#define COOKED_SECTOR_SIZE      2048
 
63
 
 
64
// Bits of Track Control Field -- These are standard for scsi cd players
 
65
 
 
66
#define PREMPHASIS 0x1
 
67
#define COPY       0x2
 
68
#define DATA       0x4
 
69
#define AUDIO      0
 
70
#define FOURTRACK  0x8
 
71
 
 
72
// Audio status -- These are standard for scsi cd players
 
73
 
 
74
#define CDROM_AUDIO_INVALID    0x00
 
75
#define CDROM_AUDIO_PLAY       0x11
 
76
#define CDROM_AUDIO_PAUSED     0x12
 
77
#define CDROM_AUDIO_COMPLETED  0x13
 
78
#define CDROM_AUDIO_ERROR      0x14
 
79
#define CDROM_AUDIO_NO_STATUS  0x15
 
80
 
 
81
typedef unsigned char uint8;
 
82
 
 
83
// cuefiles can be challenging as some information is
 
84
// implied.  For example, there may a pregap (also postgap)
 
85
// of silence that must be generated.  Here we implement
 
86
// only the pregap.
 
87
 
 
88
typedef struct {
 
89
        int number;
 
90
        unsigned int start;     // Track start in frames
 
91
        unsigned int length;    // Track length in frames
 
92
        loff_t fileoffset;              // Track frame start within file
 
93
        unsigned int pregap;    // Silence in frames to generate
 
94
        unsigned char tcf;              // Track control field
 
95
} Track;
 
96
 
 
97
typedef struct {
 
98
        char *binfile;                  // Binary file name
 
99
        unsigned int length;    // file length in frames
 
100
        int binfh;                              // binary file handle
 
101
        int tcnt;                               // number of tracks
 
102
        Track tracks[MAXTRACK];
 
103
} CueSheet;
 
104
 
 
105
typedef struct {
 
106
        CueSheet *cs;                           // cue sheet to play from
 
107
        int audiofh;                            // file handle for audio data
 
108
        unsigned int audioposition; // current position from audiostart (bytes)
 
109
        unsigned int audiostart;        // start position if playing (frame)
 
110
        unsigned int audioend;          // end position if playing (frames)
 
111
        unsigned int silence;           // pregap (silence) bytes
 
112
        unsigned char audiostatus;      // See defines above for status
 
113
        loff_t fileoffset;                      // offset from file beginning to audiostart
 
114
#ifdef OSX_CORE_AUDIO
 
115
        OSXsoundOutput soundoutput;
 
116
#endif
 
117
} CDPlayer;
 
118
 
 
119
// Minute,Second,Frame data type
 
120
 
 
121
typedef struct {
 
122
        int m, s, f; // note size matters since we scan for %d !
 
123
} MSF;
 
124
 
 
125
// Parser State
 
126
 
 
127
static unsigned int totalPregap;
 
128
static unsigned int prestart;
 
129
 
 
130
// Audio System State
 
131
 
 
132
static bool audio_enabled = false;
 
133
static uint8 silence_byte;
 
134
 
 
135
 
 
136
// CD Player state.  Note only one player is supported !
 
137
 
 
138
static CDPlayer player;
 
139
 
 
140
static void FramesToMSF(unsigned int frames, MSF *msf)
 
141
{
 
142
        msf->m = frames/(60 * CD_FRAMES);
 
143
        frames = frames%(60 * CD_FRAMES);
 
144
        msf->s = frames/CD_FRAMES;
 
145
        msf->f = frames%CD_FRAMES;
 
146
}
 
147
 
 
148
static int MSFToFrames(MSF msf)
 
149
{
 
150
        return (msf.m * 60 * CD_FRAMES) + (msf.s * CD_FRAMES) + msf.f;
 
151
}
 
152
 
 
153
 
 
154
static int PositionToTrack(CueSheet *cs, unsigned int position)
 
155
{
 
156
        int i;
 
157
        MSF msf;
 
158
 
 
159
        FramesToMSF(position, &msf);
 
160
 
 
161
        for (i = 0; i < cs->tcnt; i++) {
 
162
                if ((position >= cs->tracks[i].start) &&
 
163
                        (position <= (cs->tracks[i].start + cs->tracks[i].length)))
 
164
                        break;
 
165
        }
 
166
        return i;
 
167
}
 
168
 
 
169
static bool AddTrack(CueSheet *cs)
 
170
{
 
171
        int skip = prestart;
 
172
        Track *prev;
 
173
        Track *curr = &(cs->tracks[cs->tcnt]);
 
174
 
 
175
        prestart = 0;
 
176
 
 
177
        if (skip > 0) {
 
178
                if (skip > curr->start) {
 
179
                        D(bug("AddTrack: prestart > start\n"));
 
180
                        return false;
 
181
                }
 
182
        }
 
183
 
 
184
        curr->fileoffset = curr->start * RAW_SECTOR_SIZE;
 
185
 
 
186
        // now we patch up the indicated time
 
187
 
 
188
        curr->start += totalPregap;
 
189
 
 
190
        // curr->pregap is supposed to be part of this track, but it
 
191
        // must be generated as silence
 
192
 
 
193
        totalPregap += curr->pregap;
 
194
 
 
195
        if (cs->tcnt == 0) {
 
196
                if (curr->number != 1) {
 
197
                        D(bug("AddTrack: number != 1\n"));
 
198
                        return false;
 
199
                }
 
200
                cs->tcnt++;
 
201
                return true;
 
202
        }
 
203
 
 
204
        prev = &(cs->tracks[cs->tcnt - 1]);
 
205
 
 
206
        if (prev->start < skip)
 
207
                prev->length = skip - prev->start - curr->pregap;
 
208
        else
 
209
                prev->length = curr->start - prev->start - curr->pregap;
 
210
 
 
211
        // error checks
 
212
 
 
213
        if (curr->number <= 1) {
 
214
                D(bug("Bad track number %d\n", curr->number));
 
215
                return false;
 
216
        }
 
217
        if ((prev->number + 1 != curr->number) && (curr->number != 0xAA)) {
 
218
                D(bug("Bad track number %d\n", curr->number));
 
219
                return false;
 
220
        }
 
221
        if (curr->start < prev->start + prev->length) {
 
222
                D(bug("unexpected start %d\n", curr->start));
 
223
                return false;
 
224
        }
 
225
 
 
226
        cs->tcnt++;
 
227
        return true;
 
228
}
 
229
 
 
230
static bool ParseCueSheet(FILE *fh, CueSheet *cs, const char *cuefile)
 
231
{
 
232
        bool seen1st = false;
 
233
        char line[MAXLINE];
 
234
        unsigned int i_line=0;
 
235
        char *keyword;
 
236
        
 
237
        totalPregap = 0;
 
238
        prestart = 0;
 
239
 
 
240
        while (fgets(line, MAXLINE, fh) != NULL) {
 
241
                Track *curr = &cs->tracks[cs->tcnt];
 
242
 
 
243
                // check for CUE file
 
244
 
 
245
                if (!i_line && (strncmp("FILE", line, 4) != 0)) {
 
246
                        return false;
 
247
                }
 
248
                i_line++;
 
249
 
 
250
                // extract keyword
 
251
 
 
252
                if (NULL != (keyword = strtok(line, " \t\n\t"))) {
 
253
                        if (!strcmp("FILE", keyword)) {
 
254
                                char *filename;
 
255
                                char *filetype;
 
256
 
 
257
                                if (i_line > 1) {
 
258
                                        D(bug("More than one FILE token\n"));
 
259
                                        goto fail;      
 
260
                                }       
 
261
                                filename = strtok(NULL, "\"\t\n\r");
 
262
                                filetype = strtok(NULL, " \"\t\n\r");
 
263
                                if (strcmp("BINARY", filetype)) {
 
264
                                        D(bug("Not binary file %s", filetype));
 
265
                                        goto fail;
 
266
                                }
 
267
                                else {
 
268
                                        char *tmp = strdup(cuefile);
 
269
                                        char *b = dirname(tmp);
 
270
                                        cs->binfile = (char *) malloc(strlen(b) + strlen(filename) + 2);
 
271
                                        sprintf(cs->binfile, "%s/%s", b, filename);
 
272
                                        free(tmp);
 
273
                                }
 
274
                        } else if (!strcmp("TRACK", keyword)) {
 
275
                                char *field;
 
276
                                int i_track;
 
277
 
 
278
                                if (seen1st) {
 
279
                                        if (!AddTrack(cs)){
 
280
                                                D(bug("AddTrack failed \n"));
 
281
                                                goto fail;
 
282
                                        }
 
283
                                        curr = &cs->tracks[cs->tcnt];
 
284
                                }
 
285
 
 
286
                                seen1st = true;
 
287
 
 
288
                                // parse track number
 
289
 
 
290
                                field = strtok(NULL, " \t\n\r");
 
291
                                if (1 != sscanf(field, "%d", &i_track)) {
 
292
                                        D(bug("Expected  track number\n"));
 
293
                                        goto fail;              
 
294
                                }
 
295
                                curr->number = i_track;
 
296
 
 
297
                                // parse track type
 
298
 
 
299
                                field = strtok(NULL, " \t\n\r");
 
300
                                if (!strcmp("MODE1/2352", field)) {
 
301
                                        curr->tcf = DATA;
 
302
                                } else if (!strcmp("AUDIO", field)) {
 
303
                                        curr->tcf = AUDIO;
 
304
                                } else {
 
305
                                        D(bug("Unexpected track type %s", field));
 
306
                                        goto fail;
 
307
                                }
 
308
 
 
309
                        } else if (!strcmp("INDEX", keyword)) {
 
310
                                char *field;
 
311
                                int i_index;
 
312
                                MSF msf;
 
313
 
 
314
                                // parse INDEX number
 
315
 
 
316
                                field = strtok(NULL, " \t\n\r");
 
317
                                if (1 != sscanf(field, "%d", &i_index)) {
 
318
                                        D(bug("Expected index number"));
 
319
                                        goto fail;
 
320
                                }
 
321
 
 
322
                                // parse INDEX start
 
323
 
 
324
                                field = strtok(NULL, " \t\n\r");
 
325
                                if (3 != sscanf(field, "%d:%d:%d", 
 
326
                                                                 &msf.m, &msf.s, &msf.f)) {
 
327
                                        D(bug("Expected index start frame\n"));
 
328
                                        goto fail;
 
329
                                }
 
330
 
 
331
                                if (i_index == 1)
 
332
                                        curr->start = MSFToFrames(msf);
 
333
                                else if (i_index == 0)
 
334
                                        prestart = MSFToFrames(msf);
 
335
                        } else if (!strcmp("PREGAP", keyword)) {
 
336
                                MSF msf;
 
337
                                char *field = strtok(NULL, " \t\n\r");
 
338
                                if (3 != sscanf(field, "%d:%d:%d", 
 
339
                                                                 &msf.m, &msf.s, &msf.f)) {
 
340
                                        D(bug("Expected pregap frame\n"));
 
341
                                        goto fail;      
 
342
                                }
 
343
                                curr->pregap = MSFToFrames(msf);
 
344
 
 
345
                                // Ignored directives
 
346
 
 
347
                        } else if (!strcmp("TITLE", keyword)) {
 
348
                        } else if (!strcmp("PERFORMER", keyword)) {
 
349
                        } else if (!strcmp("REM", keyword)) {
 
350
                        } else if (!strcmp("ISRC", keyword)) {
 
351
                        } else if (!strcmp("SONGWRITER", keyword)) {
 
352
                        } else {
 
353
                                D(bug("Unexpected keyword %s\n", keyword));
 
354
                                goto fail;              
 
355
                        }
 
356
                }
 
357
        }
 
358
 
 
359
        AddTrack(cs); // add final track
 
360
        return true;
 
361
  fail:
 
362
        return false;
 
363
}
 
364
 
 
365
static bool LoadCueSheet(const char *cuefile, CueSheet *cs)
 
366
{
 
367
        FILE *fh = NULL;
 
368
        int binfh = -1;
 
369
        struct stat buf;
 
370
        Track *tlast = NULL;
 
371
 
 
372
        if (cs) {
 
373
                bzero(cs, sizeof(*cs));
 
374
                if (!(fh = fopen(cuefile, "r")))
 
375
                        return false;
 
376
 
 
377
                if (!ParseCueSheet(fh, cs, cuefile)) goto fail;
 
378
 
 
379
                // Open bin file and find length
 
380
 
 
381
                if ((binfh = open(cs->binfile,O_RDONLY)) < 0) {
 
382
                        D(bug("Can't read bin file %s\n", cs->binfile));
 
383
                        goto fail;
 
384
                }
 
385
 
 
386
                if (fstat(binfh, &buf)) {
 
387
                        D(bug("fstat returned error\n"));
 
388
                        goto fail;
 
389
                }
 
390
 
 
391
                // compute length of final track
 
392
 
 
393
 
 
394
                tlast = &cs->tracks[cs->tcnt - 1];
 
395
                tlast->length = buf.st_size/RAW_SECTOR_SIZE 
 
396
                                                - tlast->start + totalPregap;
 
397
 
 
398
                if (tlast->length < 0) {
 
399
                        D(bug("Binary file too short \n"));
 
400
                        goto fail;      
 
401
            }
 
402
 
 
403
                // save bin file length and pointer
 
404
 
 
405
                cs->length = buf.st_size/RAW_SECTOR_SIZE;
 
406
                cs->binfh = binfh;
 
407
 
 
408
                fclose(fh);
 
409
                return true;
 
410
 
 
411
          fail:
 
412
                if (binfh >= 0)
 
413
                        close(binfh);   
 
414
                fclose(fh);
 
415
                free(cs->binfile);
 
416
                return false;
 
417
 
 
418
    }
 
419
        return false;
 
420
}
 
421
 
 
422
 
 
423
 
 
424
void *open_bincue(const char *name)
 
425
{
 
426
        CueSheet *cs;
 
427
 
 
428
        if (player.cs == NULL) {
 
429
                cs = (CueSheet *) malloc(sizeof(CueSheet));
 
430
                if (!cs) {
 
431
                        D(bug("malloc failed\n"));
 
432
                        return NULL;
 
433
                }
 
434
 
 
435
                if (LoadCueSheet(name, cs)) {
 
436
                        player.cs = cs;
 
437
#ifdef OSX_CORE_AUDIO
 
438
                        audio_enabled = true;
 
439
#endif
 
440
                        if (audio_enabled)
 
441
                                player.audiostatus = CDROM_AUDIO_NO_STATUS;
 
442
                        else
 
443
                                player.audiostatus = CDROM_AUDIO_INVALID;
 
444
                        player.audiofh = dup(cs->binfh);
 
445
                        return cs;
 
446
                }
 
447
                else
 
448
                        free(cs);
 
449
        }
 
450
        return NULL;
 
451
}
 
452
 
 
453
void close_bincue(void *fh)
 
454
{
 
455
 
 
456
 
 
457
}
 
458
 
 
459
/*
 
460
 * File read (cooked)
 
461
 * Data are stored in raw sectors of which only COOKED_SECTOR_SIZE
 
462
 * bytes are valid -- the remaining include 16 bytes at the beginning
 
463
 * of each raw sector and RAW_SECTOR_SIZE - COOKED_SECTOR_SIZE - bytes
 
464
 * at the end
 
465
 *
 
466
 * We assume that a read request can land in the middle of
 
467
 * sector.  We compute the byte address of that sector (sec)
 
468
 * and the offset of the first byte we want within that sector (secoff)
 
469
 *
 
470
 * Reading is performed one raw sector at a time, extracting as many
 
471
 * valid bytes as possible from that raw sector (available)
 
472
 */
 
473
 
 
474
size_t read_bincue(void *fh, void *b, loff_t offset, size_t len)
 
475
{
 
476
        size_t bytes_read = 0;                                          // bytes read so far
 
477
        unsigned char *buf = (unsigned char *) b;       // target buffer
 
478
        unsigned char secbuf[RAW_SECTOR_SIZE];          // temporary buffer
 
479
 
 
480
        off_t sec = ((offset/COOKED_SECTOR_SIZE) * RAW_SECTOR_SIZE);
 
481
        off_t secoff = offset % COOKED_SECTOR_SIZE;
 
482
 
 
483
        // sec contains location (in bytes) of next raw sector to read
 
484
        // secoff contains offset within that sector at which to start
 
485
        // reading since we can request a read that starts in the middle
 
486
        // of a sector
 
487
 
 
488
        CueSheet *cs = (CueSheet *) fh;
 
489
 
 
490
        if (cs == NULL || lseek(cs->binfh, sec, SEEK_SET) < 0) {
 
491
                return -1;
 
492
        }
 
493
        while (len) {
 
494
 
 
495
                // bytes available in next raw sector or len (bytes)
 
496
                // we want whichever is less
 
497
 
 
498
                size_t available = COOKED_SECTOR_SIZE - secoff;
 
499
                available = (available > len) ? len : available;
 
500
 
 
501
                // read the next raw sector
 
502
 
 
503
                if (read(cs->binfh, secbuf, RAW_SECTOR_SIZE) != RAW_SECTOR_SIZE) {
 
504
                        return bytes_read;
 
505
                }
 
506
 
 
507
                // copy cooked sector bytes (skip first 16)
 
508
                // we want out of those available
 
509
 
 
510
                bcopy(&secbuf[16+secoff], &buf[bytes_read], available);
 
511
 
 
512
                // next sector we start at the beginning
 
513
 
 
514
                secoff = 0;
 
515
 
 
516
                // increment running count decrement request
 
517
 
 
518
                bytes_read += available;
 
519
                len -= available;
 
520
        }
 
521
        return bytes_read;
 
522
}
 
523
 
 
524
loff_t size_bincue(void *fh)
 
525
{
 
526
        if (fh) {
 
527
                return ((CueSheet *)fh)->length * COOKED_SECTOR_SIZE;
 
528
        }
 
529
}
 
530
 
 
531
bool readtoc_bincue(void *fh, unsigned char *toc)
 
532
{
 
533
        CueSheet *cs = (CueSheet *) fh;
 
534
        if (cs) {
 
535
 
 
536
                MSF msf;
 
537
                unsigned char *p = toc + 2;
 
538
                *p++ = cs->tracks[0].number;
 
539
                *p++ = cs->tracks[cs->tcnt - 1].number;
 
540
                for (int i = 0; i < cs->tcnt; i++) {
 
541
 
 
542
                        FramesToMSF(cs->tracks[i].start, &msf);
 
543
                        *p++ = 0;
 
544
                        *p++ = 0x10 | cs->tracks[i].tcf;
 
545
                        *p++ = cs->tracks[i].number;
 
546
                        *p++ = 0;
 
547
                        *p++ = 0;
 
548
                        *p++ = msf.m;
 
549
                        *p++ = msf.s;
 
550
                        *p++ = msf.f;
 
551
                }
 
552
                FramesToMSF(cs->length, &msf);
 
553
                *p++ = 0;
 
554
                *p++ = 0x14;
 
555
                *p++ = 0xAA;
 
556
                *p++ = 0;
 
557
                *p++ = 0;
 
558
                *p++ = msf.m;
 
559
                *p++ = msf.s;
 
560
                *p++ = msf.f;
 
561
 
 
562
                int toc_size = p - toc;
 
563
                *toc++ = toc_size >> 8;
 
564
                *toc++ = toc_size & 0xff;
 
565
                return true;
 
566
        }
 
567
}
 
568
 
 
569
bool GetPosition_bincue(void *fh, uint8 *pos)
 
570
{
 
571
        CueSheet *cs = (CueSheet *) fh;
 
572
        if (cs && player.cs == cs) {
 
573
                MSF abs, rel;
 
574
                int fpos = player.audioposition / RAW_SECTOR_SIZE + player.audiostart;
 
575
                int trackno = PositionToTrack(cs, fpos);
 
576
 
 
577
                if (!audio_enabled)
 
578
                        return false;
 
579
 
 
580
                FramesToMSF(fpos, &abs);
 
581
                if (trackno < cs->tcnt) {
 
582
                        // compute position relative to start of frame
 
583
 
 
584
                        unsigned int position =  player.audioposition/RAW_SECTOR_SIZE +
 
585
                                player.audiostart - player.cs->tracks[trackno].start;
 
586
 
 
587
                        FramesToMSF(position, &rel);
 
588
                }
 
589
                else
 
590
                        FramesToMSF(0, &rel);
 
591
 
 
592
                *pos++ = 0;
 
593
                *pos++ = player.audiostatus;
 
594
                *pos++ = 0;
 
595
                *pos++ = 12; // Sub-Q data length
 
596
                *pos++ = 0;
 
597
                if (trackno < cs->tcnt)
 
598
                        *pos++ = 0x10 | cs->tracks[trackno].tcf;
 
599
                *pos++ = (trackno < cs->tcnt) ? cs->tracks[trackno].number : 0xAA;
 
600
                *pos++ = 1;  // track index
 
601
                *pos++ = 0;
 
602
                *pos++ = abs.m;
 
603
                *pos++ = abs.s;
 
604
                *pos++ = abs.f;
 
605
                *pos++ = 0;
 
606
                *pos++ = rel.m;
 
607
                *pos++ = rel.s;
 
608
                *pos++ = rel.f;
 
609
                *pos++ = 0;
 
610
//              D(bug("CDROM position %02d:%02d:%02d track %02d\n", abs.m, abs.s, abs.f, trackno));
 
611
                return true;
 
612
        }
 
613
        else
 
614
                return false;
 
615
}
 
616
 
 
617
bool CDPause_bincue(void *fh)
 
618
{
 
619
        CueSheet *cs = (CueSheet *) fh;
 
620
        if (cs && cs == player.cs) {
 
621
                if (player.audiostatus == CDROM_AUDIO_PLAY) {
 
622
                        player.audiostatus = CDROM_AUDIO_PAUSED;
 
623
                        return true;
 
624
                }
 
625
        }
 
626
        return false;
 
627
}
 
628
 
 
629
bool CDStop_bincue(void *fh)
 
630
{
 
631
        CueSheet *cs = (CueSheet *) fh;
 
632
 
 
633
        if (cs && cs == player.cs) {
 
634
#ifdef OSX_CORE_AUDIO
 
635
                player.soundoutput.stop();
 
636
#endif
 
637
                if (player.audiostatus != CDROM_AUDIO_INVALID)
 
638
                        player.audiostatus = CDROM_AUDIO_NO_STATUS;
 
639
                return true;
 
640
        }
 
641
        return false;
 
642
}
 
643
 
 
644
bool CDResume_bincue(void *fh)
 
645
{
 
646
        CueSheet *cs = (CueSheet *) fh;
 
647
        if (cs && cs == player.cs) {
 
648
                if (player.audiostatus == CDROM_AUDIO_PAUSED) {
 
649
                        player.audiostatus = CDROM_AUDIO_PLAY;
 
650
                        return true;
 
651
                }
 
652
        }
 
653
        return false;
 
654
}
 
655
 
 
656
bool CDPlay_bincue(void *fh, uint8 start_m, uint8 start_s, uint8 start_f,
 
657
                                   uint8 end_m, uint8 end_s, uint8 end_f)
 
658
{
 
659
        CueSheet *cs = (CueSheet *)fh;
 
660
        if (cs && cs == player.cs) {
 
661
                int track;
 
662
                MSF msf;
 
663
 
 
664
#ifdef USE_SDL_AUDIO
 
665
                SDL_LockAudio();
 
666
#endif
 
667
 
 
668
                player.audiostatus = CDROM_AUDIO_NO_STATUS;
 
669
 
 
670
                player.audiostart = (start_m * 60 * CD_FRAMES) +
 
671
                        (start_s * CD_FRAMES) + start_f;
 
672
                player.audioend = (end_m * 60 * CD_FRAMES) + (end_s * CD_FRAMES) + end_f;
 
673
 
 
674
                track = PositionToTrack(player.cs, player.audiostart);
 
675
 
 
676
                if (track < player.cs->tcnt) {
 
677
                        player.audioposition = 0;
 
678
 
 
679
                        // here we need to compute silence
 
680
 
 
681
                        if (player.audiostart - player.cs->tracks[track].start >
 
682
                                player.cs->tracks[track].pregap)
 
683
                                player.silence = 0;
 
684
                        else
 
685
                                player.silence = (player.cs->tracks[track].pregap -
 
686
                                                                  player.audiostart +
 
687
                                                                  player.cs->tracks[track].start) * RAW_SECTOR_SIZE;
 
688
 
 
689
                        player.fileoffset = player.cs->tracks[track].fileoffset;
 
690
 
 
691
                        D(bug("file offset %d\n", (unsigned int) player.fileoffset));
 
692
 
 
693
                        // fix up file offset if beyond the silence bytes
 
694
 
 
695
                        if (!player.silence) // not at the beginning
 
696
                                player.fileoffset += (player.audiostart - 
 
697
                                                                          player.cs->tracks[track].start -
 
698
                                                                          player.cs->tracks[track].pregap) * RAW_SECTOR_SIZE;
 
699
 
 
700
                        FramesToMSF(player.cs->tracks[track].start, &msf);
 
701
                        D(bug("CDPlay_bincue track %02d start %02d:%02d:%02d silence %d",
 
702
                                player.cs->tracks[track].number, msf.m, msf.s, msf.f,
 
703
                                player.silence/RAW_SECTOR_SIZE));
 
704
                        D(bug(" Stop %02u:%02u:%02u\n", end_m, end_s, end_f));
 
705
                }
 
706
                else
 
707
                        D(bug("CDPlay_bincue: play beyond last track !\n"));
 
708
 
 
709
#ifdef USE_SDL_AUDIO
 
710
                SDL_UnlockAudio();
 
711
#endif
 
712
 
 
713
                if (audio_enabled) {
 
714
                        player.audiostatus = CDROM_AUDIO_PLAY;
 
715
#ifdef OSX_CORE_AUDIO
 
716
                        D(bug("starting os x sound"));
 
717
                        player.soundoutput.setCallback(bincue_core_audio_callback);
 
718
                        // should be from current track !
 
719
                        player.soundoutput.start(16, 2, 44100);
 
720
#endif
 
721
                        return true;
 
722
                }
 
723
        }
 
724
        return false;
 
725
}
 
726
 
 
727
static uint8 *fill_buffer(int stream_len)
 
728
{
 
729
        static uint8 *buf = 0;
 
730
        static int bufsize = 0;
 
731
        int offset = 0;
 
732
 
 
733
        if (bufsize < stream_len) {
 
734
                free(buf);
 
735
                buf = (uint8 *) malloc(stream_len);
 
736
                if (buf) {
 
737
                        bufsize = stream_len;
 
738
                }
 
739
                else {
 
740
                        D(bug("malloc failed \n"));
 
741
                        return NULL;
 
742
                }
 
743
        }
 
744
 
 
745
        memset(buf, silence_byte, stream_len);
 
746
 
 
747
        if (player.audiostatus == CDROM_AUDIO_PLAY) {
 
748
                int remaining_silence = player.silence - player.audioposition;
 
749
 
 
750
                if (player.audiostart + player.audioposition/RAW_SECTOR_SIZE
 
751
                        >= player.audioend) {
 
752
                        player.audiostatus = CDROM_AUDIO_COMPLETED;
 
753
                        return buf;
 
754
                }
 
755
 
 
756
                if (remaining_silence >= stream_len) {
 
757
                        player.audioposition += stream_len;
 
758
                        return buf;
 
759
                }
 
760
 
 
761
                if (remaining_silence > 0) {
 
762
                        offset += remaining_silence;
 
763
                        player.audioposition += remaining_silence;
 
764
                }
 
765
 
 
766
                int ret = 0;
 
767
                int available = ((player.audioend - player.audiostart) *
 
768
                                                         RAW_SECTOR_SIZE) - player.audioposition;
 
769
                if (available > (stream_len - offset))
 
770
                        available = stream_len - offset;
 
771
 
 
772
                if (lseek(player.audiofh,
 
773
                                  player.fileoffset + player.audioposition - player.silence,
 
774
                                          SEEK_SET) < 0)
 
775
                        return NULL;
 
776
 
 
777
                if (available < 0) {
 
778
                        player.audioposition += available; // correct end !;
 
779
                        available = 0;
 
780
                }
 
781
 
 
782
                if ((ret = read(player.audiofh, &buf[offset], available)) >= 0) {
 
783
                        player.audioposition += ret;
 
784
                        offset += ret;
 
785
                        available -= ret;
 
786
                }
 
787
 
 
788
                while (offset < stream_len) {
 
789
                        buf[offset++] = silence_byte;
 
790
                        if (available-- > 0){
 
791
                                player.audioposition++;
 
792
                        }
 
793
                }
 
794
        }               
 
795
        return buf;
 
796
}
 
797
 
 
798
 
 
799
#ifdef USE_SDL_AUDIO
 
800
void MixAudio_bincue(uint8 *stream, int stream_len)
 
801
{
 
802
        uint8 *buf;
 
803
        if (audio_enabled && (player.audiostatus == CDROM_AUDIO_PLAY)) {
 
804
                if (buf = fill_buffer(stream_len))
 
805
                        SDL_MixAudio(stream, buf, stream_len, SDL_MIX_MAXVOLUME);
 
806
        }
 
807
}
 
808
 
 
809
void OpenAudio_bincue(int freq, int format, int channels, uint8 silence)
 
810
{
 
811
        if (freq == 44100 && format == AUDIO_S16MSB && channels == 2) {
 
812
                audio_enabled = true;
 
813
                silence_byte = silence;
 
814
        }
 
815
        else {
 
816
                D(bug("unexpected frequency %d , format %d, or channels %d\n",
 
817
                          freq, format, channels));
 
818
        }
 
819
}
 
820
#endif
 
821
 
 
822
#ifdef OSX_CORE_AUDIO
 
823
static int bincue_core_audio_callback(void)
 
824
{
 
825
        int frames = player.soundoutput.bufferSizeFrames();
 
826
        uint8 *buf = fill_buffer(frames*4);
 
827
 
 
828
        //  D(bug("Audio request %d\n", stream_len));
 
829
 
 
830
        player.soundoutput.sendAudioBuffer((void *) buf, (buf ? frames : 0));
 
831
 
 
832
        return 1;
 
833
}
 
834
#endif