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