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
RedBookToSector(int rb)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
CDAudio_Reset(void)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
CDAudio_Eject(void)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
CDAudio_GetAudioTrackInfo(byte track,int * start)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
CDAudio_GetAudioDiskInfo(void)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
CDAudio_GetAudioStatus(void)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
CDAudio_MediaChange(void)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
CDAudio_SetVolume(byte volume)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
CDAudio_Play(byte track,qboolean looping)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
CDAudio_Stop(void)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
CDAudio_Pause(void)591 void CDAudio_Pause(void)
592 {
593 CDAudio_Stop();
594 }
595
596
CDAudio_Resume(void)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
CD_f(void)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
CDAudio_Update(void)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
CDAudio_Init(void)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
CDAudio_Shutdown(void)881 void CDAudio_Shutdown(void)
882 {
883 if (!initialized)
884 return;
885 CDAudio_Stop();
886 }
887