#include #include #include #include #include #include #include "mtypes.h" #include "mdriver.h" #include "vc.h" #include "mdma.h" #include "sbio.h" char *SB_DMABUF; UBYTE SB_TIMECONSTANT; UBYTE PIC1MSK; UBYTE PIC2MSK; extern UNIMOD *pf; UWORD sb_int; // interrupt vector that belongs to sb_irq UWORD sb_ver; // DSP version number UWORD sb_port; // sb base port UBYTE sb_irq; // sb irq UBYTE sb_lodma; // 8 bit dma channel (1.0/2.0/pro) UBYTE sb_hidma; // 16 bit dma channel (16/16asp) UBYTE sb_dma; // current dma channel BOOL SB_IsThere(void) { char *envptr,*endptr,c; sb_port =0xffff; sb_irq =0xff; sb_lodma=0xff; sb_hidma=0xff; if((envptr=getenv("BLASTER"))==NULL) return 0; while(1){ // skip whitespace do c=*(envptr++); while(c==' ' || c=='\t'); // reached end of string? -> exit if(c==0) break; switch(c){ case 'a': case 'A': sb_port=strtol(envptr,&endptr,16); break; case 'i': case 'I': sb_irq=strtol(envptr,&endptr,10); break; case 'd': case 'D': sb_lodma=strtol(envptr,&endptr,10); break; case 'h': case 'H': sb_hidma=strtol(envptr,&endptr,10); break; default: strtol(envptr,&endptr,16); break; } envptr=endptr; } if(sb_port==0xffff || sb_irq==0xff || sb_lodma==0xff) return 0; // determine interrupt vector sb_int = (sb_irq>7) ? sb_irq+104 : sb_irq+8; if(!SB_Ping()) return 0; // get dsp version. if((sb_ver=SB_GetDSPVersion())==0xffff) return 0; return 1; } BOOL SB_Init(void) { ULONG t; if(!SB_IsThere()){ myerr="No such hardware detected, check your 'BLASTER' env. variable"; return 0; } printf("SB version %x\n",sb_ver); // if(sb_ver>0x200) sb_ver=0x200; if(sb_ver>=0x400 && sb_hidma==0xff){ myerr="High-dma setting in 'BLASTER' variable is required for SB-16"; return 0; } if(sb_ver<0x400 && md_mode&DMODE_16BITS){ // DSP versions below 4.00 can't do 16 bit sound. md_mode&=~DMODE_16BITS; } if(sb_ver<0x300 && md_mode&DMODE_STEREO){ // DSP versions below 3.00 can't do stereo sound. md_mode&=~DMODE_STEREO; } // Use low dma channel for 8 bit, high dma for 16 bit sb_dma=(md_mode & DMODE_16BITS) ? sb_hidma : sb_lodma; if(sb_ver<0x400){ t=md_mixfreq; if(md_mode & DMODE_STEREO) t<<=1; SB_TIMECONSTANT=256-(1000000L/t); if(sb_ver<0x201){ if(SB_TIMECONSTANT>210) SB_TIMECONSTANT=210; } else{ if(SB_TIMECONSTANT>233) SB_TIMECONSTANT=233; } md_mixfreq=1000000L/(256-SB_TIMECONSTANT); if(md_mode & DMODE_STEREO) md_mixfreq>>=1; } if(!VC_Init()) return 0; SB_DMABUF=Dma_AllocMem(md_dmabufsize); if(SB_DMABUF==NULL){ myerr="Couldn't allocate page-contiguous dma-buffer"; return 0; } return 1; } void SB_Exit(void) { Dma_FreeMem(SB_DMABUF); VC_Exit(); } void interrupt newhandler(void) { if(sb_ver<0x200){ SB_WriteDSP(0x14); SB_WriteDSP(0xff); SB_WriteDSP(0xfe); } if(md_mode & DMODE_16BITS) inportb(sb_port+0xf); else inportb(DSP_DATA_AVAIL); if(sb_irq>7) outportb(0xa0,0x20); outportb(0x20,0x20); } void (interrupt far *oldhandler)(void); UWORD last=0; UWORD curr=0; void SB_Update(void) { UWORD todo; curr=(md_dmabufsize-Dma_Todo(sb_dma))&0xfffc; if(curr>last){ todo=curr-last; last+=VC_WriteBytes(&SB_DMABUF[last],todo); if(last>=md_dmabufsize) last=0; } else{ todo=md_dmabufsize-last; VC_WriteBytes(&SB_DMABUF[last],todo); last=VC_WriteBytes(SB_DMABUF,curr); } } void SB_PlayStart(void) { VC_PlayStart(); disable(); PIC1MSK=inportb(0x21); PIC2MSK=inportb(0xa1); if(sb_irq>7){ outportb(0x21,PIC1MSK & 0xfb); // 1111 1011 enable irq 2 outportb(0xa1,PIC2MSK & ~(1<<(sb_irq-8))); // and enable high irq } else{ // En de SB interrupts toestaan outportb(0x21,PIC1MSK & ~(1<=0x300 && sb_ver<0x400){ if(md_mode & DMODE_STEREO){ SB_MixerStereo(); } else{ SB_MixerMono(); } } /* clear the dma buffer to zero (16 bits signed ) or 0x80 (8 bits unsigned) */ if(md_mode & DMODE_16BITS) memset(SB_DMABUF,0,md_dmabufsize); else memset(SB_DMABUF,0x80,md_dmabufsize); if(!Dma_Start(sb_dma,SB_DMABUF,md_dmabufsize,INDEF_WRITE)){ return; } if(sb_ver<0x400){ SB_SpeakerOn(); SB_WriteDSP(0x40); SB_WriteDSP(SB_TIMECONSTANT); if(sb_ver<0x200){ SB_WriteDSP(0x14); SB_WriteDSP(0xff); SB_WriteDSP(0xfe); } else if(sb_ver==0x200){ SB_WriteDSP(0x48); SB_WriteDSP(0xff); SB_WriteDSP(0xfe); SB_WriteDSP(0x1c); } else{ SB_WriteDSP(0x48); SB_WriteDSP(0xff); SB_WriteDSP(0xfe); SB_WriteDSP(0x90); } } else{ SB_WriteDSP(0x41); SB_WriteDSP(md_mixfreq>>8); SB_WriteDSP(md_mixfreq&0xff); if(md_mode & DMODE_16BITS){ SB_WriteDSP(0xb6); SB_WriteDSP((md_mode & DMODE_STEREO) ? 0x30 : 0x10); } else{ SB_WriteDSP(0xc6); SB_WriteDSP((md_mode & DMODE_STEREO) ? 0x20 : 0x00); } SB_WriteDSP(0xff); SB_WriteDSP(0xef); } } void SB_PlayStop(void) { VC_PlayStop(); SB_SpeakerOff(); SB_ResetDSP(); SB_ResetDSP(); Dma_Stop(sb_dma); disable(); _dos_setvect(sb_int,oldhandler); outportb(0x21,PIC1MSK); outportb(0xa1,PIC2MSK); enable(); } DRIVER sbdriver={ NULL, "Soundblaster & compatibles", "MikMod Soundblaster Driver v1.0 for 1.0 / 2.0 / Pro / 16", SB_IsThere, VC_SampleLoad, VC_SampleUnload, SB_Init, SB_Exit, SB_PlayStart, SB_PlayStop, SB_Update };