home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quakeworld_src / client / cd_audio.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  18.0 KB  |  848 lines

  1. #include <dpmi.h>
  2. #include "quakedef.h"
  3. #include "dosisms.h"
  4.  
  5. extern  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.  
  75. struct playAudioRequest
  76. {
  77.   char  addressingMode;
  78.   int   startLocation;
  79.   int   sectors;
  80. };
  81.  
  82. struct readRequest
  83. {
  84.   char  mediaDescriptor;
  85.   short bufferOffset;
  86.   short bufferSegment;
  87.   short length;
  88.   short startSector;
  89.   int   volumeID;
  90. };
  91.  
  92. struct writeRequest
  93. {
  94.   char  mediaDescriptor;
  95.   short bufferOffset;
  96.   short bufferSegment;
  97.   short length;
  98.   short startSector;
  99.   int   volumeID;
  100. };
  101.  
  102. struct 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.  
  118. struct 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.  
  131. struct deviceStatus_s
  132. {
  133.   char  code;
  134.   int   status;
  135. };
  136.  
  137. struct mediaChange_s
  138. {
  139.   char  code;
  140.   char  status;
  141. };
  142.  
  143. struct audioDiskInfo_s
  144. {
  145.   char  code;
  146.   char  lowTrack;
  147.   char  highTrack;
  148.   int   leadOutStart;
  149. };
  150.  
  151. struct audioTrackInfo_s
  152. {
  153.   char  code;
  154.   char  track;
  155.   int   start;
  156.   char  control;
  157. };
  158.  
  159. struct audioStatus_s
  160. {
  161.   char  code;
  162.   short status;
  163.   int   PRstartLocation;
  164.   int   PRendLocation;
  165. };
  166.  
  167. struct reset_s
  168. {
  169.   char  code;
  170. };
  171.  
  172. union 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.  
  187. typedef struct
  188. {
  189.   int     start;
  190.   int     length;
  191.   qboolean  isData;
  192. } track_info;
  193.  
  194. typedef struct
  195. {
  196.   qboolean  valid;
  197.   int     leadOutAddress;
  198.   track_info  track[MAXIMUM_TRACKS];
  199.   byte    lowTrack;
  200.   byte    highTrack;
  201. } cd_info;
  202.  
  203. static struct cd_request  *cdRequest;
  204. static union readInfo_u   *readInfo;
  205. static cd_info        cd;
  206.  
  207. static qboolean playing = false;
  208. static qboolean wasPlaying = false;
  209. static qboolean mediaCheck = false;
  210. static qboolean initialized = false;
  211. static qboolean enabled = true;
  212. static qboolean playLooping = false;
  213. static short  cdRequestSegment;
  214. static short  cdRequestOffset;
  215. static short  readInfoSegment;
  216. static short  readInfoOffset;
  217. static byte   remap[256];
  218. static byte   cdrom;
  219. static byte   playTrack;
  220. static byte   cdvolume;
  221.  
  222.  
  223. static 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.  
  236. static 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.  
  260. static 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.  
  284. static 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.  
  321. static 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.  
  371. static 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.  
  399. static 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.  
  425. byte 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
  433. void 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.  
  479. void 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.  
  539. void 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.  
  560. void 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.  
  586. static 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.  
  696. void 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.  
  756. qboolean CDAudio_Playing(void)
  757. {
  758.   return playing;
  759. }
  760.  
  761.  
  762. int 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.  
  842. void CDAudio_Shutdown(void)
  843. {
  844.   if (!initialized)
  845.     return;
  846.   CDAudio_Stop();
  847. }
  848.