home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 June B / Pcwk6b98.iso / Mpeg3 / Dos / MP3 / MPG12304.EXE / DRV_SB.SEE < prev    next >
Text File  |  1995-12-12  |  9KB  |  512 lines

  1. /*
  2.  
  3. Name:
  4. DRV_SB.C
  5.  
  6. Description:
  7. Mikmod driver for output on Creative Labs Soundblasters & compatibles
  8. (through DSP)
  9.  
  10. Portability:
  11.  
  12. MSDOS:    BC(y)    Watcom(y)    DJGPP(y)
  13. Win95:    n
  14. Os2:    n
  15. Linux:    n
  16.  
  17. (y) - yes
  18. (n) - no (not possible or not useful)
  19. (?) - may be possible, but not tested
  20.  
  21. */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <dos.h>
  25. #include <malloc.h>
  26. #include <conio.h>
  27. #ifndef __DJGPP__
  28. #include <mem.h>
  29. #endif
  30.  
  31. #include "mikmod.h"
  32. #include "mdma.h"
  33. #include "mirq.h"
  34.  
  35. /***************************************************************************
  36. >>>>>>>>>>>>>>>>>>>>>>>>> Lowlevel SB stuff <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  37. ***************************************************************************/
  38.  
  39. static UWORD sb_port;          /* sb base port */
  40.  
  41. /*
  42.     Define some important SB i/o ports:
  43. */
  44.  
  45. #define MIXER_ADDRESS         (sb_port+0x4)
  46. #define MIXER_DATA            (sb_port+0x5)
  47. #define DSP_RESET            (sb_port+0x6)
  48. #define DSP_READ_DATA        (sb_port+0xa)
  49. #define DSP_WRITE_DATA        (sb_port+0xc)
  50. #define DSP_WRITE_STATUS    (sb_port+0xc)
  51. #define DSP_DATA_AVAIL        (sb_port+0xe)
  52.  
  53.  
  54. static void SB_MixerStereo(void)
  55. /*
  56.     Enables stereo output for DSP versions 3.00 >= ver < 4.00
  57. */
  58. {
  59.     outportb(MIXER_ADDRESS,0xe);
  60.     outportb(MIXER_DATA,inportb(MIXER_DATA)|2);
  61. }
  62.  
  63.  
  64.  
  65. static void SB_MixerMono(void)
  66. /*
  67.     Disables stereo output for DSP versions 3.00 >= ver < 4.00
  68. */
  69. {
  70.     outportb(MIXER_ADDRESS,0xe);
  71.     outportb(MIXER_DATA,inportb(MIXER_DATA)&0xfd);
  72. }
  73.  
  74.  
  75.  
  76. static BOOL SB_WaitDSPWrite(void)
  77. /*
  78.     Waits until the DSP is ready to be written to.
  79.  
  80.     returns FALSE on timeout
  81. */
  82. {
  83.     UWORD timeout=32767;
  84.  
  85.     while(timeout--){
  86.         if(!(inportb(DSP_WRITE_STATUS)&0x80)) return 1;
  87.     }
  88.     return 0;
  89. }
  90.  
  91.  
  92.  
  93. static BOOL SB_WaitDSPRead(void)
  94. /*
  95.     Waits until the DSP is ready to read from.
  96.  
  97.     returns FALSE on timeout
  98. */
  99. {
  100.     UWORD timeout=32767;
  101.  
  102.     while(timeout--){
  103.         if(inportb(DSP_DATA_AVAIL)&0x80) return 1;
  104.     }
  105.     return 0;
  106. }
  107.  
  108.  
  109.  
  110. static BOOL SB_WriteDSP(UBYTE data)
  111. /*
  112.     Writes byte 'data' to the DSP.
  113.  
  114.     returns FALSE on timeout.
  115. */
  116. {
  117.     if(!SB_WaitDSPWrite()) return 0;
  118.     outportb(DSP_WRITE_DATA,data);
  119.     return 1;
  120. }
  121.  
  122.  
  123.  
  124. static UWORD SB_ReadDSP(void)
  125. /*
  126.     Reads a byte from the DSP.
  127.  
  128.     returns 0xffff on timeout.
  129. */
  130. {
  131.     if(!SB_WaitDSPRead()) return 0xffff;
  132.     return(inportb(DSP_READ_DATA));
  133. }
  134.  
  135.  
  136.  
  137. static void SB_SpeakerOn(void)
  138. /*
  139.     Enables DAC speaker output.
  140. */
  141. {
  142.     SB_WriteDSP(0xd1);
  143. }
  144.  
  145.  
  146.  
  147. static void SB_SpeakerOff(void)
  148. /*
  149.     Disables DAC speaker output
  150. */
  151. {
  152.     SB_WriteDSP(0xd3);
  153. }
  154.  
  155.  
  156.  
  157. static void SB_ResetDSP(void)
  158. /*
  159.     Resets the DSP.
  160. */
  161. {
  162.     int t;
  163.     /* reset the DSP by sending 1, (delay), then 0 */
  164.     outportb(DSP_RESET,1);
  165.     for(t=0;t<8;t++) inportb(DSP_RESET);
  166.     outportb(DSP_RESET,0);
  167. }
  168.  
  169.  
  170.  
  171. static BOOL SB_Ping(void)
  172. /*
  173.     Checks if a SB is present at the current baseport by
  174.     resetting the DSP and checking if it returned the value 0xaa.
  175.  
  176.     returns: TRUE   => SB is present
  177.              FALSE  => No SB detected
  178. */
  179. {
  180.     SB_ResetDSP();
  181.     return(SB_ReadDSP()==0xaa);
  182. }
  183.  
  184.  
  185.  
  186. static UWORD SB_GetDSPVersion(void)
  187. /*
  188.     Gets SB-dsp version. returns 0xffff if dsp didn't respond.
  189. */
  190. {
  191.     UWORD hi,lo;
  192.  
  193.     if(!SB_WriteDSP(0xe1)) return 0xffff;
  194.  
  195.     hi=SB_ReadDSP();
  196.     lo=SB_ReadDSP();
  197.  
  198.     return((hi<<8)|lo);
  199. }
  200.  
  201.  
  202.  
  203. /***************************************************************************
  204. >>>>>>>>>>>>>>>>>>>>>>>>> The actual SB driver <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  205. ***************************************************************************/
  206.  
  207. static DMAMEM *SB_DMAMEM;
  208. static char *SB_DMABUF;
  209.  
  210. static UBYTE SB_TIMECONSTANT;
  211.  
  212. static UBYTE PIC1MSK;
  213. static UBYTE PIC2MSK;
  214.  
  215. static UWORD sb_int;           /* interrupt vector that belongs to sb_irq */
  216. static UWORD sb_ver;           /* DSP version number */
  217. static UBYTE sb_irq;           /* sb irq */
  218. static UBYTE sb_lodma;         /* 8 bit dma channel (1.0/2.0/pro) */
  219. static UBYTE sb_hidma;         /* 16 bit dma channel (16/16asp) */
  220. static UBYTE sb_dma;           /* current dma channel */
  221.  
  222.  
  223. static BOOL SB_IsThere(void)
  224. {
  225.     char *envptr,c;
  226.     static char *endptr;
  227.  
  228.     sb_port =0xffff;
  229.     sb_irq  =0xff;
  230.     sb_lodma=0xff;
  231.     sb_hidma=0xff;
  232.  
  233.     if((envptr=getenv("BLASTER"))==NULL) return 0;
  234.  
  235.     while(1){
  236.  
  237.         /* skip whitespace */
  238.  
  239.         do c=*(envptr++); while(c==' ' || c=='\t');
  240.  
  241.         /* reached end of string? -> exit */
  242.  
  243.         if(c==0) break;
  244.  
  245.         switch(c){
  246.  
  247.             case 'a':
  248.             case 'A':
  249.                 sb_port=strtol(envptr,&endptr,16);
  250.                 break;
  251.  
  252.             case 'i':
  253.             case 'I':
  254.                 sb_irq=strtol(envptr,&endptr,10);
  255.                 break;
  256.  
  257.             case 'd':
  258.             case 'D':
  259.                 sb_lodma=strtol(envptr,&endptr,10);
  260.                 break;
  261.  
  262.             case 'h':
  263.             case 'H':
  264.                 sb_hidma=strtol(envptr,&endptr,10);
  265.                 break;
  266.  
  267.             default:
  268.                 strtol(envptr,&endptr,16);
  269.                 break;
  270.         }
  271.         envptr=endptr;
  272.     }
  273.  
  274.     if(sb_port==0xffff || sb_irq==0xff || sb_lodma==0xff) return 0;
  275.  
  276.     /* determine interrupt vector */
  277.  
  278.     sb_int = (sb_irq>7) ? sb_irq+104 : sb_irq+8;
  279.  
  280.     if(!SB_Ping()) return 0;
  281.  
  282.     /* get dsp version. */
  283.  
  284.     if((sb_ver=SB_GetDSPVersion())==0xffff) return 0;
  285.  
  286.     return 1;
  287. }
  288.  
  289.  
  290. static void interrupt newhandler(MIRQARGS)
  291. {
  292.     if(sb_ver<0x200){
  293.         SB_WriteDSP(0x14);
  294.         SB_WriteDSP(0xff);
  295.         SB_WriteDSP(0xfe);
  296.     }
  297.  
  298.         if(md_mode & DMODE_16BITS)
  299.         inportb(sb_port+0xf);
  300.     else
  301.                 inportb(DSP_DATA_AVAIL);
  302.  
  303.     MIrq_EOI(sb_irq);
  304. }
  305.  
  306.  
  307. static PVI oldhandler;
  308.  
  309.  
  310. static BOOL SB_Init(void)
  311. {
  312.     ULONG t;
  313.  
  314.     if(!SB_IsThere()){
  315.         myerr="No such hardware detected, check your 'BLASTER' env. variable";
  316.         return 0;
  317.     }
  318.  
  319. /*      printf("SB version %x\n",sb_ver); */
  320. /*      if(sb_ver>0x200) sb_ver=0x200; */
  321.  
  322.     if(sb_ver>=0x400 && sb_hidma==0xff){
  323.         myerr="High-dma setting in 'BLASTER' variable is required for SB-16";
  324.         return 0;
  325.     }
  326.  
  327.     if(sb_ver<0x400 && md_mode&DMODE_16BITS){
  328.         /* DSP versions below 4.00 can't do 16 bit sound. */
  329.         md_mode&=~DMODE_16BITS;
  330.     }
  331.  
  332.     if(sb_ver<0x300 && md_mode&DMODE_STEREO){
  333.         /* DSP versions below 3.00 can't do stereo sound. */
  334.         md_mode&=~DMODE_STEREO;
  335.     }
  336.  
  337.     /* Use low dma channel for 8 bit, high dma for 16 bit */
  338.  
  339.     sb_dma=(md_mode & DMODE_16BITS) ? sb_hidma : sb_lodma;
  340.  
  341.     if(sb_ver<0x400){
  342.  
  343.         t=md_mixfreq;
  344.         if(md_mode & DMODE_STEREO) t<<=1;
  345.  
  346.         SB_TIMECONSTANT=256-(1000000L/t);
  347.  
  348.         if(sb_ver<0x201){
  349.             if(SB_TIMECONSTANT>210) SB_TIMECONSTANT=210;
  350.         }
  351.         else{
  352.             if(SB_TIMECONSTANT>233) SB_TIMECONSTANT=233;
  353.         }
  354.  
  355.         md_mixfreq=1000000L/(256-SB_TIMECONSTANT);
  356.         if(md_mode & DMODE_STEREO) md_mixfreq>>=1;
  357.     }
  358.  
  359.     if(!VC_Init()) return 0;
  360.  
  361.     SB_DMAMEM=MDma_AllocMem(md_dmabufsize);
  362.  
  363.     if(SB_DMAMEM==NULL){
  364.         VC_Exit();
  365.         myerr="Couldn't allocate page-contiguous dma-buffer";
  366.         return 0;
  367.     }
  368.  
  369.     SB_DMABUF=(char *)MDma_GetPtr(SB_DMAMEM);
  370.  
  371.     oldhandler=MIrq_SetHandler(sb_irq,newhandler);
  372.     return 1;
  373. }
  374.  
  375.  
  376.  
  377. static void SB_Exit(void)
  378. {
  379.     MIrq_SetHandler(sb_irq,oldhandler);
  380.     MDma_FreeMem(SB_DMAMEM);
  381.     VC_Exit();
  382. }
  383.  
  384.  
  385. static UWORD last=0;
  386. static UWORD curr=0;
  387.  
  388.  
  389. static void SB_Update(void)
  390. {
  391.     UWORD todo,index;
  392.  
  393.     curr=(md_dmabufsize-MDma_Todo(sb_dma))&0xfffc;
  394.  
  395.     if(curr==last) return;
  396.  
  397.     if(curr>last){
  398.         todo=curr-last; index=last;
  399.         last+=VC_WriteBytes(&SB_DMABUF[index],todo);
  400.         MDma_Commit(SB_DMAMEM,index,todo);
  401.         if(last>=md_dmabufsize) last=0;
  402.     }
  403.     else{
  404.         todo=md_dmabufsize-last;
  405.         VC_WriteBytes(&SB_DMABUF[last],todo);
  406.         MDma_Commit(SB_DMAMEM,last,todo);
  407.         last=VC_WriteBytes(SB_DMABUF,curr);
  408.         MDma_Commit(SB_DMAMEM,0,curr);
  409.     }
  410. }
  411.  
  412.  
  413.  
  414.  
  415. static void SB_PlayStart(void)
  416. {
  417.     VC_PlayStart();
  418.  
  419.     MIrq_OnOff(sb_irq,1);
  420.  
  421.     if(sb_ver>=0x300 && sb_ver<0x400){
  422.         if(md_mode & DMODE_STEREO){
  423.             SB_MixerStereo();
  424.         }
  425.         else{
  426.             SB_MixerMono();
  427.         }
  428.     }
  429.  
  430.     /* clear the dma buffer */
  431.  
  432.     VC_SilenceBytes(SB_DMABUF,md_dmabufsize);
  433.     MDma_Commit(SB_DMAMEM,0,md_dmabufsize);
  434.  
  435.     if(!MDma_Start(sb_dma,SB_DMAMEM,md_dmabufsize,INDEF_WRITE)){
  436.         return;
  437.     }
  438.  
  439.     if(sb_ver<0x400){
  440.         SB_SpeakerOn();
  441.  
  442.         SB_WriteDSP(0x40);
  443.         SB_WriteDSP(SB_TIMECONSTANT);
  444.  
  445.         if(sb_ver<0x200){
  446.             SB_WriteDSP(0x14);
  447.             SB_WriteDSP(0xff);
  448.             SB_WriteDSP(0xfe);
  449.         }
  450.         else if(sb_ver==0x200){
  451.             SB_WriteDSP(0x48);
  452.             SB_WriteDSP(0xff);
  453.             SB_WriteDSP(0xfe);
  454.             SB_WriteDSP(0x1c);
  455.         }
  456.         else{
  457.             SB_WriteDSP(0x48);
  458.             SB_WriteDSP(0xff);
  459.             SB_WriteDSP(0xfe);
  460.             SB_WriteDSP(0x90);
  461.         }
  462.     }
  463.     else{
  464.         SB_WriteDSP(0x41);
  465.  
  466.         SB_WriteDSP(md_mixfreq>>8);
  467.         SB_WriteDSP(md_mixfreq&0xff);
  468.  
  469.         if(md_mode & DMODE_16BITS){
  470.             SB_WriteDSP(0xb6);
  471.             SB_WriteDSP((md_mode & DMODE_STEREO) ? 0x30 : 0x10);
  472.         }
  473.         else{
  474.             SB_WriteDSP(0xc6);
  475.             SB_WriteDSP((md_mode & DMODE_STEREO) ? 0x20 : 0x00);
  476.         }
  477.  
  478.         SB_WriteDSP(0xff);
  479.         SB_WriteDSP(0xef);
  480.     }
  481. }
  482.  
  483.  
  484. static void SB_PlayStop(void)
  485. {
  486.     VC_PlayStop();
  487.     SB_SpeakerOff();
  488.     SB_ResetDSP();
  489.     SB_ResetDSP();
  490.     MDma_Stop(sb_dma);
  491.     MIrq_OnOff(sb_irq,0);
  492. }
  493.  
  494.  
  495. DRIVER drv_sb={
  496.     NULL,
  497.     "Soundblaster & compatibles",
  498.     "MikMod Soundblaster Driver v2.1 for 1.0 / 2.0 / Pro / 16",
  499.     SB_IsThere,
  500.     VC_SampleLoad,
  501.     VC_SampleUnload,
  502.     SB_Init,
  503.     SB_Exit,
  504.     SB_PlayStart,
  505.     SB_PlayStop,
  506.     SB_Update,
  507.     VC_VoiceSetVolume,
  508.     VC_VoiceSetFrequency,
  509.     VC_VoiceSetPanning,
  510.     VC_VoicePlay
  511. };
  512.