home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 26 / CD_ASCQ_26_1295.iso / vrac / gctv101.zip / GCTVSAPI.CPP < prev    next >
C/C++ Source or Header  |  1995-09-18  |  18KB  |  698 lines

  1.  
  2. //  ------------------------------------------------------------------
  3. //  GCTVSAPI 1.01 - Goldware Sound API for CT-VOICE.DRV.
  4. //  Released to Public Domain by Odinn Sorensen.
  5. //  ------------------------------------------------------------------
  6. //  This source was written to compile cleanly with Borland C++ 3.1.
  7. //  Compile with BCC -O1 -d -K -k- -ml -N- -v-.
  8. //  Compile with -DDEBUG for lots of diagnostics.
  9. //  ------------------------------------------------------------------
  10. //  See GOLDSAPI.DOC for a specification of the Goldware Sound API.
  11. //  ------------------------------------------------------------------
  12. //  v1.00: Initial release.
  13. //  v1.01: Now returns errorlevel from program.
  14. //  ------------------------------------------------------------------
  15. //  Acknowledgements:
  16. //  * Gody Keijzer 2:283/7.17 helped with the errorlevel stuff.
  17. //  ------------------------------------------------------------------
  18.  
  19.  
  20. //  ------------------------------------------------------------------
  21.  
  22. #include <io.h>
  23. #include <dos.h>
  24. #include <fcntl.h>
  25. #include <share.h>
  26. #include <ctype.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <process.h>
  30. #ifdef DEBUG
  31. #include <stdio.h>
  32. #endif
  33.  
  34.  
  35. //  ------------------------------------------------------------------
  36. //  Some typedefs
  37.  
  38. typedef unsigned char  byte;
  39. typedef unsigned short word;
  40. typedef unsigned int   uint;
  41.  
  42.  
  43. //  ------------------------------------------------------------------
  44. //  Some defines
  45.  
  46. #define TRUE  1
  47. #define FALSE 0
  48. #define NOT   !
  49. #define NUL   '\0'
  50. #define NW(x) (x=x)
  51.  
  52.  
  53. //  ------------------------------------------------------------------
  54. //  Goldware Sound API version
  55.  
  56. #define GSAPI_VERSION 0x0100
  57.  
  58.  
  59. //  ------------------------------------------------------------------
  60. //  Goldware Sound API function numbers
  61.  
  62. #define GSAPI_INSTALL_CHECK       0x00
  63. #define GSAPI_OPEN_API            0x10
  64. #define GSAPI_CLOSE_API           0x11
  65. #define GSAPI_OPEN_AND_LOAD_FILE  0x12
  66. #define GSAPI_CLOSE_FILE          0x13
  67. #define GSAPI_PLAY                0x14
  68. #define GSAPI_STOP                0x15
  69. #define GSAPI_PAUSE               0x16
  70. #define GSAPI_RESUME              0x17
  71. #define GSAPI_BREAK_LOOP          0x18
  72. #define GSAPI_SPEAKER_ON_OFF      0x19
  73.  
  74.  
  75. //  ------------------------------------------------------------------
  76. //  Goldware Sound API data structure
  77.  
  78. struct gsapidata {
  79.   word driver_version;
  80.   word dsp_version;
  81.   word io_port;
  82.   byte irq_number;
  83.   byte dma_channel;
  84.   word sample_rate;
  85.   volatile word status;
  86.   word buffer_segment;
  87.   word buffer_offset;
  88.   long buffer_length;
  89.   char parameters[80];
  90. };
  91.  
  92.  
  93. //  ------------------------------------------------------------------
  94. //  The AMIS signature string
  95.  
  96. struct amis_signature {
  97.   char manufacturer[8];
  98.   char product_name[8];
  99.   char product_description[64];
  100. };
  101.  
  102.  
  103. //  ------------------------------------------------------------------
  104. //  The .VOC file header structure
  105.  
  106. struct voc_header {
  107.   char filetype[20];
  108.   word dataoffset;
  109.   word vocversion;
  110.   word vocid;
  111. };
  112.  
  113.  
  114. //  ------------------------------------------------------------------
  115. //  A type for casting the argument to _dos_setvect()
  116.  
  117. typedef void interrupt (*interrupt_handler)(...);
  118.  
  119.  
  120. //  ------------------------------------------------------------------
  121. //  A pointer to the next INT 2Dh handler
  122.  
  123. static void interrupt (*old_handler)(...);
  124.  
  125.  
  126. //  ------------------------------------------------------------------
  127. //  The AMIS signature string and multiplex number
  128.  
  129. static amis_signature signature;
  130. static uint mpx;
  131.  
  132.  
  133. //  ------------------------------------------------------------------
  134. //  Goldware Sound API data structure and state variables
  135.  
  136. static gsapidata data;
  137. static int unique_key = 0;
  138. static int api_okay = FALSE;
  139. static int api_open = FALSE;
  140. static int file_open = FALSE;
  141. static int errorlevel = 0;
  142.  
  143.  
  144. //  ------------------------------------------------------------------
  145. //  CT-VOICE driver pointers and return status
  146.  
  147. static void far (*driver)(void) = NULL;
  148. static char* driver_buffer = NULL;
  149. static word ctv_status = 0;
  150.  
  151.  
  152. //  ------------------------------------------------------------------
  153.  
  154. int ctv_init() {
  155.  
  156.   memset(&data, 0, sizeof(gsapidata));
  157.  
  158.   #ifdef DEBUG
  159.   fprintf(stderr, "ctv: init\n");
  160.   #endif
  161.   char file[80];
  162.   *file = NUL;
  163.   char* sound = getenv("SOUND");
  164.   if(sound) {
  165.     #ifdef DEBUG
  166.     fprintf(stderr, "ctv: SOUND=%s\n", sound);
  167.     #endif
  168.     strcpy(file, sound);
  169.     if(file[strlen(file)-1] != '\\')
  170.       strcat(file, "\\");
  171.     strcat(file, "DRV\\");
  172.   }
  173.   strcat(file, "CT-VOICE.DRV");
  174.   #ifdef DEBUG
  175.   fprintf(stderr, "ctv: driver at %s\n", file);
  176.   #endif
  177.   int fh = sopen(file, O_RDONLY|O_BINARY, SH_DENYNO);
  178.   if(fh != -1) {
  179.     uint driver_size = (uint)filelength(fh);
  180.     driver_buffer = (char*)malloc(driver_size+32);
  181.     if(driver_buffer) {
  182.       driver = (void(far*)())MK_FP(FP_SEG(driver_buffer)+1, 0x0000);
  183.       read(fh, (void*)driver, driver_size);
  184.       #ifdef DEBUG
  185.       fprintf(stderr, "ctv: getting driver version\n");
  186.       #endif
  187.       _AX = 0;
  188.       _BX = 0;
  189.       (*driver)();
  190.       ctv_status = _AX;
  191.       data.driver_version = ctv_status;
  192.       #ifdef DEBUG
  193.       fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  194.       #endif
  195.       #ifdef DEBUG
  196.       fprintf(stderr, "ctv: found driver version %u.%02u\n", ctv_status>>8, ctv_status&0xFF);
  197.       #endif
  198.       char* blaster = getenv("BLASTER");
  199.       if(blaster) {
  200.         #ifdef DEBUG
  201.         fprintf(stderr, "ctv: BLASTER=%s\n", blaster);
  202.         #endif
  203.         while(*blaster) {
  204.           if(toupper(*blaster) == 'A') {
  205.             word p = (word)atoi(blaster+1);
  206.             data.io_port = p;
  207.             #ifdef DEBUG
  208.             fprintf(stderr, "ctv: setting i/o port to %u\n", p);
  209.             #endif
  210.             if(driver) {
  211.               _AX = p;
  212.               _BX = 1;
  213.               (*driver)();
  214.               ctv_status = _AX;
  215.               #ifdef DEBUG
  216.               fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  217.               #endif
  218.             }
  219.           }
  220.           else if(toupper(*blaster) == 'I') {
  221.             word i = (word)atoi(blaster+1);
  222.             data.irq_number = i;
  223.             #ifdef DEBUG
  224.             fprintf(stderr, "ctv: setting interrupt to %u\n", i);
  225.             #endif
  226.             if(driver) {
  227.               _AX = i;
  228.               _BX = 2;
  229.               (*driver)();
  230.               ctv_status = _AX;
  231.               #ifdef DEBUG
  232.               fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  233.               #endif
  234.             }
  235.           }
  236.           else if(toupper(*blaster) == 'D') {
  237.             word d = (word)atoi(blaster+1);
  238.             data.dma_channel = d;
  239.           }
  240.           blaster++;
  241.         }
  242.       }
  243.     }
  244.     close(fh);
  245.     #ifdef DEBUG
  246.     fprintf(stderr, "ctv: driver init\n");
  247.     #endif
  248.     ctv_status = 0xFFFF;
  249.     if(driver) {
  250.       _BX = 3;
  251.       (*driver)();
  252.       ctv_status = _AX;
  253.       #ifdef DEBUG
  254.       fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  255.       #endif
  256.     }
  257.     switch(ctv_status) {
  258.       case 0:
  259.         #ifdef DEBUG
  260.         fprintf(stderr, "ctv: no errors in driver init\n");
  261.         #endif
  262.         break;
  263.       case 1:
  264.         #ifdef DEBUG
  265.         fprintf(stderr, "ctv: voice card failure in driver init\n");
  266.         #endif
  267.         break;
  268.       case 2:
  269.         #ifdef DEBUG
  270.         fprintf(stderr, "ctv: i/o read/write failure in driver init\n");
  271.         #endif
  272.         break;
  273.       case 3:
  274.         #ifdef DEBUG
  275.         fprintf(stderr, "ctv: dma interrupt failure in driver init\n");
  276.         #endif
  277.         break;
  278.       default:
  279.         #ifdef DEBUG
  280.         fprintf(stderr, "ctv: unknown error %u in driver init\n", ctv_status);
  281.         #endif
  282.         ;
  283.     }
  284.     if(ctv_status != 0)
  285.       driver = NULL;
  286.     #ifdef DEBUG
  287.     fprintf(stderr, "ctv: setting voice status word address\n");
  288.     #endif
  289.     if(driver) {
  290.       _BX = 5;
  291.       _ES = FP_SEG(&data.status);
  292.       _DI = FP_OFF(&data.status);
  293.       (*driver)();
  294.       ctv_status = _AX;
  295.       #ifdef DEBUG
  296.       fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  297.       #endif
  298.       return TRUE;  // driver is ready and waiting for commands
  299.     }
  300.   }
  301.   if(driver_buffer) {
  302.     free(driver_buffer);
  303.     driver_buffer = NULL;
  304.   }
  305.   return FALSE;   // Error during init
  306. }
  307.  
  308.  
  309. //  ------------------------------------------------------------------
  310.  
  311. void ctv_reset() {
  312.  
  313.   #ifdef DEBUG
  314.   fprintf(stderr, "ctv: reset\n");
  315.   #endif
  316.   _BX = 9;
  317.   (*driver)();
  318.   ctv_status = _AX;
  319.   #ifdef DEBUG
  320.   fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  321.   #endif
  322.   free(driver_buffer);
  323.   driver_buffer = NULL;
  324.   driver = NULL;
  325. }
  326.  
  327.  
  328. //  ------------------------------------------------------------------
  329.  
  330. word ctv_open_and_load() {
  331.  
  332.   #ifdef DEBUG
  333.   fprintf(stderr, "ctv: requested to load \"%s\"\n", data.parameters);
  334.   #endif
  335.   #define GSND_BLOCK_SIZE 65000L
  336.   int fh = sopen(data.parameters, O_RDONLY|O_BINARY, SH_DENYNO);
  337.   if(fh != -1) {
  338.     long length = data.buffer_length;
  339.     char huge* ptr = (char huge*)MK_FP(data.buffer_segment, data.buffer_offset);
  340.     while(length > 0) {
  341.       uint chunk_length = (uint)(length > GSND_BLOCK_SIZE ? GSND_BLOCK_SIZE : length);
  342.       if(read(fh, (void*)ptr, chunk_length) != chunk_length) {
  343.         int errno_tmp = errno;
  344.         close(fh);
  345.         errno = errno_tmp;
  346.         return 0xFFFF;  // DOS error
  347.       }
  348.       length -= GSND_BLOCK_SIZE;
  349.       ptr += GSND_BLOCK_SIZE;
  350.     }
  351.     #ifdef DEBUG
  352.     fprintf(stderr, "ctv: \"%s\" loaded at %04X:%04X\n", data.parameters, data.buffer_segment, data.buffer_offset);
  353.     #endif
  354.     if(close(fh) == -1)
  355.       return 0xFFFF;
  356.     // Sample rate is not supported yet
  357.     data.sample_rate = 0;
  358.     return 0x0000;  // Success
  359.   }
  360.   return 0xFFFF;  // DOS error
  361. }
  362.  
  363.  
  364. //  ------------------------------------------------------------------
  365.  
  366. void ctv_close() {
  367.  
  368.   #ifdef DEBUG
  369.   fprintf(stderr, "ctv: close\n");
  370.   #endif
  371.   // Nothing else to do in this implementation
  372. }
  373.  
  374.  
  375. //  ------------------------------------------------------------------
  376.  
  377. void ctv_stop() {
  378.  
  379.   #ifdef DEBUG
  380.   fprintf(stderr, "ctv: stop\n");
  381.   #endif
  382.   _BX = 8;
  383.   (*driver)();
  384.   ctv_status = _AX;
  385.   #ifdef DEBUG
  386.   fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  387.   #endif
  388. }
  389.  
  390.  
  391. //  ------------------------------------------------------------------
  392.  
  393. void ctv_play(word sample_rate) {
  394.  
  395.   // Sample rate is not supported yet
  396.   NW(sample_rate);
  397.  
  398.   #ifdef DEBUG
  399.   fprintf(stderr, "ctv: play buffer at %04X:%04X\n", data.buffer_segment, data.buffer_offset);
  400.   #endif
  401.   char* vocbuf = (char*)MK_FP(data.buffer_segment, data.buffer_offset);
  402.   void* vocptr = vocbuf + ((voc_header*)vocbuf)->dataoffset;
  403.   if(data.status)
  404.     ctv_stop();
  405.   _BX = 6;
  406.   _ES = FP_SEG(vocptr);
  407.   _DI = FP_OFF(vocptr);
  408.   (*driver)();
  409.   ctv_status = _AX;
  410.   #ifdef DEBUG
  411.   fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  412.   #endif
  413. }
  414.  
  415.  
  416. //  ------------------------------------------------------------------
  417.  
  418. void ctv_pause() {
  419.  
  420.   #ifdef DEBUG
  421.   fprintf(stderr, "ctv: pause\n");
  422.   #endif
  423.   _BX = 10;
  424.   (*driver)();
  425.   ctv_status = _AX;
  426.   #ifdef DEBUG
  427.   fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  428.   #endif
  429. }
  430.  
  431.  
  432. //  ------------------------------------------------------------------
  433.  
  434. void ctv_resume() {
  435.  
  436.   #ifdef DEBUG
  437.   fprintf(stderr, "ctv: continue\n");
  438.   #endif
  439.   _BX = 11;
  440.   (*driver)();
  441.   ctv_status = _AX;
  442.   #ifdef DEBUG
  443.   fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  444.   #endif
  445. }
  446.  
  447.  
  448. //  ------------------------------------------------------------------
  449.  
  450. void ctv_break_loop(word method) {
  451.  
  452.   #ifdef DEBUG
  453.   fprintf(stderr, "ctv: break loop\n");
  454.   #endif
  455.   _AX = method;
  456.   _BX = 12;
  457.   (*driver)();
  458.   ctv_status = _AX;
  459.   #ifdef DEBUG
  460.   fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  461.   #endif
  462. }
  463.  
  464.  
  465. //  ------------------------------------------------------------------
  466.  
  467. void ctv_speaker(word onoff) {
  468.  
  469.   #ifdef DEBUG
  470.   fprintf(stderr, "ctv: speaker %s\n", onoff ? "on" : "off");
  471.   #endif
  472.   _AX = onoff;
  473.   _BX = 4;
  474.   (*driver)();
  475.   ctv_status = _AX;
  476.   #ifdef DEBUG
  477.   fprintf(stderr, "ctv: status = %04X\n", ctv_status);
  478.   #endif
  479. }
  480.  
  481.  
  482. //  ------------------------------------------------------------------
  483.  
  484. void interrupt gsapi_handler(uint, uint di, uint, uint, uint, uint dx, uint cx, uint bx, uint ax) {
  485.  
  486.   NW(di); NW(dx); NW(cx);
  487.  
  488.   if((ax >> 8) == mpx) {
  489.     switch(ax & 0xFF) {
  490.       case GSAPI_INSTALL_CHECK:
  491.         ax = 0xFF;
  492.         cx = GSAPI_VERSION;
  493.         dx = FP_SEG(&signature);
  494.         di = FP_OFF(&signature);
  495.         #ifdef DEBUG
  496.         fprintf(stderr, "gapi_handler: installation check using signature at %04X:%04X\n", dx, di);
  497.         #endif
  498.         return;
  499.       case GSAPI_OPEN_API:
  500.         if(api_okay) {
  501.           if(NOT api_open) {
  502.             api_open = ++unique_key;
  503.             bx = api_open;
  504.             cx = sizeof(gsapidata);
  505.             dx = FP_SEG(&data);
  506.             di = FP_OFF(&data);
  507.             #ifdef DEBUG
  508.             fprintf(stderr, "gsapi_handler: api opened using data at %04X:%04X, length %u\n", dx, di, cx);
  509.             #endif
  510.             ax = 0x0000;  // Success
  511.             return;
  512.           }
  513.           ax = 0x0001;  // Already open
  514.           return;
  515.         }
  516.         ax = 0xFFFF;  // Cannot open
  517.         return;
  518.       case GSAPI_CLOSE_API:
  519.         if(api_open) {
  520.           if(bx == api_open) {
  521.             if(data.status)
  522.               ctv_stop();
  523.             if(file_open) {
  524.               ctv_close();
  525.               file_open = FALSE;
  526.             }
  527.             api_open = FALSE;
  528.             ax = 0x0000;  // Success
  529.             return;
  530.           }
  531.           ax = 0xFFFF;  // Not correct key
  532.           return;
  533.         }
  534.         ax = 0x0001;  // Not open
  535.         return;
  536.       case GSAPI_OPEN_AND_LOAD_FILE:
  537.         if(NOT file_open) {
  538.           if(data.buffer_length == 0) {
  539.             #ifdef DEBUG
  540.             fprintf(stderr, "ctv: opening \"%s\"\n", data.parameters);
  541.             #endif
  542.             find_t fb;
  543.             if(_dos_findfirst(data.parameters, 0, &fb)) {
  544.               bx = errno;
  545.               ax = 0xFFFF;  // DOS error
  546.               return;
  547.             }
  548.             data.buffer_length = fb.size;
  549.             #ifdef DEBUG
  550.             fprintf(stderr, "ctv: need %li bytes for \"%s\"\n", data.buffer_length, data.parameters);
  551.             #endif
  552.             ax = 0x0002;  // Need memory
  553.             return;
  554.           }
  555.           ax = ctv_open_and_load();
  556.           if(ax == 0xFFFF)  // DOS error
  557.             bx = errno;
  558.           else
  559.             file_open = TRUE;
  560.           return;
  561.         }
  562.         ax = 0x0001;  // File already open
  563.         return;
  564.       case GSAPI_CLOSE_FILE:
  565.         if(file_open) {
  566.           ctv_close();
  567.           file_open = FALSE;
  568.           data.buffer_length = 0;
  569.           ax = 0x0000;  // Success
  570.           return;
  571.         }
  572.         ax = 0x0001;  // Not open
  573.         return;
  574.       case GSAPI_PLAY:
  575.         if(file_open) {
  576.           //if(data.status)
  577.           //  ctv_stop();
  578.           ctv_play(bx);
  579.           ax = 0x0000;  // Success
  580.           return;
  581.         }
  582.         ax = 0x0001;  // No sound
  583.         return;
  584.       case GSAPI_STOP:
  585.         if(file_open) {
  586.           ctv_stop();
  587.           ax = 0x0000;  // Success
  588.           return;
  589.         }
  590.         ax = 0x0001;  // No sound
  591.         return;
  592.       case GSAPI_PAUSE:
  593.         if(file_open) {
  594.           ctv_pause();
  595.           ax = 0x0000;  // Success
  596.           return;
  597.         }
  598.         ax = 0x0001;  // No sound
  599.         return;
  600.       case GSAPI_RESUME:
  601.         if(file_open) {
  602.           ctv_resume();
  603.           ax = 0x0000;  // Success
  604.           return;
  605.         }
  606.         ax = 0x0001;  // No sound
  607.         return;
  608.       case GSAPI_BREAK_LOOP:
  609.         if(file_open) {
  610.           ctv_break_loop(bx);
  611.           ax = 0x0000;  // Success
  612.           return;
  613.         }
  614.         ax = 0x0001;  // No sound
  615.         return;
  616.       case GSAPI_SPEAKER_ON_OFF:
  617.         ctv_speaker(bx);
  618.         return;
  619.       default:
  620.         #ifdef DEBUG
  621.         fprintf(stderr, "gsapi_handler: received function %u\n", ax & 0xFF);
  622.         #endif
  623.         ax = 0;   // Return "not implemented" for all other functions
  624.         return;
  625.     }
  626.   }
  627.   _chain_intr(old_handler);
  628. }
  629.  
  630.  
  631. //  ------------------------------------------------------------------
  632.  
  633. void gsapi_handler_install(char** argv) {
  634.  
  635.   api_okay = ctv_init();
  636.  
  637.   if(api_okay) {
  638.  
  639.     // Fill in the AMI signature
  640.     memcpy(signature.manufacturer, "Goldware", 8);
  641.     memcpy(signature.product_name, "GoldSAPI", 8);
  642.     strcpy(signature.product_description, "The Goldware Sound API by Odinn Sorensen, " __DATE__);
  643.  
  644.     // Find a free multiplex number
  645.     REGPACK regs;
  646.     for(mpx=0; mpx<256; mpx++) {
  647.       regs.r_ax = mpx << 8;
  648.       intr(0x2D, ®s);
  649.       if((regs.r_ax & 0xFF) == 0)
  650.         break;
  651.     }
  652.  
  653.     if(mpx < 256) {
  654.  
  655.       // Link in the handler
  656.       old_handler = _dos_getvect(0x2D);
  657.       _dos_setvect(0x2D, (interrupt_handler)gsapi_handler);
  658.  
  659.       #ifdef DEBUG
  660.       fprintf(stderr, "gsapi_handler_install: using mpx %u\n", mpx);
  661.       #endif
  662.  
  663.       errorlevel = spawnv(P_WAIT,*(argv+1),argv+1);
  664.  
  665.       _dos_setvect(0x2D, old_handler);
  666.     }
  667.  
  668.     ctv_reset();
  669.   }
  670. }
  671.  
  672.  
  673. //  ------------------------------------------------------------------
  674.  
  675. int main(int argc, char** argv) {
  676.  
  677.   if(argc > 1) {
  678.     gsapi_handler_install(argv);
  679.     #ifdef DEBUG
  680.     fprintf(stderr, "%s returned errorlevel %u\n", argv[1], errorlevel);
  681.     #endif
  682.   }
  683.   else {
  684.     char* syntax = "GCTVSAPI <prog> [parms]$";
  685.     REGPACK regs;
  686.     regs.r_ax = 0x0900;
  687.     regs.r_ds = FP_SEG(syntax);
  688.     regs.r_dx = FP_OFF(syntax);
  689.     intr(0x21, ®s);
  690.   }
  691.  
  692.   return errorlevel;
  693. }
  694.  
  695.  
  696. //  ------------------------------------------------------------------
  697.  
  698.