/******************************************************************************************* Sound Blaster and Miscellanoeous Stuff MHG Dec 1996 29 Jan 97 MHG make work with any Sb address 22 Feb 97 MHG inmsert_text(), insert_char() added *******************************************************************************************/ #include #include #include #include "sound.h" #define D32RealSeg(P) ((((DWORD) (P)) >> 4) & 0xFFFF) #define D32RealOff(P) (((DWORD) (P)) & 0xF) typedef unsigned int WORD; typedef unsigned long DWORD; extern void __interrupt apmhandler (void); extern void __interrupt __far armhandler (void); unsigned char dspread ( void ); #pragma aux InterruptsOff = \ "cli"; #pragma aux InterruptsOn = \ "sti"; static unsigned int thePort = 0x220; static unsigned int theIRQ = 5; //7 static unsigned int theDMA = 1; unsigned int pagePort[] = {0x87, 0x83, 0x81, 0x82}; char scan2ascii[128]= { 0,0,'!','"','œ','$','%','^','&','*','(',')','_','+',126, 9, 'Q','W','E','R','T','Y','U','I','O','P','{','}',13, 14, 'A','S','D','F','G','H','J','K','L',':','@','|', 15, '|','Z','X','C','V','B','N','M','<','>','?',16,18, 17, ' ',19, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; // // keyboard buffer pointers // char *keybuff; unsigned char *keytail; unsigned char *keyhead; // // sound buffer pointers // unsigned short *soundtail; unsigned short *soundhead; unsigned char *soundflag; // // sound dma buffer pointers // unsigned char aligned_physical; unsigned char *aligned; int soundon=0; /******************************************************************************************* Malloc Dos Memory *******************************************************************************************/ void *D32DosMemAlloc2(DWORD size) { union REGS r; r.x.eax = 0x0100; /* DPMI allocate DOS memory */ r.x.ebx = (size + 15) >> 4; /* Number of paragraphs requested */ int386 (0x31, &r, &r); if (r.x.cflag) /* Failed */ return ((DWORD) 0); return (void *) ((r.x.eax & 0xFFFF) << 4); } /******************************************************************************************* Get low memory set vector 0x34 to point to it *******************************************************************************************/ void GetDOSMemory(void) { union REGS r; struct SREGS sr; void *lowp; void far *fh; WORD orig_pm_sel; DWORD orig_pm_off; WORD orig_rm_seg; WORD orig_rm_off; int c; int *mem; int i; /* Save the starting protected-mode handler address */ r.x.eax = 0x3509; /* DOS get vector (INT 0Ch) */ sr.ds = sr.es = 0; int386x (0x21, &r, &r, &sr); orig_pm_sel = (WORD) sr.es; orig_pm_off = r.x.ebx; /* Save the starting real-mode handler address using DPMI (INT 31h). */ r.x.eax = 0x0200; /* DPMI get real mode vector */ r.h.bl = 0x09; int386 (0x31, &r, &r); orig_rm_seg = (WORD) r.x.ecx; orig_rm_off = (WORD) r.x.edx; /* Allocate 128 bytes of DOS memory for the real-mode handler, which must of course be less than 128 bytes long. Then copy the real-mode handler into that segment. */ if(! ( lowp = D32DosMemAlloc2(2000) ) ) { printf ("Couldn't get low memory!\n"); exit (1); } // memcpy (lowp, (void *) armhandler, 2000); mem=(int *)(int)(0x34*4); *mem=500+(int)lowp; /* set vector for keyboard table 500 bytes from rmhandler */ keybuff=(char *) *mem; keyhead=keybuff+256; keytail=keybuff+257; *keyhead=0; *keytail=0; } /******************************************************************************************* Get a key scan code from the keypress buffer *******************************************************************************************/ unsigned char LookKey(void) { unsigned char i; if (*keytail!=*keyhead) { i=*keyhead; i++; i&=255; *keyhead=i; return(keybuff[i]); } return(0); } /******************************************************************************************* check if a ascii key has been pressed *******************************************************************************************/ char get_ascii_key() { unsigned char a; char a1=0; a=LookKey(); if (a) { if ((a&0x80)==0) a1=scan2ascii[a]; } return(a1); } extern void __interrupt __far rm_sb (void); #define _PIC_CONTROL 0x0020 #define _PIC_MASK 0x0021 #define _READ_IN_SERVICE 0x0B #define _IRQ0_MASK 0x01 #define _IRQ1_MASK 0x02 #define _IRQ2_MASK 0x04 #define _IRQ3_MASK 0x08 #define _IRQ4_MASK 0x10 #define _IRQ5_MASK 0x20 #define _IRQ6_MASK 0x40 #define _IRQ7_MASK 0x80 /******************************************************************************************* Install Sound Blaster Interrupt *******************************************************************************************/ void InstallSBInterrupt(void) { char com_Register; char *bptr; int *dptr; int i; i=0x34*4; dptr=(int *) i; bptr=(char *)*dptr; //address of data block bptr[261]=aligned_physical; bptr[260]=0; bptr[266]=thePort&255; bptr[267]=(thePort>>8)&255; soundhead=(unsigned short *) (char *)&bptr[262]; // pointer to where dma is to get sound data soundtail=(unsigned short *) (char *)&bptr[264]; // pointer to where to put sound data soundflag=(unsigned char *) (char *)&bptr[268]; // pointer to where to put sound data *soundhead=0; *soundtail=0; *soundflag=0; com_Register = inp(_PIC_MASK); outp(_PIC_MASK, com_Register | (1 << theIRQ)); //clear int SetRMInterrupt(theIRQ+8,(void *)rm_sb); //protected mode interrupt com_Register = inp(_PIC_MASK); outp(_PIC_MASK, com_Register & ~(1 << theIRQ)); //enable int com_Register = inp(_PIC_MASK); } /******************************************************************************************* set real mode interrupt vector and move interrupt routine down into real ram *******************************************************************************************/ #define D32RealSeg(P) ((((DWORD) (P)) >> 4) & 0xFFFF) #define D32RealOff(P) (((DWORD) (P)) & 0xF) typedef unsigned int WORD; typedef unsigned long DWORD; /******************************************************************************************* Set Real Mode Interrupt *******************************************************************************************/ void SetRMInterrupt(int no,void *rmhandler) { union REGS r; void far *fh; struct SREGS sr; void *lowp; lowp = (void *)D32DosMemAlloc2(4000); memcpy (lowp, (void *) rmhandler, 4000); r.x.eax = 0x0201; r.h.bl = no; /* CX:DX == real mode &handler */ r.x.ecx = D32RealSeg(lowp); r.x.edx = D32RealOff(lowp); int386 (0x31, &r, &r); } /******************************************************************************************* Set Protected mode interrupt *******************************************************************************************/ void SetPMInterrupt(int no,void *pmhandler) { union REGS r; struct SREGS sr; void far *fh; /* Install the new protected-mode vector. Because INT 0Ch is in the auto-passup range, its normal "passdown" behavior will change as soon as we install a protected-mode handler. After this next call, when a real mode INT 0Ch is generated, it will be resignalled in protected mode and handled by pmhandler. */ r.x.eax = 0x2509; /* DOS set vector (INT 0Ch) */ fh = (void far *) pmhandler; r.x.edx = FP_OFF (fh); /* DS:EDX == &handler */ sr.ds = FP_SEG (fh); sr.es = 0; int386x (0x21, &r, &r, &sr); } /******************************************************************************************* SoundBlaster Code Copyright (c), David Welch, 1993 get sound blaster info *******************************************************************************************/ void find_sb_info() { char* blaster; // Start with some reasonable values thePort = 0x220; theIRQ = 5; theDMA = 1; // Parse the BLASTER environment variable blaster = (char *)getenv("BLASTER"); while(*blaster != 0) { // Skip white space while((*blaster == ' ') || (*blaster == '\t')) blaster++; if(tolower(*blaster) == 'a') { thePort = strtol(blaster + 1, 0, 16); } else if(tolower(*blaster) == 'd') { theDMA = strtol(blaster + 1, 0, 10); } else if(tolower(*blaster) == 'i') { theIRQ = strtol(blaster + 1, 0, 10); } // Skip over information we've parsed while((*blaster != 0) && (*blaster != ' ') && (*blaster != '\t')) ++blaster; } } //------------------------------------------------------------------------------ void InitSound() { unsigned char major; unsigned char minor; find_sb_info(); //look for enviroment if (soundon=sbinit()) //look for dsp { dspwrite(0xE1); major=dspread(); minor=dspread(); // printf("DSP version %u.%u\n",major,minor); if(major==3) { soutportb(0x4,0x00); soutportb(0x5,0xFF); soutportb(0x4,0x04); soutportb(0x5,0xFF); soutportb(0x4,0x0A); soutportb(0x5,0x00); soutportb(0x4,0x0C); soutportb(0x5,0x26); soutportb(0x4,0x0E); soutportb(0x5,0x20); soutportb(0x4,0x22); soutportb(0x5,0x99); soutportb(0x4,0x26); soutportb(0x5,0x00); soutportb(0x4,0x28); soutportb(0x5,0x00); soutportb(0x4,0x2E); soutportb(0x5,0x00); } sbmalloc(); spkon(); if (RATE>25000) SetHighSampleRate(RATE); else SetSampleRate(RATE); InstallSBInterrupt(); ClearSound(); TriggerSound(RATE); } } //------------------------------------------------------------------------------ void soutportb(int port,char data) { outp(thePort+port,data); } //------------------------------------------------------------------------------ unsigned char sinportb(int port) { return(inp(thePort+port)); } //------------------------------------------------------------------------------ void SetSampleRate(int nSamplesPerSec) { unsigned char ca; ca=256UL-(1000000UL/nSamplesPerSec); sbsettc(ca); } //------------------------------------------------------------------------------ void outportb(int port,char data) { outp(port,data); } //------------------------------------------------------------------------------ unsigned char inportb(int port) { return(inp(port)); } //------------------------------------------------------------------------------ void dspwrite ( unsigned char c ) { while(sinportb(0xC)&0x80); soutportb(0xC,c); } //------------------------------------------------------------------------------ unsigned char dspread ( void ) { while(!(sinportb(0xE)&0x80)); return(sinportb(0xA)); } //------------------------------------------------------------------------------ int sbinit ( void ) { unsigned short x; sinportb(0xE); soutportb(6,0x01); sinportb(6); sinportb(6); sinportb(6); sinportb(6); soutportb(6,0x00); for(x=0;x<100;x++) { if(sinportb(0xE)&0x80) { if(sinportb(0xA)==0xAA) break; } } if(x==100) { return(0); // printf("Sound Blaster not found at 0220h\n"); // exit(1); } return(1); } //------------------------------------------------------------------------------ void sbmalloc ( void ) { unsigned long physical; unsigned char *data; data=(unsigned char *)D32DosMemAlloc2(0x20100); if(data==NULL) { printf("Memory Allocation Error\n"); exit(1); } physical=(unsigned long)data; physical+=0x0FFFFL; physical&=0xF0000L; aligned=(unsigned char *)physical; aligned_physical=(physical>>16)&15; //0-15 memset(aligned,128,65536); //set buffer to 0x80 } //------------------------------------------------------------------------------ void spkon ( void ) { dspwrite(0xD1); } //------------------------------------------------------------------------------ void sbsettc ( unsigned char tc ) { sinportb(0x0E); dspwrite(0x40); dspwrite(tc); } //------------------------------------------------------------------------------ void sbhaltdma ( void ) { dspwrite(0xD0); } //------------------------------------------------------------------------------ unsigned short dmastatus ( void ) { return(inportb(0x0008)&2); } //------------------------------------------------------------------------------ void TriggerSound(int r) { // memcpy(aligned,mem+0xb99,16384*4); if (!dmastatus()) sbhaltdma(); //stop current sound if (r>25000) high_play_sound(256,0); else play_sound(256,0); } /******************************************************************************************* Set High sample rate *******************************************************************************************/ void SetHighSampleRate(int nSamplesPerSec) { unsigned long ca; ca=65536UL-(256000000UL/nSamplesPerSec); sbsettc(ca/256); } /******************************************************************************************* Get the GAP between read and writing *******************************************************************************************/ int lasthead; int lasttail; int GetSoundGap(void) { unsigned short p; unsigned short q; p=*soundtail; q=*soundhead; return((p-q)&65535); } /******************************************************************************************* Transfer sound sample data into low memory sound buffer *******************************************************************************************/ void SetSoundBuffer(char *buffer,int lenght,int rlenght) { unsigned short p; unsigned short q; unsigned short pp; int i; if (!soundon) return; #if 0 FILE *fred; static int thing = 0; if(!thing) fred = fopen("debug.txt","w"); else fred = fopen("debug.txt","a"); thing++; fseek(fred,0,SEEK_END); fwrite(buffer,1,lenght,fred); fclose(fred); #endif p=*soundtail; q=*soundhead; InterruptsOff(); //will not do a dma /* if (*(soundflag)) { printf("**UND len=%d write tail=%d(+%d) read head=%d(+%d) gap=%d\n",lenght,p,p-lasttail,q,q-lasthead,p-q); *(soundflag)=0; } else printf("SOUND len=%d write tail=%d(+%d) read head=%d(+%d) gap=%d\n",lenght,p,p-lasttail,q,q-lasthead,p-q); */ lasthead=q; lasttail=p; pp=p; for(i=0;i>8); outportb(DMA_BASE + (theDMA << 1), offset & 0xFF); outportb(DMA_BASE + (theDMA << 1), offset >> 8); // outportb(0x83,aligned_physical+1); // 64K page number in memory of dma buffer outportb(pagePort[theDMA], aligned_physical+1); // outportb(0x03,(unsigned char)(len&0xFF)); // lenght to dma to dsp // outportb(0x03,(unsigned char)((len>>8)&0xFF)); outportb(DMA_COUNT + (theDMA << 1), len & 0xFF); outportb(DMA_COUNT + (theDMA << 1), len >> 8); // outportb(0x0A,0x01); // clear channel 1 mask outportb(DMA_MASK, theDMA); dspwrite(0x14); // tell the sound blaster's dsp to play len bytes dspwrite((unsigned char)(len&0xFF)); dspwrite((unsigned char)((len>>8)&0xFF)); } void high_play_sound( unsigned short len,int offset ) { len--; outportb(0x0A,0x05); // set channel 1 mask outportb(0x0C,0x00); // clear command flip flop outportb(0x0B,0x19); // set dma mode to outportb(0x02,offset &255); // memory offset low;high outportb(0x02,offset>>8); outportb(0x83,aligned_physical+1); // 64K page number in memory of dma buffer outportb(0x03,(unsigned char)(len&0xFF)); // lenght to dma to dsp outportb(0x03,(unsigned char)((len>>8)&0xFF)); outportb(0x0A,0x01); // clear channel 1 mask dspwrite(0x48); // tell the sound blaster's dsp to play len bytes dspwrite((unsigned char)(len&0xFF)); dspwrite((unsigned char)((len>>8)&0xFF)); dspwrite(0x91); // tell the sound blaster's dsp to play len bytes } /******************************************************************************************* Set Dos Video Mode *******************************************************************************************/ void setrez(int a) { union REGS r; r.x.eax = a; /* DPMI allocate DOS memory */ int386 (0x10, &r, &r); } /******************************************************************************************* Set VGA Palette register *******************************************************************************************/ void dac(int no,int r,int g,int b) { outportb(0x3c8,no); outportb(0x3c9,r>>2); outportb(0x3c9,g>>2); outportb(0x3c9,b>>2); } /******************************************************************************************* Set BBC Palette *******************************************************************************************/ void SetBBCPalette(void) { dac(0,000,000,000); dac(1,255,000,000); dac(2,000,255,000); dac(3,255,255,000); dac(4,000,000,255); dac(5,255,000,255); dac(6,000,255,255); dac(7,255,255,255); } /******************************************************************************************* Clear Sound Buffer *******************************************************************************************/ void ClearSound(void) { memset(aligned,128,65536+512); } /******************************************************************************************* KEY BUFFER INSERT STUFF *******************************************************************************************/ int count=500; int cpos=0; int ccpos=0; char table[]= { 0,0,42, 40, //* 40 | 0x80, 46, //c 46 | 0x80, 30, //a 30 | 0x80, 20, //t 20 | 0x80, 28, //return 28 | 0x80, 42 | 0x80, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; /******************************************************************************************* RESET the insert pointers *******************************************************************************************/ void reset_insert() { count=500; cpos=0; ccpos=0; } /******************************************************************************************* insert a character *******************************************************************************************/ void insert_char2(char a) { table[ccpos]=a; ccpos++; } /******************************************************************************************* Insert a string *******************************************************************************************/ void insert() { if (cpos>1000) return; count--; if (count<0) { if (table[cpos]==0) cpos=2000; insert_char(table[cpos]); cpos++; count=22; } } /******************************************************************************************* convert ascii into IBM scan codes *******************************************************************************************/ unsigned char ascii2scan[]= { /* 57,2,3,4, 5,6,7,8 // _!"# $%&' // ()*+ ,-./ // 0123 4567 // 89:; <=>? // @ABC DEFG // HIJK LMNO // PQRS TUVW // XYZ[ \]^_ // 'abc defg // hijk lmno // pqrs tuvw // xyz{ |}~ */ 30,48,46,32,18,33,34,35, // abcd efgh 23,36,37,38,50,49,24,25, // ijkl mnop 16,19,31,20,22,47,17,45, // qrst uvwx 21,44 //y,z }; /******************************************************************************************* insert a string into the keyboard buffer *******************************************************************************************/ void insert_text(char *buff) { char a; char a1; while(1) { a1=44; a=*buff++; if (a==0) break; if (a==32) { a1=57; } if (a==13) { a1=28; } if (a=='$') { insert_char2(42); insert_char2(5); insert_char2(0x80+5); insert_char2(0x80+42); a1=0; } if (a=='*') { insert_char2(42); insert_char2(40); insert_char2(40+0x80); insert_char2(42+0x80); a1=0; } if (a=='"') { insert_char2(42); insert_char2(3); insert_char2(3+0x80); insert_char2(42+0x80); a1=0; } if (a=='-') a1=12; if (a=='.') { a1=52; } if (a>='A' && a<='Z') { a1=ascii2scan[a-'A']; } if (a=='0') a1=11; if (a>='1' && a<='9') a1=a+2-'1'; if (a1!=0) { insert_char2(a1); insert_char2(a1+0x80); } if (a==13) break; } } /******************************************************************************************* insert a character *******************************************************************************************/ void insert_char(unsigned char a) { unsigned char index; index=*keytail; index++; index&=255; keybuff[index]=a; *keytail=index; } typedef struct { char id; char palleted; // 0-raw 1-palette char image_type; // 0-no 1-pal 2-truecol 3-b&w 8-rle on char palette_offset_l; char palette_offset_h; char palette_size_l; char palette_size_h; char palette_width; short leftx; short uppery; short width; //pixels short height; char bits_per_pixel; char image_descriptor; //0;3 no of alpha bits 4;5 orientation 0-lrbt 1-rl 2-tb 6;7 interleave 0,2,4 } TGA; id=0;