Mail Archives: djgpp/1996/05/27/00:42:48
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 <DOS.H>
#include <STDLIB.H>
#include <PC.H>
#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
/ \
- Raw text -