Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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.