home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / client / cd_audio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-07  |  17.1 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.