1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, 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 27extern 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 97struct playAudioRequest 98{ 99 char addressingMode; 100 int startLocation; 101 int sectors; 102}; 103 104struct readRequest 105{ 106 char mediaDescriptor; 107 short bufferOffset; 108 short bufferSegment; 109 short length; 110 short startSector; 111 int volumeID; 112}; 113 114struct writeRequest 115{ 116 char mediaDescriptor; 117 short bufferOffset; 118 short bufferSegment; 119 short length; 120 short startSector; 121 int volumeID; 122}; 123 124struct 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 140struct 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 153struct deviceStatus_s 154{ 155 char code; 156 int status; 157}; 158 159struct mediaChange_s 160{ 161 char code; 162 char status; 163}; 164 165struct audioDiskInfo_s 166{ 167 char code; 168 char lowTrack; 169 char highTrack; 170 int leadOutStart; 171}; 172 173struct audioTrackInfo_s 174{ 175 char code; 176 char track; 177 int start; 178 char control; 179}; 180 181struct audioStatus_s 182{ 183 char code; 184 short status; 185 int PRstartLocation; 186 int PRendLocation; 187}; 188 189struct reset_s 190{ 191 char code; 192}; 193 194union 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 209typedef struct 210{ 211 int start; 212 int length; 213 qboolean isData; 214} track_info; 215 216typedef struct 217{ 218 qboolean valid; 219 int leadOutAddress; 220 track_info track[MAXIMUM_TRACKS]; 221 byte lowTrack; 222 byte highTrack; 223} cd_info; 224 225static struct cd_request *cdRequest; 226static union readInfo_u *readInfo; 227static cd_info cd; 228 229static qboolean playing = false; 230static qboolean wasPlaying = false; 231static qboolean mediaCheck = false; 232static qboolean initialized = false; 233static qboolean enabled = true; 234static qboolean playLooping = false; 235static short cdRequestSegment; 236static short cdRequestOffset; 237static short readInfoSegment; 238static short readInfoOffset; 239static byte remap[256]; 240static byte cdrom; 241static byte playTrack; 242static byte cdvolume; 243 244 245static 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 258static 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 282static 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 306static 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 343static 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 393static 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 421static 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 449void 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 495void 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 570void 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 591void CDAudio_Pause(void) 592{ 593 CDAudio_Stop(); 594} 595 596 597void 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 623static 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 739void 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 801int 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 881void CDAudio_Shutdown(void) 882{ 883 if (!initialized) 884 return; 885 CDAudio_Stop(); 886} 887