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

  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.