Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 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 
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
}