www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1996/05/27/00:42:48

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 <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 -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019