Xref: news2.mv.net comp.os.msdos.djgpp:4270 From: br516 AT FreeNet DOT Carleton DOT CA (Nicholas Lynch) Newsgroups: comp.os.msdos.djgpp Subject: GUS sound library (err...almost a library :) Date: 26 May 1996 21:28:22 GMT Organization: The National Capital FreeNet Lines: 522 Sender: br516 AT freenet3 DOT carleton DOT ca (Nicholas Lynch) Message-ID: <4oaidm$am@freenet-news.carleton.ca> Reply-To: br516 AT FreeNet DOT Carleton DOT CA (Nicholas Lynch) NNTP-Posting-Host: freenet3.carleton.ca To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp A while back someone posted a message about the GUS SDK not working with DJGPP. So, I've written a skeleton library of GUS functions (no DMA, sorry) to play a sound file. A few notes first: 1) The init may be commented as incomplete, but it hasn't failed me yet :) 2) There may be some stuff about allocating GUS memory, ignore that crap I haven't finished writing a way of allocating GUS memory. To play a sound, you'll need to init the GUS, load the raw sound data into RAM (or directly to the GUS using gus_poke if you want). You'll have to XOR each byte by 127 if it's an 8 bit sound file, or else I find it sounds funny. Poke the data into the GUS RAM. Use the play sound function with your options, example: gus_play_channel(1, (GUS_8BIT | GUS_LOOP), 0x0000, 0xA000); And the rest should be selft explanatory. Refrences: GUS SDK, PCGPE, and some Mod player I ran into :) -- GUS.H (cut here) ---------------------------------------------------------- #define GUS_MODUAL #define GUS_16BIT 0x004 #define GUS_8BIT 0x000 #define GUS_LOOP 0x008 #define GUS_BIDIR 0x010 #define GUS_WAVIRQ 0x020 #define GUS_DIR 0x040 #define GUS_IRQP 0x080 typedef struct { long start; long end; } gus_ptr; #ifdef __cplusplus extern "C" { #endif extern unsigned GUS_base_port; extern short GUS_DMA; extern short GUS_IRQ; extern short GUS_ready; extern long GUS_memory; extern unsigned char GUS_memory_map[256]; extern unsigned char gus_peek(unsigned long); extern void gus_poke(unsigned long, unsigned char); extern signed char gus_peeks(unsigned long); extern void gus_pokes(unsigned long, signed char); extern void gus_delay(void); extern long gus_mem_scan(void); extern long gus_mem_test(void); extern int gus_detect(void); extern int gus_init(short); extern void gus_set_volume(char, unsigned short); extern void gus_set_balance(char, char); extern void gus_set_freq(char, short); extern void gus_play_channel(char, char, long, long, long); extern void gus_stop_channel(char); extern unsigned long gus_channel_position(char); extern void gus_channel_control(char, unsigned char); extern gus_ptr gus_allocmem(short); extern void gus_8bit(long, unsigned char *); #ifdef __cplusplus } #endif-- GUS.C (cut here) -------------------------------------------- /* ======================================================================== */ /* GUS.C => Gravis Ultrasound Interface */ /* ------------------------------------------------------------------------ */ /* Purpose: To interface with the Gravis Ultrasound and play music and */ /* sound effects. */ /* ======================================================================== */ #include #include #include #include "GUS.H" const char *GUS_env_setting = "ULTRASND"; const char *GUS_env_dir = "ULTRADIR"; unsigned GUS_base_port; short GUS_DMA; short GUS_IRQ; short GUS_ready = -1; long GUS_memory; /* Map of each 4K block in GUS RAM, 1 = used, 0 = unused, 2 = unavailible */ unsigned char GUS_memory_map[256]; /* ======================================================================== */ /* General GUS procedures: */ /* ------------------------------------------------------------------------ */ /* unsigned char gus_peek(long) => read a value in GUS RAM */ /* void gus_poke(long, char) => Write a value to GUS RAM */ /* void gus_delay(void) => Wait 7 cycles */ /* long gus_mem_scan(void) => find out how much GUS RAM there is. */ /* long gus_mem_test(void) => Test every GUS RAM byte (slow as hell)*/ /* int gus_detect(void) => Find the GUS */ /* int gus_init(void) => Setup the GUS */ /* int gus_reset(void) => Reset the GUS */ /* ======================================================================== */ /* unsigned char gus_peek(long offset) */ /* ------------------------------------------------------------------------ */ /* Read a value from GUS memory at the specified offset. */ unsigned char gus_peek(unsigned long offset) { short lowval; char hival; lowval = (offset & 0xFFFF); hival = (unsigned long)(offset & 0xFF0000) >> 16; outportb(GUS_base_port + 0x103, 0x43); outportw(GUS_base_port + 0x104, lowval); outportb(GUS_base_port + 0x103, 0x44); outportb(GUS_base_port + 0x105, hival); return(inportb(GUS_base_port + 0x107)); } /* void gus_poke(long offset, unsigned char value) */ /* ------------------------------------------------------------------------ */ /* Enter a value into GUS RAM. */ void gus_poke(unsigned long offset, unsigned char value) { short lowval; char hival; lowval = (offset & 0xFFFF); hival = (unsigned long)(offset & 0xFF0000) >> 16; outportb(GUS_base_port + 0x103, 0x43); outportw(GUS_base_port + 0x104, lowval); outportb(GUS_base_port + 0x103, 0x44); outportb(GUS_base_port + 0x105, hival); outportb(GUS_base_port + 0x107, value); } /* unsigned char gus_peeks(long offset) */ /* ------------------------------------------------------------------------ */ /* Read a value from GUS memory at the specified offset. */ signed char gus_peeks(unsigned long offset) { short lowval; char hival; lowval = (offset & 0xFFFF); hival = (unsigned long)(offset & 0xFF0000) >> 16; outportb(GUS_base_port + 0x103, 0x43); outportw(GUS_base_port + 0x104, lowval); outportb(GUS_base_port + 0x103, 0x44); outportb(GUS_base_port + 0x105, hival); return(inportb(GUS_base_port + 0x107)); } /* void gus_poke(long offset, signed char value) */ /* ------------------------------------------------------------------------ */ /* Enter a value into GUS RAM. */ void gus_pokes(unsigned long offset, signed char value) { short lowval; char hival; lowval = (offset & 0xFFFF); hival = (unsigned long)(offset & 0xFF0000) >> 16; outportb(GUS_base_port + 0x103, 0x43); outportw(GUS_base_port + 0x104, lowval); outportb(GUS_base_port + 0x103, 0x44); outportb(GUS_base_port + 0x105, hival); outportb(GUS_base_port + 0x107, value); } /* void gus_delay(void) */ /* ------------------------------------------------------------------------ */ /* Do a 7 cycle delay for the GUS. */ void gus_delay(void) { asm (" pushw %dx pushw %ax movw $0x0300, %dx inb %dx, %al inb %dx, %al inb %dx, %al inb %dx, %al inb %dx, %al inb %dx, %al inb %dx, %al popw %ax popw %dx "); } /* long gus_mem_scan(void) */ /* ------------------------------------------------------------------------ */ /* Returns free GUS memory by scanning key points. */ long gus_mem_scan(void) { long ret_mem; gus_poke(0x40000, 0xFF); /* A GUS must have at least 256K of ram to be a GUS */ if(gus_peek(0x40000) != 0xFF) return(-1); else{ ret_mem = 0x40000; gus_poke(0x7FFFF, 0xAA); if(gus_peek(0x7FFFF) != 0xAA){ return(ret_mem); } else ret_mem = 0x80000; gus_poke(0xBFFFF, 0xBB); if(gus_peek(0xBFFFF) != 0xBB) return(ret_mem); else return(0xFFFFF); } /* Something went wrong */ return(-1); } /* long gus_test_mem(void) */ /* ------------------------------------------------------------------------ */ /* Read every byte in GUS RAM. WARNING: Will wipe out any data written to */ /* the GUS memory before the test. */ long gus_test_mem(void) { long mem_offset = 0; short scan_ok = 0; while(scan_ok == 0){ gus_poke(mem_offset, 0xAF); if(gus_peek(mem_offset) != 0xAF) scan_ok = -1; else mem_offset++; } return(mem_offset); } /* int gus_detect(void) */ /* ------------------------------------------------------------------------ */ /* Scan for Gravis Ultrasound card, first by Dos Environment, if it's not */ /* in an evironment variable, then scan all possible I/O addresses. This */ /* function sets all the GUS data and returns a 0 on success. */ int gus_detect(void) { char *GUS_env; char base_str[5]; short z; /* Read the environment string */ if((GUS_env = getenv(GUS_env_setting)) != NULL){ /* Suck the GUS values out of the string */ for(z=0; z<3; z++) base_str[z] = GUS_env[z]; base_str[4] = 0; /* Convert the 3 byte string into an integer, then to a HEX (+324) */ GUS_base_port = atoi(base_str) + 324; /* Scan the GUS memory */ GUS_memory = gus_mem_scan(); } return(0); } /* int gus_init(void) */ /* ------------------------------------------------------------------------ */ /* INCOMPLETE initialize the GUS for playing sounds. */ int gus_init(short max_channels) { short count; if((gus_detect()) == 0){ outportb(GUS_base_port + 0x103, 0x4C); outportb(GUS_base_port + 0x105, 0x06); gus_delay(); outportb(GUS_base_port + 0x103, 0x4C); outportb(GUS_base_port + 0x105, 0x07); /* Setup the gus for the maximum number of channels */ outportb(GUS_base_port + 0x103, 0x8E); outportb(GUS_base_port + 0x105, (max_channels | 0x0C0)); /* Set the global GUS variable to OK */ GUS_ready = 0; /* Setup the GUS allocation map */ for( count = 0; count < (short)(GUS_memory / 4096); count++) GUS_memory_map[count] = 0; /* Set the end of memory */ GUS_memory_map[count + 1] = 2; /* Return okay */ return(0); } /* Return error */ return(-1); } /* ======================================================================== */ /* GUS Mixer interface */ /* ------------------------------------------------------------------------ */ /* void gus_set_volume(char, unsigned int) => set the channel volume */ /* void gus_set_balance(char, char) => set the GUS pan position /* void gus_set_freq(char, int) => set the GUS frequency /* ======================================================================== */ /* void gus_set_volume(char channel, unsigned int volume) */ /* ------------------------------------------------------------------------ */ /* Set the volume for a specific channel. */ void gus_set_volume(char channel, unsigned short volume) { outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x103, 0x09); outportw(GUS_base_port + 0x104, volume); } /* void gus_set_balance(char channel, char balance) */ /* ------------------------------------------------------------------------ */ /* Set the pan position of the GUS. 0-15 (7 is middle) */ void gus_set_balance(char channel, char balance) { outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x103, 0x0C); outportb(GUS_base_port + 0x105, balance); } /* void gus_set_freq(char channel, int freq) */ /* ------------------------------------------------------------------------ */ /* Set the frequency of a channel. */ void gus_set_freq(char channel, short freq) { outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x103, 0x01); outportw(GUS_base_port + 0x104, freq); } /* ======================================================================== */ /* GUS output procedures */ /* ------------------------------------------------------------------------ */ /* void gus_play_channel(...) => Play a sound in RAM */ /* void gus_stop_channel(...) => Stop playing a sound. */ /* unsigned long gus_channel_position(...) => Returns position of chnl RAM */ /* ======================================================================== */ void gus_play_channel(char channel, char mode, long wbegin, long wstart, long wend) { outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x103, 0x0A); outportw(GUS_base_port + 0x104, (wbegin >> 7) & 8191); outportb(GUS_base_port + 0x103, 0x0B); outportw(GUS_base_port + 0x104, (wbegin & 0x127) << 8); outportb(GUS_base_port + 0x103, 0x02); outportw(GUS_base_port + 0x104, (wstart >> 7) & 8191); outportb(GUS_base_port + 0x103, 0x03); outportw(GUS_base_port + 0x104, (wstart & 0x127) << 8); outportb(GUS_base_port + 0x103, 0x04); outportw(GUS_base_port + 0x104, (wend >> 7) & 8191); outportb(GUS_base_port + 0x103, 0x05); outportw(GUS_base_port + 0x104, (wend & 0x127) << 8); outportb(GUS_base_port + 0x103, 0x00); outportb(GUS_base_port + 0x105, mode); outportb(GUS_base_port + 0x000, 0x01); outportb(GUS_base_port + 0x103, 0x4C); outportb(GUS_base_port + 0x105, 0x03); } void gus_stop_channel(char channel) { char tmp; outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x103, 0x80); tmp = inportb(GUS_base_port + 0x105); outportb(GUS_base_port + 0x103, 0x00); outportb(GUS_base_port + 0x105, (tmp & 0xDF) | 3); gus_delay(); outportb(GUS_base_port + 0x103, 0x00); outportb(GUS_base_port + 0x105, (tmp & 0xDF) | 3); } unsigned long gus_channel_position(char channel) { short temp0, temp1; outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x103, 0x8A); temp0 = inportw(GUS_base_port + 0x104); outportb(GUS_base_port + 0x103, 0x8B); temp1 = inportw(GUS_base_port + 0x104); return((temp0 << 7) + (temp1 >> 8)); } void gus_channel_control(char channel, unsigned char val) { outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x102, channel); outportb(GUS_base_port + 0x103, 0x00); outportb(GUS_base_port + 0x105, val); } /* ======================================================================== */ /* GUS memory procedures */ /* ------------------------------------------------------------------------ */ /* ======================================================================== */ /* Allocate GUS RAM in 4K chunks */ gus_ptr gus_allocmem(short chunks) { gus_ptr return_ptr; short block_found = -1; short gus_start = -1; short count; while(block_found == -1){ gus_start++; if(GUS_memory_map[gus_start] == 0){ /* Scan all blocks from start to see if any are used */ for(count = 0; count < chunks; count++){ gus_start++; /* If this block in not used then set the flag */ if(GUS_memory_map[gus_start] == 0) block_found = 0; /* Else, we've ran into a little trouble so reset flag and break */ else{ block_found = -1; break; } } } /* At the end of memory :( */ else if (GUS_memory_map[gus_start] == 2){ return_ptr.start = -1; return_ptr.end = -1; return(return_ptr); } } /* Setup the return pointer */ return_ptr.start = (long)(gus_start * 4096); return_ptr.end = (long)((gus_start * 4096) + (chunks * 4096)); /* Knock the memory allocated */ for( count = gus_start; count < (gus_start + chunks); count++) GUS_memory_map[count] = 1; /* Return the new pointer */ return(return_ptr); } /* ======================================================================== */ /* GUS misc functions */ /* ------------------------------------------------------------------------ */ /* ======================================================================== */ /* Perform the 8 bit fix on a sound in SYSTEM RAM */ void gus_8bit(long length, unsigned char *wave_8bit) { long counter; unsigned char temp; for(counter = 0; counter < length; counter++){ /* Get the temp */ temp = wave_8bit[counter]; /* Shove the new value back into RAM, XOR by 127 */ wave_8bit[counter] = temp ^ 127; } } Well. That should work :) IF you've got any suggestions, complements (no critisims thanks :) I'ld love to hear them :) -- O Nicholas Lynch -|- br516 AT freenet DOT carleton DOT ca / \