cd_audio.c revision 9fd67c44777b350dc56f3e70c88963b0d966ffc7
1#include <dpmi.h> 2#include "quakedef.h" 3#include "dosisms.h" 4 5extern cvar_t bgmvolume; 6 7#define ADDRESS_MODE_HSG 0 8#define ADDRESS_MODE_RED_BOOK 1 9 10#define STATUS_ERROR_BIT 0x8000 11#define STATUS_BUSY_BIT 0x0200 12#define STATUS_DONE_BIT 0x0100 13#define STATUS_ERROR_MASK 0x00ff 14 15#define ERROR_WRITE_PROTECT 0 16#define ERROR_UNKNOWN_UNIT 1 17#define ERROR_DRIVE_NOT_READY 2 18#define ERROR_UNKNOWN_COMMAND 3 19#define ERROR_CRC_ERROR 4 20#define ERROR_BAD_REQUEST_LEN 5 21#define ERROR_SEEK_ERROR 6 22#define ERROR_UNKNOWN_MEDIA 7 23#define ERROR_SECTOR_NOT_FOUND 8 24#define ERROR_OUT_OF_PAPER 9 25#define ERROR_WRITE_FAULT 10 26#define ERROR_READ_FAULT 11 27#define ERROR_GENERAL_FAILURE 12 28#define ERROR_RESERVED_13 13 29#define ERROR_RESERVED_14 14 30#define ERROR_BAD_DISK_CHANGE 15 31 32#define COMMAND_READ 3 33#define COMMAND_WRITE 12 34#define COMMAND_PLAY_AUDIO 132 35#define COMMAND_STOP_AUDIO 133 36#define COMMAND_RESUME_AUDIO 136 37 38#define READ_REQUEST_AUDIO_CHANNEL_INFO 4 39#define READ_REQUEST_DEVICE_STATUS 6 40#define READ_REQUEST_MEDIA_CHANGE 9 41#define READ_REQUEST_AUDIO_DISK_INFO 10 42#define READ_REQUEST_AUDIO_TRACK_INFO 11 43#define READ_REQUEST_AUDIO_STATUS 15 44 45#define WRITE_REQUEST_EJECT 0 46#define WRITE_REQUEST_RESET 2 47#define WRITE_REQUEST_AUDIO_CHANNEL_INFO 3 48 49#define STATUS_DOOR_OPEN 0x00000001 50#define STATUS_DOOR_UNLOCKED 0x00000002 51#define STATUS_RAW_SUPPORT 0x00000004 52#define STATUS_READ_WRITE 0x00000008 53#define STATUS_AUDIO_SUPPORT 0x00000010 54#define STATUS_INTERLEAVE_SUPPORT 0x00000020 55#define STATUS_BIT_6_RESERVED 0x00000040 56#define STATUS_PREFETCH_SUPPORT 0x00000080 57#define STATUS_AUDIO_MANIPLUATION_SUPPORT 0x00000100 58#define STATUS_RED_BOOK_ADDRESS_SUPPORT 0x00000200 59 60#define MEDIA_NOT_CHANGED 1 61#define MEDIA_STATUS_UNKNOWN 0 62#define MEDIA_CHANGED -1 63 64#define AUDIO_CONTROL_MASK 0xd0 65#define AUDIO_CONTROL_DATA_TRACK 0x40 66#define AUDIO_CONTROL_AUDIO_2_TRACK 0x00 67#define AUDIO_CONTROL_AUDIO_2P_TRACK 0x10 68#define AUDIO_CONTROL_AUDIO_4_TRACK 0x80 69#define AUDIO_CONTROL_AUDIO_4P_TRACK 0x90 70 71#define AUDIO_STATUS_PAUSED 0x0001 72 73#pragma pack(1) 74 75struct playAudioRequest 76{ 77 char addressingMode; 78 int startLocation; 79 int sectors; 80}; 81 82struct readRequest 83{ 84 char mediaDescriptor; 85 short bufferOffset; 86 short bufferSegment; 87 short length; 88 short startSector; 89 int volumeID; 90}; 91 92struct writeRequest 93{ 94 char mediaDescriptor; 95 short bufferOffset; 96 short bufferSegment; 97 short length; 98 short startSector; 99 int volumeID; 100}; 101 102struct cd_request 103{ 104 char headerLength; 105 char unit; 106 char command; 107 short status; 108 char reserved[8]; 109 union 110 { 111 struct playAudioRequest playAudio; 112 struct readRequest read; 113 struct writeRequest write; 114 } x; 115}; 116 117 118struct audioChannelInfo_s 119{ 120 char code; 121 char channel0input; 122 char channel0volume; 123 char channel1input; 124 char channel1volume; 125 char channel2input; 126 char channel2volume; 127 char channel3input; 128 char channel3volume; 129}; 130 131struct deviceStatus_s 132{ 133 char code; 134 int status; 135}; 136 137struct mediaChange_s 138{ 139 char code; 140 char status; 141}; 142 143struct audioDiskInfo_s 144{ 145 char code; 146 char lowTrack; 147 char highTrack; 148 int leadOutStart; 149}; 150 151struct audioTrackInfo_s 152{ 153 char code; 154 char track; 155 int start; 156 char control; 157}; 158 159struct audioStatus_s 160{ 161 char code; 162 short status; 163 int PRstartLocation; 164 int PRendLocation; 165}; 166 167struct reset_s 168{ 169 char code; 170}; 171 172union readInfo_u 173{ 174 struct audioChannelInfo_s audioChannelInfo; 175 struct deviceStatus_s deviceStatus; 176 struct mediaChange_s mediaChange; 177 struct audioDiskInfo_s audioDiskInfo; 178 struct audioTrackInfo_s audioTrackInfo; 179 struct audioStatus_s audioStatus; 180 struct reset_s reset; 181}; 182 183#pragma pack() 184 185#define MAXIMUM_TRACKS 32 186 187typedef struct 188{ 189 int start; 190 int length; 191 qboolean isData; 192} track_info; 193 194typedef struct 195{ 196 qboolean valid; 197 int leadOutAddress; 198 track_info track[MAXIMUM_TRACKS]; 199 byte lowTrack; 200 byte highTrack; 201} cd_info; 202 203static struct cd_request *cdRequest; 204static union readInfo_u *readInfo; 205static cd_info cd; 206 207static qboolean playing = false; 208static qboolean wasPlaying = false; 209static qboolean mediaCheck = false; 210static qboolean initialized = false; 211static qboolean enabled = true; 212static qboolean playLooping = false; 213static short cdRequestSegment; 214static short cdRequestOffset; 215static short readInfoSegment; 216static short readInfoOffset; 217static byte remap[256]; 218static byte cdrom; 219static byte playTrack; 220static byte cdvolume; 221 222 223static int RedBookToSector(int rb) 224{ 225 byte minute; 226 byte second; 227 byte frame; 228 229 minute = (rb >> 16) & 0xff; 230 second = (rb >> 8) & 0xff; 231 frame = rb & 0xff; 232 return minute * 60 * 75 + second * 75 + frame; 233} 234 235 236static void CDAudio_Reset(void) 237{ 238 cdRequest->headerLength = 13; 239 cdRequest->unit = 0; 240 cdRequest->command = COMMAND_WRITE; 241 cdRequest->status = 0; 242 243 cdRequest->x.write.mediaDescriptor = 0; 244 cdRequest->x.write.bufferOffset = readInfoOffset; 245 cdRequest->x.write.bufferSegment = readInfoSegment; 246 cdRequest->x.write.length = sizeof(struct reset_s); 247 cdRequest->x.write.startSector = 0; 248 cdRequest->x.write.volumeID = 0; 249 250 readInfo->reset.code = WRITE_REQUEST_RESET; 251 252 regs.x.ax = 0x1510; 253 regs.x.cx = cdrom; 254 regs.x.es = cdRequestSegment; 255 regs.x.bx = cdRequestOffset; 256 dos_int86 (0x2f); 257} 258 259 260static void CDAudio_Eject(void) 261{ 262 cdRequest->headerLength = 13; 263 cdRequest->unit = 0; 264 cdRequest->command = COMMAND_WRITE; 265 cdRequest->status = 0; 266 267 cdRequest->x.write.mediaDescriptor = 0; 268 cdRequest->x.write.bufferOffset = readInfoOffset; 269 cdRequest->x.write.bufferSegment = readInfoSegment; 270 cdRequest->x.write.length = sizeof(struct reset_s); 271 cdRequest->x.write.startSector = 0; 272 cdRequest->x.write.volumeID = 0; 273 274 readInfo->reset.code = WRITE_REQUEST_EJECT; 275 276 regs.x.ax = 0x1510; 277 regs.x.cx = cdrom; 278 regs.x.es = cdRequestSegment; 279 regs.x.bx = cdRequestOffset; 280 dos_int86 (0x2f); 281} 282 283 284static int CDAudio_GetAudioTrackInfo(byte track, int *start) 285{ 286 byte control; 287 288 cdRequest->headerLength = 13; 289 cdRequest->unit = 0; 290 cdRequest->command = COMMAND_READ; 291 cdRequest->status = 0; 292 293 cdRequest->x.read.mediaDescriptor = 0; 294 cdRequest->x.read.bufferOffset = readInfoOffset; 295 cdRequest->x.read.bufferSegment = readInfoSegment; 296 cdRequest->x.read.length = sizeof(struct audioTrackInfo_s); 297 cdRequest->x.read.startSector = 0; 298 cdRequest->x.read.volumeID = 0; 299 300 readInfo->audioTrackInfo.code = READ_REQUEST_AUDIO_TRACK_INFO; 301 readInfo->audioTrackInfo.track = track; 302 303 regs.x.ax = 0x1510; 304 regs.x.cx = cdrom; 305 regs.x.es = cdRequestSegment; 306 regs.x.bx = cdRequestOffset; 307 dos_int86 (0x2f); 308 309 if (cdRequest->status & STATUS_ERROR_BIT) 310 { 311 Con_DPrintf("CDAudio_GetAudioTrackInfo %04x\n", cdRequest->status & 0xffff); 312 return -1; 313 } 314 315 *start = readInfo->audioTrackInfo.start; 316 control = readInfo->audioTrackInfo.control & AUDIO_CONTROL_MASK; 317 return (control & AUDIO_CONTROL_DATA_TRACK); 318} 319 320 321static int CDAudio_GetAudioDiskInfo(void) 322{ 323 int n; 324 325 cdRequest->headerLength = 13; 326 cdRequest->unit = 0; 327 cdRequest->command = COMMAND_READ; 328 cdRequest->status = 0; 329 330 cdRequest->x.read.mediaDescriptor = 0; 331 cdRequest->x.read.bufferOffset = readInfoOffset; 332 cdRequest->x.read.bufferSegment = readInfoSegment; 333 cdRequest->x.read.length = sizeof(struct audioDiskInfo_s); 334 cdRequest->x.read.startSector = 0; 335 cdRequest->x.read.volumeID = 0; 336 337 readInfo->audioDiskInfo.code = READ_REQUEST_AUDIO_DISK_INFO; 338 339 regs.x.ax = 0x1510; 340 regs.x.cx = cdrom; 341 regs.x.es = cdRequestSegment; 342 regs.x.bx = cdRequestOffset; 343 dos_int86 (0x2f); 344 345 if (cdRequest->status & STATUS_ERROR_BIT) 346 { 347 Con_DPrintf("CDAudio_GetAudioDiskInfo %04x\n", cdRequest->status & 0xffff); 348 return -1; 349 } 350 351 cd.valid = true; 352 cd.lowTrack = readInfo->audioDiskInfo.lowTrack; 353 cd.highTrack = readInfo->audioDiskInfo.highTrack; 354 cd.leadOutAddress = readInfo->audioDiskInfo.leadOutStart; 355 356 for (n = cd.lowTrack; n <= cd.highTrack; n++) 357 { 358 cd.track[n].isData = CDAudio_GetAudioTrackInfo (n, &cd.track[n].start); 359 if (n > cd.lowTrack) 360 { 361 cd.track[n-1].length = RedBookToSector(cd.track[n].start) - RedBookToSector(cd.track[n-1].start); 362 if (n == cd.highTrack) 363 cd.track[n].length = RedBookToSector(cd.leadOutAddress) - RedBookToSector(cd.track[n].start); 364 } 365 } 366 367 return 0; 368} 369 370 371static int CDAudio_GetAudioStatus(void) 372{ 373 cdRequest->headerLength = 13; 374 cdRequest->unit = 0; 375 cdRequest->command = COMMAND_READ; 376 cdRequest->status = 0; 377 378 cdRequest->x.read.mediaDescriptor = 0; 379 cdRequest->x.read.bufferOffset = readInfoOffset; 380 cdRequest->x.read.bufferSegment = readInfoSegment; 381 cdRequest->x.read.length = sizeof(struct audioStatus_s); 382 cdRequest->x.read.startSector = 0; 383 cdRequest->x.read.volumeID = 0; 384 385 readInfo->audioDiskInfo.code = READ_REQUEST_AUDIO_STATUS; 386 387 regs.x.ax = 0x1510; 388 regs.x.cx = cdrom; 389 regs.x.es = cdRequestSegment; 390 regs.x.bx = cdRequestOffset; 391 dos_int86 (0x2f); 392 393 if (cdRequest->status & STATUS_ERROR_BIT) 394 return -1; 395 return 0; 396} 397 398 399static int CDAudio_MediaChange(void) 400{ 401 cdRequest->headerLength = 13; 402 cdRequest->unit = 0; 403 cdRequest->command = COMMAND_READ; 404 cdRequest->status = 0; 405 406 cdRequest->x.read.mediaDescriptor = 0; 407 cdRequest->x.read.bufferOffset = readInfoOffset; 408 cdRequest->x.read.bufferSegment = readInfoSegment; 409 cdRequest->x.read.length = sizeof(struct mediaChange_s); 410 cdRequest->x.read.startSector = 0; 411 cdRequest->x.read.volumeID = 0; 412 413 readInfo->mediaChange.code = READ_REQUEST_MEDIA_CHANGE; 414 415 regs.x.ax = 0x1510; 416 regs.x.cx = cdrom; 417 regs.x.es = cdRequestSegment; 418 regs.x.bx = cdRequestOffset; 419 dos_int86 (0x2f); 420 421 return readInfo->mediaChange.status; 422} 423 424 425byte CDAudio_GetVolume (void) 426{ 427 return cdvolume; 428} 429 430 431// we set the volume to 0 first and then to the desired volume 432// some cd-rom drivers seem to need it done this way 433void CDAudio_SetVolume (byte volume) 434{ 435 if (!initialized || !enabled) 436 return; 437 438 cdRequest->headerLength = 13; 439 cdRequest->unit = 0; 440 cdRequest->command = COMMAND_WRITE; 441 cdRequest->status = 0; 442 443 cdRequest->x.read.mediaDescriptor = 0; 444 cdRequest->x.read.bufferOffset = readInfoOffset; 445 cdRequest->x.read.bufferSegment = readInfoSegment; 446 cdRequest->x.read.length = sizeof(struct audioChannelInfo_s); 447 cdRequest->x.read.startSector = 0; 448 cdRequest->x.read.volumeID = 0; 449 450 readInfo->audioChannelInfo.code = WRITE_REQUEST_AUDIO_CHANNEL_INFO; 451 readInfo->audioChannelInfo.channel0input = 0; 452 readInfo->audioChannelInfo.channel0volume = 0; 453 readInfo->audioChannelInfo.channel1input = 1; 454 readInfo->audioChannelInfo.channel1volume = 0; 455 readInfo->audioChannelInfo.channel2input = 2; 456 readInfo->audioChannelInfo.channel2volume = 0; 457 readInfo->audioChannelInfo.channel3input = 3; 458 readInfo->audioChannelInfo.channel3volume = 0; 459 460 regs.x.ax = 0x1510; 461 regs.x.cx = cdrom; 462 regs.x.es = cdRequestSegment; 463 regs.x.bx = cdRequestOffset; 464 dos_int86 (0x2f); 465 466 readInfo->audioChannelInfo.channel0volume = volume; 467 readInfo->audioChannelInfo.channel1volume = volume; 468 469 regs.x.ax = 0x1510; 470 regs.x.cx = cdrom; 471 regs.x.es = cdRequestSegment; 472 regs.x.bx = cdRequestOffset; 473 dos_int86 (0x2f); 474 475 cdvolume = volume; 476} 477 478 479void CDAudio_Play(byte track, qboolean looping) 480{ 481 if (!initialized || !enabled) 482 return; 483 484 if (!cd.valid) 485 return; 486 487 track = remap[track]; 488 489 if (playing) 490 { 491 if (playTrack == track) 492 return; 493 CDAudio_Stop(); 494 } 495 496 playLooping = looping; 497 498 if (track < cd.lowTrack || track > cd.highTrack) 499 { 500 Con_DPrintf("CDAudio_Play: Bad track number %u.\n", track); 501 return; 502 } 503 504 playTrack = track; 505 506 if (cd.track[track].isData) 507 { 508 Con_DPrintf("CDAudio_Play: Can not play data.\n"); 509 return; 510 } 511 512 cdRequest->headerLength = 13; 513 cdRequest->unit = 0; 514 cdRequest->command = COMMAND_PLAY_AUDIO; 515 cdRequest->status = 0; 516 517 cdRequest->x.playAudio.addressingMode = ADDRESS_MODE_RED_BOOK; 518 cdRequest->x.playAudio.startLocation = cd.track[track].start; 519 cdRequest->x.playAudio.sectors = cd.track[track].length; 520 521 regs.x.ax = 0x1510; 522 regs.x.cx = cdrom; 523 regs.x.es = cdRequestSegment; 524 regs.x.bx = cdRequestOffset; 525 dos_int86 (0x2f); 526 527 if (cdRequest->status & STATUS_ERROR_BIT) 528 { 529 Con_DPrintf("CDAudio_Play: track %u failed\n", track); 530 cd.valid = false; 531 playing = false; 532 return; 533 } 534 535 playing = true; 536} 537 538 539void CDAudio_Stop(void) 540{ 541 if (!initialized || !enabled) 542 return; 543 544 cdRequest->headerLength = 13; 545 cdRequest->unit = 0; 546 cdRequest->command = COMMAND_STOP_AUDIO; 547 cdRequest->status = 0; 548 549 regs.x.ax = 0x1510; 550 regs.x.cx = cdrom; 551 regs.x.es = cdRequestSegment; 552 regs.x.bx = cdRequestOffset; 553 dos_int86 (0x2f); 554 555 wasPlaying = playing; 556 playing = false; 557} 558 559 560void CDAudio_Resume(void) 561{ 562 if (!initialized || !enabled) 563 return; 564 565 if (!cd.valid) 566 return; 567 568 if (!wasPlaying) 569 return; 570 571 cdRequest->headerLength = 13; 572 cdRequest->unit = 0; 573 cdRequest->command = COMMAND_RESUME_AUDIO; 574 cdRequest->status = 0; 575 576 regs.x.ax = 0x1510; 577 regs.x.cx = cdrom; 578 regs.x.es = cdRequestSegment; 579 regs.x.bx = cdRequestOffset; 580 dos_int86 (0x2f); 581 582 playing = true; 583} 584 585 586static void CD_f (void) 587{ 588 char *command; 589 int ret; 590 int n; 591 int startAddress; 592 593 if (Cmd_Argc() < 2) 594 return; 595 596 command = Cmd_Argv (1); 597 598 if (Q_strcasecmp(command, "on") == 0) 599 { 600 enabled = true; 601 return; 602 } 603 604 if (Q_strcasecmp(command, "off") == 0) 605 { 606 if (playing) 607 CDAudio_Stop(); 608 enabled = false; 609 return; 610 } 611 612 if (Q_strcasecmp(command, "reset") == 0) 613 { 614 enabled = true; 615 if (playing) 616 CDAudio_Stop(); 617 for (n = 0; n < 256; n++) 618 remap[n] = n; 619 CDAudio_Reset(); 620 CDAudio_GetAudioDiskInfo(); 621 return; 622 } 623 624 if (Q_strcasecmp(command, "remap") == 0) 625 { 626 ret = Cmd_Argc() - 2; 627 if (ret <= 0) 628 { 629 for (n = 1; n < 256; n++) 630 if (remap[n] != n) 631 Con_Printf(" %u -> %u\n", n, remap[n]); 632 return; 633 } 634 for (n = 1; n <= ret; n++) 635 remap[n] = Q_atoi(Cmd_Argv (n+1)); 636 return; 637 } 638 639 if (!cd.valid) 640 { 641 Con_Printf("No CD in player.\n"); 642 return; 643 } 644 645 if (Q_strcasecmp(command, "play") == 0) 646 { 647 CDAudio_Play(Q_atoi(Cmd_Argv (2)), false); 648 return; 649 } 650 651 if (Q_strcasecmp(command, "loop") == 0) 652 { 653 CDAudio_Play(Q_atoi(Cmd_Argv (2)), true); 654 return; 655 } 656 657 if (Q_strcasecmp(command, "stop") == 0) 658 { 659 CDAudio_Stop(); 660 return; 661 } 662 663 if (Q_strcasecmp(command, "resume") == 0) 664 { 665 CDAudio_Resume(); 666 return; 667 } 668 669 if (Q_strcasecmp(command, "eject") == 0) 670 { 671 if (playing) 672 CDAudio_Stop(); 673 CDAudio_Eject(); 674 cd.valid = false; 675 return; 676 } 677 678 if (Q_strcasecmp(command, "info") == 0) 679 { 680 Con_Printf("%u tracks\n", cd.highTrack - cd.lowTrack + 1); 681 for (n = cd.lowTrack; n <= cd.highTrack; n++) 682 { 683 ret = CDAudio_GetAudioTrackInfo (n, &startAddress); 684 Con_Printf("Track %2u: %s at %2u:%02u\n", n, ret ? "data " : "music", (startAddress >> 16) & 0xff, (startAddress >> 8) & 0xff); 685 } 686 if (playing) 687 Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack); 688 Con_Printf("Volume is %u\n", cdvolume); 689 CDAudio_MediaChange(); 690 Con_Printf("Status %04x\n", cdRequest->status & 0xffff); 691 return; 692 } 693} 694 695 696void CDAudio_Update(void) 697{ 698 int ret; 699 int newVolume; 700 static double lastUpdate; 701 702 if (!initialized || !enabled) 703 return; 704 705 if ((realtime - lastUpdate) < 0.25) 706 return; 707 lastUpdate = realtime; 708 709 if (mediaCheck) 710 { 711 static double lastCheck; 712 713 if ((realtime - lastCheck) < 5.0) 714 return; 715 lastCheck = realtime; 716 717 ret = CDAudio_MediaChange(); 718 if (ret == MEDIA_CHANGED) 719 { 720 Con_DPrintf("CDAudio: media changed\n"); 721 playing = false; 722 wasPlaying = false; 723 cd.valid = false; 724 CDAudio_GetAudioDiskInfo(); 725 return; 726 } 727 } 728 729 newVolume = (int)(bgmvolume.value * 255.0); 730 if (newVolume < 0) 731 { 732 Cvar_SetValue ("bgmvolume", 0.0); 733 newVolume = 0; 734 } 735 else if (newVolume > 255) 736 { 737 Cvar_SetValue ("bgmvolume", 1.0); 738 newVolume = 255; 739 } 740 if (cdvolume != newVolume) 741 CDAudio_SetVolume (newVolume); 742 743 if (playing) 744 { 745 CDAudio_GetAudioStatus(); 746 if ((cdRequest->status & STATUS_BUSY_BIT) == 0) 747 { 748 playing = false; 749 if (playLooping) 750 CDAudio_Play(playTrack, true); 751 } 752 } 753} 754 755 756qboolean CDAudio_Playing(void) 757{ 758 return playing; 759} 760 761 762int CDAudio_Init(void) 763{ 764 char *memory; 765 int n; 766 767 if (cls.state == ca_dedicated) 768 return -1; 769 770 if (COM_CheckParm("-nocdaudio")) 771 return -1; 772 773 if (COM_CheckParm("-cdmediacheck")) 774 mediaCheck = true; 775 776 regs.x.ax = 0x1500; 777 regs.x.bx = 0; 778 dos_int86 (0x2f); 779 if (regs.x.bx == 0) 780 { 781 Con_NotifyBox ( 782 "MSCDEX not loaded, music is\n" 783 "disabled. Use \"-nocdaudio\" if you\n" 784 "wish to avoid this message in the\n" 785 "future. See README.TXT for help.\n" 786 ); 787 return -1; 788 } 789 if (regs.x.bx > 1) 790 Con_DPrintf("CDAudio_Init: First CD-ROM drive will be used\n"); 791 cdrom = regs.x.cx; 792 793 regs.x.ax = 0x150c; 794 regs.x.bx = 0; 795 dos_int86 (0x2f); 796 if (regs.x.bx == 0) 797 { 798 Con_NotifyBox ( 799 "MSCDEX version 2.00 or later\n" 800 "required for music. See README.TXT\n" 801 "for help.\n" 802 ); 803 Con_DPrintf("CDAudio_Init: MSCDEX version 2.00 or later required.\n"); 804 return -1; 805 } 806 807 memory = dos_getmemory(sizeof(struct cd_request 808) + sizeof(union readInfo_u)); 809 if (memory == NULL) 810 { 811 Con_DPrintf("CDAudio_Init: Unable to allocate low memory.\n"); 812 return -1; 813 } 814 815 cdRequest = (struct cd_request *)memory; 816 cdRequestSegment = ptr2real(cdRequest) >> 4; 817 cdRequestOffset = ptr2real(cdRequest) & 0xf; 818 819 readInfo = (union readInfo_u *)(memory + sizeof(struct cd_request)); 820 readInfoSegment = ptr2real(readInfo) >> 4; 821 readInfoOffset = ptr2real(readInfo) & 0xf; 822 823 for (n = 0; n < 256; n++) 824 remap[n] = n; 825 initialized = true; 826 827 CDAudio_SetVolume (255); 828 if (CDAudio_GetAudioDiskInfo()) 829 { 830 Con_Printf("CDAudio_Init: No CD in player.\n"); 831 enabled = false; 832 } 833 834 Cmd_AddCommand ("cd", CD_f); 835 836 Con_Printf("CD Audio Initialized\n"); 837 838 return 0; 839} 840 841 842void CDAudio_Shutdown(void) 843{ 844 if (!initialized) 845 return; 846 CDAudio_Stop(); 847} 848