ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/bincue_unix.cpp
Revision: 1.1
Committed: 2010-10-06T00:30:23Z (13 years, 7 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Log Message:
[Geoffrey Brown]

Add bin/cue support. The following should work:

1) Basilisk and SheepShaver with sdl-audio and bincue on linux and os x
2) SheepShaver with bincue and core audio on os x

File Contents

# Content
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