diff --git a/.cvsignore b/.cvsignore deleted file mode 100644 index e69de29..0000000 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f52f7d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +rott-1.0.tar.gz diff --git a/Makefile b/Makefile deleted file mode 100644 index 31a7a71..0000000 --- a/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Makefile for source rpm: rott -# $Id$ -NAME := rott -SPECFILE = $(firstword $(wildcard *.spec)) - -define find-makefile-common -for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done -endef - -MAKEFILE_COMMON := $(shell $(find-makefile-common)) - -ifeq ($(MAKEFILE_COMMON),) -# attept a checkout -define checkout-makefile-common -test -f CVS/Root && { cvs -Q -d $$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2 -endef - -MAKEFILE_COMMON := $(shell $(checkout-makefile-common)) -endif - -include $(MAKEFILE_COMMON) diff --git a/rott-1.0-64bit.patch b/rott-1.0-64bit.patch new file mode 100644 index 0000000..a3cd1e7 --- /dev/null +++ b/rott-1.0-64bit.patch @@ -0,0 +1,911 @@ +diff -ur rott-1.0.orig/rott/audiolib/dpmi.h rott-1.0/rott/audiolib/dpmi.h +--- rott-1.0.orig/rott/audiolib/dpmi.h 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/audiolib/dpmi.h 2007-05-06 22:03:17.000000000 +0200 +@@ -62,8 +62,8 @@ + unsigned long DPMI_GetRealModeVector( int num ); + void DPMI_SetRealModeVector( int num, unsigned long vector ); + int DPMI_CallRealModeFunction( dpmi_regs *callregs ); +-int DPMI_GetDOSMemory( void **ptr, int *descriptor, unsigned length ); +-int DPMI_FreeDOSMemory( int descriptor ); ++int DPMI_GetDOSMemory( void **ptr, long *descriptor, unsigned length ); ++int DPMI_FreeDOSMemory( long descriptor ); + int DPMI_LockMemory( void *address, unsigned length ); + int DPMI_LockMemoryRegion( void *start, void *end ); + int DPMI_UnlockMemory( void *address, unsigned length ); +diff -ur rott-1.0.orig/rott/audiolib/multivoc.c rott-1.0/rott/audiolib/multivoc.c +--- rott-1.0.orig/rott/audiolib/multivoc.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/audiolib/multivoc.c 2007-05-06 22:03:17.000000000 +0200 +@@ -107,7 +107,7 @@ + + static int MV_TotalMemory; + +-static int MV_BufferDescriptor; ++static long MV_BufferDescriptor; + static int MV_BufferEmpty[ NumberOfBuffers ]; + char *MV_MixBuffer[ NumberOfBuffers + 1 ]; + +diff -ur rott-1.0.orig/rott/audiolib/nodpmi.c rott-1.0/rott/audiolib/nodpmi.c +--- rott-1.0.orig/rott/audiolib/nodpmi.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/audiolib/nodpmi.c 2007-05-06 22:03:17.000000000 +0200 +@@ -160,18 +160,18 @@ + return( status ); + } + +-int DPMI_GetDOSMemory( void **ptr, int *descriptor, unsigned length ) ++int DPMI_GetDOSMemory( void **ptr, long *descriptor, unsigned length ) + { + /* Lovely... */ + + *ptr = (void *)malloc(length); + +- *descriptor = (int) *ptr; ++ *descriptor = (long) *ptr; + + return (descriptor == 0) ? DPMI_Error : DPMI_Ok; + } + +-int DPMI_FreeDOSMemory( int descriptor ) ++int DPMI_FreeDOSMemory( long descriptor ) + { + free((void *)descriptor); + +diff -ur rott-1.0.orig/rott/modexlib.c rott-1.0/rott/modexlib.c +--- rott-1.0.orig/rott/modexlib.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/modexlib.c 2007-05-06 22:03:17.000000000 +0200 +@@ -45,12 +45,12 @@ + + int linewidth; + int ylookup[MAXSCREENHEIGHT]; +-int page1start; +-int page2start; +-int page3start; ++byte *page1start; ++byte *page2start; ++byte *page3start; + int screensize; +-unsigned bufferofs; +-unsigned displayofs; ++byte *bufferofs; ++byte *displayofs; + boolean graphicsmode=false; + + #ifdef DOS +@@ -248,7 +248,7 @@ + = + ======================= + */ +-void VL_CopyBufferToAll ( unsigned buffer ) ++void VL_CopyBufferToAll ( byte *buffer ) + { + int plane; + +@@ -506,9 +506,9 @@ + + screensize=MAXSCREENHEIGHT*MAXSCREENWIDTH; + +- page1start=(int)sdl_surface->pixels; +- page2start=(int)sdl_surface->pixels; +- page3start=(int)sdl_surface->pixels; ++ page1start=sdl_surface->pixels; ++ page2start=sdl_surface->pixels; ++ page3start=sdl_surface->pixels; + displayofs = page1start; + bufferofs = page2start; + XFlipPage (); +@@ -570,7 +570,7 @@ + = + ======================= + */ +-void VL_CopyBufferToAll ( unsigned buffer ) ++void VL_CopyBufferToAll ( byte *buffer ) + { + #ifdef DOS + int plane; +@@ -611,7 +611,7 @@ + ================= + */ + +-void VL_ClearBuffer (unsigned buf, byte color) ++void VL_ClearBuffer (byte *buf, byte color) + { + #ifdef DOS + VGAMAPMASK(15); +diff -ur rott-1.0.orig/rott/modexlib.h rott-1.0/rott/modexlib.h +--- rott-1.0.orig/rott/modexlib.h 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/modexlib.h 2007-05-06 22:03:17.000000000 +0200 +@@ -105,23 +105,23 @@ + + extern int ylookup[MAXSCREENHEIGHT]; // Table of row offsets + extern int linewidth; +-extern int page1start; +-extern int page2start; +-extern int page3start; ++extern byte *page1start; ++extern byte *page2start; ++extern byte *page3start; + extern int screensize; +-extern unsigned bufferofs; +-extern unsigned displayofs; ++extern byte *bufferofs; ++extern byte *displayofs; + extern boolean graphicsmode; + + + void GraphicsMode ( void ); + void SetTextMode ( void ); + void VL_SetVGAPlaneMode ( void ); +-void VL_ClearBuffer (unsigned buf, byte color); ++void VL_ClearBuffer (byte *buf, byte color); + void VL_ClearVideo (byte color); + void VL_DePlaneVGA (void); + void VL_CopyDisplayToHidden ( void ); +-void VL_CopyBufferToAll ( unsigned buffer ); ++void VL_CopyBufferToAll ( byte *buffer ); + void VL_CopyPlanarPage ( byte * src, byte * dest ); + void VL_CopyPlanarPageToMemory ( byte * src, byte * dest ); + void XFlipPage ( void ); +diff -ur rott-1.0.orig/rott/rt_actor.c rott-1.0/rott/rt_actor.c +--- rott-1.0.orig/rott/rt_actor.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/rt_actor.c 2007-05-06 22:03:17.000000000 +0200 +@@ -88,7 +88,7 @@ + + byte deathshapeoffset[8] = {0,7,7,8,8,9,8,7}; + +-unsigned MAXFUNCTION,MINFUNCTION,MAXSTATE,MINSTATE; ++unsigned long MAXFUNCTION,MINFUNCTION,MAXSTATE,MINSTATE; + + objtype *PLAYER0MISSILE; + objtype *SCREENEYE; +@@ -992,16 +992,16 @@ + void FindAddresses(void) + { + int i; +- unsigned tstate,tfunct; ++ unsigned long tstate,tfunct; + +- MINFUNCTION = 0xffffffff; ++ MINFUNCTION = -1l; + MAXFUNCTION = 0x00000000; +- MINSTATE = 0xffffffff; ++ MINSTATE = -1l; + MAXSTATE = 0x00000000; + + for(i=0;ithink); ++ tfunct = (unsigned long)(statetable[i]->think); + if (tfunct < MINFUNCTION) + MINFUNCTION = tfunct; + +@@ -1021,10 +1021,10 @@ + + void CheckBounds(objtype*ob) + { +- unsigned tstate,tfunct; ++ unsigned long tstate,tfunct; + +- tstate = (unsigned)(ob->state); +- tfunct = (unsigned)(ob->state->think); ++ tstate = (unsigned long)(ob->state); ++ tfunct = (unsigned long)(ob->state->think); + + if ((tfunct < MINFUNCTION) || (tfunct > MAXFUNCTION) || + (tstate < MINSTATE) || (tstate > MAXSTATE)) +@@ -10077,7 +10077,7 @@ + if (ob->hitpoints <= 0) + {objtype*column = (objtype*)(ob->whatever); + +- EnableObject((int)column); ++ EnableObject((long)column); + ob->whatever = NULL; + + KillActor(ob); +@@ -10442,7 +10442,7 @@ + { + objtype*column = (objtype*)(ob->whatever); + +- EnableObject((int)column); ++ EnableObject((long)column); + ob->whatever = NULL; + + KillActor(ob); +@@ -10663,7 +10663,7 @@ + {touchplatetype *tplate; + + for(tplate=touchplate[tempstat->linked_to];tplate;tplate = tplate->nextaction) +- if (tplate->whichobj == (int)(tempstat)) ++ if (tplate->whichobj == (long)(tempstat)) + RemoveTouchplateAction(tplate,tempstat->linked_to); + } + +@@ -10879,7 +10879,7 @@ + (tempstat->itemnumber == stat_tntcrate) + ) + { +- tempstat->linked_to = (int)(LASTSTAT); ++ tempstat->linked_to = (long)(LASTSTAT); + tempstat->flags |= FL_RESPAWN; + } + +@@ -10900,7 +10900,7 @@ + + + +-void EnableObject(int object) ++void EnableObject(long object) + { + objtype* ob; + int i,gasicon; +@@ -10951,7 +10951,7 @@ + } + } + +-void DisableObject(int object) ++void DisableObject(long object) + {objtype*ob; + + ob = (objtype*)object; +diff -ur rott-1.0.orig/rott/rt_actor.h rott-1.0/rott/rt_actor.h +--- rott-1.0.orig/rott/rt_actor.h 2007-05-06 22:30:12.000000000 +0200 ++++ rott-1.0/rott/rt_actor.h 2007-05-06 22:03:17.000000000 +0200 +@@ -358,8 +358,8 @@ + void A_Drain(objtype*ob); + void T_Explosion(objtype*ob); + void T_MoveColumn(objtype*); +-void EnableObject(int object); +-void DisableObject(int); ++void EnableObject(long object); ++void DisableObject(long object); + + void T_Collide(objtype*); + void Collision(objtype*ob,objtype *attacker,int hitmomentumx,int hitmomentumy); +diff -ur rott-1.0.orig/rott/rt_def.h rott-1.0/rott/rt_def.h +--- rott-1.0.orig/rott/rt_def.h 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/rt_def.h 2007-05-06 22:03:17.000000000 +0200 +@@ -300,7 +300,7 @@ + typedef unsigned char byte; + typedef unsigned short int word; + typedef unsigned long longword; +-typedef long fixed; ++typedef int fixed; + + + ////////////////////////////////////////////////////////////////////////// +diff -ur rott-1.0.orig/rott/rt_door.c rott-1.0/rott/rt_door.c +--- rott-1.0.orig/rott/rt_door.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/rt_door.c 2007-05-06 22:03:17.000000000 +0200 +@@ -94,7 +94,7 @@ + + // Local Variables + +-static void (*touchactions[NUMTOUCHPLATEACTIONS])(int) = ++static void (*touchactions[NUMTOUCHPLATEACTIONS])(long) = + {ActivatePushWall, + ActivateMoveWall, + LinkedOpenDoor, +@@ -315,7 +315,7 @@ + } + + +-int GetIndexForAction(void (*action)(int)) ++int GetIndexForAction(void (*action)(long)) + {int i; + + for(i=0;icomplete = dummy.complete; + + if (dummy.whichobj & FL_TACT) +- temp->whichobj = (int)(objlist[dummy.whichobj & ~FL_TACT]); ++ temp->whichobj = (long)(objlist[dummy.whichobj & ~FL_TACT]); + + else if (dummy.whichobj & FL_TSTAT) +- temp->whichobj = (int)(GetStatForIndex(dummy.whichobj & ~FL_TSTAT)); ++ temp->whichobj = (long)(GetStatForIndex(dummy.whichobj & ~FL_TSTAT)); + else + temp->whichobj = dummy.whichobj; + if (dummy.actionindex != -1) +@@ -613,7 +613,7 @@ + + + +-void Link_To_Touchplate(word touchlocx, word touchlocy, void (*maction)(int), void (*swapaction)(int), int wobj, int delaytime) ++void Link_To_Touchplate(word touchlocx, word touchlocy, void (*maction)(long), void (*swapaction)(long), long wobj, int delaytime) + {touchplatetype *temp; + int index; + +@@ -640,7 +640,7 @@ + + + +-void ClockLink (void (*saction)(int), void (*eaction)(int), int wobj,int whichclock) ++void ClockLink (void (*saction)(long), void (*eaction)(long), long wobj,int whichclock) + {touchplatetype*temp; + + +@@ -731,7 +731,7 @@ + touchplatetype *temp; + int i,touchcomplete,j; + int playeron; +- void (*tempact)(int); ++ void (*tempact)(long); + boolean wallmessage,doormessage,columnmessage; + + for(i=0;i>2)); ++ olddest = ylookup[ypos] + (xpos>>2); + #else +- olddest = (byte *)(ylookup[ypos] + xpos); ++ olddest = ylookup[ypos] + xpos; + #endif + + for (planes = 0; planes < 4; planes++) +@@ -1637,8 +1637,8 @@ + + void DrawColoredMPPic (int xpos, int ypos, int width, int height, int heightmod, byte *src, boolean bufferofsonly, int color) + { +- byte *olddest; +- byte *dest; ++ int olddest; ++ int dest; + int x; + int y; + int planes; +@@ -1651,9 +1651,9 @@ + mask = 1 << (xpos&3); + + #ifdef DOS +- olddest = (byte *)(ylookup[ypos] + (xpos>>2)); ++ olddest = ylookup[ypos] + (xpos>>2); + #else +- olddest = (byte *)(ylookup[ypos] + xpos); ++ olddest = ylookup[ypos] + xpos; + #endif + + for (planes = 0; planes < 4; planes++) +@@ -1822,8 +1822,8 @@ + + void DrawPPic (int xpos, int ypos, int width, int height, byte *src, int num, boolean up, boolean bufferofsonly) + { +- byte *olddest; +- byte *dest; ++ int olddest; ++ int dest; + int x; + int y; + int planes; +@@ -1847,9 +1847,9 @@ + mask = 1; + + #ifdef DOS +- olddest = (byte *)(ylookup[ypos] + (xpos>>2)); ++ olddest = ylookup[ypos] + (xpos>>2); + #else +- olddest = (byte *)(ylookup[ypos] + xpos); ++ olddest = ylookup[ypos] + xpos; + #endif + + for (planes = 0; planes < 4; planes++) +@@ -2254,7 +2254,7 @@ + void DrawPause (void) + { + pic_t *p; +- int bufftemp = bufferofs; ++ byte *bufftemp = bufferofs; + + bufferofs -= screenofs; + +@@ -2610,15 +2610,16 @@ + + void GM_MemToScreen (byte *source, int width, int height, int x, int y) + { +- byte *dest, *dest1, *dest2, *dest3, mask; ++ int dest; ++ byte *dest1, *dest2, *dest3, mask; + byte *screen1, *screen2, *screen3; + int plane; + int w; + + #ifdef DOS +- dest = (byte *)(ylookup[y]+(x>>2)); ++ dest = ylookup[y]+(x>>2); + #else +- dest = (byte *)(ylookup[y]+x); ++ dest = ylookup[y]+x; + #endif + mask = 1 << (x&3); + +@@ -4450,7 +4451,7 @@ + { + if ((SaveTime+1) < GetTicCount()) + { +- int temp = bufferofs; ++ byte *temp = bufferofs; + + bufferofs = displayofs; + SaveTime = GetTicCount(); +diff -ur rott-1.0.orig/rott/rt_main.c rott-1.0/rott/rt_main.c +--- rott-1.0.orig/rott/rt_main.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/rt_main.c 2007-05-06 22:13:55.000000000 +0200 +@@ -962,7 +962,7 @@ + while ((!LastScan) && (!IN_GetMouseButtons())) + { + int i; +- unsigned tempbuf; ++ byte *tempbuf; + MenuFadeOut(); + ClearGraphicsScreen(); + SetPalette(&dimpal[0]); +diff -ur rott-1.0.orig/rott/rt_stat.c rott-1.0/rott/rt_stat.c +--- rott-1.0.orig/rott/rt_stat.c 2002-12-24 05:34:15.000000000 +0100 ++++ rott-1.0/rott/rt_stat.c 2007-05-06 22:03:17.000000000 +0200 +@@ -397,7 +397,7 @@ + } + + +-void ActivateLight(int light) ++void ActivateLight(long light) + {statobj_t*tstat; + + tstat = (statobj_t*)light; +@@ -409,7 +409,7 @@ + } + + +-void DeactivateLight(int light) ++void DeactivateLight(long light) + {statobj_t*tstat; + + tstat = (statobj_t*)light; +diff -ur rott-1.0.orig/rott/rt_stat.h rott-1.0/rott/rt_stat.h +--- rott-1.0.orig/rott/rt_stat.h 2002-12-20 21:15:28.000000000 +0100 ++++ rott-1.0/rott/rt_stat.h 2007-05-06 22:03:17.000000000 +0200 +@@ -151,7 +151,7 @@ + short int whichstat; + short int areanumber; + +- int linked_to; ++ long linked_to; + struct statstruct *statnext; + struct statstruct *statprev; + struct statstruct *nextactive; +@@ -167,8 +167,7 @@ + int spawnz; + struct respstruct *next; + struct respstruct *prev; +- int linked_to; +- ++ long linked_to; + } respawn_t; + + +@@ -205,8 +204,8 @@ + void Set_NewZ_to_MapValue(fixed*,int,const char*,int,int); + void RemoveFromFreeStaticList(statobj_t*); + void CheckCriticalStatics(void); +-void ActivateLight(int); +-void DeactivateLight(int); ++void ActivateLight(long); ++void DeactivateLight(long); + void TurnOnLight(int,int); + void TurnOffLight(int,int); + void MakeStatActive(statobj_t*); +diff -ur rott-1.0.orig/rott/rt_ted.c rott-1.0/rott/rt_ted.c +--- rott-1.0.orig/rott/rt_ted.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/rt_ted.c 2007-05-06 22:14:56.000000000 +0200 +@@ -1139,7 +1139,7 @@ + int lastmem=0; + int lastcache=0; + int ticdelay; +- unsigned tempbuf; ++ byte *tempbuf; + + #if defined(PLATFORM_MACOSX) || defined(__sparc__) + #warning "Precaching is disabled. Fix." +@@ -1329,7 +1329,7 @@ + { + int filehandle; + char RTLSignature[ 4 ]; +- unsigned long RTLVersion; ++ unsigned int RTLVersion; + + filehandle = SafeOpenRead( filename ); + +@@ -1395,12 +1395,12 @@ + SEEK_SET ); + SafeRead( filehandle, &RTLMap, sizeof( RTLMap ) ); + +- SwapIntelLong((long *)&RTLMap.used); +- SwapIntelLong((long *)&RTLMap.CRC); +- SwapIntelLong((long *)&RTLMap.RLEWtag); +- SwapIntelLong((long *)&RTLMap.MapSpecials); +- SwapIntelLongArray((long *)&RTLMap.planestart, NUMPLANES); +- SwapIntelLongArray((long *)&RTLMap.planelength, NUMPLANES); ++ SwapIntelLong((int *)&RTLMap.used); ++ SwapIntelLong((int *)&RTLMap.CRC); ++ SwapIntelLong((int *)&RTLMap.RLEWtag); ++ SwapIntelLong((int *)&RTLMap.MapSpecials); ++ SwapIntelLongArray((int *)&RTLMap.planestart, NUMPLANES); ++ SwapIntelLongArray((int *)&RTLMap.planelength, NUMPLANES); + + if ( !RTLMap.used ) + { +@@ -3568,7 +3568,7 @@ + + + void LinkActor (objtype *ob,int tilex,int tiley, +- void (*action)(int),void (*swapaction)(int) ++ void (*action)(long),void (*swapaction)(long) + ) + { + word touchx,touchy; +@@ -3585,7 +3585,7 @@ + if ((clockx == tilex) && (clocky == tiley)) + { + clocklinked = 1; +- ClockLink(EnableObject,DisableObject,(int)ob,k); ++ ClockLink(EnableObject,DisableObject,(long)ob,k); + } + } + +@@ -3612,9 +3612,9 @@ + + + if (tswitch && (tswitch->flags & FL_ON)) +- Link_To_Touchplate(touchx,touchy,swapaction,action,(int)ob,0); ++ Link_To_Touchplate(touchx,touchy,swapaction,action,(long)ob,0); + else +- Link_To_Touchplate(touchx,touchy,action,swapaction,(int)ob,0); ++ Link_To_Touchplate(touchx,touchy,action,swapaction,(long)ob,0); + if (ob->obclass == gasgrateobj) + { + ob->temp1 = touchx; +@@ -3645,7 +3645,7 @@ + { + int i,j,linked; + word *map,tile; +- void (*action)(int),(*swapaction)(int); ++ void (*action)(long),(*swapaction)(long); + + + map = mapplanes[1]; +@@ -4051,7 +4051,7 @@ + if (!(tswitch->flags & FL_ON)) + {sprites[i][j]->shapenum --; + if (touchindices[touchx][touchy]) +- {Link_To_Touchplate(touchx,touchy,ActivateLight,DeactivateLight,(int)(sprites[i][j]),0); ++ {Link_To_Touchplate(touchx,touchy,ActivateLight,DeactivateLight,(long)(sprites[i][j]),0); + sprites[i][j]->linked_to = touchindices[touchx][touchy]-1; + } + else +@@ -4059,7 +4059,7 @@ + } + else + {if (touchindices[touchx][touchy]) +- {Link_To_Touchplate(touchx,touchy,DeactivateLight,ActivateLight,(int)(sprites[i][j]),0); ++ {Link_To_Touchplate(touchx,touchy,DeactivateLight,ActivateLight,(long)(sprites[i][j]),0); + sprites[i][j]->linked_to = touchindices[touchx][touchy]-1; + } + else +@@ -4069,7 +4069,7 @@ + } + else + {if (touchindices[touchx][touchy]) +- {Link_To_Touchplate(touchx,touchy,DeactivateLight,ActivateLight,(int)(sprites[i][j]),0); ++ {Link_To_Touchplate(touchx,touchy,DeactivateLight,ActivateLight,(long)(sprites[i][j]),0); + sprites[i][j]->linked_to = touchindices[touchx][touchy]-1; + } + else +diff -ur rott-1.0.orig/rott/rt_util.c rott-1.0/rott/rt_util.c +--- rott-1.0.orig/rott/rt_util.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/rt_util.c 2007-05-06 22:03:17.000000000 +0200 +@@ -1171,7 +1171,7 @@ + } + + +-long SwapLong (long l) ++int SwapLong (int l) + { + byte b1,b2,b3,b4; + +@@ -1180,10 +1180,10 @@ + b3 = (l>>16)&255; + b4 = (l>>24)&255; + +- return ((long)b1<<24) + ((long)b2<<16) + ((long)b3<<8) + b4; ++ return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; + } + +-long KeepLong (long l) ++int KeepLong (int l) + { + return l; + } +@@ -1194,7 +1194,7 @@ + #undef SwapShort + #undef SwapLong + +-void SwapIntelLong(long *l) ++void SwapIntelLong(int *l) + { + *l = IntelLong(*l); + } +@@ -1204,7 +1204,7 @@ + *s = IntelShort(*s); + } + +-void SwapIntelLongArray(long *l, int num) ++void SwapIntelLongArray(int *l, int num) + { + while (num--) { + SwapIntelLong(l); +diff -ur rott-1.0.orig/rott/rt_util.h rott-1.0/rott/rt_util.h +--- rott-1.0.orig/rott/rt_util.h 2002-12-25 09:00:13.000000000 +0100 ++++ rott-1.0/rott/rt_util.h 2007-05-06 22:03:17.000000000 +0200 +@@ -67,11 +67,11 @@ + long ParseNum (char *str); + short MotoShort (short l); + short IntelShort (short l); +-long MotoLong (long l); +-long IntelLong (long l); +-void SwapIntelLong (long *l); ++int MotoLong (int l); ++int IntelLong (int l); ++void SwapIntelLong (int *l); + void SwapIntelShort(short *s); +-void SwapIntelLongArray (long *l, int num); ++void SwapIntelLongArray (int *l, int num); + void SwapIntelShortArray (short *s, int num); + int US_CheckParm (char *parm, char **strings); + byte BestColor (int r, int g, int b, byte *palette); +diff -ur rott-1.0.orig/rott/rt_vid.c rott-1.0/rott/rt_vid.c +--- rott-1.0.orig/rott/rt_vid.c 2002-12-24 08:29:52.000000000 +0100 ++++ rott-1.0/rott/rt_vid.c 2007-05-06 22:15:21.000000000 +0200 +@@ -968,7 +968,7 @@ + + void SwitchPalette (byte * newpal, int steps) + { +- int temp; ++ byte *temp; + + VL_FadeOut(0,255,0,0,0,steps>>1); + +diff -ur rott-1.0.orig/rott/rt_view.c rott-1.0/rott/rt_view.c +--- rott-1.0.orig/rott/rt_view.c 2003-01-01 10:24:39.000000000 +0100 ++++ rott-1.0/rott/rt_view.c 2007-05-06 22:03:17.000000000 +0200 +@@ -220,7 +220,7 @@ + { + int i; + int frac; +- long intang; ++ int intang; + byte * table; + byte * ptr; + int length; +@@ -246,7 +246,7 @@ + // + + memcpy(&length,ptr,sizeof(int)); +- SwapIntelLong((long *)&length); ++ SwapIntelLong(&length); + ptr+=sizeof(int); + pangle=SafeMalloc(length*sizeof(int)); + memcpy(pangle,ptr,length*sizeof(int)); +@@ -447,7 +447,7 @@ + lump = W_GetNumForName("colormap"); + length = W_LumpLength (lump) + 255; + colormap = SafeMalloc (length); +- colormap = (byte *)( ((int)colormap + 255)&~0xff); ++ colormap = (byte *)( ((long)colormap + 255)&~0xff); + W_ReadLump (lump,colormap); + + // Fix fire colors in colormap +@@ -461,7 +461,7 @@ + lump = W_GetNumForName("specmaps"); + length = W_LumpLength (lump+1) + 255; + redmap = SafeMalloc (length); +- redmap = (byte *)( ((int)redmap + 255)&~0xff); ++ redmap = (byte *)( ((long)redmap + 255)&~0xff); + W_ReadLump (lump+1,redmap); + greenmap = redmap+(16*256); + +@@ -474,7 +474,7 @@ + { + length = W_LumpLength (lump+i) + 255; + playermaps[i] = SafeMalloc (length); +- playermaps[i] = (byte *)( ((int)playermaps[i] + 255)&~0xff); ++ playermaps[i] = (byte *)( ((long)playermaps[i] + 255)&~0xff); + W_ReadLump (lump+i,playermaps[i]); + } + } +diff -ur rott-1.0.orig/rott/watcom.c rott-1.0/rott/watcom.c +--- rott-1.0.orig/rott/watcom.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/watcom.c 2007-05-06 22:03:17.000000000 +0200 +@@ -24,8 +24,8 @@ + + fixed FixedDiv2(fixed a, fixed b) + { +- __int64 x = (signed long)a; +- __int64 y = (signed long)b; ++ __int64 x = (signed int)a; ++ __int64 y = (signed int)b; + __int64 z = x * 65536 / y; + + return (z) & 0xffffffff; +diff -ur rott-1.0.orig/rott/rt_main.h rott-1.0/rott/rt_main.h +--- rott-1.0.orig/rott/rt_main.h 2002-12-20 22:18:39.000000000 +0100 ++++ rott-1.0/rott/rt_main.h 2007-05-10 11:49:11.000000000 +0200 +@@ -76,8 +76,8 @@ + // Variable for which version of the game can be played + version_type Product; + +- long TimeCount; +- long frame; ++ int TimeCount; ++ int frame; + int secrettotal,treasuretotal,killtotal; + int secretcount,treasurecount,killcount; + int supertotal,healthtotal,missiletotal; +@@ -88,7 +88,7 @@ + int difficulty; + int violence; + int mapon; +- long score; ++ int score; + int episode; + int battlemode; + int battleoption; diff --git a/rott-1.0-compile.patch b/rott-1.0-compile.patch new file mode 100644 index 0000000..9894b15 --- /dev/null +++ b/rott-1.0-compile.patch @@ -0,0 +1,39 @@ +diff -ur rott-1.0/rott/Makefile trunk/rott/Makefile +--- rott-1.0/rott/Makefile 2007-05-05 20:44:31.000000000 +0200 ++++ trunk/rott/Makefile 2007-05-05 15:47:26.000000000 +0200 +@@ -47,7 +47,7 @@ + + + CC = gcc +-CFLAGS = -g $(SDL_CFLAGS) -DUSE_SDL=1 -DPLATFORM_UNIX=1 -W -Wall -Wno-unused $(EXTRACFLAGS) ++CFLAGS = -g $(SDL_CFLAGS) -DUSE_SDL=1 -DPLATFORM_UNIX=1 -W -Wall -Wno-unused -Wno-pointer-sign $(EXTRACFLAGS) + LDLIBS = $(SDL_LDFLAGS) -lSDL -lSDL_mixer $(EXTRALDFLAGS) -Wl,-E + + all: rott +diff -ur rott-1.0/rott/rt_actor.h trunk/rott/rt_actor.h +--- rott-1.0/rott/rt_actor.h 2007-05-05 20:44:31.000000000 +0200 ++++ trunk/rott/rt_actor.h 2007-05-05 15:46:36.000000000 +0200 +@@ -315,7 +315,7 @@ + extern void *actorat[MAPSIZE][MAPSIZE]; + extern int angletodir[ANGLES]; + extern _2Dpoint SNAKEPATH[512]; +-extern int STOPSPEED; ++/* extern int STOPSPEED; */ + extern int FRICTION; + + extern int objcount; +diff -ur rott-1.0/rott/rt_in.h trunk/rott/rt_in.h +--- rott-1.0/rott/rt_in.h 2007-05-05 20:44:31.000000000 +0200 ++++ trunk/rott/rt_in.h 2007-05-05 15:20:49.000000000 +0200 +@@ -147,9 +147,9 @@ + + extern boolean Paused; + extern volatile int LastScan; +-extern KeyboardDef KbdDefs; ++/* extern KeyboardDef KbdDefs; + extern JoystickDef JoyDefs[]; +-extern ControlType Controls[MAXPLAYERS]; ++extern ControlType Controls[MAXPLAYERS]; */ + + extern boolean SpaceBallPresent; + extern boolean CybermanPresent; diff --git a/rott-1.0-cvs-fixes.patch b/rott-1.0-cvs-fixes.patch new file mode 100644 index 0000000..b61536e --- /dev/null +++ b/rott-1.0-cvs-fixes.patch @@ -0,0 +1,32124 @@ +diff -urN rott-1.0/rott/Makefile trunk/rott/Makefile +--- rott-1.0/rott/Makefile 2003-01-01 10:23:03.000000000 +0100 ++++ trunk/rott/Makefile 2007-05-05 20:44:31.000000000 +0200 +@@ -52,6 +52,9 @@ + + all: rott + ++audiolib/audiolib.a: ++ $(MAKE) -C audiolib CC="$(CC)" CFLAGS="$(CFLAGS)" LDLIBS="$(LDLIBS)" ++ + rott: \ + cin_actr.o \ + cin_efct.o \ +@@ -61,7 +64,6 @@ + cin_util.o \ + dosutil.o \ + engine.o \ +- fx_man.o \ + isr.o \ + modexlib.o \ + rt_actor.o \ +@@ -101,11 +103,15 @@ + w_wad.o \ + watcom.o \ + z_zone.o \ +- byteordr.o ++ byteordr.o \ ++ dukemusc.o \ ++ audiolib/audiolib.a + $(CC) $^ $(LDLIBS) -o $@ + + clean: +- rm -rf *.o ++ $(MAKE) -C audiolib clean ++ rm -rf rott *.o + + distclean: clean ++ $(MAKE) -C audiolib distclean + rm -rf *~ +diff -urN rott-1.0/rott/_rt_util.h trunk/rott/_rt_util.h +--- rott-1.0/rott/_rt_util.h 2002-12-24 07:46:41.000000000 +0100 ++++ trunk/rott/_rt_util.h 2007-05-05 20:44:31.000000000 +0200 +@@ -20,10 +20,12 @@ + #ifndef _rt_util_private + #define _rt_util_private + ++#ifdef DOS + #define PEL_WRITE_ADR 0x3c8 + #define PEL_READ_ADR 0x3c7 + #define PEL_DATA 0x3c9 + #define PEL_MASK 0x3c6 ++#endif + + #define ERRORROW 2 + #define ERRORCOL 11 +Binary files rott-1.0/rott/audio_wf.lib and trunk/rott/audio_wf.lib differ +diff -urN rott-1.0/rott/audiolib/Makefile trunk/rott/audiolib/Makefile +--- rott-1.0/rott/audiolib/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/Makefile 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,22 @@ ++CC=gcc ++AR=ar ++RANLIB=ranlib ++CFLAGS=-g -O2 ++LDLIBS= ++ ++CFLAGS += $(shell sdl-config --cflags) ++LDLIBS += $(shell sdl-config --libs) ++ ++OBJ=fx_man.o dsl.o ll_man.o multivoc.o mv_mix.o mvreverb.o nodpmi.o \ ++ pitch.o user.o usrhooks.o ++ ++audiolib.a: $(OBJ) ++ rm -rf $@ ++ $(AR) rc $@ $^ ++ $(RANLIB) $@ ++ ++clean: ++ rm -rf audiolib.a *.o ++ ++distclean: clean ++ rm -rf *~ +diff -urN rott-1.0/rott/audiolib/_al_midi.h trunk/rott/audiolib/_al_midi.h +--- rott-1.0/rott/audiolib/_al_midi.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/_al_midi.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,174 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++#ifndef ___AL_MIDI_H ++#define ___AL_MIDI_H ++ ++#define NO_ADLIB_DETECTION "NOAL" ++ ++#define STEREO_DETUNE 5 ++ ++#define lobyte( num ) ( ( unsigned )*( ( char * )&( num ) ) ) ++#define hibyte( num ) ( ( unsigned )*( ( ( char * )&( num ) ) + 1 ) ) ++ ++#define AL_VoiceNotFound -1 ++ ++#define alFreqH 0xb0 ++#define alEffects 0xbd ++ ++/* Number of slots for the voices on the chip */ ++#define NumChipSlots 18 ++ ++#define NUM_VOICES 9 ++#define NUM_CHANNELS 16 ++ ++#define NOTE_ON 0x2000 /* Used to turn note on or toggle note */ ++#define NOTE_OFF 0x0000 ++ ++#define MAX_VELOCITY 0x7f ++#define MAX_OCTAVE 7 ++#define MAX_NOTE ( MAX_OCTAVE * 12 + 11 ) ++#define FINETUNE_MAX 31 ++#define FINETUNE_RANGE ( FINETUNE_MAX + 1 ) ++ ++#define PITCHBEND_CENTER 1638400 ++ ++#define note_off 0x80 ++#define note_on 0x90 ++#define poly_aftertouch 0xa0 ++#define control_change 0xb0 ++#define program_chng 0xc0 ++#define channel_aftertouch 0xd0 ++#define pitch_wheel 0xe0 ++ ++#define MIDI_VOLUME 7 ++#define MIDI_PAN 10 ++#define MIDI_DETUNE 94 ++#define MIDI_ALL_NOTES_OFF 0x7B ++#define MIDI_RESET_ALL_CONTROLLERS 0x79 ++#define MIDI_RPN_MSB 100 ++#define MIDI_RPN_LSB 101 ++#define MIDI_DATAENTRY_MSB 6 ++#define MIDI_DATAENTRY_LSB 38 ++#define MIDI_PITCHBEND_RPN 0 ++ ++enum cromatic_scale ++ { ++ C = 0x157, ++ C_SHARP = 0x16B, ++ D_FLAT = 0x16B, ++ D = 0x181, ++ D_SHARP = 0x198, ++ E_FLAT = 0x198, ++ E = 0x1B0, ++ F_FLAT = 0x1B0, ++ E_SHARP = 0x1CA, ++ F = 0x1CA, ++ F_SHARP = 0x1E5, ++ G_FLAT = 0x1E5, ++ G = 0x202, ++ G_SHARP = 0x220, ++ A_FLAT = 0x220, ++ A = 0x241, ++ A_SHARP = 0x263, ++ B_FLAT = 0x263, ++ B = 0x287, ++ C_FLAT = 0x287, ++ B_SHARP = 0x2AE, ++ }; ++ ++/* Definition of octave information to be ORed onto F-Number */ ++ ++enum octaves ++ { ++ OCTAVE_0 = 0x0000, ++ OCTAVE_1 = 0x0400, ++ OCTAVE_2 = 0x0800, ++ OCTAVE_3 = 0x0C00, ++ OCTAVE_4 = 0x1000, ++ OCTAVE_5 = 0x1400, ++ OCTAVE_6 = 0x1800, ++ OCTAVE_7 = 0x1C00 ++ }; ++ ++typedef struct VOICE ++ { ++ struct VOICE *next; ++ struct VOICE *prev; ++ ++ unsigned num; ++ unsigned key; ++ unsigned velocity; ++ unsigned channel; ++ unsigned pitchleft; ++ unsigned pitchright; ++ int timbre; ++ int port; ++ unsigned status; ++ } VOICE; ++ ++typedef struct ++ { ++ VOICE *start; ++ VOICE *end; ++ } VOICELIST; ++ ++typedef struct ++ { ++ VOICELIST Voices; ++ int Timbre; ++ int Pitchbend; ++ int KeyOffset; ++ unsigned KeyDetune; ++ unsigned Volume; ++ unsigned EffectiveVolume; ++ int Pan; ++ int Detune; ++ unsigned RPN; ++ short PitchBendRange; ++ short PitchBendSemiTones; ++ short PitchBendHundreds; ++ } CHANNEL; ++ ++typedef struct ++ { ++ unsigned char SAVEK[ 2 ]; ++ unsigned char Level[ 2 ]; ++ unsigned char Env1[ 2 ]; ++ unsigned char Env2[ 2 ]; ++ unsigned char Wave[ 2 ]; ++ unsigned char Feedback; ++ signed char Transpose; ++ signed char Velocity; ++ } TIMBRE; ++ ++extern TIMBRE ADLIB_TimbreBank[ 256 ]; ++ ++static void AL_ResetVoices( void ); ++static void AL_CalcPitchInfo( void ); ++static void AL_SetVoiceTimbre( int voice ); ++static void AL_SetVoiceVolume( int voice ); ++static int AL_AllocVoice( void ); ++static int AL_GetVoice( int channel, int key ); ++static void AL_SetVoicePitch( int voice ); ++static void AL_SetChannelVolume( int channel, int volume ); ++static void AL_SetChannelPan( int channel, int pan ); ++static void AL_SetChannelDetune( int channel, int detune ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/_blaster.h trunk/rott/audiolib/_blaster.h +--- rott-1.0/rott/audiolib/_blaster.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/_blaster.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,133 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: _BLASTER.H ++ ++ author: James R. Dose ++ date: February 4, 1994 ++ ++ Private header for for BLASTER.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef ___BLASTER_H ++#define ___BLASTER_H ++ ++#define VALID ( 1 == 1 ) ++#define INVALID ( !VALID ) ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++#define YES ( 1 == 1 ) ++#define NO ( !YES ) ++ ++#define lobyte( num ) ( ( int )*( ( char * )&( num ) ) ) ++#define hibyte( num ) ( ( int )*( ( ( char * )&( num ) ) + 1 ) ) ++ ++#define BLASTER_MixerAddressPort 0x04 ++#define BLASTER_MixerDataPort 0x05 ++#define BLASTER_ResetPort 0x06 ++#define BLASTER_ReadPort 0x0A ++#define BLASTER_WritePort 0x0C ++#define BLASTER_DataAvailablePort 0x0E ++#define BLASTER_Ready 0xAA ++#define BLASTER_16BitDMAAck 0x0F ++ ++#define MIXER_DSP4xxISR_Ack 0x82 ++#define MIXER_DSP4xxISR_Enable 0x83 ++#define MIXER_MPU401_INT 0x4 ++#define MIXER_16BITDMA_INT 0x2 ++#define MIXER_8BITDMA_INT 0x1 ++#define MIXER_DisableMPU401Interrupts 0xB ++#define MIXER_SBProOutputSetting 0x0E ++#define MIXER_SBProStereoFlag 0x02 ++#define MIXER_SBProVoice 0x04 ++#define MIXER_SBProMidi 0x26 ++#define MIXER_SB16VoiceLeft 0x32 ++#define MIXER_SB16VoiceRight 0x33 ++#define MIXER_SB16MidiLeft 0x34 ++#define MIXER_SB16MidiRight 0x35 ++ ++#define DSP_Version1xx 0x0100 ++#define DSP_Version2xx 0x0200 ++#define DSP_Version201 0x0201 ++#define DSP_Version3xx 0x0300 ++#define DSP_Version4xx 0x0400 ++#define DSP_SB16Version DSP_Version4xx ++ ++#define DSP_MaxNormalRate 22000 ++#define DSP_MaxHighSpeedRate 44000 ++ ++#define DSP_8BitAutoInitRecord 0x2c ++#define DSP_8BitHighSpeedAutoInitRecord 0x98 ++#define DSP_Old8BitADC 0x24 ++#define DSP_8BitAutoInitMode 0x1c ++#define DSP_8BitHighSpeedAutoInitMode 0x90 ++#define DSP_SetBlockLength 0x48 ++#define DSP_Old8BitDAC 0x14 ++#define DSP_16BitDAC 0xB6 ++#define DSP_8BitDAC 0xC6 ++#define DSP_8BitADC 0xCe ++#define DSP_SetTimeConstant 0x40 ++#define DSP_Set_DA_Rate 0x41 ++#define DSP_Set_AD_Rate 0x42 ++#define DSP_Halt8bitTransfer 0xd0 ++#define DSP_Continue8bitTransfer 0xd4 ++#define DSP_Halt16bitTransfer 0xd5 ++#define DSP_Continue16bitTransfer 0xd6 ++#define DSP_SpeakerOn 0xd1 ++#define DSP_SpeakerOff 0xd3 ++#define DSP_GetVersion 0xE1 ++#define DSP_Reset 0xFFFF ++ ++#define DSP_SignedBit 0x10 ++#define DSP_StereoBit 0x20 ++ ++#define DSP_UnsignedMonoData 0x00 ++#define DSP_SignedMonoData ( DSP_SignedBit ) ++#define DSP_UnsignedStereoData ( DSP_StereoBit ) ++#define DSP_SignedStereoData ( DSP_SignedBit | DSP_StereoBit ) ++ ++#define BlasterEnv_Address 'A' ++#define BlasterEnv_Interrupt 'I' ++#define BlasterEnv_8bitDma 'D' ++#define BlasterEnv_16bitDma 'H' ++#define BlasterEnv_Type 'T' ++#define BlasterEnv_Midi 'P' ++#define BlasterEnv_EmuAddress 'E' ++ ++#define CalcTimeConstant( rate, samplesize ) \ ++ ( ( 65536L - ( 256000000L / ( ( samplesize ) * ( rate ) ) ) ) >> 8 ) ++ ++#define CalcSamplingRate( tc ) \ ++ ( 256000000L / ( 65536L - ( tc << 8 ) ) ) ++ ++typedef struct ++ { ++ int IsSupported; ++ int HasMixer; ++ int MaxMixMode; ++ int MinSamplingRate; ++ int MaxSamplingRate; ++ } CARD_CAPABILITY; ++ ++#endif +diff -urN rott-1.0/rott/audiolib/_guswave.h trunk/rott/audiolib/_guswave.h +--- rott-1.0/rott/audiolib/_guswave.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/_guswave.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,164 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ file: _GUSWAVE.H ++ ++ author: James R. Dose ++ date: March 23, 1994 ++ ++ Private header for GUSWAVE.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef ___GUSWAVE_H ++#define ___GUSWAVE_H ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++#define LOADDS _loadds ++ ++#define VOC_8BIT 0x0 ++#define VOC_CT4_ADPCM 0x1 ++#define VOC_CT3_ADPCM 0x2 ++#define VOC_CT2_ADPCM 0x3 ++#define VOC_16BIT 0x4 ++#define VOC_ALAW 0x6 ++#define VOC_MULAW 0x7 ++#define VOC_CREATIVE_ADPCM 0x200 ++ ++#define MAX_BLOCK_LENGTH 0x8000 ++ ++#define GF1BSIZE 896L /* size of buffer per wav on GUS */ ++//#define GF1BSIZE 512L /* size of buffer per wav on GUS */ ++ ++//#define VOICES 8 /* maximum amount of concurrent wav files */ ++#define VOICES 2 /* maximum amount of concurrent wav files */ ++#define MAX_VOICES 32 /* This should always be 32 */ ++#define MAX_VOLUME 4095 ++#define BUFFER 2048U /* size of DMA buffer for patch loading */ ++ ++typedef enum ++ { ++ Raw, ++ VOC, ++ DemandFeed, ++ WAV ++ } wavedata; ++ ++typedef enum ++ { ++ NoMoreData, ++ KeepPlaying, ++ SoundDone ++ } playbackstatus; ++ ++ ++typedef volatile struct VoiceNode ++ { ++ struct VoiceNode *next; ++ struct VoiceNode *prev; ++ ++ wavedata wavetype; ++ int bits; ++ playbackstatus ( *GetSound )( struct VoiceNode *voice ); ++ ++ int num; ++ ++ unsigned long mem; /* location in ultrasound memory */ ++ int Active; /* this instance in use */ ++ int GF1voice; /* handle to active voice */ ++ ++ char *NextBlock; ++ char *LoopStart; ++ char *LoopEnd; ++ unsigned LoopCount; ++ unsigned long LoopSize; ++ unsigned long BlockLength; ++ ++ unsigned long PitchScale; ++ ++ unsigned char *sound; ++ unsigned long length; ++ unsigned long SamplingRate; ++ unsigned long RateScale; ++ int Playing; ++ ++ int handle; ++ int priority; ++ ++ void ( *DemandFeed )( char **ptr, unsigned long *length ); ++ ++ unsigned long callbackval; ++ ++ int Volume; ++ int Pan; ++ } ++VoiceNode; ++ ++typedef struct ++ { ++ VoiceNode *start; ++ VoiceNode *end; ++ } ++voicelist; ++ ++typedef volatile struct voicestatus ++ { ++ VoiceNode *Voice; ++ int playing; ++ } ++voicestatus; ++ ++typedef struct ++ { ++ char RIFF[ 4 ]; ++ unsigned long file_size; ++ char WAVE[ 4 ]; ++ char fmt[ 4 ]; ++ unsigned long format_size; ++ } riff_header; ++ ++typedef struct ++ { ++ unsigned short wFormatTag; ++ unsigned short nChannels; ++ unsigned long nSamplesPerSec; ++ unsigned long nAvgBytesPerSec; ++ unsigned short nBlockAlign; ++ unsigned short nBitsPerSample; ++ } format_header; ++ ++typedef struct ++ { ++ unsigned char DATA[ 4 ]; ++ unsigned long size; ++ } data_header; ++ ++playbackstatus GUSWAVE_GetNextVOCBlock( VoiceNode *voice ); ++VoiceNode *GUSWAVE_GetVoice( int handle ); ++ ++int GUSWAVE_Play( VoiceNode *voice, int angle, int volume, int channels ); ++ ++VoiceNode *GUSWAVE_AllocVoice( int priority ); ++static int GUSWAVE_InitVoices( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/_midi.h trunk/rott/audiolib/_midi.h +--- rott-1.0/rott/audiolib/_midi.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/_midi.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,290 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: _MIDI.H ++ ++ author: James R. Dose ++ date: May 25, 1994 ++ ++ Private header for MIDI.C. Midi song file playback routines. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef ___MIDI_H ++#define ___MIDI_H ++ ++#define RELATIVE_BEAT( measure, beat, tick ) \ ++ ( ( tick ) + ( ( beat ) << 9 ) + ( ( measure ) << 16 ) ) ++ ++//Bobby Prince thinks this may be 100 ++//#define GENMIDI_DefaultVolume 100 ++#define GENMIDI_DefaultVolume 90 ++ ++#define MAX_FORMAT 1 ++ ++#define NUM_MIDI_CHANNELS 16 ++ ++#define TIME_PRECISION 16 ++ ++#define MIDI_HEADER_SIGNATURE 0x6468544d // "MThd" ++#define MIDI_TRACK_SIGNATURE 0x6b72544d // "MTrk" ++ ++#define MIDI_VOLUME 7 ++#define MIDI_PAN 10 ++#define MIDI_DETUNE 94 ++#define MIDI_RHYTHM_CHANNEL 9 ++#define MIDI_RPN_MSB 100 ++#define MIDI_RPN_LSB 101 ++#define MIDI_DATAENTRY_MSB 6 ++#define MIDI_DATAENTRY_LSB 38 ++#define MIDI_PITCHBEND_MSB 0 ++#define MIDI_PITCHBEND_LSB 0 ++#define MIDI_RUNNING_STATUS 0x80 ++#define MIDI_NOTE_OFF 0x8 ++#define MIDI_NOTE_ON 0x9 ++#define MIDI_POLY_AFTER_TCH 0xA ++#define MIDI_CONTROL_CHANGE 0xB ++#define MIDI_PROGRAM_CHANGE 0xC ++#define MIDI_AFTER_TOUCH 0xD ++#define MIDI_PITCH_BEND 0xE ++#define MIDI_SPECIAL 0xF ++#define MIDI_SYSEX 0xF0 ++#define MIDI_SYSEX_CONTINUE 0xF7 ++#define MIDI_META_EVENT 0xFF ++#define MIDI_END_OF_TRACK 0x2F ++#define MIDI_TEMPO_CHANGE 0x51 ++#define MIDI_TIME_SIGNATURE 0x58 ++#define MIDI_RESET_ALL_CONTROLLERS 0x79 ++#define MIDI_ALL_NOTES_OFF 0x7b ++#define MIDI_MONO_MODE_ON 0x7E ++#define MIDI_SYSTEM_RESET 0xFF ++ ++#define GET_NEXT_EVENT( track, data ) \ ++ ( data ) = *( track )->pos; \ ++ ( track )->pos += 1 ++ ++#define GET_MIDI_CHANNEL( event ) ( ( event ) & 0xf ) ++#define GET_MIDI_COMMAND( event ) ( ( event ) >> 4 ) ++ ++#define EMIDI_INFINITE -1 ++#define EMIDI_END_LOOP_VALUE 127 ++#define EMIDI_ALL_CARDS 127 ++#define EMIDI_INCLUDE_TRACK 110 ++#define EMIDI_EXCLUDE_TRACK 111 ++#define EMIDI_PROGRAM_CHANGE 112 ++#define EMIDI_VOLUME_CHANGE 113 ++#define EMIDI_CONTEXT_START 114 ++#define EMIDI_CONTEXT_END 115 ++#define EMIDI_LOOP_START 116 ++#define EMIDI_LOOP_END 117 ++#define EMIDI_SONG_LOOP_START 118 ++#define EMIDI_SONG_LOOP_END 119 ++ ++#define EMIDI_GeneralMIDI 0 ++#define EMIDI_SoundCanvas 1 ++#define EMIDI_AWE32 2 ++#define EMIDI_WaveBlaster 3 ++#define EMIDI_SoundBlaster 4 ++#define EMIDI_ProAudio 5 ++#define EMIDI_SoundMan16 6 ++#define EMIDI_Adlib 7 ++#define EMIDI_Soundscape 8 ++#define EMIDI_Ultrasound 9 ++ ++#define EMIDI_AffectsCurrentCard( c, type ) \ ++ ( ( ( c ) == EMIDI_ALL_CARDS ) || ( ( c ) == ( type ) ) ) ++ ++ ++#define EMIDI_NUM_CONTEXTS 7 ++typedef struct ++ { ++ unsigned char *pos; ++ unsigned char *loopstart; ++ short loopcount; ++ short RunningStatus; ++ unsigned time; ++ long FPSecondsPerTick; ++ short tick; ++ short beat; ++ short measure; ++ short BeatsPerMeasure; ++ short TicksPerBeat; ++ short TimeBase; ++ long delay; ++ short active; ++ } songcontext; ++ ++typedef struct ++ { ++ unsigned char *start; ++ unsigned char *pos; ++ ++ long delay; ++ short active; ++ short RunningStatus; ++ ++ short currentcontext; ++ songcontext context[ EMIDI_NUM_CONTEXTS ]; ++ ++ char EMIDI_IncludeTrack; ++ char EMIDI_ProgramChange; ++ char EMIDI_VolumeChange; ++ } track; ++ ++static long _MIDI_ReadNumber( void *from, size_t size ); ++static long _MIDI_ReadDelta( track *ptr ); ++static void _MIDI_ResetTracks( void ); ++static void _MIDI_AdvanceTick( void ); ++static void _MIDI_MetaEvent( track *Track ); ++static void _MIDI_SysEx( track *Track ); ++static int _MIDI_InterpretControllerInfo( track *Track, int TimeSet, ++ int channel, int c1, int c2 ); ++//static ++ void _MIDI_ServiceRoutine( task *Task ); ++static int _MIDI_SendControlChange( int channel, int c1, int c2 ); ++static void _MIDI_SetChannelVolume( int channel, int volume ); ++static void _MIDI_SendChannelVolumes( void ); ++static int _MIDI_ProcessNextTick( void ); ++static void _MIDI_InitEMIDI( void ); ++ ++/* ++ if ( c1 == EMIDI_LOOP_START ) ++ { ++ if ( c2 == 0 ) ++ { ++ Track->context[ 0 ].loopcount = EMIDI_INFINITE; ++ } ++ else ++ { ++ Track->context[ 0 ].loopcount = c2; ++ } ++ ++ Track->context[ 0 ].pos = Track->pos; ++ Track->context[ 0 ].loopstart = Track->pos; ++ Track->context[ 0 ].RunningStatus = Track->RunningStatus; ++ Track->context[ 0 ].time = _MIDI_Time; ++ Track->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick; ++ Track->context[ 0 ].tick = _MIDI_Tick; ++ Track->context[ 0 ].beat = _MIDI_Beat; ++ Track->context[ 0 ].measure = _MIDI_Measure; ++ Track->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure; ++ Track->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat; ++ Track->context[ 0 ].TimeBase = _MIDI_TimeBase; ++ break; ++ } ++ ++ if ( ( c1 == EMIDI_LOOP_END ) && ++ ( c2 == EMIDI_END_LOOP_VALUE ) ) ++ { ++ if ( ( Track->context[ 0 ].loopstart != NULL ) && ++ ( Track->context[ 0 ].loopcount != 0 ) ) ++ { ++ if ( Track->context[ 0 ].loopcount != EMIDI_INFINITE ) ++ { ++ Track->context[ 0 ].loopcount--; ++ } ++ ++ Track->pos = Track->context[ 0 ].loopstart; ++ Track->RunningStatus = Track->context[ 0 ].RunningStatus; ++ ++ if ( !TimeSet ) ++ { ++ _MIDI_Time = Track->context[ 0 ].time; ++ _MIDI_FPSecondsPerTick = Track->context[ 0 ].FPSecondsPerTick; ++ _MIDI_Tick = Track->context[ 0 ].tick; ++ _MIDI_Beat = Track->context[ 0 ].beat; ++ _MIDI_Measure = Track->context[ 0 ].measure; ++ _MIDI_BeatsPerMeasure = Track->context[ 0 ].BeatsPerMeasure; ++ _MIDI_TicksPerBeat = Track->context[ 0 ].TicksPerBeat; ++ _MIDI_TimeBase = Track->context[ 0 ].TimeBase; ++ TimeSet = TRUE; ++ } ++ } ++ break; ++ } ++ ++ if ( c1 == MIDI_MONO_MODE_ON ) ++ { ++ Track->pos++; ++ } ++ ++ if ( ( c1 == MIDI_VOLUME ) && ( !Track->EMIDI_VolumeChange ) ) ++ { ++ _MIDI_SetChannelVolume( channel, c2 ); ++ break; ++ } ++ else if ( ( c1 == EMIDI_VOLUME_CHANGE ) && ++ ( Track->EMIDI_VolumeChange ) ) ++ { ++ _MIDI_SetChannelVolume( channel, c2 ); ++ break; ++ } ++ ++ if ( ( c1 == EMIDI_PROGRAM_CHANGE ) && ++ ( Track->EMIDI_ProgramChange ) ) ++ { ++ _MIDI_Funcs->ProgramChange( channel, MIDI_PatchMap[ c2 & 0x7f ] ); ++ break; ++ } ++ ++ if ( c1 == EMIDI_CONTEXT_START ) ++ { ++ break; ++ } ++ ++ if ( c1 == EMIDI_CONTEXT_END ) ++ { ++ if ( ( Track->currentcontext != _MIDI_Context ) || ++ ( Track->context[ _MIDI_Context ].pos == NULL ) ++ { ++ break; ++ } ++ ++ Track->currentcontext = _MIDI_Context; ++ Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart; ++ Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount; ++ Track->pos = Track->context[ _MIDI_Context ].pos; ++ Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus; ++ ++ if ( TimeSet ) ++ { ++ break; ++ } ++ ++ _MIDI_Time = Track->context[ _MIDI_Context ].time; ++ _MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick; ++ _MIDI_Tick = Track->context[ _MIDI_Context ].tick; ++ _MIDI_Beat = Track->context[ _MIDI_Context ].beat; ++ _MIDI_Measure = Track->context[ _MIDI_Context ].measure; ++ _MIDI_BeatsPerMeasure = Track->context[ _MIDI_Context ].BeatsPerMeasure; ++ _MIDI_TicksPerBeat = Track->context[ _MIDI_Context ].TicksPerBeat; ++ _MIDI_TimeBase = Track->context[ _MIDI_Context ].TimeBase; ++ TimeSet = TRUE; ++ break; ++ } ++ ++ if ( _MIDI_Funcs->ControlChange ) ++ { ++ _MIDI_Funcs->ControlChange( channel, c1, c2 ); ++ } ++ */ ++ ++#endif +diff -urN rott-1.0/rott/audiolib/_multivc.h trunk/rott/audiolib/_multivc.h +--- rott-1.0/rott/audiolib/_multivc.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/_multivc.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,286 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ file: _MULTIVC.H ++ ++ author: James R. Dose ++ date: December 20, 1993 ++ ++ Private header for MULTIVOC.C ++ ++ (c) Copyright 1993 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef ___MULTIVC_H ++#define ___MULTIVC_H ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++#define VOC_8BIT 0x0 ++#define VOC_CT4_ADPCM 0x1 ++#define VOC_CT3_ADPCM 0x2 ++#define VOC_CT2_ADPCM 0x3 ++#define VOC_16BIT 0x4 ++#define VOC_ALAW 0x6 ++#define VOC_MULAW 0x7 ++#define VOC_CREATIVE_ADPCM 0x200 ++ ++#define T_SIXTEENBIT_STEREO 0 ++#define T_8BITS 1 ++#define T_MONO 2 ++#define T_16BITSOURCE 4 ++#define T_LEFTQUIET 8 ++#define T_RIGHTQUIET 16 ++#define T_DEFAULT T_SIXTEENBIT_STEREO ++ ++#define MV_MaxPanPosition 31 ++#define MV_NumPanPositions ( MV_MaxPanPosition + 1 ) ++#define MV_MaxTotalVolume 255 ++//#define MV_MaxVolume 63 ++#define MV_NumVoices 8 ++ ++#define MIX_VOLUME( volume ) \ ++ ( ( max( 0, min( ( volume ), 255 ) ) * ( MV_MaxVolume + 1 ) ) >> 8 ) ++// ( ( max( 0, min( ( volume ), 255 ) ) ) >> 2 ) ++ ++//#define SILENCE_16BIT 0x80008000 ++#define SILENCE_16BIT 0 ++#define SILENCE_8BIT 0x80808080 ++//#define SILENCE_16BIT_PAS 0 ++ ++#define MixBufferSize 256 ++ ++#define NumberOfBuffers 16 ++#define TotalBufferSize ( MixBufferSize * NumberOfBuffers ) ++ ++#define PI 3.1415926536 ++ ++typedef enum ++ { ++ Raw, ++ VOC, ++ DemandFeed, ++ WAV ++ } wavedata; ++ ++typedef enum ++ { ++ NoMoreData, ++ KeepPlaying ++ } playbackstatus; ++ ++ ++typedef struct VoiceNode ++ { ++ struct VoiceNode *next; ++ struct VoiceNode *prev; ++ ++ wavedata wavetype; ++ char bits; ++ ++ playbackstatus ( *GetSound )( struct VoiceNode *voice ); ++ ++ void ( *mix )( unsigned long position, unsigned long rate, ++ const char *start, unsigned long length ); ++ ++ char *NextBlock; ++ char *LoopStart; ++ char *LoopEnd; ++ unsigned LoopCount; ++ unsigned long LoopSize; ++ unsigned long BlockLength; ++ ++ unsigned long PitchScale; ++ unsigned long FixedPointBufferSize; ++ ++ char *sound; ++ unsigned long length; ++ unsigned long SamplingRate; ++ unsigned long RateScale; ++ unsigned long position; ++ int Playing; ++ ++ int handle; ++ int priority; ++ ++ void ( *DemandFeed )( char **ptr, unsigned long *length ); ++ ++ short *LeftVolume; ++ short *RightVolume; ++ ++ unsigned long callbackval; ++ ++ } VoiceNode; ++ ++typedef struct ++ { ++ VoiceNode *start; ++ VoiceNode *end; ++ } VList; ++ ++typedef struct ++ { ++ unsigned char left; ++ unsigned char right; ++ } Pan; ++ ++typedef signed short MONO16; ++typedef signed char MONO8; ++ ++typedef struct ++ { ++ MONO16 left; ++ MONO16 right; ++// unsigned short left; ++// unsigned short right; ++ } STEREO16; ++ ++typedef struct ++ { ++ MONO16 left; ++ MONO16 right; ++ } SIGNEDSTEREO16; ++ ++typedef struct ++ { ++// MONO8 left; ++// MONO8 right; ++ char left; ++ char right; ++ } STEREO8; ++ ++typedef struct ++ { ++ char RIFF[ 4 ]; ++ unsigned long file_size; ++ char WAVE[ 4 ]; ++ char fmt[ 4 ]; ++ unsigned long format_size; ++ } riff_header; ++ ++typedef struct ++ { ++ unsigned short wFormatTag; ++ unsigned short nChannels; ++ unsigned long nSamplesPerSec; ++ unsigned long nAvgBytesPerSec; ++ unsigned short nBlockAlign; ++ unsigned short nBitsPerSample; ++ } format_header; ++ ++typedef struct ++ { ++ unsigned char DATA[ 4 ]; ++ unsigned long size; ++ } data_header; ++ ++typedef MONO8 VOLUME8[ 256 ]; ++typedef MONO16 VOLUME16[ 256 ]; ++ ++typedef char HARSH_CLIP_TABLE_8[ MV_NumVoices * 256 ]; ++ ++static void MV_Mix( VoiceNode *voice, int buffer ); ++static void MV_PlayVoice( VoiceNode *voice ); ++static void MV_StopVoice( VoiceNode *voice ); ++static void MV_ServiceVoc( void ); ++ ++static playbackstatus MV_GetNextVOCBlock( VoiceNode *voice ); ++static playbackstatus MV_GetNextDemandFeedBlock( VoiceNode *voice ); ++static playbackstatus MV_GetNextRawBlock( VoiceNode *voice ); ++static playbackstatus MV_GetNextWAVBlock( VoiceNode *voice ); ++ ++static void MV_ServiceRecord( void ); ++static VoiceNode *MV_GetVoice( int handle ); ++static VoiceNode *MV_AllocVoice( int priority ); ++ ++static short *MV_GetVolumeTable( int vol ); ++ ++static void MV_SetVoiceMixMode( VoiceNode *voice ); ++ ++static void MV_SetVoicePitch( VoiceNode *voice, unsigned long rate, int pitchoffset ); ++static void MV_CalcVolume( int MaxLevel ); ++static void MV_CalcPanTable( void ); ++ ++#ifdef PLAT_DOS ++#define ATR_INDEX 0x3c0 ++#define STATUS_REGISTER_1 0x3da ++ ++#define SetBorderColor(color) \ ++ { \ ++ inp (STATUS_REGISTER_1); \ ++ outp (ATR_INDEX,0x31); \ ++ outp (ATR_INDEX,color); \ ++ } ++#endif ++ ++void ClearBuffer_DW( void *ptr, unsigned data, int length ); ++ ++#ifdef PLAT_DOS ++#pragma aux ClearBuffer_DW = \ ++ "cld", \ ++ "push es", \ ++ "push ds", \ ++ "pop es", \ ++ "rep stosd", \ ++ "pop es", \ ++parm [ edi ] [ eax ] [ ecx ] modify exact [ ecx edi ]; ++#endif ++ ++void MV_Mix8BitMono( unsigned long position, unsigned long rate, ++ const char *start, unsigned long length ); ++ ++void MV_Mix8BitStereo( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ); ++ ++void MV_Mix16BitMono( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ); ++ ++void MV_Mix16BitStereo( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ); ++ ++void MV_Mix16BitMono16( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ); ++ ++void MV_Mix8BitMono16( unsigned long position, unsigned long rate, ++ const char *start, unsigned long length ); ++ ++void MV_Mix8BitStereo16( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ); ++ ++void MV_Mix16BitStereo16( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ); ++ ++void MV_16BitReverb( const char *src, char *dest, const VOLUME16 *volume, int count ); ++ ++void MV_8BitReverb( const signed char *src, signed char *dest, const VOLUME16 *volume, int count ); ++ ++void MV_16BitReverbFast( const char *src, char *dest, int count, int shift ); ++ ++void MV_8BitReverbFast( const signed char *src, signed char *dest, int count, int shift ); ++ ++#ifdef PLAT_DOS ++#pragma aux MV_16BitReverb parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi] ++#pragma aux MV_8BitReverb parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi] ++#pragma aux MV_16BitReverbFast parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi] ++#pragma aux MV_8BitReverbFast parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi] ++#endif ++ ++#endif +diff -urN rott-1.0/rott/audiolib/_pas16.h trunk/rott/audiolib/_pas16.h +--- rott-1.0/rott/audiolib/_pas16.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/_pas16.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,250 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: _PAS16.H ++ ++ author: James R. Dose ++ date: March 27, 1994 ++ ++ Private header for for PAS16.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef ___PAS16_H ++#define ___PAS16_H ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++#define VALID ( 1 == 1 ) ++#define INVALID ( !VALID ) ++ ++#define lobyte( num ) ( ( int )*( ( char * )&( num ) ) ) ++#define hibyte( num ) ( ( int )*( ( ( char * )&( num ) ) + 1 ) ) ++ ++#define STEREO 1 ++#define SIXTEEN_BIT 2 ++ ++#define MONO_8BIT 0 ++#define STEREO_8BIT ( STEREO ) ++#define MONO_16BIT ( SIXTEEN_BIT ) ++#define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) ++ ++#define PAS_MaxMixMode STEREO_16BIT ++ ++#define MONO_8BIT_SAMPLE_SIZE 1 ++#define MONO_16BIT_SAMPLE_SIZE 2 ++#define STEREO_8BIT_SAMPLE_SIZE ( 2 * MONO_8BIT_SAMPLE_SIZE ) ++#define STEREO_16BIT_SAMPLE_SIZE ( 2 * MONO_16BIT_SAMPLE_SIZE ) ++ ++#define PAS_RevisionBits 0xe0 ++ ++#define AudioFilterControl 0xb8a ++#define InterruptControl 0xb8b ++#define InterruptStatus 0xb89 ++#define PCMDataRegister 0xf88 ++#define CrossChannelControl 0xf8a ++#define SampleRateTimer 0x1388 ++#define SampleBufferCount 0x1389 ++#define LocalSpeakerTimerCount 0x138a ++#define LocalTimerControl 0x138b ++#define SampleSizeConfiguration 0x8389 ++ ++#define AudioMuteFlag 0x20 ++#define SampleRateTimerGateFlag 0x40 ++#define SampleBufferCountGateFlag 0x80 ++ ++#define SampleRateInterruptFlag 0x04 ++#define SampleBufferInterruptFlag 0x08 ++ ++#define PAS_SampleSizeMask 0xf3 ++#define PAS_SignedSampleMask 0xe3 ++#define PAS_16BitSampleFlag 0x04 ++#define PAS_UnsignedSampleFlag 0x10 ++//bSC2msbinv equ 00010000b ;; invert MSB from standard method ++ ++#define PAS_OverSamplingMask 0xfc ++ ++#define PAS_1xOverSampling 0x00 ++#define PAS_2xOverSampling 0x01 ++#define PAS_4xOverSampling 0x03 ++ ++#define PAS_StereoFlag 0x20 ++ ++#define PAS_AudioMuteFlag 0x20 ++ ++#define DEFAULT_BASE ( 0x0388 ^ 0x388 ) /* default base I/O address */ ++#define ALT_BASE_1 ( 0x0384 ^ 0x388 ) /* first alternate address */ ++#define ALT_BASE_2 ( 0x038C ^ 0x388 ) /* second alternate address */ ++#define ALT_BASE_3 ( 0x0288 ^ 0x388 ) /* third alternate address */ ++ ++#define PAS_DMAEnable 0x80 ++#define PAS_ChannelConnectMask 0x0f ++#define PAS_PCMStartDAC 0xD0 ++#define PAS_PCMStartADC 0xC0 ++#define PAS_PCMStopMask 0x3f ++ ++#define RECORD 0 ++#define PLAYBACK 1 ++ ++#define SelectSampleRateTimer 0x36 // 00110110b ++#define SelectSampleBufferCount 0x74 // 01110100b ++ ++#define CalcTimeInterval( rate ) \ ++ ( 1193180UL / ( rate ) ) ++ ++#define CalcSamplingRate( interval ) \ ++ ( 1193180UL / ( interval ) ) ++ ++#define MV_Signature 0x4d56 ++#define MV_SoundInt 0x2f ++#define MV_CheckForDriver 0xbc00 ++#define MV_GetVersion 0xbc01 ++#define MV_GetPointerToStateTable 0xbc02 ++#define MV_GetPointerToFunctionTable 0xbc03 ++#define MV_GetDmaIrqInt 0xbc04 ++#define MV_SendCommandStructure 0xbc05 ++#define MV_GetDriverMessage 0xbc06 ++#define MV_SetHotkeyScanCodes 0xbc0a ++#define MV_GetPathToDriver 0xbc0b ++ ++#define OUTPUTMIXER 0x00 /* output mixer H/W select */ ++#define INPUTMIXER 0x40 /* input mixer select */ ++#define DEFMIXER -1 /* use last mixer selected */ ++ ++/* left channel values */ ++ ++#define L_FM 0x01 ++#define L_IMIXER 0x02 ++#define L_EXT 0x03 ++#define L_INT 0x04 ++#define L_MIC 0x05 ++#define L_PCM 0x06 ++#define L_SPEAKER 0x07 ++#define L_FREE 0x00 ++#define L_SBDAC 0x00 ++ ++/* right channel values */ ++ ++#define R_FM 0x08 ++#define R_IMIXER 0x09 ++#define R_EXT 0x0A ++#define R_INT 0x0B ++#define R_MIC 0x0C ++#define R_PCM 0x0D ++#define R_SPEAKER 0x0E ++#define R_FREE 0x0F ++#define R_SBDAC 0x0F ++ ++typedef struct ++ { ++ unsigned char sysspkrtmr; /* 42 System Speaker Timer Address */ ++ unsigned char systmrctlr; /* 43 System Timer Control */ ++ unsigned char sysspkrreg; /* 61 System Speaker Register */ ++ unsigned char joystick; /* 201 Joystick Register */ ++ unsigned char lfmaddr; /* 388 Left FM Synth Address */ ++ unsigned char lfmdata; /* 389 Left FM Synth Data */ ++ unsigned char rfmaddr; /* 38A Right FM Synth Address */ ++ unsigned char rfmdata; /* 38B Right FM Synth Data */ ++ unsigned char dfmaddr; /* 788 Dual FM Synth Address */ ++ unsigned char dfmdata; /* 789 Dual FM Synth Data */ ++ unsigned char RESRVD1[1]; /* reserved */ ++ unsigned char paudiomixr; /* 78B Paralllel Audio Mixer Control*/ ++ unsigned char audiomixr; /* B88 Audio Mixer Control */ ++ unsigned char intrctlrst; /* B89 Interrupt Status */ ++ unsigned char audiofilt; /* B8A Audio Filter Control */ ++ unsigned char intrctlr; /* B8B Interrupt Control */ ++ unsigned char pcmdata; /* F88 PCM Data I/O Register */ ++ unsigned char RESRVD2; /* reserved */ ++ unsigned char crosschannel; /* F8A Cross Channel */ ++ unsigned char RESRVD3; /* reserved */ ++ unsigned short samplerate; /* 1388 Sample Rate Timer */ ++ unsigned short samplecnt; /* 1389 Sample Count Register */ ++ unsigned short spkrtmr; /* 138A Shadow Speaker Timer Count */ ++ unsigned char tmrctlr; /* 138B Shadow Speaker Timer Control */ ++ unsigned char mdirqvect; /* 1788 MIDI IRQ Vector Register */ ++ unsigned char mdsysctlr; /* 1789 MIDI System Control Register */ ++ unsigned char mdsysstat; /* 178A MIDI IRQ Status Register */ ++ unsigned char mdirqclr; /* 178B MIDI IRQ Clear Register */ ++ unsigned char mdgroup1; /* 1B88 MIDI Group #1 Register */ ++ unsigned char mdgroup2; /* 1B89 MIDI Group #2 Register */ ++ unsigned char mdgroup3; /* 1B8A MIDI Group #3 Register */ ++ unsigned char mdgroup4; /* 1B8B MIDI Group #4 Register */ ++ } MVState; ++ ++typedef struct ++ { ++ unsigned long SetMixer; ++ unsigned long SetVolume; ++ unsigned long SetFilter; ++ unsigned long SetCrossChannel; ++ unsigned long GetMixer; ++ unsigned long GetVolume; ++ unsigned long GetFilter; ++ unsigned long GetCrossChannel; ++ unsigned long ReadSound; ++ unsigned long FMSplit; ++ } MVFunc; ++ ++int PAS_CheckForDriver( void ); ++MVState *PAS_GetStateTable( void ); ++MVFunc *PAS_GetFunctionTable( void ); ++int PAS_GetCardSettings( void ); ++void PAS_EnableInterrupt( void ); ++void PAS_DisableInterrupt( void ); ++void interrupt far PAS_ServiceInterrupt( void ); ++//void interrupt PAS_ServiceInterrupt( void ); ++void PAS_Write( int Register, int Data ); ++int PAS_Read( int Register ); ++void PAS_SetSampleRateTimer( void ); ++void PAS_SetSampleBufferCount( void ); ++int PAS_SetupDMABuffer( char *BufferPtr, int BufferSize, int mode ); ++int PAS_GetFilterSetting( int rate ); ++void PAS_BeginTransfer( int mode ); ++int PAS_TestAddress( int address ); ++int PAS_FindCard( void ); ++int PAS_CallMVFunction( unsigned long function, int ebx, int ecx, int edx ); ++void PAS_SaveState( void ); ++void PAS_RestoreState( void ); ++ ++ ++#pragma aux PAS_TestAddress = \ ++ "mov dx, 0b8bh", \ ++ "xor dx, ax", \ ++ "in al, dx", \ ++ "cmp al, 0ffh", \ ++ "je TestExit", \ ++ "mov ah, al", \ ++ "xor al, 0e0h", \ ++ "out dx, al", \ ++ "jmp TestDelay1", \ ++ "TestDelay1:", \ ++ "jmp TestDelay2", \ ++ "TestDelay2:", \ ++ "in al, dx", \ ++ "xchg al, ah", \ ++ "out dx, al", \ ++ "sub al, ah", \ ++ "TestExit:", \ ++ "and eax, 0ffh" \ ++ parm [ eax ] modify exact [ eax dx ]; ++ ++#endif +diff -urN rott-1.0/rott/audiolib/_sndscap.h trunk/rott/audiolib/_sndscap.h +--- rott-1.0/rott/audiolib/_sndscap.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/_sndscap.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,136 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: _SNDSCAP.H ++ ++ author: James R. Dose ++ date: October 26, 1994 ++ ++ Private header for SNDSCAPE.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef ___SNDSCAP_H ++#define ___SNDSCAP_H ++ ++#define VALID ( 1 == 1 ) ++#define INVALID ( !VALID ) ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++#define lobyte( num ) ( ( int )*( ( char * )&( num ) ) ) ++#define hibyte( num ) ( ( int )*( ( ( char * )&( num ) ) + 1 ) ) ++ ++#define STEREO 1 ++#define SIXTEEN_BIT 2 ++ ++#define MONO_8BIT 0 ++#define STEREO_8BIT ( STEREO ) ++#define MONO_16BIT ( SIXTEEN_BIT ) ++#define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) ++ ++#define SOUNDSCAPE_MaxMixMode STEREO_16BIT ++ ++#define MONO_8BIT_SAMPLE_SIZE 1 ++#define MONO_16BIT_SAMPLE_SIZE 2 ++#define STEREO_8BIT_SAMPLE_SIZE ( 2 * MONO_8BIT_SAMPLE_SIZE ) ++#define STEREO_16BIT_SAMPLE_SIZE ( 2 * MONO_16BIT_SAMPLE_SIZE ) ++ ++#define SOUNDSCAPE_DefaultSampleRate 11000 ++#define SOUNDSCAPE_DefaultMixMode MONO_8BIT ++#define SOUNDSCAPE_MaxIrq 15 ++ ++/* Ensoniq gate-array chip defines ... */ ++#define ODIE 0 /* ODIE gate array */ ++#define OPUS 1 /* OPUS gate array */ ++#define MMIC 2 /* MiMIC gate array */ ++ ++/* relevant direct register defines - offsets from base address */ ++#define GA_HOSTCSTAT 2 /* host port ctrl/stat reg */ ++#define GA_HOSTDATA 3 /* host port data reg */ ++#define GA_REGADDR 4 /* indirect address reg */ ++#define GA_REGDATA 5 /* indirect data reg */ ++#define SB_IACK 0x22e /* SoundBlaster IACK register */ ++ ++/* relevant indirect register defines */ ++#define GA_DMACHB 3 /* DMA chan B assign reg */ ++#define GA_INTCFG 4 /* interrupt configuration reg */ ++#define GA_DMACFG 5 /* DMA config reg */ ++#define GA_CDCFG 6 /* CD-ROM (AD-1848) config reg */ ++#define GA_HMCTL 9 /* host master control reg */ ++#define GA_CHIPSEL 10 /* programmable external chip select */ ++ ++/* AD-1848 chip defines ... */ ++/* relevant direct register defines */ ++#define AD_REGADDR 0 /* indirect address reg */ ++#define AD_REGDATA 1 /* indirect data reg */ ++#define AD_STATUS 2 /* status register */ ++#define AD_OFFSET 8 /* for some boards, a fixed BasePort offset */ ++ ++/* relevant indirect register defines */ ++#define AD_LEFTOUT 6 /* left DAC output control reg */ ++#define AD_RIGHTOUT 7 /* right DAC output control reg */ ++#define AD_FORMAT 8 /* clock and data format reg */ ++#define AD_CONFIG 9 /* interface config register */ ++#define AD_PINCTRL 10 /* external pin control reg */ ++#define AD_UCOUNT 14 /* upper count reg */ ++#define AD_LCOUNT 15 /* lower count reg */ ++ ++/* some firmware command and communication defines */ ++#define SET_CTL 0x88 /* set a control value */ ++#define GET_CTL 0x89 /* get a control value */ ++#define SET_REV 0xb0 /* set synth reverb */ ++#define SYNTH_VOL 0x04 /* Synth Vol control number */ ++#define RXRDY 0x01 /* Receive-Ready bit mask */ ++#define TXRDY 0x02 /* Transmit-Ready bit mask */ ++ ++/* some miscellaneous defines ... soundscape reg values, sytem int regs, ... */ ++#define INTCONT1 0x20 /* Interrupt Controller 1 control register */ ++#define INTCONT2 0xa0 /* Interrupt Controller 2 control register */ ++#define INTMASK1 0x21 /* Interrupt Controller 1 mask register */ ++#define INTMASK2 0xa1 /* Interrupt Controller 2 mask register */ ++#define VECTBASE1 0x08 /* vector base for XT interrupts */ ++#define VECTBASE2 0x70 /* vector base for AT extended interrupts */ ++#define EOI 0x20 /* End Of Interrupt command */ ++#define AUTO_OUT 0x58 /* DMA controller mode */ ++ ++static void SOUNDSCAPE_EnableInterrupt( void ); ++static void SOUNDSCAPE_DisableInterrupt( void ); ++static void __interrupt __far SOUNDSCAPE_ServiceInterrupt( void ); ++static int ga_read( int rnum ); ++static void ga_write( int rnum, int value ); ++static int ad_read( int rnum ); ++static void ad_write( int rnum, int value ); ++static void tdelay( void ); ++static void pcm_format( void ); ++static int SOUNDSCAPE_SetupDMABuffer( char *BufferPtr, int BufferSize, int mode ); ++static int SOUNDSCAPE_BeginPlayback( int length ); ++static void SOUNDSCAPE_LockEnd( void ); ++static void SOUNDSCAPE_UnlockMemory( void ); ++static int SOUNDSCAPE_LockMemory( void ); ++static unsigned short allocateTimerStack( unsigned short size ); ++static void deallocateTimerStack( unsigned short selector ); ++static int parse( char *val, char *str, FILE *p1 ); ++static int SOUNDSCAPE_FindCard( void ); ++static int SOUNDSCAPE_Setup( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/adlibfx.c trunk/rott/audiolib/adlibfx.c +--- rott-1.0/rott/audiolib/adlibfx.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/adlibfx.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,552 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: ADLIBFX.C ++ ++ author: James R. Dose ++ date: April 1, 1994 ++ ++ Low level routines to support Adlib sound effects created by Muse. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include "dpmi.h" ++#include "task_man.h" ++#include "interrup.h" ++#include "al_midi.h" ++#include "adlibfx.h" ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++static void ADLIBFX_SendOutput( int reg, int data ); ++static void ADLIBFX_Service( task *Task ); ++ ++static long ADLIBFX_LengthLeft; ++static int ADLIBFX_Block; ++static ALSound *ADLIBFX_Sound = NULL; ++static char *ADLIBFX_SoundPtr = NULL; ++static int ADLIBFX_Priority; ++static unsigned long ADLIBFX_CallBackVal; ++static void ( *ADLIBFX_CallBackFunc )( unsigned long ) = NULL; ++static int ADLIBFX_SoundVolume; ++static int ADLIBFX_TotalVolume = ADLIBFX_MaxVolume; ++static task *ADLIBFX_ServiceTask = NULL; ++static int ADLIBFX_VoiceHandle = ADLIBFX_MinVoiceHandle; ++ ++int ADLIBFX_Installed = FALSE; ++ ++int ADLIBFX_ErrorCode = ADLIBFX_Ok; ++ ++#define ADLIBFX_SetErrorCode( status ) \ ++ ADLIBFX_ErrorCode = ( status ); ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *ADLIBFX_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case ADLIBFX_Warning : ++ case ADLIBFX_Error : ++ ErrorString = ADLIBFX_ErrorString( ADLIBFX_ErrorCode ); ++ break; ++ ++ case ADLIBFX_Ok : ++ ErrorString = "Adlib FX ok."; ++ break; ++ ++ case ADLIBFX_NoVoices : ++ ErrorString = "No free voices available in Adlib FX."; ++ break; ++ ++ case ADLIBFX_VoiceNotFound : ++ ErrorString = "No voice with matching handle found."; ++ break; ++ ++ case ADLIBFX_DPMI_Error : ++ ErrorString = "DPMI Error in AdlibFX."; ++ break; ++ ++ default : ++ ErrorString = "Unknown Adlib FX error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define ADLIBFX_LockStart ADLIBFX_SendOutput ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_SendOutput ++ ++ Writes a byte of data to the specified register on the Adlib card. ++---------------------------------------------------------------------*/ ++ ++static void ADLIBFX_SendOutput ++ ( ++ int reg, ++ int data ++ ) ++ ++ { ++ int i; ++ int adlib_port = 0x388; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ outp( adlib_port, reg ); ++ ++ for( i = 6; i ; i-- ) ++ { ++ inp( adlib_port ); ++ } ++ ++ outp( adlib_port + 1, data ); ++ ++ for( i = 35; i ; i-- ) ++ { ++ inp( adlib_port ); ++ } ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_Stop ++ ++ Halts playback of the currently playing sound effect. ++---------------------------------------------------------------------*/ ++ ++int ADLIBFX_Stop ++ ( ++ int handle ++ ) ++ ++ { ++ unsigned flags; ++ ++ if ( ( handle != ADLIBFX_VoiceHandle ) || ( ADLIBFX_Sound == NULL ) ) ++ { ++ ADLIBFX_SetErrorCode( ADLIBFX_VoiceNotFound ); ++ return( ADLIBFX_Warning ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ ADLIBFX_SendOutput( 0xb0, 0 ); ++ ++ ADLIBFX_Sound = NULL; ++ ADLIBFX_SoundPtr = NULL; ++ ADLIBFX_LengthLeft = 0; ++ ADLIBFX_Priority = 0; ++ ++ RestoreInterrupts( flags ); ++ ++ if ( ADLIBFX_CallBackFunc ) ++ { ++ ADLIBFX_CallBackFunc( ADLIBFX_CallBackVal ); ++ } ++ ++ return( ADLIBFX_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_Service ++ ++ Task Manager routine to perform the playback of a sound effect. ++---------------------------------------------------------------------*/ ++ ++static void ADLIBFX_Service ++ ( ++ task *Task ++ ) ++ ++ { ++ int value; ++ ++ if ( ADLIBFX_SoundPtr ) ++ { ++ value = *ADLIBFX_SoundPtr++; ++ if ( value != 0 ) ++ { ++ ADLIBFX_SendOutput( 0xa0, value ); ++ ADLIBFX_SendOutput( 0xb0, ADLIBFX_Block ); ++ } ++ else ++ { ++ ADLIBFX_SendOutput( 0xb0, 0 ); ++ } ++ ++ ADLIBFX_LengthLeft--; ++ if ( ADLIBFX_LengthLeft <= 0 ) ++ { ++ ADLIBFX_Stop( ADLIBFX_VoiceHandle ); ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_SetVolume ++ ++ Sets the volume of the currently playing sound effect. ++---------------------------------------------------------------------*/ ++ ++int ADLIBFX_SetVolume ++ ( ++ int handle, ++ int volume ++ ) ++ ++ { ++ unsigned flags; ++ int carrierlevel; ++ ++ flags = DisableInterrupts(); ++ if ( ( handle != ADLIBFX_VoiceHandle ) || ( ADLIBFX_Sound == NULL ) ) ++ { ++ RestoreInterrupts( flags ); ++ ADLIBFX_SetErrorCode( ADLIBFX_VoiceNotFound ); ++ return( ADLIBFX_Warning ); ++ } ++ ++ volume = min( volume, ADLIBFX_MaxVolume ); ++ volume = max( volume, 0 ); ++ ADLIBFX_SoundVolume = volume; ++ ++ volume *= ADLIBFX_TotalVolume; ++ volume /= ADLIBFX_MaxVolume; ++ ++ carrierlevel = ADLIBFX_Sound->cScale & 0x3f; ++ carrierlevel ^= 0x3f; ++ carrierlevel *= ( volume / 2 ) + 0x80; ++ carrierlevel /= ADLIBFX_MaxVolume; ++ carrierlevel ^= 0x3f; ++ carrierlevel |= ADLIBFX_Sound->cScale & 0xc0; ++ ++ ADLIBFX_SendOutput( 0x43, carrierlevel ); ++ ++ RestoreInterrupts( flags ); ++ return( ADLIBFX_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_SetTotalVolume ++ ++ Sets the total volume of the sound effect. ++---------------------------------------------------------------------*/ ++ ++int ADLIBFX_SetTotalVolume ++ ( ++ int volume ++ ) ++ ++ { ++ volume = max( volume, 0 ); ++ volume = min( volume, ADLIBFX_MaxVolume ); ++ ++ ADLIBFX_TotalVolume = volume; ++ ADLIBFX_SetVolume( ADLIBFX_VoiceHandle, ADLIBFX_SoundVolume ); ++ ++ return( ADLIBFX_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_GetTotalVolume ++ ++ Returns the total volume of the sound effect. ++---------------------------------------------------------------------*/ ++ ++int ADLIBFX_GetTotalVolume ++ ( ++ void ++ ) ++ ++ { ++ return( ADLIBFX_TotalVolume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_VoiceAvailable ++ ++ Checks if a voice can be play at the specified priority. ++---------------------------------------------------------------------*/ ++ ++int ADLIBFX_VoiceAvailable ++ ( ++ int priority ++ ) ++ ++ { ++ if ( priority < ADLIBFX_Priority ) ++ { ++ return( FALSE ); ++ } ++ ++ return( TRUE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_Play ++ ++ Starts playback of a Muse sound effect. ++---------------------------------------------------------------------*/ ++ ++int ADLIBFX_Play ++ ( ++ ALSound *sound, ++ int volume, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ unsigned flags; ++ int carrierlevel; ++ ++ if ( priority < ADLIBFX_Priority ) ++ { ++ ADLIBFX_SetErrorCode( ADLIBFX_NoVoices ); ++ return( ADLIBFX_Warning ); ++ } ++ ++ ADLIBFX_Stop( ADLIBFX_VoiceHandle ); ++ ++ ADLIBFX_VoiceHandle++; ++ if ( ADLIBFX_VoiceHandle < ADLIBFX_MinVoiceHandle ) ++ { ++ ADLIBFX_VoiceHandle = ADLIBFX_MinVoiceHandle; ++ } ++ ++ flags = DisableInterrupts(); ++ ++ ADLIBFX_LengthLeft = sound->length; ++ ADLIBFX_Priority = priority; ++ ADLIBFX_Sound = sound; ++ ADLIBFX_SoundPtr = &sound->data; ++ ADLIBFX_CallBackVal = callbackval; ++ ++ ADLIBFX_Block = ( ( sound->block & 7 ) << 2 ) | 0x20; ++ ++ volume = min( volume, ADLIBFX_MaxVolume ); ++ volume = max( volume, 0 ); ++ ADLIBFX_SoundVolume = volume; ++ ++ volume *= ADLIBFX_TotalVolume; ++ volume /= ADLIBFX_MaxVolume; ++ ++ carrierlevel = sound->cScale & 0x3f; ++ carrierlevel ^= 0x3f; ++ carrierlevel *= ( volume / 2 ) + 0x80; ++ carrierlevel /= ADLIBFX_MaxVolume; ++ carrierlevel ^= 0x3f; ++ carrierlevel |= sound->cScale & 0xc0; ++ ++ ADLIBFX_SendOutput( 0x20, sound->mChar ); ++ ADLIBFX_SendOutput( 0x40, sound->mScale ); ++ ADLIBFX_SendOutput( 0x60, sound->mAttack ); ++ ADLIBFX_SendOutput( 0x80, sound->mSus ); ++ ADLIBFX_SendOutput( 0xe0, sound->mWave ); ++ ++ ADLIBFX_SendOutput( 0x23, sound->cChar ); ++ ADLIBFX_SendOutput( 0x43, carrierlevel ); ++ ADLIBFX_SendOutput( 0x63, sound->cAttack ); ++ ADLIBFX_SendOutput( 0x83, sound->cSus ); ++ ADLIBFX_SendOutput( 0xe3, sound->cWave ); ++ ++ ADLIBFX_SendOutput( 0xc0, 0 ); ++ ++ RestoreInterrupts( flags ); ++ ++ return( ADLIBFX_VoiceHandle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_SoundPlaying ++ ++ Checks if a sound effect is currently playing. ++---------------------------------------------------------------------*/ ++ ++int ADLIBFX_SoundPlaying ++ ( ++ int handle ++ ) ++ ++ { ++ int status; ++ ++ status = FALSE; ++ if ( ( handle == ADLIBFX_VoiceHandle ) && ( ADLIBFX_LengthLeft > 0 ) ) ++ { ++ status = TRUE; ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void ADLIBFX_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_SetCallBack ++ ++ Set the function to call when a voice stops. ++---------------------------------------------------------------------*/ ++ ++void ADLIBFX_SetCallBack ++ ( ++ void ( *function )( unsigned long ) ++ ) ++ ++ { ++ ADLIBFX_CallBackFunc = function; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_Init ++ ++ Initializes the sound effect engine. ++---------------------------------------------------------------------*/ ++ ++int ADLIBFX_Init ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ if ( ADLIBFX_Installed ) ++ { ++ ADLIBFX_Shutdown(); ++ } ++ ++ status = DPMI_LockMemoryRegion( ADLIBFX_LockStart, ADLIBFX_LockEnd ); ++ status |= DPMI_Lock( ADLIBFX_VoiceHandle ); ++ status |= DPMI_Lock( ADLIBFX_Sound ); ++ status |= DPMI_Lock( ADLIBFX_ErrorCode ); ++ status |= DPMI_Lock( ADLIBFX_SoundPtr ); ++ status |= DPMI_Lock( ADLIBFX_LengthLeft ); ++ status |= DPMI_Lock( ADLIBFX_Priority ); ++ status |= DPMI_Lock( ADLIBFX_CallBackFunc ); ++ status |= DPMI_Lock( ADLIBFX_Block ); ++ ++ if ( status != DPMI_Ok ) ++ { ++ ADLIBFX_SetErrorCode( ADLIBFX_DPMI_Error ); ++ return( ADLIBFX_Error ); ++ } ++ ++//JIM ++// AL_ReserveVoice( 0 ); ++ ADLIBFX_Stop( ADLIBFX_VoiceHandle ); ++ ADLIBFX_ServiceTask = TS_ScheduleTask( &ADLIBFX_Service, 140, 2, NULL ); ++ TS_Dispatch(); ++ ADLIBFX_Installed = TRUE; ++ ADLIBFX_CallBackFunc = NULL; ++ ++ ADLIBFX_SetErrorCode( ADLIBFX_Ok ); ++ return( ADLIBFX_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ADLIBFX_Shutdown ++ ++ Ends the use of the sound effect engine. ++---------------------------------------------------------------------*/ ++ ++int ADLIBFX_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ if ( ADLIBFX_Installed ) ++ { ++ ADLIBFX_Stop( ADLIBFX_VoiceHandle ); ++ TS_Terminate( ADLIBFX_ServiceTask ); ++ ADLIBFX_ServiceTask = NULL; ++//JIM ++// AL_ReleaseVoice( 0 ); ++ ADLIBFX_Installed = FALSE; ++ ++ DPMI_UnlockMemoryRegion( ADLIBFX_LockStart, ADLIBFX_LockEnd ); ++ DPMI_Unlock( ADLIBFX_VoiceHandle ); ++ DPMI_Unlock( ADLIBFX_Sound ); ++ DPMI_Unlock( ADLIBFX_ErrorCode ); ++ DPMI_Unlock( ADLIBFX_SoundPtr ); ++ DPMI_Unlock( ADLIBFX_LengthLeft ); ++ DPMI_Unlock( ADLIBFX_Priority ); ++ DPMI_Unlock( ADLIBFX_CallBackFunc ); ++ DPMI_Unlock( ADLIBFX_Block ); ++ } ++ ++ ADLIBFX_SetErrorCode( ADLIBFX_Ok ); ++ return( ADLIBFX_Ok ); ++ } +diff -urN rott-1.0/rott/audiolib/adlibfx.h trunk/rott/audiolib/adlibfx.h +--- rott-1.0/rott/audiolib/adlibfx.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/adlibfx.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,80 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: ADLIBFX.H ++ ++ author: James R. Dose ++ date: April 1, 1994 ++ ++ Public header for ADLIBFX.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __ADLIBFX_H ++#define __ADLIBFX_H ++ ++enum ADLIBFX_Errors ++ { ++ ADLIBFX_Warning = -2, ++ ADLIBFX_Error = -1, ++ ADLIBFX_Ok = 0, ++ ADLIBFX_NoVoices, ++ ADLIBFX_VoiceNotFound, ++ ADLIBFX_DPMI_Error ++ }; ++ ++typedef struct ++ { ++ unsigned long length; ++ short int priority; ++ char mChar, cChar; ++ char mScale, cScale; ++ char mAttack, cAttack; ++ char mSus, cSus; ++ char mWave, cWave; ++ char nConn; ++ char voice; ++ char mode; ++ char unused[ 3 ]; ++ char block; ++ char data[]; ++ } ALSound; ++ ++#define ADLIBFX_MaxVolume 255 ++#define ADLIBFX_MinVoiceHandle 1 ++ ++char *ADLIBFX_ErrorString( int ErrorNumber ); ++int ADLIBFX_Stop( int handle ); ++int ADLIBFX_SetVolume( int handle, int volume ); ++int ADLIBFX_SetTotalVolume( int volume ); ++int ADLIBFX_GetTotalVolume( void ); ++int ADLIBFX_VoiceAvailable( int priority ); ++int ADLIBFX_Play( ALSound *sound, int volume, int priority, unsigned long callbackval ); ++int ADLIBFX_SoundPlaying( int handle ); ++void ADLIBFX_SetCallBack( void ( *function )( unsigned long ) ); ++int ADLIBFX_Init( void ); ++int ADLIBFX_Shutdown( void ); ++ #pragma aux ADLIBFX_Shutdown frame; ++void PCFX_UnlockMemory( void ); ++ #pragma aux ADLIBFX_UnlockMemory frame; ++int PCFX_LockMemory( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/al_midi.c trunk/rott/audiolib/al_midi.c +--- rott-1.0/rott/audiolib/al_midi.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/al_midi.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,1510 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: AL_MIDI.C ++ ++ author: James R. Dose ++ date: April 1, 1994 ++ ++ Low level routines to support General MIDI music on Adlib compatible ++ cards. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include ++//#include ++#include "dpmi.h" ++#include "interrup.h" ++#include "sndcards.h" ++#include "blaster.h" ++#include "user.h" ++#include "al_midi.h" ++#include "_al_midi.h" ++#include "ll_man.h" ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++static unsigned OctavePitch[ MAX_OCTAVE + 1 ] = ++ { ++ OCTAVE_0, OCTAVE_1, OCTAVE_2, OCTAVE_3, ++ OCTAVE_4, OCTAVE_5, OCTAVE_6, OCTAVE_7, ++ }; ++ ++static unsigned NoteMod12[ MAX_NOTE + 1 ]; ++static unsigned NoteDiv12[ MAX_NOTE + 1 ]; ++ ++// Pitch table ++ ++//static unsigned NotePitch[ FINETUNE_MAX + 1 ][ 12 ] = ++// { ++// { C, C_SHARP, D, D_SHARP, E, F, F_SHARP, G, G_SHARP, A, A_SHARP, B }, ++// }; ++ ++static unsigned NotePitch[ FINETUNE_MAX + 1 ][ 12 ] = ++ { ++ { 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x287 }, ++ { 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x242, 0x264, 0x288 }, ++ { 0x158, 0x16c, 0x182, 0x199, 0x1b1, 0x1cb, 0x1e6, 0x203, 0x221, 0x243, 0x265, 0x289 }, ++ { 0x158, 0x16c, 0x183, 0x19a, 0x1b2, 0x1cc, 0x1e7, 0x204, 0x222, 0x244, 0x266, 0x28a }, ++ { 0x159, 0x16d, 0x183, 0x19a, 0x1b3, 0x1cd, 0x1e8, 0x205, 0x223, 0x245, 0x267, 0x28b }, ++ { 0x15a, 0x16e, 0x184, 0x19b, 0x1b3, 0x1ce, 0x1e9, 0x206, 0x224, 0x246, 0x268, 0x28c }, ++ { 0x15a, 0x16e, 0x185, 0x19c, 0x1b4, 0x1ce, 0x1ea, 0x207, 0x225, 0x247, 0x269, 0x28e }, ++ { 0x15b, 0x16f, 0x185, 0x19d, 0x1b5, 0x1cf, 0x1eb, 0x208, 0x226, 0x248, 0x26a, 0x28f }, ++ { 0x15b, 0x170, 0x186, 0x19d, 0x1b6, 0x1d0, 0x1ec, 0x209, 0x227, 0x249, 0x26b, 0x290 }, ++ { 0x15c, 0x170, 0x187, 0x19e, 0x1b7, 0x1d1, 0x1ec, 0x20a, 0x228, 0x24a, 0x26d, 0x291 }, ++ { 0x15d, 0x171, 0x188, 0x19f, 0x1b7, 0x1d2, 0x1ed, 0x20b, 0x229, 0x24b, 0x26e, 0x292 }, ++ { 0x15d, 0x172, 0x188, 0x1a0, 0x1b8, 0x1d3, 0x1ee, 0x20c, 0x22a, 0x24c, 0x26f, 0x293 }, ++ { 0x15e, 0x172, 0x189, 0x1a0, 0x1b9, 0x1d4, 0x1ef, 0x20d, 0x22b, 0x24d, 0x270, 0x295 }, ++ { 0x15f, 0x173, 0x18a, 0x1a1, 0x1ba, 0x1d4, 0x1f0, 0x20e, 0x22c, 0x24e, 0x271, 0x296 }, ++ { 0x15f, 0x174, 0x18a, 0x1a2, 0x1bb, 0x1d5, 0x1f1, 0x20f, 0x22d, 0x24f, 0x272, 0x297 }, ++ { 0x160, 0x174, 0x18b, 0x1a3, 0x1bb, 0x1d6, 0x1f2, 0x210, 0x22e, 0x250, 0x273, 0x298 }, ++ { 0x161, 0x175, 0x18c, 0x1a3, 0x1bc, 0x1d7, 0x1f3, 0x211, 0x22f, 0x251, 0x274, 0x299 }, ++ { 0x161, 0x176, 0x18c, 0x1a4, 0x1bd, 0x1d8, 0x1f4, 0x212, 0x230, 0x252, 0x276, 0x29b }, ++ { 0x162, 0x176, 0x18d, 0x1a5, 0x1be, 0x1d9, 0x1f5, 0x212, 0x231, 0x254, 0x277, 0x29c }, ++ { 0x162, 0x177, 0x18e, 0x1a6, 0x1bf, 0x1d9, 0x1f5, 0x213, 0x232, 0x255, 0x278, 0x29d }, ++ { 0x163, 0x178, 0x18f, 0x1a6, 0x1bf, 0x1da, 0x1f6, 0x214, 0x233, 0x256, 0x279, 0x29e }, ++ { 0x164, 0x179, 0x18f, 0x1a7, 0x1c0, 0x1db, 0x1f7, 0x215, 0x235, 0x257, 0x27a, 0x29f }, ++ { 0x164, 0x179, 0x190, 0x1a8, 0x1c1, 0x1dc, 0x1f8, 0x216, 0x236, 0x258, 0x27b, 0x2a1 }, ++ { 0x165, 0x17a, 0x191, 0x1a9, 0x1c2, 0x1dd, 0x1f9, 0x217, 0x237, 0x259, 0x27c, 0x2a2 }, ++ { 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1de, 0x1fa, 0x218, 0x238, 0x25a, 0x27e, 0x2a3 }, ++ { 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1df, 0x1fb, 0x219, 0x239, 0x25b, 0x27f, 0x2a4 }, ++ { 0x167, 0x17c, 0x193, 0x1ab, 0x1c4, 0x1e0, 0x1fc, 0x21a, 0x23a, 0x25c, 0x280, 0x2a6 }, ++ { 0x168, 0x17d, 0x194, 0x1ac, 0x1c5, 0x1e0, 0x1fd, 0x21b, 0x23b, 0x25d, 0x281, 0x2a7 }, ++ { 0x168, 0x17d, 0x194, 0x1ad, 0x1c6, 0x1e1, 0x1fe, 0x21c, 0x23c, 0x25e, 0x282, 0x2a8 }, ++ { 0x169, 0x17e, 0x195, 0x1ad, 0x1c7, 0x1e2, 0x1ff, 0x21d, 0x23d, 0x260, 0x283, 0x2a9 }, ++ { 0x16a, 0x17f, 0x196, 0x1ae, 0x1c8, 0x1e3, 0x1ff, 0x21e, 0x23e, 0x261, 0x284, 0x2ab }, ++ { 0x16a, 0x17f, 0x197, 0x1af, 0x1c8, 0x1e4, 0x200, 0x21f, 0x23f, 0x262, 0x286, 0x2ac } ++ }; ++ ++// Slot numbers as a function of the voice and the operator. ++// ( melodic only) ++ ++static int slotVoice[ NUM_VOICES ][ 2 ] = ++ { ++ { 0, 3 }, // voice 0 ++ { 1, 4 }, // 1 ++ { 2, 5 }, // 2 ++ { 6, 9 }, // 3 ++ { 7, 10 }, // 4 ++ { 8, 11 }, // 5 ++ { 12, 15 }, // 6 ++ { 13, 16 }, // 7 ++ { 14, 17 }, // 8 ++ }; ++ ++static int VoiceLevel[ NumChipSlots ][ 2 ]; ++static int VoiceKsl[ NumChipSlots ][ 2 ]; ++ ++// This table gives the offset of each slot within the chip. ++// offset = fn( slot) ++ ++static char offsetSlot[ NumChipSlots ] = ++ { ++ 0, 1, 2, 3, 4, 5, ++ 8, 9, 10, 11, 12, 13, ++ 16, 17, 18, 19, 20, 21 ++ }; ++ ++static int VoiceReserved[ NUM_VOICES * 2 ] = ++ { ++ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, ++ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE ++ }; ++ ++static VOICE Voice[ NUM_VOICES * 2 ]; ++static VOICELIST Voice_Pool; ++ ++static CHANNEL Channel[ NUM_CHANNELS ]; ++ ++static int AL_LeftPort = 0x388; ++static int AL_RightPort = 0x388; ++static int AL_Stereo = FALSE; ++static int AL_SendStereo = FALSE; ++static int AL_OPL3 = FALSE; ++static int AL_MaxMidiChannel = 16; ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define AL_LockStart AL_SendOutputToPort ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_SendOutputToPort ++ ++ Sends data to the Adlib using a specified port. ++---------------------------------------------------------------------*/ ++ ++void AL_SendOutputToPort ++ ( ++ int port, ++ int reg, ++ int data ++ ) ++ ++ { ++ int delay; ++ ++ outp( port, reg ); ++ ++ for( delay = 6; delay > 0 ; delay-- ) ++// for( delay = 2; delay > 0 ; delay-- ) ++ { ++ inp( port ); ++ } ++ ++ outp( port + 1, data ); ++ ++// for( delay = 35; delay > 0 ; delay-- ) ++ for( delay = 27; delay > 0 ; delay-- ) ++// for( delay = 2; delay > 0 ; delay-- ) ++ { ++ inp( port ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_SendOutput ++ ++ Sends data to the Adlib. ++---------------------------------------------------------------------*/ ++ ++void AL_SendOutput ++ ( ++ int voice, ++ int reg, ++ int data ++ ) ++ ++ { ++ int port; ++ ++ if ( AL_SendStereo ) ++ { ++ AL_SendOutputToPort( AL_LeftPort, reg, data ); ++ AL_SendOutputToPort( AL_RightPort, reg, data ); ++ } ++ else ++ { ++ port = ( voice == 0 ) ? AL_RightPort : AL_LeftPort; ++ AL_SendOutputToPort( port, reg, data ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_SetVoiceTimbre ++ ++ Programs the specified voice's timbre. ++---------------------------------------------------------------------*/ ++ ++static void AL_SetVoiceTimbre ++ ( ++ int voice ++ ) ++ ++ { ++ int off; ++ int slot; ++ int port; ++ int voc; ++ int patch; ++ int channel; ++ TIMBRE *timbre; ++ ++ channel = Voice[ voice ].channel; ++ ++ if ( channel == 9 ) ++ { ++ patch = Voice[ voice ].key + 128; ++ } ++ else ++ { ++ patch = Channel[ channel ].Timbre; ++ } ++ ++ if ( Voice[ voice ].timbre == patch ) ++ { ++ return; ++ } ++ ++ Voice[ voice ].timbre = patch; ++ timbre = &ADLIB_TimbreBank[ patch ]; ++ ++ port = Voice[ voice ].port; ++ voc = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice; ++ slot = slotVoice[ voc ][ 0 ]; ++ off = offsetSlot[ slot ]; ++ ++ VoiceLevel[ slot ][ port ] = 63 - ( timbre->Level[ 0 ] & 0x3f ); ++ VoiceKsl[ slot ][ port ] = timbre->Level[ 0 ] & 0xc0; ++ ++ AL_SendOutput( port, 0xA0 + voc, 0 ); ++ AL_SendOutput( port, 0xB0 + voc, 0 ); ++ ++ // Let voice clear the release ++ AL_SendOutput( port, 0x80 + off, 0xff ); ++ ++ AL_SendOutput( port, 0x60 + off, timbre->Env1[ 0 ] ); ++ AL_SendOutput( port, 0x80 + off, timbre->Env2[ 0 ] ); ++ AL_SendOutput( port, 0x20 + off, timbre->SAVEK[ 0 ] ); ++ AL_SendOutput( port, 0xE0 + off, timbre->Wave[ 0 ] ); ++ ++ AL_SendOutput( port, 0x40 + off, timbre->Level[ 0 ] ); ++ slot = slotVoice[ voc ][ 1 ]; ++ ++ if ( AL_SendStereo ) ++ { ++ AL_SendOutputToPort( AL_LeftPort, 0xC0 + voice, ++ ( timbre->Feedback & 0x0f ) | 0x20 ); ++ AL_SendOutputToPort( AL_RightPort, 0xC0 + voice, ++ ( timbre->Feedback & 0x0f ) | 0x10 ); ++ } ++ else ++ { ++ if ( AL_OPL3 ) ++ { ++ AL_SendOutput( port, 0xC0 + voc, ( timbre->Feedback & 0x0f ) | ++ 0x30 ); ++ } ++ else ++ { ++ AL_SendOutputToPort( ADLIB_PORT, 0xC0 + voice, timbre->Feedback ); ++ } ++ } ++ ++ off = offsetSlot[ slot ]; ++ ++ VoiceLevel[ slot ][ port ] = 63 - ( timbre->Level[ 1 ] & 0x3f ); ++ VoiceKsl[ slot ][ port ] = timbre->Level[ 1 ] & 0xc0; ++ AL_SendOutput( port, 0x40 + off, 63 ); ++ ++ // Let voice clear the release ++ AL_SendOutput( port, 0x80 + off, 0xff ); ++ ++ AL_SendOutput( port, 0x60 + off, timbre->Env1[ 1 ] ); ++ AL_SendOutput( port, 0x80 + off, timbre->Env2[ 1 ] ); ++ AL_SendOutput( port, 0x20 + off, timbre->SAVEK[ 1 ] ); ++ AL_SendOutput( port, 0xE0 + off, timbre->Wave[ 1 ] ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_SetVoiceVolume ++ ++ Sets the volume of the specified voice. ++---------------------------------------------------------------------*/ ++ ++static void AL_SetVoiceVolume ++ ( ++ int voice ++ ) ++ ++ { ++ int channel; ++ int velocity; ++ int slot; ++ int port; ++ int voc; ++ unsigned long t1; ++ unsigned long t2; ++ unsigned long volume; ++ TIMBRE *timbre; ++ ++ channel = Voice[ voice ].channel; ++ ++ timbre = &ADLIB_TimbreBank[ Voice[ voice ].timbre ]; ++ ++ velocity = Voice[ voice ].velocity + timbre->Velocity; ++ velocity = min( velocity, MAX_VELOCITY ); ++ ++ voc = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice; ++ slot = slotVoice[ voc ][ 1 ]; ++ port = Voice[ voice ].port; ++ ++ // amplitude ++ t1 = ( unsigned )VoiceLevel[ slot ][ port ]; ++ t1 *= ( velocity + 0x80 ); ++ t1 = ( Channel[ channel ].Volume * t1 ) >> 15; ++ ++ if ( !AL_SendStereo ) ++ { ++ volume = t1 ^ 63; ++ volume |= ( unsigned )VoiceKsl[ slot ][ port ]; ++ ++ AL_SendOutput( port, 0x40 + offsetSlot[ slot ], volume ); ++ ++ // Check if this timbre is Additive ++ if ( timbre->Feedback & 0x01 ) ++ { ++ slot = slotVoice[ voc ][ 0 ]; ++ ++ // amplitude ++ t2 = ( unsigned )VoiceLevel[ slot ][ port ]; ++ t2 *= ( velocity + 0x80 ); ++ t2 = ( Channel[ channel ].Volume * t1 ) >> 15; ++ ++ volume = t2 ^ 63; ++ volume |= ( unsigned )VoiceKsl[ slot ][ port ]; ++ ++ AL_SendOutput( port, 0x40 + offsetSlot[ slot ], volume ); ++ } ++ } ++ else ++ { ++ // Set left channel volume ++ volume = t1; ++ if ( Channel[ channel ].Pan < 64 ) ++ { ++ volume *= Channel[ channel ].Pan; ++ volume >>= 6; ++ } ++ ++ volume ^= 63; ++ volume |= ( unsigned )VoiceKsl[ slot ][ port ]; ++ ++ AL_SendOutputToPort( AL_LeftPort, 0x40 + offsetSlot[ slot ], volume ); ++ ++ // Set right channel volume ++ volume = t1; ++ if ( Channel[ channel ].Pan > 64 ) ++ { ++ volume *= 127 - Channel[ channel ].Pan; ++ volume >>= 6; ++ } ++ ++ volume ^= 63; ++ volume |= ( unsigned )VoiceKsl[ slot ][ port ]; ++ ++ AL_SendOutputToPort( AL_RightPort, 0x40 + offsetSlot[ slot ], volume ); ++ ++ // Check if this timbre is Additive ++ if ( timbre->Feedback & 0x01 ) ++ { ++ // amplitude ++ t2 = ( unsigned )VoiceLevel[ slot ][ port ]; ++ t2 *= ( velocity + 0x80 ); ++ t2 = ( Channel[ channel ].Volume * t1 ) >> 15; ++ ++ slot = slotVoice[ voc ][ 0 ]; ++ ++ // Set left channel volume ++ volume = t2; ++ if ( Channel[ channel ].Pan < 64 ) ++ { ++ volume *= Channel[ channel ].Pan; ++ volume >>= 6; ++ } ++ ++ volume ^= 63; ++ volume |= ( unsigned )VoiceKsl[ slot ][ port ]; ++ ++ AL_SendOutputToPort( AL_LeftPort, 0x40 + offsetSlot[ slot ], volume ); ++ ++ // Set right channel volume ++ volume = t2; ++ if ( Channel[ channel ].Pan > 64 ) ++ { ++ volume *= 127 - Channel[ channel ].Pan; ++ volume >>= 6; ++ } ++ ++ volume ^= 63; ++ volume |= ( unsigned )VoiceKsl[ slot ][ port ]; ++ ++ AL_SendOutputToPort( AL_RightPort, 0x40 + offsetSlot[ slot ], volume ); ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_AllocVoice ++ ++ Retrieves a free voice from the voice pool. ++---------------------------------------------------------------------*/ ++ ++static int AL_AllocVoice ++ ( ++ void ++ ) ++ ++ { ++ int voice; ++ ++ if ( Voice_Pool.start ) ++ { ++ voice = Voice_Pool.start->num; ++ LL_Remove( VOICE, &Voice_Pool, &Voice[ voice ] ); ++ return( voice ); ++ } ++ ++ return( AL_VoiceNotFound ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_GetVoice ++ ++ Determines which voice is associated with a specified note and ++ MIDI channel. ++---------------------------------------------------------------------*/ ++ ++static int AL_GetVoice ++ ( ++ int channel, ++ int key ++ ) ++ ++ { ++ VOICE *voice; ++ ++ voice = Channel[ channel ].Voices.start; ++ ++ while( voice != NULL ) ++ { ++ if ( voice->key == key ) ++ { ++ return( voice->num ); ++ } ++ voice = voice->next; ++ } ++ ++ return( AL_VoiceNotFound ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_SetVoicePitch ++ ++ Programs the pitch of the specified voice. ++---------------------------------------------------------------------*/ ++ ++static void AL_SetVoicePitch ++ ( ++ int voice ++ ) ++ ++ { ++ int note; ++ int channel; ++ int patch; ++ int detune; ++ int ScaleNote; ++ int Octave; ++ int pitch; ++ int port; ++ int voc; ++ ++ port = Voice[ voice ].port; ++ voc = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice; ++ channel = Voice[ voice ].channel; ++ ++ if ( channel == 9 ) ++ { ++ patch = Voice[ voice ].key + 128; ++ note = ADLIB_TimbreBank[ patch ].Transpose; ++ } ++ else ++ { ++ patch = Channel[ channel ].Timbre; ++ note = Voice[ voice ].key + ADLIB_TimbreBank[ patch ].Transpose; ++ } ++ ++ note += Channel[ channel ].KeyOffset - 12; ++ if ( note > MAX_NOTE ) ++ { ++ note = MAX_NOTE; ++ } ++ if ( note < 0 ) ++ { ++ note = 0; ++ } ++ ++ detune = Channel[ channel ].KeyDetune; ++ ++ ScaleNote = NoteMod12[ note ]; ++ Octave = NoteDiv12[ note ]; ++ ++ pitch = OctavePitch[ Octave ] | NotePitch[ detune ][ ScaleNote ]; ++ ++ Voice[ voice ].pitchleft = pitch; ++ ++ pitch |= Voice[ voice ].status; ++ ++ if ( !AL_SendStereo ) ++ { ++ AL_SendOutput( port, 0xA0 + voc, pitch ); ++ AL_SendOutput( port, 0xB0 + voc, pitch >> 8 ); ++ } ++ else ++ { ++ AL_SendOutputToPort( AL_LeftPort, 0xA0 + voice, pitch ); ++ AL_SendOutputToPort( AL_LeftPort, 0xB0 + voice, pitch >> 8 ); ++ ++ if ( channel != 9 ) ++ { ++ detune += STEREO_DETUNE; ++ } ++ ++ if ( detune > FINETUNE_MAX ) ++ { ++ detune -= FINETUNE_RANGE; ++ if ( note < MAX_NOTE ) ++ { ++ note++; ++ ScaleNote = NoteMod12[ note ]; ++ Octave = NoteDiv12[ note ]; ++ } ++ } ++ ++ pitch = OctavePitch[ Octave ] | NotePitch[ detune ][ ScaleNote ]; ++ ++ Voice[ voice ].pitchright = pitch; ++ ++ pitch |= Voice[ voice ].status; ++ ++ AL_SendOutputToPort( AL_RightPort, 0xA0 + voice, pitch ); ++ AL_SendOutputToPort( AL_RightPort, 0xB0 + voice, pitch >> 8 ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_SetChannelVolume ++ ++ Sets the volume of the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++static void AL_SetChannelVolume ++ ( ++ int channel, ++ int volume ++ ) ++ ++ { ++ VOICE *voice; ++ ++ volume = max( 0, volume ); ++ volume = min( volume, AL_MaxVolume ); ++ Channel[ channel ].Volume = volume; ++ ++ voice = Channel[ channel ].Voices.start; ++ while( voice != NULL ) ++ { ++ AL_SetVoiceVolume( voice->num ); ++ voice = voice->next; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_SetChannelPan ++ ++ Sets the pan position of the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++static void AL_SetChannelPan ++ ( ++ int channel, ++ int pan ++ ) ++ ++ { ++ // Don't pan drum sounds ++ if ( channel != 9 ) ++ { ++ Channel[ channel ].Pan = pan; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_SetChannelDetune ++ ++ Sets the stereo voice detune of the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++static void AL_SetChannelDetune ++ ( ++ int channel, ++ int detune ++ ) ++ ++ { ++ Channel[ channel ].Detune = detune; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_ResetVoices ++ ++ Sets all voice info to the default state. ++---------------------------------------------------------------------*/ ++ ++static void AL_ResetVoices ++ ( ++ void ++ ) ++ ++ { ++ int index; ++ int numvoices; ++ ++ Voice_Pool.start = NULL; ++ Voice_Pool.end = NULL; ++ ++ numvoices = NUM_VOICES; ++ if ( ( AL_OPL3 ) && ( !AL_Stereo ) ) ++ { ++ numvoices = NUM_VOICES * 2; ++ } ++ for( index = 0; index < numvoices; index++ ) ++ { ++ if ( VoiceReserved[ index ] == FALSE ) ++ { ++ Voice[ index ].num = index; ++ Voice[ index ].key = 0; ++ Voice[ index ].velocity = 0; ++ Voice[ index ].channel = -1; ++ Voice[ index ].timbre = -1; ++ Voice[ index ].port = ( index < NUM_VOICES ) ? 0 : 1; ++ Voice[ index ].status = NOTE_OFF; ++ LL_AddToTail( VOICE, &Voice_Pool, &Voice[ index ] ); ++ } ++ } ++ ++ for( index = 0; index < NUM_CHANNELS; index++ ) ++ { ++ Channel[ index ].Voices.start = NULL; ++ Channel[ index ].Voices.end = NULL; ++ Channel[ index ].Timbre = 0; ++ Channel[ index ].Pitchbend = 0; ++ Channel[ index ].KeyOffset = 0; ++ Channel[ index ].KeyDetune = 0; ++ Channel[ index ].Volume = AL_DefaultChannelVolume; ++ Channel[ index ].Pan = 64; ++ Channel[ index ].RPN = 0; ++ Channel[ index ].PitchBendRange = AL_DefaultPitchBendRange; ++ Channel[ index ].PitchBendSemiTones = AL_DefaultPitchBendRange / 100; ++ Channel[ index ].PitchBendHundreds = AL_DefaultPitchBendRange % 100; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_CalcPitchInfo ++ ++ Calculates the pitch table. ++---------------------------------------------------------------------*/ ++ ++static void AL_CalcPitchInfo ++ ( ++ void ++ ) ++ ++ { ++ int note; ++// int finetune; ++// double detune; ++ ++ for( note = 0; note <= MAX_NOTE; note++ ) ++ { ++ NoteMod12[ note ] = note % 12; ++ NoteDiv12[ note ] = note / 12; ++ } ++ ++// for( finetune = 1; finetune <= FINETUNE_MAX; finetune++ ) ++// { ++// detune = pow( 2, ( double )finetune / ( 12.0 * FINETUNE_RANGE ) ); ++// for( note = 0; note < 12; note++ ) ++// { ++// NotePitch[ finetune ][ note ] = ( ( double )NotePitch[ 0 ][ note ] * detune ); ++// } ++// } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_FlushCard ++ ++ Sets all voices to a known (quiet) state. ++---------------------------------------------------------------------*/ ++ ++void AL_FlushCard ++ ( ++ int port ++ ) ++ ++ { ++ int i; ++ unsigned slot1; ++ unsigned slot2; ++ ++ for( i = 0 ; i < NUM_VOICES; i++ ) ++ { ++ if ( VoiceReserved[ i ] == FALSE ) ++ { ++ slot1 = offsetSlot[ slotVoice[ i ][ 0 ] ]; ++ slot2 = offsetSlot[ slotVoice[ i ][ 1 ] ]; ++ ++ AL_SendOutputToPort( port, 0xA0 + i, 0 ); ++ AL_SendOutputToPort( port, 0xB0 + i, 0 ); ++ ++ AL_SendOutputToPort( port, 0xE0 + slot1, 0 ); ++ AL_SendOutputToPort( port, 0xE0 + slot2, 0 ); ++ ++ // Set the envelope to be fast and quiet ++ AL_SendOutputToPort( port, 0x60 + slot1, 0xff ); ++ AL_SendOutputToPort( port, 0x60 + slot2, 0xff ); ++ AL_SendOutputToPort( port, 0x80 + slot1, 0xff ); ++ AL_SendOutputToPort( port, 0x80 + slot2, 0xff ); ++ ++ // Maximum attenuation ++ AL_SendOutputToPort( port, 0x40 + slot1, 0xff ); ++ AL_SendOutputToPort( port, 0x40 + slot2, 0xff ); ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_StereoOn ++ ++ Sets the card send info in stereo. ++---------------------------------------------------------------------*/ ++ ++void AL_StereoOn ++ ( ++ void ++ ) ++ ++ { ++ if ( ( AL_Stereo ) && ( !AL_SendStereo ) ) ++ { ++ AL_SendStereo = TRUE; ++ if ( AL_OPL3 ) ++ { ++ // Set card to OPL3 operation ++ AL_SendOutputToPort( AL_RightPort, 0x5, 1 ); ++ } ++ } ++ else if ( AL_OPL3 ) ++ { ++ // Set card to OPL3 operation ++ AL_SendOutputToPort( AL_RightPort, 0x5, 1 ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_StereoOff ++ ++ Sets the card send info in mono. ++---------------------------------------------------------------------*/ ++ ++void AL_StereoOff ++ ( ++ void ++ ) ++ ++ { ++ if ( ( AL_Stereo ) && ( AL_SendStereo ) ) ++ { ++ AL_SendStereo = FALSE; ++ if ( AL_OPL3 ) ++ { ++ // Set card back to OPL2 operation ++ AL_SendOutputToPort( AL_RightPort, 0x5, 0 ); ++ } ++ } ++ else if ( AL_OPL3 ) ++ { ++ // Set card back to OPL2 operation ++ AL_SendOutputToPort( AL_RightPort, 0x5, 0 ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_Reset ++ ++ Sets the card to a known (quiet) state. ++---------------------------------------------------------------------*/ ++ ++void AL_Reset ++ ( ++ void ++ ) ++ ++ { ++ AL_SendOutputToPort( ADLIB_PORT, 1, 0x20 ); ++ AL_SendOutputToPort( ADLIB_PORT, 0x08, 0 ); ++ ++ // Set the values: AM Depth, VIB depth & Rhythm ++ AL_SendOutputToPort( ADLIB_PORT, 0xBD, 0 ); ++ ++ AL_StereoOn(); ++ ++ if ( ( AL_SendStereo ) || ( AL_OPL3 ) ) ++ { ++ AL_FlushCard( AL_LeftPort ); ++ AL_FlushCard( AL_RightPort ); ++ } ++ else ++ { ++ AL_FlushCard( ADLIB_PORT ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_ReserveVoice ++ ++ Marks a voice as being not available for use. This allows the ++ driver to use the rest of the card while another driver uses the ++ reserved voice. ++---------------------------------------------------------------------*/ ++ ++int AL_ReserveVoice ++ ( ++ int voice ++ ) ++ ++ { ++ unsigned flags; ++ ++ if ( ( voice < 0 ) || ( voice >= NUM_VOICES ) ) ++ { ++ return( AL_Error ); ++ } ++ ++ if ( VoiceReserved[ voice ] ) ++ { ++ return( AL_Warning ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ if ( Voice[ voice ].status == NOTE_ON ) ++ { ++ AL_NoteOff( Voice[ voice ].channel, Voice[ voice ].key, 0 ); ++ } ++ ++ VoiceReserved[ voice ] = TRUE; ++ LL_Remove( VOICE, &Voice_Pool, &Voice[ voice ] ); ++ ++ RestoreInterrupts( flags ); ++ return( AL_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_ReleaseVoice ++ ++ Marks a previously reserved voice as being free to use. ++---------------------------------------------------------------------*/ ++ ++int AL_ReleaseVoice ++ ( ++ int voice ++ ) ++ ++ { ++ unsigned flags; ++ ++ if ( ( voice < 0 ) || ( voice >= NUM_VOICES ) ) ++ { ++ return( AL_Error ); ++ } ++ ++ if ( !VoiceReserved[ voice ] ) ++ { ++ return( AL_Warning ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ VoiceReserved[ voice ] = FALSE; ++ LL_AddToTail( VOICE, &Voice_Pool, &Voice[ voice ] ); ++ ++ RestoreInterrupts( flags ); ++ return( AL_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_NoteOff ++ ++ Turns off a note on the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++void AL_NoteOff ++ ( ++ int channel, ++ int key, ++ int velocity ++ ) ++ ++ { ++ int voice; ++ int port; ++ int voc; ++ ++ // We only play channels 1 through 10 ++ if ( channel > AL_MaxMidiChannel ) ++ { ++ return; ++ } ++ ++ voice = AL_GetVoice( channel, key ); ++ ++ if ( voice == AL_VoiceNotFound ) ++ { ++ return; ++ } ++ ++ Voice[ voice ].status = NOTE_OFF; ++ ++ port = Voice[ voice ].port; ++ voc = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice; ++ ++ if ( AL_SendStereo ) ++ { ++ AL_SendOutputToPort( AL_LeftPort, 0xB0 + voice, ++ hibyte( Voice[ voice ].pitchleft ) ); ++ AL_SendOutputToPort( AL_RightPort, 0xB0 + voice, ++ hibyte( Voice[ voice ].pitchright ) ); ++ } ++ else ++ { ++ AL_SendOutput( port, 0xB0 + voc, hibyte( Voice[ voice ].pitchleft ) ); ++ } ++ ++ LL_Remove( VOICE, &Channel[ channel ].Voices, &Voice[ voice ] ); ++ LL_AddToTail( VOICE, &Voice_Pool, &Voice[ voice ] ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_NoteOn ++ ++ Plays a note on the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++void AL_NoteOn ++ ( ++ int channel, ++ int key, ++ int velocity ++ ) ++ ++ { ++ int voice; ++ ++ // We only play channels 1 through 10 ++ if ( channel > AL_MaxMidiChannel ) ++ { ++ return; ++ } ++ ++ if ( velocity == 0 ) ++ { ++ AL_NoteOff( channel, key, velocity ); ++ return; ++ } ++ ++ voice = AL_AllocVoice(); ++ ++ if ( voice == AL_VoiceNotFound ) ++ { ++ if ( Channel[ 9 ].Voices.start ) ++ { ++ AL_NoteOff( 9, Channel[ 9 ].Voices.start->key, 0 ); ++ voice = AL_AllocVoice(); ++ } ++ if ( voice == AL_VoiceNotFound ) ++ { ++ return; ++ } ++ } ++ ++ Voice[ voice ].key = key; ++ Voice[ voice ].channel = channel; ++ Voice[ voice ].velocity = velocity; ++ Voice[ voice ].status = NOTE_ON; ++ ++ LL_AddToTail( VOICE, &Channel[ channel ].Voices, &Voice[ voice ] ); ++ ++ AL_SetVoiceTimbre( voice ); ++ AL_SetVoiceVolume( voice ); ++ AL_SetVoicePitch( voice ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_AllNotesOff ++ ++ Turns off all currently playing voices. ++---------------------------------------------------------------------*/ ++ ++void AL_AllNotesOff ++ ( ++ int channel ++ ) ++ ++ { ++ while( Channel[ channel ].Voices.start != NULL ) ++ { ++ AL_NoteOff( channel, Channel[ channel ].Voices.start->key, 0 ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_ControlChange ++ ++ Sets the value of a controller on the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++void AL_ControlChange ++ ( ++ int channel, ++ int type, ++ int data ++ ) ++ ++ { ++ // We only play channels 1 through 10 ++ if ( channel > AL_MaxMidiChannel ) ++ { ++ return; ++ } ++ ++ switch( type ) ++ { ++ case MIDI_VOLUME : ++ AL_SetChannelVolume( channel, data ); ++ break; ++ ++ case MIDI_PAN : ++ AL_SetChannelPan( channel, data ); ++ break; ++ ++ case MIDI_DETUNE : ++ AL_SetChannelDetune( channel, data ); ++ break; ++ ++ case MIDI_ALL_NOTES_OFF : ++ AL_AllNotesOff( channel ); ++ break; ++ ++ case MIDI_RESET_ALL_CONTROLLERS : ++ AL_ResetVoices(); ++ AL_SetChannelVolume( channel, AL_DefaultChannelVolume ); ++ AL_SetChannelPan( channel, 64 ); ++ AL_SetChannelDetune( channel, 0 ); ++ break; ++ ++ case MIDI_RPN_MSB : ++ Channel[ channel ].RPN &= 0x00FF; ++ Channel[ channel ].RPN |= ( data & 0xFF ) << 8; ++ break; ++ ++ case MIDI_RPN_LSB : ++ Channel[ channel ].RPN &= 0xFF00; ++ Channel[ channel ].RPN |= data & 0xFF; ++ break; ++ ++ case MIDI_DATAENTRY_MSB : ++ if ( Channel[ channel ].RPN == MIDI_PITCHBEND_RPN ) ++ { ++ Channel[ channel ].PitchBendSemiTones = data; ++ Channel[ channel ].PitchBendRange = ++ Channel[ channel ].PitchBendSemiTones * 100 + ++ Channel[ channel ].PitchBendHundreds; ++ } ++ break; ++ ++ case MIDI_DATAENTRY_LSB : ++ if ( Channel[ channel ].RPN == MIDI_PITCHBEND_RPN ) ++ { ++ Channel[ channel ].PitchBendHundreds = data; ++ Channel[ channel ].PitchBendRange = ++ Channel[ channel ].PitchBendSemiTones * 100 + ++ Channel[ channel ].PitchBendHundreds; ++ } ++ break; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_ProgramChange ++ ++ Selects the instrument to use on the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++void AL_ProgramChange ++ ( ++ int channel, ++ int patch ++ ) ++ ++ { ++ // We only play channels 1 through 10 ++ if ( channel > AL_MaxMidiChannel ) ++ { ++ return; ++ } ++ ++ Channel[ channel ].Timbre = patch; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_SetPitchBend ++ ++ Sets the pitch bend amount on the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++void AL_SetPitchBend ++ ( ++ int channel, ++ int lsb, ++ int msb ++ ) ++ ++ { ++ int pitchbend; ++ unsigned long TotalBend; ++ VOICE *voice; ++ ++ // We only play channels 1 through 10 ++ if ( channel > AL_MaxMidiChannel ) ++ { ++ return; ++ } ++ ++ pitchbend = lsb + ( msb << 8 ); ++ Channel[ channel ].Pitchbend = pitchbend; ++ ++ TotalBend = pitchbend * Channel[ channel ].PitchBendRange; ++ TotalBend /= ( PITCHBEND_CENTER / FINETUNE_RANGE ); ++ ++ Channel[ channel ].KeyOffset = ( int )( TotalBend / FINETUNE_RANGE ); ++ Channel[ channel ].KeyOffset -= Channel[ channel ].PitchBendSemiTones; ++ ++ Channel[ channel ].KeyDetune = ( unsigned )( TotalBend % FINETUNE_RANGE ); ++ ++ voice = Channel[ channel ].Voices.start; ++ while( voice != NULL ) ++ { ++ AL_SetVoicePitch( voice->num ); ++ voice = voice->next; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_DetectFM ++ ++ Determines if an Adlib compatible card is installed in the machine. ++---------------------------------------------------------------------*/ ++ ++int AL_DetectFM ++ ( ++ void ++ ) ++ ++ { ++ int status1; ++ int status2; ++ int i; ++ ++ if ( USER_CheckParameter( NO_ADLIB_DETECTION ) ) ++ { ++ return( FALSE ); ++ } ++ ++ AL_SendOutputToPort( ADLIB_PORT, 4, 0x60 ); // Reset T1 & T2 ++ AL_SendOutputToPort( ADLIB_PORT, 4, 0x80 ); // Reset IRQ ++ ++ status1 = inp( ADLIB_PORT ); ++ ++ AL_SendOutputToPort( ADLIB_PORT, 2, 0xff ); // Set timer 1 ++ AL_SendOutputToPort( ADLIB_PORT, 4, 0x21 ); // Start timer 1 ++ ++ for( i = 100; i > 0; i-- ) ++ { ++ inp( ADLIB_PORT ); ++ } ++ ++ status2 = inp( ADLIB_PORT ); ++ ++ AL_SendOutputToPort( ADLIB_PORT, 4, 0x60 ); ++ AL_SendOutputToPort( ADLIB_PORT, 4, 0x80 ); ++ ++ return( ( ( status1 & 0xe0 ) == 0x00 ) && ( ( status2 & 0xe0 ) == 0xc0 ) ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void AL_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_Shutdown ++ ++ Ends use of the sound card and resets it to a quiet state. ++---------------------------------------------------------------------*/ ++ ++void AL_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ AL_StereoOff(); ++ ++ AL_OPL3 = FALSE; ++ AL_ResetVoices(); ++ AL_Reset(); ++ ++ DPMI_UnlockMemoryRegion( AL_LockStart, AL_LockEnd ); ++ DPMI_Unlock( slotVoice ); ++ DPMI_Unlock( VoiceLevel ); ++ DPMI_Unlock( VoiceKsl ); ++ DPMI_Unlock( offsetSlot ); ++ DPMI_Unlock( NotePitch ); ++ DPMI_Unlock( OctavePitch ); ++ DPMI_Unlock( NoteMod12 ); ++ DPMI_Unlock( NoteDiv12 ); ++ DPMI_Unlock( VoiceReserved ); ++ DPMI_Unlock( Voice ); ++ DPMI_Unlock( Voice_Pool ); ++ DPMI_Unlock( Channel ); ++ DPMI_Unlock( AL_LeftPort ); ++ DPMI_Unlock( AL_RightPort ); ++ DPMI_Unlock( AL_Stereo ); ++ DPMI_Unlock( AL_SendStereo ); ++ DPMI_Unlock( AL_OPL3 ); ++ DPMI_Unlock( AL_MaxMidiChannel ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_SetMaxMidiChannel ++ ++ Sets the maximum MIDI channel that FM cards respond to. ++---------------------------------------------------------------------*/ ++ ++void AL_SetMaxMidiChannel ++ ( ++ int channel ++ ) ++ ++ { ++ AL_MaxMidiChannel = channel - 1; ++ } ++ ++/*--------------------------------------------------------------------- ++ Function: AL_Init ++ ++ Begins use of the sound card. ++---------------------------------------------------------------------*/ ++ ++int AL_Init ++ ( ++ int soundcard ++ ) ++ ++ { ++ BLASTER_CONFIG Blaster; ++ int status; ++ ++ status = DPMI_LockMemoryRegion( AL_LockStart, AL_LockEnd ); ++ status |= DPMI_Lock( slotVoice ); ++ status |= DPMI_Lock( VoiceLevel ); ++ status |= DPMI_Lock( VoiceKsl ); ++ status |= DPMI_Lock( offsetSlot ); ++ status |= DPMI_Lock( NotePitch ); ++ status |= DPMI_Lock( OctavePitch ); ++ status |= DPMI_Lock( NoteMod12 ); ++ status |= DPMI_Lock( NoteDiv12 ); ++ status |= DPMI_Lock( VoiceReserved ); ++ status |= DPMI_Lock( Voice ); ++ status |= DPMI_Lock( Voice_Pool ); ++ status |= DPMI_Lock( Channel ); ++ status |= DPMI_Lock( AL_LeftPort ); ++ status |= DPMI_Lock( AL_RightPort ); ++ status |= DPMI_Lock( AL_Stereo ); ++ status |= DPMI_Lock( AL_SendStereo ); ++ status |= DPMI_Lock( AL_OPL3 ); ++ status |= DPMI_Lock( AL_MaxMidiChannel ); ++ ++ if ( status != DPMI_Ok ) ++ { ++ return( AL_Error ); ++ } ++ ++ AL_Stereo = FALSE; ++ AL_OPL3 = FALSE; ++ AL_LeftPort = 0x388; ++ AL_RightPort = 0x388; ++ ++ switch( soundcard ) ++ { ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ AL_OPL3 = TRUE; ++ AL_LeftPort = 0x388; ++ AL_RightPort = 0x38A; ++ break; ++ ++ case SoundBlaster : ++ status = BLASTER_GetCardSettings( &Blaster ); ++ if ( status != BLASTER_Ok ) ++ { ++ status = BLASTER_GetEnv( &Blaster ); ++ if ( status != BLASTER_Ok ) ++ { ++ break; ++ } ++ } ++ ++ switch( Blaster.Type ) ++ { ++ case SBPro2 : ++ case SB16 : ++ AL_OPL3 = TRUE; ++ AL_LeftPort = Blaster.Address; ++ AL_RightPort = Blaster.Address + 2; ++ break; ++ } ++ break; ++ } ++// Temporarally commented out for ROTT. ++// Stereo FM seems to take too long on some computers and ++// causes the mouse driver to miss interrupts. ++ ++/* ++ switch( soundcard ) ++ { ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ AL_OPL3 = TRUE; ++ AL_Stereo = TRUE; ++ AL_LeftPort = 0x388; ++ AL_RightPort = 0x38A; ++ break; ++ ++ case SoundBlaster : ++ status = BLASTER_GetCardSettings( &Blaster ); ++ if ( status != BLASTER_Ok ) ++ { ++ status = BLASTER_GetEnv( &Blaster ); ++ if ( status != BLASTER_Ok ) ++ { ++ break; ++ } ++ } ++ ++ switch( Blaster.Type ) ++ { ++ case SBPro2 : ++ case SB16 : ++ AL_OPL3 = TRUE; ++ AL_Stereo = TRUE; ++ AL_LeftPort = Blaster.Address; ++ AL_RightPort = Blaster.Address + 2; ++ break; ++ ++ case SBPro : ++ AL_Stereo = TRUE; ++ AL_LeftPort = Blaster.Address; ++ AL_RightPort = Blaster.Address + 2; ++ break; ++ } ++ break; ++ } ++*/ ++ ++ AL_CalcPitchInfo(); ++ AL_Reset(); ++ AL_ResetVoices(); ++ ++ return( AL_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AL_RegisterTimbreBank ++ ++ Copies user supplied timbres over the default timbre bank. ++---------------------------------------------------------------------*/ ++ ++void AL_RegisterTimbreBank ++ ( ++ unsigned char *timbres ++ ) ++ ++ { ++ int i; ++ ++ for( i = 0; i < 256; i++ ) ++ { ++ ADLIB_TimbreBank[ i ].SAVEK[ 0 ] = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].SAVEK[ 1 ] = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].Level[ 0 ] = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].Level[ 1 ] = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].Env1[ 0 ] = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].Env1[ 1 ] = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].Env2[ 0 ] = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].Env2[ 1 ] = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].Wave[ 0 ] = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].Wave[ 1 ] = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].Feedback = *( timbres++ ); ++ ADLIB_TimbreBank[ i ].Transpose = *( signed char * )( timbres++ ); ++ ADLIB_TimbreBank[ i ].Velocity = *( signed char * )( timbres++ ); ++ } ++ } +diff -urN rott-1.0/rott/audiolib/al_midi.h trunk/rott/audiolib/al_midi.h +--- rott-1.0/rott/audiolib/al_midi.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/al_midi.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,58 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++#ifndef __AL_MIDI_H ++#define __AL_MIDI_H ++ ++enum AL_Errors ++ { ++ AL_Warning = -2, ++ AL_Error = -1, ++ AL_Ok = 0, ++ }; ++ ++#define AL_MaxVolume 127 ++#define AL_DefaultChannelVolume 90 ++//#define AL_DefaultPitchBendRange 2 ++#define AL_DefaultPitchBendRange 200 ++ ++#define ADLIB_PORT 0x388 ++ ++void AL_SendOutputToPort( int port, int reg, int data ); ++void AL_SendOutput( int voice, int reg, int data ); ++void AL_StereoOn( void ); ++void AL_StereoOff( void ); ++int AL_ReserveVoice( int voice ); ++int AL_ReleaseVoice( int voice ); ++void AL_Shutdown( void ); ++int AL_Init( int soundcard ); ++void AL_SetMaxMidiChannel( int channel ); ++void AL_Reset( void ); ++void AL_NoteOff( int channel, int key, int velocity ); ++void AL_NoteOn( int channel, int key, int vel ); ++//Turned off to test if it works with Watcom 10a ++// #pragma aux AL_NoteOn frame; ++void AL_AllNotesOff( int channel ); ++void AL_ControlChange( int channel, int type, int data ); ++void AL_ProgramChange( int channel, int patch ); ++void AL_SetPitchBend( int channel, int lsb, int msb ); ++int AL_DetectFM( void ); ++void AL_RegisterTimbreBank( unsigned char *timbres ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/assert.h trunk/rott/audiolib/assert.h +--- rott-1.0/rott/audiolib/assert.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/assert.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,45 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++#ifndef __ASSERT_H ++ ++ #define __ASSERT_H ++ ++ #ifdef NDEBUG ++ ++ #define ASSERT(f) ++ ++ #else ++ ++ #pragma aux _Assert aborts; /* _Assert will not return */ ++ extern void _Assert( char *strFile, unsigned uLine ); /*prototype */ ++ ++ #define ASSERT(f) \ ++ if (f) \ ++ ; \ ++ else \ ++ _Assert( __FILE__, __LINE__ ) ++ ++ #endif ++ ++#else ++ ++ #error Multiple definition of ASSERT() ++ ++#endif +diff -urN rott-1.0/rott/audiolib/awe32.c trunk/rott/audiolib/awe32.c +--- rott-1.0/rott/audiolib/awe32.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/awe32.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,540 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: AWE32.C ++ ++ author: James R. Dose ++ date: August 23, 1994 ++ ++ Cover functions for calling the AWE32 low-level library. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include "dpmi.h" ++#include "blaster.h" ++#include "ctaweapi.h" ++#include "awe32.h" ++ ++#define _inp inp ++#define _outp outp ++ ++/* DSP defines */ ++#define MPU_ACK_OK 0xfe ++#define MPU_RESET_CMD 0xff ++#define MPU_ENTER_UART 0x3f ++ ++static WORD wSBCBaseAddx; /* Sound Blaster base address */ ++static WORD wEMUBaseAddx; /* EMU8000 subsystem base address */ ++static WORD wMpuBaseAddx; /* MPU401 base address */ ++ ++static unsigned short NoteFlags[ 128 ]; ++ ++/* macros */ ++#define SBCPort( x ) ( ( x ) + wSBCBaseAddx ) ++#define MPUPort( x ) ( ( x ) + wMpuBaseAddx ) ++ ++static SOUND_PACKET spSound = ++ { ++ 0 ++ }; ++ ++static LONG lBankSizes[ MAXBANKS ] = ++ { ++ 0 ++ }; ++ ++unsigned SetES( void ); ++#pragma aux SetES = \ ++ "xor eax, eax" \ ++ "mov ax, es" \ ++ "mov bx, ds" \ ++ "mov es, bx" \ ++ modify [ eax ebx ]; ++ ++void RestoreES( unsigned num ); ++#pragma aux RestoreES = \ ++ "mov es, ax" \ ++ parm [ eax ]; ++ ++int AWE32_ErrorCode = AWE32_Ok; ++ ++#define AWE32_SetErrorCode( status ) \ ++ AWE32_ErrorCode = ( status ); ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AWE32_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *AWE32_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case AWE32_Warning : ++ case AWE32_Error : ++ ErrorString = AWE32_ErrorString( AWE32_ErrorCode ); ++ break; ++ ++ case AWE32_Ok : ++ ErrorString = "AWE32 ok."; ++ break; ++ ++ case AWE32_SoundBlasterError : ++ ErrorString = BLASTER_ErrorString( BLASTER_Error ); ++ break; ++ ++ case AWE32_NotDetected : ++ ErrorString = "Could not detect AWE32."; ++ break; ++ ++ case AWE32_UnableToInitialize : ++ ErrorString = "Unable to initialize AWE32."; ++ ++ case AWE32_MPU401Error : ++ ErrorString = "MPU-401 initialization failed in AWE32."; ++ break; ++ ++ case AWE32_DPMI_Error : ++ ErrorString = "DPMI Error in AWE32."; ++ break; ++ ++ default : ++ ErrorString = "Unknown AWE32 error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define AWE32_LockStart AWE32_NoteOff ++ ++ ++void AWE32_NoteOff ++ ( ++ int channel, ++ int key, ++ int velocity ++ ) ++ ++ { ++ unsigned temp; ++ ++ temp = SetES(); ++ awe32NoteOff( channel, key, velocity ); ++ RestoreES( temp ); ++ NoteFlags[ key ] ^= ( 1 << channel ); ++ } ++ ++void AWE32_NoteOn ++ ( ++ int channel, ++ int key, ++ int velocity ++ ) ++ ++ { ++ unsigned temp; ++ ++ temp = SetES(); ++ awe32NoteOn( channel, key, velocity ); ++ RestoreES( temp ); ++ NoteFlags[ key ] |= ( 1 << channel ); ++ } ++ ++void AWE32_PolyAftertouch ++ ( ++ int channel, ++ int key, ++ int pressure ++ ) ++ ++ { ++ unsigned temp; ++ ++ temp = SetES(); ++ awe32PolyKeyPressure( channel, key, pressure ); ++ RestoreES( temp ); ++ } ++ ++void AWE32_ChannelAftertouch ++ ( ++ int channel, ++ int pressure ++ ) ++ ++ { ++ unsigned temp; ++ ++ temp = SetES(); ++ awe32ChannelPressure( channel, pressure ); ++ RestoreES( temp ); ++ } ++ ++void AWE32_ControlChange ++ ( ++ int channel, ++ int number, ++ int value ++ ) ++ ++ { ++ unsigned temp; ++ int i; ++ unsigned channelmask; ++ ++ temp = SetES(); ++ ++ if ( number == 0x7b ) ++ { ++ channelmask = 1 << channel; ++ for( i = 0; i < 128; i++ ) ++ { ++ if ( NoteFlags[ i ] & channelmask ) ++ { ++ awe32NoteOff( channel, i, 0 ); ++ NoteFlags[ i ] ^= channelmask; ++ } ++ } ++ } ++ else ++ { ++ awe32Controller( channel, number, value ); ++ } ++ RestoreES( temp ); ++ } ++ ++void AWE32_ProgramChange ++ ( ++ int channel, ++ int program ++ ) ++ ++ { ++ unsigned temp; ++ ++ temp = SetES(); ++ awe32ProgramChange( channel, program ); ++ RestoreES( temp ); ++ } ++ ++void AWE32_PitchBend ++ ( ++ int channel, ++ int lsb, ++ int msb ++ ) ++ ++ { ++ unsigned temp; ++ ++ temp = SetES(); ++ awe32PitchBend( channel, lsb, msb ); ++ RestoreES( temp ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: AWE32_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void AWE32_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/* ++static int InitMPU ++ ( ++ void ++ ) ++ ++ { ++ volatile DWORD dwCount; ++ ++ for (dwCount=0; dwCount<0x2000; dwCount++) ; ++ dwCount = 0x2000; ++ while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; ++ _outp(MPUPort(1), MPU_RESET_CMD); ++ ++ for (dwCount=0; dwCount<0x2000; dwCount++) ; ++ dwCount = 0x2000; ++ while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount; ++ _inp(MPUPort(0)); ++ ++ for (dwCount=0; dwCount<0x2000; dwCount++) ; ++ dwCount = 0x2000; ++ while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; ++ _outp(MPUPort(1), MPU_RESET_CMD); ++ ++ for (dwCount=0; dwCount<0x2000; dwCount++) ; ++ dwCount = 0x2000; ++ while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount; ++ _inp(MPUPort(0)); ++ ++ for (dwCount=0; dwCount<0x2000; dwCount++) ; ++ dwCount = 0x2000; ++ while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; ++ _outp(MPUPort(1), MPU_ENTER_UART); ++ ++ for (dwCount=0; dwCount<0x2000; dwCount++) ; ++ dwCount = 0x2000; ++ while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount; ++ if (!dwCount) return TRUE; ++ if (_inp(MPUPort(0)) != MPU_ACK_OK) return TRUE; ++ ++ // mask MPU-401 interrupt ++ _outp(SBCPort(0x4), 0x83); ++ _outp(SBCPort(0x5), _inp(SBCPort(0x5)) & ~0x04); ++ ++ return FALSE; ++ } ++*/ ++ ++/*ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸*/ ++/*³ ShutdownMPU ³*/ ++/*³ Cleans up Sound Blaster to normal state. ³*/ ++/*ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ;*/ ++ ++static void ShutdownMPU ++ ( ++ void ++ ) ++ ++ { ++ volatile DWORD dwCount; ++ ++ for (dwCount=0; dwCount<0x2000; dwCount++) ; ++ dwCount = 0x2000; ++ while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; ++ _outp(MPUPort(1), MPU_RESET_CMD); ++ for (dwCount=0; dwCount<0x2000; dwCount++) ; ++ _inp(MPUPort(0)); ++ ++ for (dwCount=0; dwCount<0x2000; dwCount++) ; ++ dwCount = 0x2000; ++ while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; ++ _outp(MPUPort(1), MPU_RESET_CMD); ++ for (dwCount=0; dwCount<0x2000; dwCount++) ; ++ _inp(MPUPort(0)); ++ } ++ ++ ++/*ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸*/ ++/*³ LoadSBK ³*/ ++/*ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ;*/ ++ ++static void LoadSBK ++ ( ++ void ++ ) ++ ++ { ++ /* use embeded preset objects */ ++ spSound.bank_no = 0; /* load as Bank 0 */ ++ spSound.total_banks = 1; /* use 1 bank first */ ++ lBankSizes[ 0 ] = 0; /* ram is not needed */ ++ ++ spSound.banksizes = lBankSizes; ++ awe32DefineBankSizes( &spSound ); ++ awe32SoundPad.SPad1 = awe32SPad1Obj; ++ awe32SoundPad.SPad2 = awe32SPad2Obj; ++ awe32SoundPad.SPad3 = awe32SPad3Obj; ++ awe32SoundPad.SPad4 = awe32SPad4Obj; ++ awe32SoundPad.SPad5 = awe32SPad5Obj; ++ awe32SoundPad.SPad6 = awe32SPad6Obj; ++ awe32SoundPad.SPad7 = awe32SPad7Obj; ++ } ++ ++ ++int AWE32_Init ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ BLASTER_CONFIG Blaster; ++ ++ wSBCBaseAddx = 0x220; ++ wEMUBaseAddx = 0x620; ++ wMpuBaseAddx = 0x330; ++ ++ status = BLASTER_GetCardSettings( &Blaster ); ++ if ( status != BLASTER_Ok ) ++ { ++ status = BLASTER_GetEnv( &Blaster ); ++ if ( status != BLASTER_Ok ) ++ { ++ AWE32_SetErrorCode( AWE32_SoundBlasterError ); ++ return( AWE32_Error ); ++ } ++ } ++ ++ wSBCBaseAddx = Blaster.Address; ++ if ( wSBCBaseAddx == UNDEFINED ) ++ { ++ wSBCBaseAddx = 0x220; ++ } ++ ++ wMpuBaseAddx = Blaster.Midi; ++ if ( wMpuBaseAddx == UNDEFINED ) ++ { ++ wMpuBaseAddx = 0x330; ++ } ++ ++ wEMUBaseAddx = Blaster.Emu; ++ if ( wEMUBaseAddx <= 0 ) ++ { ++ wEMUBaseAddx = wSBCBaseAddx + 0x400; ++ } ++ ++ status = awe32Detect( wEMUBaseAddx ); ++ if ( status ) ++ { ++ AWE32_SetErrorCode( AWE32_NotDetected ); ++ return( AWE32_Error ); ++ } ++ ++ status = awe32InitHardware(); ++ if ( status ) ++ { ++ AWE32_SetErrorCode( AWE32_UnableToInitialize ); ++ return( AWE32_Error ); ++ } ++ ++ ++ status = awe32InitMIDI(); ++ if ( status ) ++ { ++ AWE32_Shutdown(); ++ AWE32_SetErrorCode( AWE32_MPU401Error ) ++ return( AWE32_Error ); ++ } ++ ++/* ++ status = InitMPU(); ++ if ( status ) ++ { ++ ShutdownMPU(); ++ status = InitMPU(); ++ if ( status ) ++ { ++ ShutdownMPU(); ++ status = InitMPU(); ++ if ( status ) ++ { ++ AWE32_Shutdown(); ++ AWE32_SetErrorCode( AWE32_MPU401Error ) ++ return( AWE32_Error ); ++ } ++ } ++ } ++*/ ++ status = DPMI_LockMemoryRegion( AWE32_LockStart, AWE32_LockEnd ); ++ status |= DPMI_Lock( wSBCBaseAddx ); ++ status |= DPMI_Lock( wEMUBaseAddx ); ++ status |= DPMI_Lock( wMpuBaseAddx ); ++ status |= DPMI_Lock( spSound ); ++ status |= DPMI_Lock( lBankSizes ); ++ status |= DPMI_LockMemory( NoteFlags, sizeof( NoteFlags ) ); ++ ++ // Lock awe32 library ++ status = DPMI_LockMemoryRegion( __midieng_code, __midieng_ecode ); ++ status = DPMI_LockMemoryRegion( __midieng_code(), __midieng_ecode() ); ++ status = DPMI_LockMemoryRegion( __nrpn_code, __nrpn_ecode ); ++ status = DPMI_LockMemoryRegion( __nrpn_code(), __nrpn_ecode() ); ++ status = DPMI_LockMemoryRegion( &__midivar_data, &__midivar_edata ); ++ status = DPMI_LockMemoryRegion( &__nrpnvar_data, &__nrpnvar_edata ); ++ status = DPMI_LockMemoryRegion( &__embed_data, &__embed_edata ); ++ ++ if ( status != DPMI_Ok ) ++ { ++ ShutdownMPU(); ++ awe32Terminate(); ++ AWE32_SetErrorCode( AWE32_DPMI_Error ); ++ return( AWE32_Error ); ++ } ++ ++ // Set the number of voices to use to 32 ++ awe32NumG = 32; ++ ++ awe32TotalPatchRam(&spSound); ++ ++ LoadSBK(); ++ awe32InitMIDI(); ++ awe32InitNRPN(); ++ ++ memset( NoteFlags, 0, sizeof( NoteFlags ) ); ++ ++ return( AWE32_Ok ); ++ } ++ ++void AWE32_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ ShutdownMPU(); ++ awe32Terminate(); ++ ++ DPMI_UnlockMemoryRegion( AWE32_LockStart, AWE32_LockEnd ); ++ DPMI_Unlock( wSBCBaseAddx ); ++ DPMI_Unlock( wEMUBaseAddx ); ++ DPMI_Unlock( wMpuBaseAddx ); ++ DPMI_Unlock( spSound ); ++ DPMI_Unlock( lBankSizes ); ++ DPMI_UnlockMemory( NoteFlags, sizeof( NoteFlags ) ); ++ ++ // Unlock awe32 library ++ DPMI_UnlockMemoryRegion( __midieng_code, __midieng_ecode ); ++ DPMI_UnlockMemoryRegion( __midieng_code(), __midieng_ecode() ); ++ DPMI_UnlockMemoryRegion( __nrpn_code, __nrpn_ecode ); ++ DPMI_UnlockMemoryRegion( __nrpn_code(), __nrpn_ecode() ); ++ DPMI_UnlockMemoryRegion( &__midivar_data, &__midivar_edata ); ++ DPMI_UnlockMemoryRegion( &__nrpnvar_data, &__nrpnvar_edata ); ++ DPMI_UnlockMemoryRegion( &__embed_data, &__embed_edata ); ++ } +diff -urN rott-1.0/rott/audiolib/awe32.h trunk/rott/audiolib/awe32.h +--- rott-1.0/rott/audiolib/awe32.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/awe32.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,58 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: AWE32.H ++ ++ author: James R. Dose ++ date: August 23, 1994 ++ ++ Public header for AWE32.C Cover functions for calling the ++ AWE32 low-level library. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __AWE32_H ++#define __AWE32_H ++ ++enum AWE32_ERRORS ++ { ++ AWE32_Warning = -2, ++ AWE32_Error = -1, ++ AWE32_Ok = 0, ++ AWE32_SoundBlasterError, ++ AWE32_NotDetected, ++ AWE32_UnableToInitialize, ++ AWE32_MPU401Error, ++ AWE32_DPMI_Error ++ }; ++ ++char *AWE32_ErrorString( int ErrorNumber ); ++int AWE32_Init( void ); ++void AWE32_Shutdown( void ); ++void AWE32_NoteOff( int channel, int key, int velocity ); ++void AWE32_NoteOn( int channel, int key, int velocity ); ++void AWE32_PolyAftertouch( int channel, int key, int pressure ); ++void AWE32_ChannelAftertouch( int channel, int pressure ); ++void AWE32_ControlChange( int channel, int number, int value ); ++void AWE32_ProgramChange( int channel, int program ); ++void AWE32_PitchBend( int channel, int lsb, int msb ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/blaster.c trunk/rott/audiolib/blaster.c +--- rott-1.0/rott/audiolib/blaster.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/blaster.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,2330 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: BLASTER.C ++ ++ author: James R. Dose ++ date: February 4, 1994 ++ ++ Low level routines to support Sound Blaster, Sound Blaster Pro, ++ Sound Blaster 16, and compatible sound cards. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dpmi.h" ++#include "dma.h" ++#include "irq.h" ++#include "blaster.h" ++#include "_blaster.h" ++ ++#define USESTACK ++ ++const int BLASTER_Interrupts[ BLASTER_MaxIrq + 1 ] = ++ { ++ INVALID, INVALID, 0xa, 0xb, ++ INVALID, 0xd, INVALID, 0xf, ++ INVALID, INVALID, 0x72, 0x73, ++ 0x74, INVALID, INVALID, 0x77 ++ }; ++ ++const int BLASTER_SampleSize[ BLASTER_MaxMixMode + 1 ] = ++ { ++ MONO_8BIT_SAMPLE_SIZE, STEREO_8BIT_SAMPLE_SIZE, ++ MONO_16BIT_SAMPLE_SIZE, STEREO_16BIT_SAMPLE_SIZE ++ }; ++ ++const CARD_CAPABILITY BLASTER_CardConfig[ BLASTER_MaxCardType + 1 ] = ++ { ++ { FALSE, INVALID, INVALID, INVALID, INVALID }, // Unsupported ++ { TRUE, NO, MONO_8BIT, 4000, 23000 }, // SB 1.0 ++ { TRUE, YES, STEREO_8BIT, 4000, 44100 }, // SBPro ++ { TRUE, NO, MONO_8BIT, 4000, 23000 }, // SB 2.xx ++ { TRUE, YES, STEREO_8BIT, 4000, 44100 }, // SBPro 2 ++ { FALSE, INVALID, INVALID, INVALID, INVALID }, // Unsupported ++ { TRUE, YES, STEREO_16BIT, 5000, 44100 }, // SB16 ++ }; ++ ++CARD_CAPABILITY BLASTER_Card; ++ ++static void ( __interrupt __far *BLASTER_OldInt )( void ); ++ ++BLASTER_CONFIG BLASTER_Config = ++ { ++ UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED ++ }; ++ ++static int BLASTER_Installed = FALSE; ++ ++int BLASTER_Version; ++ ++static char *BLASTER_DMABuffer; ++static char *BLASTER_DMABufferEnd; ++static char *BLASTER_CurrentDMABuffer; ++static int BLASTER_TotalDMABufferSize; ++ ++static int BLASTER_TransferLength = 0; ++static int BLASTER_MixMode = BLASTER_DefaultMixMode; ++static int BLASTER_SamplePacketSize = MONO_16BIT_SAMPLE_SIZE; ++static unsigned BLASTER_SampleRate = BLASTER_DefaultSampleRate; ++ ++static unsigned BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; ++ ++volatile int BLASTER_SoundPlaying; ++volatile int BLASTER_SoundRecording; ++ ++void ( *BLASTER_CallBack )( void ); ++ ++static int BLASTER_IntController1Mask; ++static int BLASTER_IntController2Mask; ++ ++static int BLASTER_MixerAddress = UNDEFINED; ++static int BLASTER_MixerType = 0; ++static int BLASTER_OriginalMidiVolumeLeft = 255; ++static int BLASTER_OriginalMidiVolumeRight = 255; ++static int BLASTER_OriginalVoiceVolumeLeft = 255; ++static int BLASTER_OriginalVoiceVolumeRight = 255; ++ ++static int BLASTER_WaveBlasterState = 0x0F; ++ ++// adequate stack size ++#define kStackSize 2048 ++ ++static unsigned short StackSelector = NULL; ++static unsigned long StackPointer; ++ ++static unsigned short oldStackSelector; ++static unsigned long oldStackPointer; ++ ++// This is defined because we can't create local variables in a ++// function that switches stacks. ++static int GlobalStatus; ++ ++// These declarations are necessary to use the inline assembly pragmas. ++ ++extern void GetStack(unsigned short *selptr,unsigned long *stackptr); ++extern void SetStack(unsigned short selector,unsigned long stackptr); ++ ++// This function will get the current stack selector and pointer and save ++// them off. ++#pragma aux GetStack = \ ++ "mov [edi],esp" \ ++ "mov ax,ss" \ ++ "mov [esi],ax" \ ++ parm [esi] [edi] \ ++ modify [eax esi edi]; ++ ++// This function will set the stack selector and pointer to the specified ++// values. ++#pragma aux SetStack = \ ++ "mov ss,ax" \ ++ "mov esp,edx" \ ++ parm [ax] [edx] \ ++ modify [eax edx]; ++ ++int BLASTER_DMAChannel; ++ ++int BLASTER_ErrorCode = BLASTER_Ok; ++ ++#define BLASTER_SetErrorCode( status ) \ ++ BLASTER_ErrorCode = ( status ); ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *BLASTER_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case BLASTER_Warning : ++ case BLASTER_Error : ++ ErrorString = BLASTER_ErrorString( BLASTER_ErrorCode ); ++ break; ++ ++ case BLASTER_Ok : ++ ErrorString = "Sound Blaster ok."; ++ break; ++ ++ case BLASTER_EnvNotFound : ++ ErrorString = "BLASTER environment variable not set."; ++ break; ++ ++ case BLASTER_AddrNotSet : ++ ErrorString = "Sound Blaster address not set."; ++ break; ++ ++ case BLASTER_DMANotSet : ++ ErrorString = "Sound Blaster 8-bit DMA channel not set."; ++ break; ++ ++ case BLASTER_DMA16NotSet : ++ ErrorString = "Sound Blaster 16-bit DMA channel not set."; ++ break; ++ ++ case BLASTER_InvalidParameter : ++ ErrorString = "Invalid parameter in BLASTER environment variable."; ++ break; ++ ++ case BLASTER_CardNotReady : ++ ErrorString = "Sound Blaster not responding on selected port."; ++ break; ++ ++ case BLASTER_NoSoundPlaying : ++ ErrorString = "No sound playing on Sound Blaster."; ++ break; ++ ++ case BLASTER_InvalidIrq : ++ ErrorString = "Invalid Sound Blaster Irq."; ++ break; ++ ++ case BLASTER_UnableToSetIrq : ++ ErrorString = "Unable to set Sound Blaster IRQ. Try selecting an IRQ of 7 or below."; ++ break; ++ ++ case BLASTER_DmaError : ++ ErrorString = DMA_ErrorString( DMA_Error ); ++ break; ++ ++ case BLASTER_NoMixer : ++ ErrorString = "Mixer not available on selected Sound Blaster card."; ++ break; ++ ++ case BLASTER_DPMI_Error : ++ ErrorString = "DPMI Error in Blaster."; ++ break; ++ ++ case BLASTER_OutOfMemory : ++ ErrorString = "Out of conventional memory in Blaster."; ++ break; ++ ++ default : ++ ErrorString = "Unknown Sound Blaster error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define BLASTER_LockStart BLASTER_EnableInterrupt ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_EnableInterrupt ++ ++ Enables the triggering of the sound card interrupt. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_EnableInterrupt ++ ( ++ void ++ ) ++ ++ { ++ int Irq; ++ int mask; ++ ++ // Unmask system interrupt ++ Irq = BLASTER_Config.Interrupt; ++ if ( Irq < 8 ) ++ { ++ mask = inp( 0x21 ) & ~( 1 << Irq ); ++ outp( 0x21, mask ); ++ } ++ else ++ { ++ mask = inp( 0xA1 ) & ~( 1 << ( Irq - 8 ) ); ++ outp( 0xA1, mask ); ++ ++ mask = inp( 0x21 ) & ~( 1 << 2 ); ++ outp( 0x21, mask ); ++ } ++ ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_DisableInterrupt ++ ++ Disables the triggering of the sound card interrupt. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_DisableInterrupt ++ ( ++ void ++ ) ++ ++ { ++ int Irq; ++ int mask; ++ ++ // Restore interrupt mask ++ Irq = BLASTER_Config.Interrupt; ++ if ( Irq < 8 ) ++ { ++ mask = inp( 0x21 ) & ~( 1 << Irq ); ++ mask |= BLASTER_IntController1Mask & ( 1 << Irq ); ++ outp( 0x21, mask ); ++ } ++ else ++ { ++ mask = inp( 0x21 ) & ~( 1 << 2 ); ++ mask |= BLASTER_IntController1Mask & ( 1 << 2 ); ++ outp( 0x21, mask ); ++ ++ mask = inp( 0xA1 ) & ~( 1 << ( Irq - 8 ) ); ++ mask |= BLASTER_IntController2Mask & ( 1 << ( Irq - 8 ) ); ++ outp( 0xA1, mask ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_ServiceInterrupt ++ ++ Handles interrupt generated by sound card at the end of a voice ++ transfer. Calls the user supplied callback function. ++---------------------------------------------------------------------*/ ++ ++void __interrupt __far BLASTER_ServiceInterrupt ++ ( ++ void ++ ) ++ ++ { ++ #ifdef USESTACK ++ // save stack ++ GetStack( &oldStackSelector, &oldStackPointer ); ++ ++ // set our stack ++ SetStack( StackSelector, StackPointer ); ++ #endif ++ ++ // Acknowledge interrupt ++ // Check if this is this an SB16 or newer ++ if ( BLASTER_Version >= DSP_Version4xx ) ++ { ++ outp( BLASTER_Config.Address + BLASTER_MixerAddressPort, ++ MIXER_DSP4xxISR_Ack ); ++ ++ GlobalStatus = inp( BLASTER_Config.Address + BLASTER_MixerDataPort ); ++ ++ // Check if a 16-bit DMA interrupt occurred ++ if ( GlobalStatus & MIXER_16BITDMA_INT ) ++ { ++ // Acknowledge 16-bit transfer interrupt ++ inp( BLASTER_Config.Address + BLASTER_16BitDMAAck ); ++ } ++ else if ( GlobalStatus & MIXER_8BITDMA_INT ) ++ { ++ inp( BLASTER_Config.Address + BLASTER_DataAvailablePort ); ++ } ++ else ++ { ++ #ifdef USESTACK ++ // restore stack ++ SetStack( oldStackSelector, oldStackPointer ); ++ #endif ++ ++ // Wasn't our interrupt. Call the old one. ++ _chain_intr( BLASTER_OldInt ); ++ } ++ } ++ else ++ { ++ // Older card - can't detect if an interrupt occurred. ++ inp( BLASTER_Config.Address + BLASTER_DataAvailablePort ); ++ } ++ ++ // Keep track of current buffer ++ BLASTER_CurrentDMABuffer += BLASTER_TransferLength; ++ ++ if ( BLASTER_CurrentDMABuffer >= BLASTER_DMABufferEnd ) ++ { ++ BLASTER_CurrentDMABuffer = BLASTER_DMABuffer; ++ } ++ ++ // Continue playback on cards without autoinit mode ++ if ( BLASTER_Version < DSP_Version2xx ) ++ { ++ if ( BLASTER_SoundPlaying ) ++ { ++ BLASTER_DSP1xx_BeginPlayback( BLASTER_TransferLength ); ++ } ++ ++ if ( BLASTER_SoundRecording ) ++ { ++ BLASTER_DSP1xx_BeginRecord( BLASTER_TransferLength ); ++ } ++ } ++ ++ // Call the caller's callback function ++ if ( BLASTER_CallBack != NULL ) ++ { ++ BLASTER_CallBack(); ++ } ++ ++ #ifdef USESTACK ++ // restore stack ++ SetStack( oldStackSelector, oldStackPointer ); ++ #endif ++ ++ // send EOI to Interrupt Controller ++ if ( BLASTER_Config.Interrupt > 7 ) ++ { ++ outp( 0xA0, 0x20 ); ++ } ++ ++ outp( 0x20, 0x20 ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_WriteDSP ++ ++ Writes a byte of data to the sound card's DSP. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_WriteDSP ++ ( ++ unsigned data ++ ) ++ ++ { ++ int port; ++ unsigned count; ++ int status; ++ ++ port = BLASTER_Config.Address + BLASTER_WritePort; ++ ++ status = BLASTER_Error; ++ ++ count = 0xFFFF; ++ ++ do ++ { ++ if ( ( inp( port ) & 0x80 ) == 0 ) ++ { ++ outp( port, data ); ++ status = BLASTER_Ok; ++ break; ++ } ++ ++ count--; ++ } ++ while( count > 0 ); ++ ++ if ( status != BLASTER_Ok ) ++ { ++ BLASTER_SetErrorCode( BLASTER_CardNotReady ); ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_ReadDSP ++ ++ Reads a byte of data from the sound card's DSP. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_ReadDSP ++ ( ++ void ++ ) ++ ++ { ++ int port; ++ unsigned count; ++ int status; ++ ++ port = BLASTER_Config.Address + BLASTER_DataAvailablePort; ++ ++ status = BLASTER_Error; ++ ++ count = 0xFFFF; ++ ++ do ++ { ++ if ( inp( port ) & 0x80 ) ++ { ++ status = inp( BLASTER_Config.Address + BLASTER_ReadPort ); ++ break; ++ } ++ ++ count--; ++ } ++ while( count > 0 ); ++ ++ if ( status == BLASTER_Error ) ++ { ++ BLASTER_SetErrorCode( BLASTER_CardNotReady ); ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_ResetDSP ++ ++ Sends a reset command to the sound card's Digital Signal Processor ++ (DSP), causing it to perform an initialization. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_ResetDSP ++ ( ++ void ++ ) ++ ++ { ++ volatile int count; ++ int port; ++ int status; ++ ++ port = BLASTER_Config.Address + BLASTER_ResetPort; ++ ++ status = BLASTER_CardNotReady; ++ ++ outp( port, 1 ); ++ ++/* What the hell am I doing here? ++ count = 100; ++ ++ do ++ { ++ if ( inp( port ) == 255 ) ++ { ++ break; ++ } ++ ++ count--; ++ } ++ while( count > 0 ); ++*/ ++ ++ count = 0x100; ++ do ++ { ++ count--; ++ } ++ while( count > 0 ); ++ ++ outp( port, 0 ); ++ ++ count = 100; ++ ++ do ++ { ++ if ( BLASTER_ReadDSP() == BLASTER_Ready ) ++ { ++ status = BLASTER_Ok; ++ break; ++ } ++ ++ count--; ++ } ++ while( count > 0 ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_GetDSPVersion ++ ++ Returns the version number of the sound card's DSP. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_GetDSPVersion ++ ( ++ void ++ ) ++ ++ { ++ int MajorVersion; ++ int MinorVersion; ++ int version; ++ ++ BLASTER_WriteDSP( DSP_GetVersion ); ++ ++ MajorVersion = BLASTER_ReadDSP(); ++ MinorVersion = BLASTER_ReadDSP(); ++ ++ if ( ( MajorVersion == BLASTER_Error ) || ++ ( MinorVersion == BLASTER_Error ) ) ++ { ++ BLASTER_SetErrorCode( BLASTER_CardNotReady ); ++ return( BLASTER_Error ); ++ } ++ ++ version = ( MajorVersion << 8 ) + MinorVersion; ++ ++ if ( version >= DSP_Version4xx ) ++ { ++ BLASTER_Card.IsSupported = TRUE; ++ BLASTER_Card.HasMixer = YES; ++ BLASTER_Card.MaxMixMode = STEREO_16BIT; ++ BLASTER_Card.MinSamplingRate = 5000; ++ BLASTER_Card.MaxSamplingRate = 44100; ++ BLASTER_MixerType = SB16; ++ } ++ else if ( version >= DSP_Version3xx ) ++ { ++ BLASTER_Card.IsSupported = TRUE; ++ BLASTER_Card.HasMixer = YES; ++ BLASTER_Card.MaxMixMode = STEREO_8BIT; ++ BLASTER_Card.MinSamplingRate = 4000; ++ BLASTER_Card.MaxSamplingRate = 44100; ++ BLASTER_MixerType = SBPro; ++ } ++ else if ( version >= DSP_Version2xx ) ++ { ++ BLASTER_Card.IsSupported = TRUE; ++ BLASTER_Card.HasMixer = NO; ++ BLASTER_Card.MaxMixMode = MONO_8BIT; ++ BLASTER_Card.MinSamplingRate = 4000; ++ BLASTER_Card.MaxSamplingRate = 23000; ++ BLASTER_MixerType = 0; ++ } ++ else ++ { ++ // DSP_Version1xx ++ BLASTER_Card.IsSupported = TRUE; ++ BLASTER_Card.HasMixer = NO; ++ BLASTER_Card.MaxMixMode = MONO_8BIT; ++ BLASTER_Card.MinSamplingRate = 4000; ++ BLASTER_Card.MaxSamplingRate = 23000; ++ BLASTER_MixerType = 0; ++ } ++ ++ return( version ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SpeakerOn ++ ++ Enables output from the DAC. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_SpeakerOn ++ ( ++ void ++ ) ++ ++ { ++ BLASTER_WriteDSP( DSP_SpeakerOn ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SpeakerOff ++ ++ Disables output from the DAC. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_SpeakerOff ++ ( ++ void ++ ) ++ ++ { ++ BLASTER_WriteDSP( DSP_SpeakerOff ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SetPlaybackRate ++ ++ Sets the rate at which the digitized sound will be played in ++ hertz. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_SetPlaybackRate ++ ( ++ unsigned rate ++ ) ++ ++ { ++ int LoByte; ++ int HiByte; ++ ++ if ( BLASTER_Version < DSP_Version4xx ) ++ { ++ int timeconstant; ++ long ActualRate; ++ ++ // Send sampling rate as time constant for older Sound ++ // Blaster compatible cards. ++ ++ ActualRate = rate * BLASTER_SamplePacketSize; ++ if ( ActualRate < BLASTER_Card.MinSamplingRate ) ++ { ++ rate = BLASTER_Card.MinSamplingRate / BLASTER_SamplePacketSize; ++ } ++ ++ if ( ActualRate > BLASTER_Card.MaxSamplingRate ) ++ { ++ rate = BLASTER_Card.MaxSamplingRate / BLASTER_SamplePacketSize; ++ } ++ ++ timeconstant = ( int )CalcTimeConstant( rate, BLASTER_SamplePacketSize ); ++ ++ // Keep track of what the actual rate is ++ BLASTER_SampleRate = ( unsigned )CalcSamplingRate( timeconstant ); ++ BLASTER_SampleRate /= BLASTER_SamplePacketSize; ++ ++ BLASTER_WriteDSP( DSP_SetTimeConstant ); ++ BLASTER_WriteDSP( timeconstant ); ++ } ++ else ++ { ++ // Send literal sampling rate for cards with DSP version ++ // 4.xx (Sound Blaster 16) ++ ++ BLASTER_SampleRate = rate; ++ ++ if ( BLASTER_SampleRate < BLASTER_Card.MinSamplingRate ) ++ { ++ BLASTER_SampleRate = BLASTER_Card.MinSamplingRate; ++ } ++ ++ if ( BLASTER_SampleRate > BLASTER_Card.MaxSamplingRate ) ++ { ++ BLASTER_SampleRate = BLASTER_Card.MaxSamplingRate; ++ } ++ ++ HiByte = hibyte( BLASTER_SampleRate ); ++ LoByte = lobyte( BLASTER_SampleRate ); ++ ++ // Set playback rate ++ BLASTER_WriteDSP( DSP_Set_DA_Rate ); ++ BLASTER_WriteDSP( HiByte ); ++ BLASTER_WriteDSP( LoByte ); ++ ++ // Set recording rate ++ BLASTER_WriteDSP( DSP_Set_AD_Rate ); ++ BLASTER_WriteDSP( HiByte ); ++ BLASTER_WriteDSP( LoByte ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_GetPlaybackRate ++ ++ Returns the rate at which the digitized sound will be played in ++ hertz. ++---------------------------------------------------------------------*/ ++ ++unsigned BLASTER_GetPlaybackRate ++ ( ++ void ++ ) ++ ++ { ++ return( BLASTER_SampleRate ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SetMixMode ++ ++ Sets the sound card to play samples in mono or stereo. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_SetMixMode ++ ( ++ int mode ++ ) ++ ++ { ++ int port; ++ int data; ++ int CardType; ++ ++ CardType = BLASTER_Config.Type; ++ ++ mode &= BLASTER_MaxMixMode; ++ ++ if ( !( BLASTER_Card.MaxMixMode & STEREO ) ) ++ { ++ mode &= ~STEREO; ++ } ++ ++ if ( !( BLASTER_Card.MaxMixMode & SIXTEEN_BIT ) ) ++ { ++ mode &= ~SIXTEEN_BIT; ++ } ++ ++ BLASTER_MixMode = mode; ++ BLASTER_SamplePacketSize = BLASTER_SampleSize[ mode ]; ++ ++ // For the Sound Blaster Pro, we have to set the mixer chip ++ // to play mono or stereo samples. ++ ++ if ( ( CardType == SBPro ) || ( CardType == SBPro2 ) ) ++ { ++ port = BLASTER_Config.Address + BLASTER_MixerAddressPort; ++ outp( port, MIXER_SBProOutputSetting ); ++ ++ port = BLASTER_Config.Address + BLASTER_MixerDataPort; ++ ++ // Get current mode ++ data = inp( port ); ++ ++ // set stereo mode bit ++ if ( mode & STEREO ) ++ { ++ data |= MIXER_SBProStereoFlag; ++ } ++ else ++ { ++ data &= ~MIXER_SBProStereoFlag; ++ } ++ ++ // set the mode ++ outp( port, data ); ++ ++ BLASTER_SetPlaybackRate( BLASTER_SampleRate ); ++ } ++ ++ return( mode ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_StopPlayback ++ ++ Ends the DMA transfer of digitized sound to the sound card. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_StopPlayback ++ ( ++ void ++ ) ++ ++ { ++ int DmaChannel; ++ ++ // Don't allow anymore interrupts ++ BLASTER_DisableInterrupt(); ++ ++ if ( BLASTER_HaltTransferCommand == DSP_Reset ) ++ { ++ BLASTER_ResetDSP(); ++ } ++ else ++ { ++ BLASTER_WriteDSP( BLASTER_HaltTransferCommand ); ++ } ++ ++ // Disable the DMA channel ++ if ( BLASTER_MixMode & SIXTEEN_BIT ) ++ { ++ DmaChannel = BLASTER_Config.Dma16; ++ } ++ else ++ { ++ DmaChannel = BLASTER_Config.Dma8; ++ } ++ DMA_EndTransfer( DmaChannel ); ++ ++ // Turn off speaker ++ BLASTER_SpeakerOff(); ++ ++ BLASTER_SoundPlaying = FALSE; ++ BLASTER_SoundRecording = FALSE; ++ ++ BLASTER_DMABuffer = NULL; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SetupDMABuffer ++ ++ Programs the DMAC for sound transfer. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_SetupDMABuffer ++ ( ++ char *BufferPtr, ++ int BufferSize, ++ int mode ++ ) ++ ++ { ++ int DmaChannel; ++ int DmaStatus; ++ int errorcode; ++ ++ if ( BLASTER_MixMode & SIXTEEN_BIT ) ++ { ++ DmaChannel = BLASTER_Config.Dma16; ++ errorcode = BLASTER_DMA16NotSet; ++ } ++ else ++ { ++ DmaChannel = BLASTER_Config.Dma8; ++ errorcode = BLASTER_DMANotSet; ++ } ++ ++ if ( DmaChannel == UNDEFINED ) ++ { ++ BLASTER_SetErrorCode( errorcode ); ++ return( BLASTER_Error ); ++ } ++ ++ DmaStatus = DMA_SetupTransfer( DmaChannel, BufferPtr, BufferSize, mode ); ++ if ( DmaStatus == DMA_Error ) ++ { ++ BLASTER_SetErrorCode( BLASTER_DmaError ); ++ return( BLASTER_Error ); ++ } ++ ++ BLASTER_DMAChannel = DmaChannel; ++ ++ BLASTER_DMABuffer = BufferPtr; ++ BLASTER_CurrentDMABuffer = BufferPtr; ++ BLASTER_TotalDMABufferSize = BufferSize; ++ BLASTER_DMABufferEnd = BufferPtr + BufferSize; ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_GetCurrentPos ++ ++ Returns the offset within the current sound being played. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_GetCurrentPos ++ ( ++ void ++ ) ++ ++ { ++ char *CurrentAddr; ++ int DmaChannel; ++ int offset; ++ ++ if ( !BLASTER_SoundPlaying ) ++ { ++ BLASTER_SetErrorCode( BLASTER_NoSoundPlaying ); ++ return( BLASTER_Error ); ++ } ++ ++ if ( BLASTER_MixMode & SIXTEEN_BIT ) ++ { ++ DmaChannel = BLASTER_Config.Dma16; ++ } ++ else ++ { ++ DmaChannel = BLASTER_Config.Dma8; ++ } ++ ++ if ( DmaChannel == UNDEFINED ) ++ { ++ BLASTER_SetErrorCode( BLASTER_DMANotSet ); ++ return( BLASTER_Error ); ++ } ++ ++ CurrentAddr = DMA_GetCurrentPos( DmaChannel ); ++ ++ offset = ( int )( ( ( unsigned long )CurrentAddr ) - ++ ( ( unsigned long )BLASTER_CurrentDMABuffer ) ); ++ ++ if ( BLASTER_MixMode & SIXTEEN_BIT ) ++ { ++ offset >>= 1; ++ } ++ ++ if ( BLASTER_MixMode & STEREO ) ++ { ++ offset >>= 1; ++ } ++ ++ return( offset ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_DSP1xx_BeginPlayback ++ ++ Starts playback of digitized sound on cards compatible with DSP ++ version 1.xx. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_DSP1xx_BeginPlayback ++ ( ++ int length ++ ) ++ ++ { ++ int SampleLength; ++ int LoByte; ++ int HiByte; ++ ++ SampleLength = length - 1; ++ HiByte = hibyte( SampleLength ); ++ LoByte = lobyte( SampleLength ); ++ ++ // Program DSP to play sound ++ BLASTER_WriteDSP( DSP_Old8BitDAC ); ++ BLASTER_WriteDSP( LoByte ); ++ BLASTER_WriteDSP( HiByte ); ++ ++ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; ++ ++ BLASTER_SoundPlaying = TRUE; ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_DSP2xx_BeginPlayback ++ ++ Starts playback of digitized sound on cards compatible with DSP ++ version 2.xx. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_DSP2xx_BeginPlayback ++ ( ++ int length ++ ) ++ ++ { ++ int SampleLength; ++ int LoByte; ++ int HiByte; ++ ++ SampleLength = length - 1; ++ HiByte = hibyte( SampleLength ); ++ LoByte = lobyte( SampleLength ); ++ ++ BLASTER_WriteDSP( DSP_SetBlockLength ); ++ BLASTER_WriteDSP( LoByte ); ++ BLASTER_WriteDSP( HiByte ); ++ ++ if ( ( BLASTER_Version >= DSP_Version201 ) && ( DSP_MaxNormalRate < ++ ( BLASTER_SampleRate * BLASTER_SamplePacketSize ) ) ) ++ { ++ BLASTER_WriteDSP( DSP_8BitHighSpeedAutoInitMode ); ++ BLASTER_HaltTransferCommand = DSP_Reset; ++ } ++ else ++ { ++ BLASTER_WriteDSP( DSP_8BitAutoInitMode ); ++ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; ++ } ++ ++ BLASTER_SoundPlaying = TRUE; ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_DSP4xx_BeginPlayback ++ ++ Starts playback of digitized sound on cards compatible with DSP ++ version 4.xx, such as the Sound Blaster 16. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_DSP4xx_BeginPlayback ++ ( ++ int length ++ ) ++ ++ { ++ int TransferCommand; ++ int TransferMode; ++ int SampleLength; ++ int LoByte; ++ int HiByte; ++ ++ if ( BLASTER_MixMode & SIXTEEN_BIT ) ++ { ++ TransferCommand = DSP_16BitDAC; ++ SampleLength = ( length / 2 ) - 1; ++ BLASTER_HaltTransferCommand = DSP_Halt16bitTransfer; ++ if ( BLASTER_MixMode & STEREO ) ++ { ++ TransferMode = DSP_SignedStereoData; ++ } ++ else ++ { ++ TransferMode = DSP_SignedMonoData; ++ } ++ } ++ else ++ { ++ TransferCommand = DSP_8BitDAC; ++ SampleLength = length - 1; ++ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; ++ if ( BLASTER_MixMode & STEREO ) ++ { ++ TransferMode = DSP_UnsignedStereoData; ++ } ++ else ++ { ++ TransferMode = DSP_UnsignedMonoData; ++ } ++ } ++ ++ HiByte = hibyte( SampleLength ); ++ LoByte = lobyte( SampleLength ); ++ ++ // Program DSP to play sound ++ BLASTER_WriteDSP( TransferCommand ); ++ BLASTER_WriteDSP( TransferMode ); ++ BLASTER_WriteDSP( LoByte ); ++ BLASTER_WriteDSP( HiByte ); ++ ++ BLASTER_SoundPlaying = TRUE; ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_BeginBufferedPlayback ++ ++ Begins multibuffered playback of digitized sound on the sound card. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_BeginBufferedPlayback ++ ( ++ char *BufferStart, ++ int BufferSize, ++ int NumDivisions, ++ unsigned SampleRate, ++ int MixMode, ++ void ( *CallBackFunc )( void ) ++ ) ++ ++ { ++ int DmaStatus; ++ int TransferLength; ++ ++//JIM ++// if ( BLASTER_SoundPlaying || BLASTER_SoundRecording ) ++ { ++ BLASTER_StopPlayback(); ++ } ++ ++ BLASTER_SetMixMode( MixMode ); ++ ++ DmaStatus = BLASTER_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitRead ); ++ if ( DmaStatus == BLASTER_Error ) ++ { ++ return( BLASTER_Error ); ++ } ++ ++ BLASTER_SetPlaybackRate( SampleRate ); ++ ++ BLASTER_SetCallBack( CallBackFunc ); ++ ++ BLASTER_EnableInterrupt(); ++ ++ // Turn on speaker ++ BLASTER_SpeakerOn(); ++ ++ TransferLength = BufferSize / NumDivisions; ++ BLASTER_TransferLength = TransferLength; ++ ++ // Program the sound card to start the transfer. ++ if ( BLASTER_Version < DSP_Version2xx ) ++ { ++ BLASTER_DSP1xx_BeginPlayback( TransferLength ); ++ } ++ else if ( BLASTER_Version < DSP_Version4xx ) ++ { ++ BLASTER_DSP2xx_BeginPlayback( TransferLength ); ++ } ++ else ++ { ++ BLASTER_DSP4xx_BeginPlayback( TransferLength ); ++ } ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_DSP4xx_BeginRecord ++ ++ Starts recording of digitized sound on cards compatible with DSP ++ version 4.xx, such as the Sound Blaster 16. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_DSP4xx_BeginRecord ++ ( ++ int length ++ ) ++ ++ { ++ int TransferCommand; ++ int TransferMode; ++ int SampleLength; ++ int LoByte; ++ int HiByte; ++ ++ TransferCommand = DSP_8BitADC; ++ SampleLength = length - 1; ++ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; ++ ++ TransferMode = DSP_UnsignedMonoData; ++ ++ HiByte = hibyte( SampleLength ); ++ LoByte = lobyte( SampleLength ); ++ ++ // Program DSP to play sound ++ BLASTER_WriteDSP( TransferCommand ); ++ BLASTER_WriteDSP( TransferMode ); ++ BLASTER_WriteDSP( LoByte ); ++ BLASTER_WriteDSP( HiByte ); ++ ++ BLASTER_SoundRecording = TRUE; ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_DSP2xx_BeginRecord ++ ++ Starts recording of digitized sound on cards compatible with DSP ++ version 2.xx. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_DSP2xx_BeginRecord ++ ( ++ int length ++ ) ++ ++ { ++ int SampleLength; ++ int LoByte; ++ int HiByte; ++ ++ SampleLength = length - 1; ++ HiByte = hibyte( SampleLength ); ++ LoByte = lobyte( SampleLength ); ++ ++ BLASTER_WriteDSP( DSP_SetBlockLength ); ++ BLASTER_WriteDSP( LoByte ); ++ BLASTER_WriteDSP( HiByte ); ++ ++ if ( ( BLASTER_Version >= DSP_Version201 ) && ( DSP_MaxNormalRate < ++ ( BLASTER_SampleRate * BLASTER_SamplePacketSize ) ) ) ++ { ++ BLASTER_WriteDSP( DSP_8BitHighSpeedAutoInitRecord ); ++ BLASTER_HaltTransferCommand = DSP_Reset; ++ } ++ else ++ { ++ BLASTER_WriteDSP( DSP_8BitAutoInitRecord ); ++ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; ++ } ++ ++ BLASTER_SoundRecording = TRUE; ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_DSP1xx_BeginRecord ++ ++ Starts recording of digitized sound on cards compatible with DSP ++ version 1.xx. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_DSP1xx_BeginRecord ++ ( ++ int length ++ ) ++ ++ { ++ int SampleLength; ++ int LoByte; ++ int HiByte; ++ ++ SampleLength = length - 1; ++ HiByte = hibyte( SampleLength ); ++ LoByte = lobyte( SampleLength ); ++ ++ // Program DSP to play sound ++ BLASTER_WriteDSP( DSP_Old8BitADC ); ++ BLASTER_WriteDSP( LoByte ); ++ BLASTER_WriteDSP( HiByte ); ++ ++ BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; ++ ++ BLASTER_SoundRecording = TRUE; ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_BeginBufferedRecord ++ ++ Begins multibuffered recording of digitized sound on the sound card. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_BeginBufferedRecord ++ ( ++ char *BufferStart, ++ int BufferSize, ++ int NumDivisions, ++ unsigned SampleRate, ++ int MixMode, ++ void ( *CallBackFunc )( void ) ++ ) ++ ++ { ++ int DmaStatus; ++ int TransferLength; ++ ++//JIM ++// if ( BLASTER_SoundPlaying || BLASTER_SoundRecording ) ++ { ++ BLASTER_StopPlayback(); ++ } ++ ++ BLASTER_SetMixMode( MixMode ); ++ ++ DmaStatus = BLASTER_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitWrite ); ++ if ( DmaStatus == BLASTER_Error ) ++ { ++ return( BLASTER_Error ); ++ } ++ ++ BLASTER_SetPlaybackRate( SampleRate ); ++ ++ BLASTER_SetCallBack( CallBackFunc ); ++ ++ BLASTER_EnableInterrupt(); ++ ++ // Turn off speaker ++ BLASTER_SpeakerOff(); ++ ++ TransferLength = BufferSize / NumDivisions; ++ BLASTER_TransferLength = TransferLength; ++ ++ // Program the sound card to start the transfer. ++ if ( BLASTER_Version < DSP_Version2xx ) ++ { ++ BLASTER_DSP1xx_BeginRecord( TransferLength ); ++ } ++ else if ( BLASTER_Version < DSP_Version4xx ) ++ { ++ BLASTER_DSP2xx_BeginRecord( TransferLength ); ++ } ++ else ++ { ++ BLASTER_DSP4xx_BeginRecord( TransferLength ); ++ } ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_WriteMixer ++ ++ Writes a byte of data to the Sound Blaster's mixer chip. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_WriteMixer ++ ( ++ int reg, ++ int data ++ ) ++ ++ { ++ outp( BLASTER_MixerAddress + BLASTER_MixerAddressPort, reg ); ++ outp( BLASTER_MixerAddress + BLASTER_MixerDataPort, data ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_ReadMixer ++ ++ Reads a byte of data from the Sound Blaster's mixer chip. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_ReadMixer ++ ( ++ int reg ++ ) ++ ++ { ++ int data; ++ ++ outp( BLASTER_MixerAddress + BLASTER_MixerAddressPort, reg ); ++ data = inp( BLASTER_MixerAddress + BLASTER_MixerDataPort ); ++ return( data ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_GetVoiceVolume ++ ++ Reads the average volume of the digitized sound channel from the ++ Sound Blaster's mixer chip. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_GetVoiceVolume ++ ( ++ void ++ ) ++ ++ { ++ int volume; ++ int left; ++ int right; ++ ++ switch( BLASTER_MixerType ) ++ { ++ case SBPro : ++ case SBPro2 : ++ left = BLASTER_ReadMixer( MIXER_SBProVoice ); ++ right = ( left & 0x0f ) << 4; ++ left &= 0xf0; ++ volume = ( left + right ) / 2; ++ break; ++ ++ case SB16 : ++ left = BLASTER_ReadMixer( MIXER_SB16VoiceLeft ); ++ right = BLASTER_ReadMixer( MIXER_SB16VoiceRight ); ++ volume = ( left + right ) / 2; ++ break; ++ ++ default : ++ BLASTER_SetErrorCode( BLASTER_NoMixer ); ++ volume = BLASTER_Error; ++ } ++ ++ return( volume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SetVoiceVolume ++ ++ Sets the volume of the digitized sound channel on the Sound ++ Blaster's mixer chip. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_SetVoiceVolume ++ ( ++ int volume ++ ) ++ ++ { ++ int data; ++ int status; ++ ++ volume = min( 255, volume ); ++ volume = max( 0, volume ); ++ ++ status = BLASTER_Ok; ++ switch( BLASTER_MixerType ) ++ { ++ case SBPro : ++ case SBPro2 : ++ data = ( volume & 0xf0 ) + ( volume >> 4 ); ++ BLASTER_WriteMixer( MIXER_SBProVoice, data ); ++ break; ++ ++ case SB16 : ++ BLASTER_WriteMixer( MIXER_SB16VoiceLeft, volume & 0xf8 ); ++ BLASTER_WriteMixer( MIXER_SB16VoiceRight, volume & 0xf8 ); ++ break; ++ ++ default : ++ BLASTER_SetErrorCode( BLASTER_NoMixer ); ++ status = BLASTER_Error; ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_GetMidiVolume ++ ++ Reads the average volume of the Midi sound channel from the ++ Sound Blaster's mixer chip. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_GetMidiVolume ++ ( ++ void ++ ) ++ ++ { ++ int volume; ++ int left; ++ int right; ++ ++ switch( BLASTER_MixerType ) ++ { ++ case SBPro : ++ case SBPro2 : ++ left = BLASTER_ReadMixer( MIXER_SBProMidi ); ++ right = ( left & 0x0f ) << 4; ++ left &= 0xf0; ++ volume = ( left + right ) / 2; ++ break; ++ ++ case SB16 : ++ left = BLASTER_ReadMixer( MIXER_SB16MidiLeft ); ++ right = BLASTER_ReadMixer( MIXER_SB16MidiRight ); ++ volume = ( left + right ) / 2; ++ break; ++ ++ default : ++ BLASTER_SetErrorCode( BLASTER_NoMixer ); ++ volume = BLASTER_Error; ++ } ++ ++ return( volume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SetMidiVolume ++ ++ Sets the volume of the Midi sound channel on the Sound ++ Blaster's mixer chip. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_SetMidiVolume ++ ( ++ int volume ++ ) ++ ++ { ++ int data; ++ int status; ++ ++ volume = min( 255, volume ); ++ volume = max( 0, volume ); ++ ++ status = BLASTER_Ok; ++ switch( BLASTER_MixerType ) ++ { ++ case SBPro : ++ case SBPro2 : ++ data = ( volume & 0xf0 ) + ( volume >> 4 ); ++ BLASTER_WriteMixer( MIXER_SBProMidi, data ); ++ break; ++ ++ case SB16 : ++ BLASTER_WriteMixer( MIXER_SB16MidiLeft, volume & 0xf8 ); ++ BLASTER_WriteMixer( MIXER_SB16MidiRight, volume & 0xf8 ); ++ break; ++ ++ default : ++ BLASTER_SetErrorCode( BLASTER_NoMixer ); ++ status = BLASTER_Error; ++ } ++ ++ return( status ); ++ } ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_CardHasMixer ++ ++ Checks if the selected Sound Blaster card has a mixer. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_CardHasMixer ++ ( ++ void ++ ) ++ ++ { ++ return( BLASTER_Card.HasMixer ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SaveVoiceVolume ++ ++ Saves the user's voice mixer settings. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_SaveVoiceVolume ++ ( ++ void ++ ) ++ ++ { ++ switch( BLASTER_MixerType ) ++ { ++ case SBPro : ++ case SBPro2 : ++ BLASTER_OriginalVoiceVolumeLeft = ++ BLASTER_ReadMixer( MIXER_SBProVoice ); ++ break; ++ ++ case SB16 : ++ BLASTER_OriginalVoiceVolumeLeft = ++ BLASTER_ReadMixer( MIXER_SB16VoiceLeft ); ++ BLASTER_OriginalVoiceVolumeRight = ++ BLASTER_ReadMixer( MIXER_SB16VoiceRight ); ++ break; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_RestoreVoiceVolume ++ ++ Restores the user's voice mixer settings. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_RestoreVoiceVolume ++ ( ++ void ++ ) ++ ++ { ++ switch( BLASTER_MixerType ) ++ { ++ case SBPro : ++ case SBPro2 : ++ BLASTER_WriteMixer( MIXER_SBProVoice, ++ BLASTER_OriginalVoiceVolumeLeft ); ++ break; ++ ++ case SB16 : ++ BLASTER_WriteMixer( MIXER_SB16VoiceLeft, ++ BLASTER_OriginalVoiceVolumeLeft ); ++ BLASTER_WriteMixer( MIXER_SB16VoiceRight, ++ BLASTER_OriginalVoiceVolumeRight ); ++ break; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SaveMidiVolume ++ ++ Saves the user's FM mixer settings. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_SaveMidiVolume ++ ( ++ void ++ ) ++ ++ { ++ switch( BLASTER_MixerType ) ++ { ++ case SBPro : ++ case SBPro2 : ++ BLASTER_OriginalMidiVolumeLeft = ++ BLASTER_ReadMixer( MIXER_SBProMidi ); ++ break; ++ ++ case SB16 : ++ BLASTER_OriginalMidiVolumeLeft = ++ BLASTER_ReadMixer( MIXER_SB16MidiLeft ); ++ BLASTER_OriginalMidiVolumeRight = ++ BLASTER_ReadMixer( MIXER_SB16MidiRight ); ++ break; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_RestoreMidiVolume ++ ++ Restores the user's FM mixer settings. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_RestoreMidiVolume ++ ( ++ void ++ ) ++ ++ { ++ switch( BLASTER_MixerType ) ++ { ++ case SBPro : ++ case SBPro2 : ++ BLASTER_WriteMixer( MIXER_SBProMidi, ++ BLASTER_OriginalMidiVolumeLeft ); ++ break; ++ ++ case SB16 : ++ BLASTER_WriteMixer( MIXER_SB16MidiLeft, ++ BLASTER_OriginalMidiVolumeLeft ); ++ BLASTER_WriteMixer( MIXER_SB16MidiRight, ++ BLASTER_OriginalMidiVolumeRight ); ++ break; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_GetEnv ++ ++ Retrieves the BLASTER environment settings and returns them to ++ the caller. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_GetEnv ++ ( ++ BLASTER_CONFIG *Config ++ ) ++ ++ { ++ char *Blaster; ++ char parameter; ++ ++ Config->Address = UNDEFINED; ++ Config->Type = UNDEFINED; ++ Config->Interrupt = UNDEFINED; ++ Config->Dma8 = UNDEFINED; ++ Config->Dma16 = UNDEFINED; ++ Config->Midi = UNDEFINED; ++ Config->Emu = UNDEFINED; ++ ++ Blaster = getenv( "BLASTER" ); ++ if ( Blaster == NULL ) ++ { ++ BLASTER_SetErrorCode( BLASTER_EnvNotFound ); ++ return( BLASTER_Error ); ++ } ++ ++ while( *Blaster != 0 ) ++ { ++ if ( *Blaster == ' ' ) ++ { ++ Blaster++; ++ continue; ++ } ++ ++ parameter = toupper( *Blaster ); ++ Blaster++; ++ ++ if ( !isxdigit( *Blaster ) ) ++ { ++ BLASTER_SetErrorCode( BLASTER_InvalidParameter ); ++ return( BLASTER_Error ); ++ } ++ ++ switch( parameter ) ++ { ++ case BlasterEnv_Address : ++ sscanf( Blaster, "%x", &Config->Address ); ++ break; ++ case BlasterEnv_Interrupt : ++ sscanf( Blaster, "%d", &Config->Interrupt ); ++ break; ++ case BlasterEnv_8bitDma : ++ sscanf( Blaster, "%d", &Config->Dma8 ); ++ break; ++ case BlasterEnv_Type : ++ sscanf( Blaster, "%d", &Config->Type ); ++ break; ++ case BlasterEnv_16bitDma : ++ sscanf( Blaster, "%d", &Config->Dma16 ); ++ break; ++ case BlasterEnv_Midi : ++ sscanf( Blaster, "%x", &Config->Midi ); ++ break; ++ case BlasterEnv_EmuAddress : ++ sscanf( Blaster, "%x", &Config->Emu ); ++ break; ++ default : ++ // Skip the offending data ++ // sscanf( Blaster, "%*s" ); ++ break; ++ } ++ ++ while( isxdigit( *Blaster ) ) ++ { ++ Blaster++; ++ } ++ } ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SetCardSettings ++ ++ Sets up the sound card's parameters. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_SetCardSettings ++ ( ++ BLASTER_CONFIG Config ++ ) ++ ++ { ++ if ( BLASTER_Installed ) ++ { ++ BLASTER_Shutdown(); ++ } ++ ++ BLASTER_Config.Address = Config.Address; ++ BLASTER_Config.Type = Config.Type; ++ BLASTER_Config.Interrupt = Config.Interrupt; ++ BLASTER_Config.Dma8 = Config.Dma8; ++ BLASTER_Config.Dma16 = Config.Dma16; ++ BLASTER_Config.Midi = Config.Midi; ++ BLASTER_Config.Emu = Config.Emu; ++ BLASTER_MixerAddress = Config.Address; ++ BLASTER_MixerType = Config.Type; ++ ++ if ( BLASTER_Config.Emu == UNDEFINED ) ++ { ++ BLASTER_Config.Emu = BLASTER_Config.Address + 0x400; ++ } ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_GetCardSettings ++ ++ Sets up the sound card's parameters. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_GetCardSettings ++ ( ++ BLASTER_CONFIG *Config ++ ) ++ ++ { ++ if ( BLASTER_Config.Address == UNDEFINED ) ++ { ++ return( BLASTER_Warning ); ++ } ++ else ++ { ++ Config->Address = BLASTER_Config.Address; ++ Config->Type = BLASTER_Config.Type; ++ Config->Interrupt = BLASTER_Config.Interrupt; ++ Config->Dma8 = BLASTER_Config.Dma8; ++ Config->Dma16 = BLASTER_Config.Dma16; ++ Config->Midi = BLASTER_Config.Midi; ++ Config->Emu = BLASTER_Config.Emu; ++ } ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_GetCardInfo ++ ++ Returns the maximum number of bits that can represent a sample ++ (8 or 16) and the number of channels (1 for mono, 2 for stereo). ++---------------------------------------------------------------------*/ ++ ++int BLASTER_GetCardInfo ++ ( ++ int *MaxSampleBits, ++ int *MaxChannels ++ ) ++ ++ { ++ if ( BLASTER_Card.MaxMixMode & STEREO ) ++ { ++ *MaxChannels = 2; ++ } ++ else ++ { ++ *MaxChannels = 1; ++ } ++ ++ if ( BLASTER_Card.MaxMixMode & SIXTEEN_BIT ) ++ { ++ *MaxSampleBits = 16; ++ } ++ else ++ { ++ *MaxSampleBits = 8; ++ } ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SetCallBack ++ ++ Specifies the user function to call at the end of a sound transfer. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_SetCallBack ++ ( ++ void ( *func )( void ) ++ ) ++ ++ { ++ BLASTER_CallBack = func; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void BLASTER_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_UnlockMemory ++ ++ Unlocks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_UnlockMemory ++ ( ++ void ++ ) ++ ++ { ++ DPMI_UnlockMemoryRegion( BLASTER_LockStart, BLASTER_LockEnd ); ++ DPMI_UnlockMemory( ( void * )&BLASTER_Interrupts[ 0 ], ++ sizeof( BLASTER_Interrupts ) ); ++ DPMI_UnlockMemory( ( void * )&BLASTER_SampleSize[ 0 ], ++ sizeof( BLASTER_SampleSize ) ); ++ DPMI_Unlock( BLASTER_Card ); ++ DPMI_Unlock( BLASTER_OldInt ); ++ DPMI_Unlock( BLASTER_Config ); ++ DPMI_Unlock( BLASTER_Installed ); ++ DPMI_Unlock( BLASTER_Version ); ++ DPMI_Unlock( BLASTER_DMABuffer ); ++ DPMI_Unlock( BLASTER_DMABufferEnd ); ++ DPMI_Unlock( BLASTER_CurrentDMABuffer ); ++ DPMI_Unlock( BLASTER_TotalDMABufferSize ); ++ DPMI_Unlock( BLASTER_TransferLength ); ++ DPMI_Unlock( BLASTER_MixMode ); ++ DPMI_Unlock( BLASTER_SamplePacketSize ); ++ DPMI_Unlock( BLASTER_SampleRate ); ++ DPMI_Unlock( BLASTER_HaltTransferCommand ); ++ DPMI_Unlock( ( int )BLASTER_SoundPlaying ); ++ DPMI_Unlock( ( int )BLASTER_SoundRecording ); ++ DPMI_Unlock( BLASTER_CallBack ); ++ DPMI_Unlock( BLASTER_IntController1Mask ); ++ DPMI_Unlock( BLASTER_IntController2Mask ); ++ DPMI_Unlock( BLASTER_MixerAddress ); ++ DPMI_Unlock( BLASTER_MixerType ); ++ DPMI_Unlock( BLASTER_OriginalMidiVolumeLeft ); ++ DPMI_Unlock( BLASTER_OriginalMidiVolumeRight ); ++ DPMI_Unlock( BLASTER_OriginalVoiceVolumeLeft ); ++ DPMI_Unlock( BLASTER_OriginalVoiceVolumeRight ); ++ DPMI_Unlock( GlobalStatus ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_LockMemory ++ ++ Locks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_LockMemory ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_LockMemoryRegion( BLASTER_LockStart, BLASTER_LockEnd ); ++ status |= DPMI_LockMemory( ( void * )&BLASTER_Interrupts[ 0 ], ++ sizeof( BLASTER_Interrupts ) ); ++ status |= DPMI_LockMemory( ( void * )&BLASTER_SampleSize[ 0 ], ++ sizeof( BLASTER_SampleSize ) ); ++ status |= DPMI_Lock( BLASTER_Card ); ++ status |= DPMI_Lock( BLASTER_OldInt ); ++ status |= DPMI_Lock( BLASTER_Config ); ++ status |= DPMI_Lock( BLASTER_Installed ); ++ status |= DPMI_Lock( BLASTER_Version ); ++ status |= DPMI_Lock( BLASTER_DMABuffer ); ++ status |= DPMI_Lock( BLASTER_DMABufferEnd ); ++ status |= DPMI_Lock( BLASTER_CurrentDMABuffer ); ++ status |= DPMI_Lock( BLASTER_TotalDMABufferSize ); ++ status |= DPMI_Lock( BLASTER_TransferLength ); ++ status |= DPMI_Lock( BLASTER_MixMode ); ++ status |= DPMI_Lock( BLASTER_SamplePacketSize ); ++ status |= DPMI_Lock( BLASTER_SampleRate ); ++ status |= DPMI_Lock( BLASTER_HaltTransferCommand ); ++ status |= DPMI_Lock( ( ( int )BLASTER_SoundPlaying ) ); ++ status |= DPMI_Lock( ( ( int )BLASTER_SoundRecording ) ); ++ status |= DPMI_Lock( BLASTER_CallBack ); ++ status |= DPMI_Lock( BLASTER_IntController1Mask ); ++ status |= DPMI_Lock( BLASTER_IntController2Mask ); ++ status |= DPMI_Lock( BLASTER_MixerAddress ); ++ status |= DPMI_Lock( BLASTER_MixerType ); ++ status |= DPMI_Lock( BLASTER_OriginalMidiVolumeLeft ); ++ status |= DPMI_Lock( BLASTER_OriginalMidiVolumeRight ); ++ status |= DPMI_Lock( BLASTER_OriginalVoiceVolumeLeft ); ++ status |= DPMI_Lock( BLASTER_OriginalVoiceVolumeRight ); ++ status |= DPMI_Lock( GlobalStatus ); ++ ++ if ( status != DPMI_Ok ) ++ { ++ BLASTER_UnlockMemory(); ++ BLASTER_SetErrorCode( BLASTER_DPMI_Error ); ++ return( BLASTER_Error ); ++ } ++ ++ return( BLASTER_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: allocateTimerStack ++ ++ Allocate a block of memory from conventional (low) memory and return ++ the selector (which can go directly into a segment register) of the ++ memory block or 0 if an error occured. ++---------------------------------------------------------------------*/ ++ ++static unsigned short allocateTimerStack ++ ( ++ unsigned short size ++ ) ++ ++ { ++ union REGS regs; ++ ++ // clear all registers ++ memset( ®s, 0, sizeof( regs ) ); ++ ++ // DPMI allocate conventional memory ++ regs.w.ax = 0x100; ++ ++ // size in paragraphs ++ regs.w.bx = ( size + 15 ) / 16; ++ ++ int386( 0x31, ®s, ®s ); ++ if (!regs.w.cflag) ++ { ++ // DPMI call returns selector in dx ++ // (ax contains real mode segment ++ // which is ignored here) ++ ++ return( regs.w.dx ); ++ } ++ ++ // Couldn't allocate memory. ++ return( NULL ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: deallocateTimerStack ++ ++ Deallocate a block of conventional (low) memory given a selector to ++ it. Assumes the block was allocated with DPMI function 0x100. ++---------------------------------------------------------------------*/ ++ ++static void deallocateTimerStack ++ ( ++ unsigned short selector ++ ) ++ ++ { ++ union REGS regs; ++ ++ if ( selector != NULL ) ++ { ++ // clear all registers ++ memset( ®s, 0, sizeof( regs ) ); ++ ++ regs.w.ax = 0x101; ++ regs.w.dx = selector; ++ int386( 0x31, ®s, ®s ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_SetupWaveBlaster ++ ++ Allows the WaveBlaster to play music while the Sound Blaster 16 ++ plays digital sound. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_SetupWaveBlaster ++ ( ++ void ++ ) ++ ++ { ++ ++ if ( BLASTER_MixerType == SB16 ) ++ { ++ // Disable MPU401 interrupts. If they are not disabled, ++ // the SB16 will not produce sound or music. ++ BLASTER_WaveBlasterState = BLASTER_ReadMixer( MIXER_DSP4xxISR_Enable ); ++ BLASTER_WriteMixer( MIXER_DSP4xxISR_Enable, MIXER_DisableMPU401Interrupts ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_ShutdownWaveBlaster ++ ++ Restores WaveBlaster mixer to original state. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_ShutdownWaveBlaster ++ ( ++ void ++ ) ++ ++ { ++ if ( BLASTER_MixerType == SB16 ) ++ { ++ // Restore the state of MPU401 interrupts. If they are not disabled, ++ // the SB16 will not produce sound or music. ++ BLASTER_WriteMixer( MIXER_DSP4xxISR_Enable, BLASTER_WaveBlasterState ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_Init ++ ++ Initializes the sound card and prepares the module to play ++ digitized sounds. ++---------------------------------------------------------------------*/ ++ ++int BLASTER_Init ++ ( ++ void ++ ) ++ ++ { ++ int Irq; ++ int Interrupt; ++ int status; ++ ++ if ( BLASTER_Installed ) ++ { ++ BLASTER_Shutdown(); ++ } ++ ++ if ( BLASTER_Config.Address == UNDEFINED ) ++ { ++ BLASTER_SetErrorCode( BLASTER_AddrNotSet ); ++ return( BLASTER_Error ); ++ } ++ ++ // Save the interrupt masks ++ BLASTER_IntController1Mask = inp( 0x21 ); ++ BLASTER_IntController2Mask = inp( 0xA1 ); ++ ++ status = BLASTER_ResetDSP(); ++ if ( status == BLASTER_Ok ) ++ { ++ BLASTER_SaveVoiceVolume(); ++ ++ BLASTER_SoundPlaying = FALSE; ++ ++ BLASTER_SetCallBack( NULL ); ++ ++ BLASTER_DMABuffer = NULL; ++ ++ BLASTER_Version = BLASTER_GetDSPVersion(); ++ ++ BLASTER_SetPlaybackRate( BLASTER_DefaultSampleRate ); ++ BLASTER_SetMixMode( BLASTER_DefaultMixMode ); ++ ++ if ( BLASTER_Config.Dma16 != UNDEFINED ) ++ { ++ status = DMA_VerifyChannel( BLASTER_Config.Dma16 ); ++ if ( status == DMA_Error ) ++ { ++ BLASTER_SetErrorCode( BLASTER_DmaError ); ++ return( BLASTER_Error ); ++ } ++ } ++ ++ if ( BLASTER_Config.Dma8 != UNDEFINED ) ++ { ++ status = DMA_VerifyChannel( BLASTER_Config.Dma8 ); ++ if ( status == DMA_Error ) ++ { ++ BLASTER_SetErrorCode( BLASTER_DmaError ); ++ return( BLASTER_Error ); ++ } ++ } ++ ++ // Install our interrupt handler ++ Irq = BLASTER_Config.Interrupt; ++ if ( !VALID_IRQ( Irq ) ) ++ { ++ BLASTER_SetErrorCode( BLASTER_InvalidIrq ); ++ return( BLASTER_Error ); ++ } ++ ++ Interrupt = BLASTER_Interrupts[ Irq ]; ++ if ( Interrupt == INVALID ) ++ { ++ BLASTER_SetErrorCode( BLASTER_InvalidIrq ); ++ return( BLASTER_Error ); ++ } ++ ++ status = BLASTER_LockMemory(); ++ if ( status != BLASTER_Ok ) ++ { ++ BLASTER_UnlockMemory(); ++ return( status ); ++ } ++ ++ StackSelector = allocateTimerStack( kStackSize ); ++ if ( StackSelector == NULL ) ++ { ++ BLASTER_UnlockMemory(); ++ BLASTER_SetErrorCode( BLASTER_OutOfMemory ); ++ return( BLASTER_Error ); ++ } ++ ++ // Leave a little room at top of stack just for the hell of it... ++ StackPointer = kStackSize - sizeof( long ); ++ ++ BLASTER_OldInt = _dos_getvect( Interrupt ); ++ if ( Irq < 8 ) ++ { ++ _dos_setvect( Interrupt, BLASTER_ServiceInterrupt ); ++ } ++ else ++ { ++ status = IRQ_SetVector( Interrupt, BLASTER_ServiceInterrupt ); ++ if ( status != IRQ_Ok ) ++ { ++ BLASTER_UnlockMemory(); ++ deallocateTimerStack( StackSelector ); ++ StackSelector = NULL; ++ BLASTER_SetErrorCode( BLASTER_UnableToSetIrq ); ++ return( BLASTER_Error ); ++ } ++ } ++ ++ BLASTER_Installed = TRUE; ++ status = BLASTER_Ok; ++ } ++ ++ BLASTER_SetErrorCode( status ); ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: BLASTER_Shutdown ++ ++ Ends transfer of sound data to the sound card and restores the ++ system resources used by the card. ++---------------------------------------------------------------------*/ ++ ++void BLASTER_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ int Irq; ++ int Interrupt; ++ ++ // Halt the DMA transfer ++ BLASTER_StopPlayback(); ++ ++ BLASTER_RestoreVoiceVolume(); ++ ++ // Reset the DSP ++ BLASTER_ResetDSP(); ++ ++ // Restore the original interrupt ++ Irq = BLASTER_Config.Interrupt; ++ Interrupt = BLASTER_Interrupts[ Irq ]; ++ if ( Irq >= 8 ) ++ { ++ IRQ_RestoreVector( Interrupt ); ++ } ++ _dos_setvect( Interrupt, BLASTER_OldInt ); ++ ++ BLASTER_SoundPlaying = FALSE; ++ ++ BLASTER_DMABuffer = NULL; ++ ++ BLASTER_SetCallBack( NULL ); ++ ++ BLASTER_UnlockMemory(); ++ ++ deallocateTimerStack( StackSelector ); ++ StackSelector = NULL; ++ ++ BLASTER_Installed = FALSE; ++ } +diff -urN rott-1.0/rott/audiolib/blaster.h trunk/rott/audiolib/blaster.h +--- rott-1.0/rott/audiolib/blaster.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/blaster.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,148 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: BLASTER.H ++ ++ author: James R. Dose ++ date: February 4, 1994 ++ ++ Public header for BLASTER.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __BLASTER_H ++#define __BLASTER_H ++ ++typedef struct ++ { ++ unsigned Address; ++ unsigned Type; ++ unsigned Interrupt; ++ unsigned Dma8; ++ unsigned Dma16; ++ unsigned Midi; ++ unsigned Emu; ++ } BLASTER_CONFIG; ++ ++extern BLASTER_CONFIG BLASTER_Config; ++extern int BLASTER_DMAChannel; ++ ++#define UNDEFINED -1 ++ ++enum BLASTER_ERRORS ++ { ++ BLASTER_Warning = -2, ++ BLASTER_Error = -1, ++ BLASTER_Ok = 0, ++ BLASTER_EnvNotFound, ++ BLASTER_AddrNotSet, ++ BLASTER_DMANotSet, ++ BLASTER_DMA16NotSet, ++ BLASTER_InvalidParameter, ++ BLASTER_CardNotReady, ++ BLASTER_NoSoundPlaying, ++ BLASTER_InvalidIrq, ++ BLASTER_UnableToSetIrq, ++ BLASTER_DmaError, ++ BLASTER_NoMixer, ++ BLASTER_DPMI_Error, ++ BLASTER_OutOfMemory ++ }; ++ ++enum BLASTER_Types ++ { ++ SB = 1, ++ SBPro = 2, ++ SB20 = 3, ++ SBPro2 = 4, ++ SB16 = 6 ++ }; ++ ++#define BLASTER_MinCardType SB ++#define BLASTER_MaxCardType SB16 ++ ++#define STEREO 1 ++#define SIXTEEN_BIT 2 ++ ++#define MONO_8BIT 0 ++#define STEREO_8BIT ( STEREO ) ++#define MONO_16BIT ( SIXTEEN_BIT ) ++#define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) ++ ++#define BLASTER_MaxMixMode STEREO_16BIT ++ ++#define MONO_8BIT_SAMPLE_SIZE 1 ++#define MONO_16BIT_SAMPLE_SIZE 2 ++#define STEREO_8BIT_SAMPLE_SIZE ( 2 * MONO_8BIT_SAMPLE_SIZE ) ++#define STEREO_16BIT_SAMPLE_SIZE ( 2 * MONO_16BIT_SAMPLE_SIZE ) ++ ++#define BLASTER_DefaultSampleRate 11000 ++#define BLASTER_DefaultMixMode MONO_8BIT ++#define BLASTER_MaxIrq 15 ++ ++char *BLASTER_ErrorString( int ErrorNumber ); ++void BLASTER_EnableInterrupt( void ); ++void BLASTER_DisableInterrupt( void ); ++int BLASTER_WriteDSP( unsigned data ); ++int BLASTER_ReadDSP( void ); ++int BLASTER_ResetDSP( void ); ++int BLASTER_GetDSPVersion( void ); ++void BLASTER_SpeakerOn( void ); ++void BLASTER_SpeakerOff( void ); ++void BLASTER_SetPlaybackRate( unsigned rate ); ++unsigned BLASTER_GetPlaybackRate( void ); ++int BLASTER_SetMixMode( int mode ); ++void BLASTER_StopPlayback( void ); ++int BLASTER_SetupDMABuffer( char *BufferPtr, int BufferSize, int mode ); ++int BLASTER_GetCurrentPos( void ); ++int BLASTER_DSP1xx_BeginPlayback( int length ); ++int BLASTER_DSP2xx_BeginPlayback( int length ); ++int BLASTER_DSP4xx_BeginPlayback( int length ); ++int BLASTER_BeginBufferedRecord( char *BufferStart, int BufferSize, ++ int NumDivisions, unsigned SampleRate, int MixMode, ++ void ( *CallBackFunc )( void ) ); ++int BLASTER_BeginBufferedPlayback( char *BufferStart, ++ int BufferSize, int NumDivisions, unsigned SampleRate, ++ int MixMode, void ( *CallBackFunc )( void ) ); ++void BLASTER_WriteMixer( int reg, int data ); ++int BLASTER_ReadMixer( int reg ); ++int BLASTER_GetVoiceVolume( void ); ++int BLASTER_SetVoiceVolume( int volume ); ++int BLASTER_GetMidiVolume( void ); ++int BLASTER_SetMidiVolume( int volume ); ++int BLASTER_CardHasMixer( void ); ++void BLASTER_SaveVoiceVolume( void ); ++void BLASTER_RestoreVoiceVolume( void ); ++void BLASTER_SaveMidiVolume( void ); ++void BLASTER_RestoreMidiVolume( void ); ++int BLASTER_GetEnv( BLASTER_CONFIG *Config ); ++int BLASTER_SetCardSettings( BLASTER_CONFIG Config ); ++int BLASTER_GetCardSettings( BLASTER_CONFIG *Config ); ++int BLASTER_GetCardInfo( int *MaxSampleBits, int *MaxChannels ); ++void BLASTER_SetCallBack( void ( *func )( void ) ); ++void BLASTER_SetupWaveBlaster( void ); ++void BLASTER_ShutdownWaveBlaster( void ); ++int BLASTER_Init( void ); ++void BLASTER_Shutdown( void ); ++void BLASTER_UnlockMemory( void ); ++int BLASTER_LockMemory( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/ctaweapi.h trunk/rott/audiolib/ctaweapi.h +--- rott-1.0/rott/audiolib/ctaweapi.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/ctaweapi.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,352 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/****************************************************************************\ ++* * ++* CTAWEAPI.H SB AWE32 DOS API header * ++* * ++* (C) Copyright Creative Technology Ltd. 1992-94. All rights reserved * ++* worldwide. * ++* * ++* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY * ++* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * ++* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR * ++* PURPOSE. * ++* * ++* You have a royalty-free right to use, modify, reproduce and * ++* distribute the Sample Files (and/or any modified version) in * ++* any way you find useful, provided that you agree to * ++* the Creative's Software Licensing Aggreement and you also agree that * ++* Creative has no warranty obligations or liability for any Sample Files. * ++* * ++\****************************************************************************/ ++ ++/****************************************************************************\ ++* File name : CTAWEAPI.H * ++* * ++* Programmer : Creative SB AWE32 Team * ++* Creative Technology Ltd, 1994. All rights reserved. * ++* * ++* Version : 2.0b * ++* * ++\****************************************************************************/ ++ ++#ifndef _CTAWEAPI ++#define _CTAWEAPI ++ ++ ++#define MAXBANKS 64 /* maximum number of banks */ ++#define MAXNRPN 32 /* maximum number of NRPN */ ++ ++ ++#if defined(__FLAT__) || defined(__HIGHC__) || defined(DOS386) ++#define PACKETSIZE 8192 /* packet size for 32bit libraries */ ++#else ++#define PACKETSIZE 512 /* packet size for real mode libraries */ ++#endif ++ ++ ++#if defined(__FLAT__) ++ #define NEAR ++ #define FAR ++#endif ++ ++ ++#if defined(__SC__) ++ #pragma pack(1) ++ #if defined(DOS386) ++ #define NEAR ++ #define FAR ++ #endif ++#endif ++ ++ ++#if defined(__WATCOMC__) ++ #pragma pack(1) ++#endif ++ ++ ++#if defined(__HIGHC__) ++ #define NEAR ++ #define FAR ++ #define PASCAL _DCC((_DEFAULT_CALLING_CONVENTION|_CALLEE_POPS_STACK) & \ ++ ~ (_REVERSE_PARMS|_OVERLOADED)) ++ #pragma Push_align_members(1) ++ #pragma Global_aliasing_convention("_%r") ++#endif ++ ++ ++typedef int BOOL; ++#define FALSE 0 ++#define TRUE 1 ++ ++typedef unsigned char BYTE; ++typedef unsigned short WORD; ++typedef unsigned long DWORD; ++ ++typedef short int SHORT; ++typedef unsigned int UINT; ++typedef signed long LONG; ++ ++#ifndef FAR ++#define FAR __far ++#endif ++ ++#ifndef HUGE ++#define HUGE __huge ++#endif ++ ++#ifndef PASCAL ++#define PASCAL __pascal ++#endif ++ ++typedef void FAR* LPVOID; ++typedef BYTE FAR* LPBYTE; ++typedef WORD FAR* LPWORD; ++typedef DWORD FAR* LPDWORD; ++ ++#define LOBYTE(w) ((BYTE)(w)) ++#define HIBYTE(w) ((BYTE)(((UINT)(w) >> 8) & 0xFF)) ++ ++#define LOWORD(l) ((WORD)(DWORD)(l)) ++#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF)) ++ ++ ++#if defined(__cplusplus) ++extern "C" { ++#endif ++ ++ ++/* Start of modules */ ++extern int* __midieng_code(void); ++extern int* __hardware_code(void); ++extern int* __sbkload_code(void); ++extern int* __nrpn_code(void); ++extern int __midivar_data; ++extern int __nrpnvar_data; ++extern int __embed_data; ++ ++ ++typedef char SCRATCH[702]; ++typedef char SOUNDFONT[124]; ++typedef char GCHANNEL[20]; ++typedef char MIDICHANNEL[32]; ++typedef char NRPNCHANNEL[96]; ++ ++typedef struct { ++ SHORT bank_no; /* Slot number being used */ ++ SHORT total_banks; /* Total number of banks */ ++ LONG FAR* banksizes; /* Pointer to a list of bank sizes */ ++ LONG file_size; /* exact size of the sound font file */ ++ char FAR* data; /* Address of buffer of size >= PACKETSIZE */ ++ char FAR* presets; /* Allocated memory for preset data */ ++ ++ LONG total_patch_ram; /* Total patch ram available */ ++ SHORT no_sample_packets;/* Number of packets of sound sample to stream */ ++ LONG sample_seek; /* Start file location of sound sample */ ++ LONG preset_seek; /* Address of preset_seek location */ ++ LONG preset_read_size; /* Number of bytes from preset_seek to allocate and read */ ++ LONG preset_size; /* Preset actual size */ ++} SOUND_PACKET; ++ ++typedef struct { ++ SHORT tag; /* Must be 0x100 or 0x101 */ ++ SHORT preset_size; /* Preset table of this size is required */ ++ SHORT no_wave_packets; /* Number of packets of Wave sample to stream. */ ++ LONG reserved; ++ ++ SHORT bank_no; /* bank number */ ++ char FAR* data; /* Address of packet of size PACKETSIZE */ ++ char FAR* presets; /* Allocated memory for preset data */ ++ LONG sample_size; /* Sample size, i.e. number of samples */ ++ LONG samples_per_sec; /* Samples per second */ ++ SHORT bits_per_sample; /* Bits per sample, 8 or 16 */ ++ SHORT no_channels; /* Number of channels, 1=mono, 2=stereo */ ++ SHORT looping; /* Looping? 0=no, 1=yes */ ++ LONG startloop; /* if looping, then these are the addresses */ ++ LONG endloop; ++ SHORT release; /* release time, 0=24ms, 8191=23.78s */ ++} WAVE_PACKET; ++ ++typedef struct { ++ LPBYTE SPad1; ++ LPBYTE SPad2; ++ LPBYTE SPad3; ++ LPBYTE SPad4; ++ LPBYTE SPad5; ++ LPBYTE SPad6; ++ LPBYTE SPad7; ++} SOUNDPAD; ++ ++/* AWE32 variables */ ++extern WORD awe32NumG; ++extern WORD awe32BaseAddx; ++extern DWORD awe32DramSize; ++ ++/* MIDI variables */ ++extern SCRATCH awe32Scratch; ++extern SOUNDFONT awe32SFont[4]; ++extern GCHANNEL awe32GChannel[32]; ++extern MIDICHANNEL awe32MIDIChannel[16]; ++extern SOUNDPAD awe32SoundPad; ++ ++/* NRPN variables */ ++extern NRPNCHANNEL awe32NRPNChannel[16]; ++ ++/* SoundFont objects */ ++extern BYTE awe32SPad1Obj[]; ++extern BYTE awe32SPad2Obj[]; ++extern BYTE awe32SPad3Obj[]; ++extern BYTE awe32SPad4Obj[]; ++extern BYTE awe32SPad5Obj[]; ++extern BYTE awe32SPad6Obj[]; ++extern BYTE awe32SPad7Obj[]; ++ ++/* AWE register functions */ ++extern void PASCAL awe32RegW(WORD, WORD); ++extern WORD PASCAL awe32RegRW(WORD); ++extern void PASCAL awe32RegDW(WORD, DWORD); ++extern DWORD PASCAL awe32RegRDW(WORD); ++ ++/* MIDI support functions */ ++extern WORD PASCAL awe32InitMIDI(void); ++extern WORD PASCAL awe32NoteOn(WORD, WORD, WORD); ++extern WORD PASCAL awe32NoteOff(WORD, WORD, WORD); ++extern WORD PASCAL awe32ProgramChange(WORD, WORD); ++extern WORD PASCAL awe32Controller(WORD, WORD, WORD); ++extern WORD PASCAL awe32PolyKeyPressure(WORD, WORD, WORD); ++extern WORD PASCAL awe32ChannelPressure(WORD, WORD); ++extern WORD PASCAL awe32PitchBend(WORD, WORD, WORD); ++extern WORD PASCAL awe32Sysex(WORD, LPBYTE, WORD); ++extern WORD PASCAL __awe32NoteOff(WORD, WORD, WORD, WORD); ++extern WORD PASCAL __awe32IsPlaying(WORD, WORD, WORD, WORD); ++ ++/* NRPN support functions */ ++extern WORD PASCAL awe32InitNRPN(void); ++ ++/* Hardware support functions */ ++extern WORD PASCAL awe32Detect(WORD); ++extern WORD PASCAL awe32InitHardware(void); ++extern WORD PASCAL awe32Terminate(void); ++ ++/* SoundFont support functions */ ++extern WORD PASCAL awe32TotalPatchRam(SOUND_PACKET FAR*); ++extern WORD PASCAL awe32DefineBankSizes(SOUND_PACKET FAR*); ++extern WORD PASCAL awe32SFontLoadRequest(SOUND_PACKET FAR*); ++extern WORD PASCAL awe32StreamSample(SOUND_PACKET FAR*); ++extern WORD PASCAL awe32SetPresets(SOUND_PACKET FAR*); ++extern WORD PASCAL awe32ReleaseBank(SOUND_PACKET FAR*); ++extern WORD PASCAL awe32ReleaseAllBanks(SOUND_PACKET FAR*); ++extern WORD PASCAL awe32WPLoadRequest(WAVE_PACKET FAR*); ++extern WORD PASCAL awe32WPLoadWave(WAVE_PACKET FAR*); ++extern WORD PASCAL awe32WPStreamWave(WAVE_PACKET FAR*); ++extern WORD PASCAL awe32WPBuildSFont(WAVE_PACKET FAR*); ++ ++/* End of modules */ ++extern int* __midieng_ecode(void); ++extern int* __hardware_ecode(void); ++extern int* __sbkload_ecode(void); ++extern int* __nrpn_ecode(void); ++extern int __midivar_edata; ++extern int __nrpnvar_edata; ++extern int __embed_edata; ++ ++ ++#if defined(__cplusplus) ++} ++#endif ++ ++ ++#if defined(__SC__) ++ #pragma pack() ++#endif ++ ++ ++#if defined(__HIGHC__) ++ #pragma Pop_align_members ++ #pragma Global_aliasing_convention() ++ #pragma Alias(awe32RegW,"AWE32REGW") ++ #pragma Alias(awe32RegRW,"AWE32REGRW") ++ #pragma Alias(awe32RegDW,"AWE32REGDW") ++ #pragma Alias(awe32RegRDW,"AWE32REGRDW") ++ #pragma Alias(awe32InitMIDI,"AWE32INITMIDI") ++ #pragma Alias(awe32NoteOn,"AWE32NOTEON") ++ #pragma Alias(awe32NoteOff,"AWE32NOTEOFF") ++ #pragma Alias(awe32ProgramChange,"AWE32PROGRAMCHANGE") ++ #pragma Alias(awe32Controller,"AWE32CONTROLLER") ++ #pragma Alias(awe32PolyKeyPressure,"AWE32POLYKEYPRESSURE") ++ #pragma Alias(awe32ChannelPressure,"AWE32CHANNELPRESSURE") ++ #pragma Alias(awe32PitchBend,"AWE32PITCHBEND") ++ #pragma Alias(awe32Sysex,"AWE32SYSEX") ++ #pragma Alias(__awe32NoteOff,"__AWE32NOTEOFF") ++ #pragma Alias(__awe32IsPlaying,"__AWE32ISPLAYING") ++ #pragma Alias(awe32InitNRPN,"AWE32INITNRPN") ++ #pragma Alias(awe32Detect,"AWE32DETECT") ++ #pragma Alias(awe32InitHardware,"AWE32INITHARDWARE") ++ #pragma Alias(awe32Terminate,"AWE32TERMINATE") ++ #pragma Alias(awe32TotalPatchRam,"AWE32TOTALPATCHRAM") ++ #pragma Alias(awe32DefineBankSizes,"AWE32DEFINEBANKSIZES") ++ #pragma Alias(awe32SFontLoadRequest,"AWE32SFONTLOADREQUEST") ++ #pragma Alias(awe32StreamSample,"AWE32STREAMSAMPLE") ++ #pragma Alias(awe32SetPresets,"AWE32SETPRESETS") ++ #pragma Alias(awe32ReleaseBank,"AWE32RELEASEBANK") ++ #pragma Alias(awe32ReleaseAllBanks,"AWE32RELEASEALLBANKS") ++ #pragma Alias(awe32WPLoadRequest,"AWE32WPLOADREQUEST") ++ #pragma Alias(awe32WPLoadWave,"AWE32WPLOADWAVE") ++ #pragma Alias(awe32WPStreamWave,"AWE32WPSTREAMWAVE") ++ #pragma Alias(awe32WPBuildSFont,"AWE32WPBUILDSFONT") ++#endif ++ ++ ++#if defined(__WATCOMC__) ++ #pragma pack() ++ #pragma aux awe32NumG "_*" ++ #pragma aux awe32BaseAddx "_*" ++ #pragma aux awe32DramSize "_*" ++ #pragma aux awe32Scratch "_*" ++ #pragma aux awe32SFont "_*" ++ #pragma aux awe32GChannel "_*" ++ #pragma aux awe32MIDIChannel "_*" ++ #pragma aux awe32SoundPad "_*" ++ #pragma aux awe32NRPNChannel "_*" ++ #pragma aux awe32SPad1Obj "_*" ++ #pragma aux awe32SPad2Obj "_*" ++ #pragma aux awe32SPad3Obj "_*" ++ #pragma aux awe32SPad4Obj "_*" ++ #pragma aux awe32SPad5Obj "_*" ++ #pragma aux awe32SPad6Obj "_*" ++ #pragma aux awe32SPad7Obj "_*" ++ #pragma aux __midieng_code "_*" ++ #pragma aux __midieng_ecode "_*" ++ #pragma aux __hardware_code "_*" ++ #pragma aux __hardware_ecode "_*" ++ #pragma aux __sbkload_code "_*" ++ #pragma aux __sbkload_ecode "_*" ++ #pragma aux __nrpn_code "_*" ++ #pragma aux __nrpn_ecode "_*" ++ #pragma aux __midivar_data "_*" ++ #pragma aux __midivar_edata "_*" ++ #pragma aux __nrpnvar_data "_*" ++ #pragma aux __nrpnvar_edata "_*" ++ #pragma aux __embed_data "_*" ++ #pragma aux __embed_edata "_*" ++#endif ++ ++ ++#endif /* _CTAWEAPI */ +diff -urN rott-1.0/rott/audiolib/debugio.c trunk/rott/audiolib/debugio.c +--- rott-1.0/rott/audiolib/debugio.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/debugio.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,251 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++#include ++#include ++#include ++#include "debugio.h" ++ ++static unsigned short disp_offset = 160 * 24; ++static void myutoa( unsigned num, char *string, int radix ); ++static void myitoa( int num, char *string, int radix ); ++ ++void DB_SetXY ++ ( ++ int x, ++ int y ++ ) ++ ++ { ++ disp_offset = ( x * 2 ) + ( y * 160 ); ++ } ++ ++void DB_PutChar ++ ( ++ char ch ++ ) ++ ++ { ++ int j; ++ char *disp_start = (char *)( 0xb0000 ); ++ ++ if ( disp_offset >= 160 * 24 ) ++ { ++ for ( j = 160; j < 160 * 24; j += 2 ) ++ { ++ *( disp_start + j - 160 ) = *( disp_start + j ); ++ } ++ ++ disp_offset = 160 * 23; ++ ++ for ( j = disp_offset; j < ( 160 * 24 ); j += 2 ) ++ { ++ *( disp_start + j ) = ' '; ++ } ++ } ++ ++ if ( ch >= 32 ) ++ { ++ *( disp_start + disp_offset ) = ch; ++ disp_offset = disp_offset + 2; ++ } ++ ++ if ( ch == '\r' ) ++ { ++ disp_offset = disp_offset / 160; ++ disp_offset = disp_offset * 160; ++ } ++ ++ if ( ch == '\n' ) ++ { ++ disp_offset = disp_offset + 160; ++ if ( disp_offset < 160 * 24 ) ++ { ++ for ( j = disp_offset; j < ( ( ( disp_offset / 160 ) + 1 ) * ++ 160 ); j += 2 ) ++ { ++ *( disp_start + j ) = ' '; ++ } ++ } ++ } ++ } ++ ++int DB_PrintString ++ ( ++ char *string ++ ) ++ ++ { ++ int count; ++ char *ptr; ++ ++ ptr = string; ++ count = 0; ++ ++ while ( *ptr ) ++ { ++ DB_PutChar( *ptr ); ++ count++; ++ ptr++; ++ } ++ ++ return( count ); ++ } ++ ++static void myutoa ++ ( ++ unsigned num, ++ char *string, ++ int radix ++ ) ++ ++ { ++ int val; ++ int length; ++ int pos; ++ char temp[ 100 ]; ++ ++ length = 0; ++ do ++ { ++ val = num % radix; ++ if ( val < 10 ) ++ { ++ temp[ length ] = '0' + val; ++ } ++ else ++ { ++ temp[ length ] = 'A' + val - 10; ++ } ++ num /= radix; ++ length++; ++ } ++ while( num > 0 ); ++ ++ pos = 0; ++ while( length > 0 ) ++ { ++ length--; ++ string[ length ] = temp[ pos ]; ++ pos++; ++ } ++ string[ pos ] = 0; ++ } ++ ++static void myitoa ++ ( ++ int num, ++ char *string, ++ int radix ++ ) ++ ++ { ++ if ( num < 0 ) ++ { ++ *string++ = '-'; ++ num = -num; ++ } ++ ++ myutoa( num, string, radix ); ++ } ++ ++int DB_PrintNum ++ ( ++ int number ++ ) ++ ++ { ++ char string[ 100 ]; ++ int count; ++ ++ myitoa( number, &string[ 0 ], 10 ); ++ count = DB_PrintString( &string[ 0 ] ); ++ ++ return( count ); ++ } ++ ++int DB_PrintUnsigned ++ ( ++ unsigned long number, ++ int radix ++ ) ++ ++ { ++ char string[ 100 ]; ++ int count; ++ ++ myutoa( number, &string[ 0 ], radix ); ++ count = DB_PrintString( &string[ 0 ] ); ++ ++ return( count ); ++ } ++ ++int DB_printf ++ ( ++ char *fmt, ++ ... ++ ) ++ ++ { ++ va_list argptr; ++ int count; ++ char *ptr; ++ ++ va_start( argptr, fmt ); ++ ptr = fmt; ++ count = 0; ++ ++ while( *ptr != 0 ) ++ { ++ if ( *ptr == '%' ) ++ { ++ ptr++; ++ switch( *ptr ) ++ { ++ case 0 : ++ return( EOF ); ++ break; ++ case 'd' : ++ count += DB_PrintNum( va_arg( argptr, int ) ); ++ break; ++ case 's' : ++ count += DB_PrintString( va_arg( argptr, char * ) ); ++ break; ++ case 'u' : ++ count += DB_PrintUnsigned( va_arg( argptr, int ), 10 ); ++ break; ++ case 'x' : ++ case 'X' : ++ count += DB_PrintUnsigned( va_arg( argptr, int ), 16 ); ++ break; ++ } ++ ptr++; ++ } ++ else ++ { ++ DB_PutChar( *ptr ); ++ count++; ++ ptr++; ++ } ++ } ++ ++ va_end( argptr ); ++ ++ return( count ); ++ } +diff -urN rott-1.0/rott/audiolib/debugio.h trunk/rott/audiolib/debugio.h +--- rott-1.0/rott/audiolib/debugio.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/debugio.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,30 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++#ifndef __DEBUGIO_H ++#define __DEBUGIO_H ++ ++void DB_SetXY( int x, int y ); ++void DB_PutChar( char ch ); ++int DB_PrintString( char *string ); ++int DB_PrintNum( int number ); ++int DB_PrintUnsigned( unsigned long number, int radix ); ++int DB_printf( char *fmt, ... ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/dma.c trunk/rott/audiolib/dma.c +--- rott-1.0/rott/audiolib/dma.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/dma.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,379 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: DMA.C ++ ++ author: James R. Dose ++ date: February 4, 1994 ++ ++ Low level routines to for programming the DMA controller for 8 bit ++ and 16 bit transfers. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include "dma.h" ++ ++#define DMA_MaxChannel 7 ++ ++#define VALID ( 1 == 1 ) ++#define INVALID ( !VALID ) ++ ++#define BYTE 0 ++#define WORD 1 ++ ++typedef struct ++ { ++ int Valid; ++ int Width; ++ int Mask; ++ int Mode; ++ int Clear; ++ int Page; ++ int Address; ++ int Length; ++ } DMA_PORT; ++ ++static const DMA_PORT DMA_PortInfo[ DMA_MaxChannel + 1 ] = ++ { ++ { VALID, BYTE, 0xA, 0xB, 0xC, 0x87, 0x0, 0x1 }, ++ { VALID, BYTE, 0xA, 0xB, 0xC, 0x83, 0x2, 0x3 }, ++ { INVALID, BYTE, 0xA, 0xB, 0xC, 0x81, 0x4, 0x5 }, ++ { VALID, BYTE, 0xA, 0xB, 0xC, 0x82, 0x6, 0x7 }, ++ { INVALID, WORD, 0xD4, 0xD6, 0xD8, 0x8F, 0xC0, 0xC2 }, ++ { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x8B, 0xC4, 0xC6 }, ++ { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x89, 0xC8, 0xCA }, ++ { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x8A, 0xCC, 0xCE }, ++ }; ++ ++int DMA_ErrorCode = DMA_Ok; ++ ++#define DMA_SetErrorCode( status ) \ ++ DMA_ErrorCode = ( status ); ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DMA_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *DMA_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case DMA_Error : ++ ErrorString = DMA_ErrorString( DMA_ErrorCode ); ++ break; ++ ++ case DMA_Ok : ++ ErrorString = "DMA channel ok."; ++ break; ++ ++ case DMA_ChannelOutOfRange : ++ ErrorString = "DMA channel out of valid range."; ++ break; ++ ++ case DMA_InvalidChannel : ++ ErrorString = "Unsupported DMA channel."; ++ break; ++ ++ default : ++ ErrorString = "Unknown DMA error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DMA_VerifyChannel ++ ++ Verifies whether a DMA channel is available to transfer data. ++---------------------------------------------------------------------*/ ++ ++int DMA_VerifyChannel ++ ( ++ int channel ++ ) ++ ++ { ++ int status; ++ int Error; ++ ++ status = DMA_Ok; ++ Error = DMA_Ok; ++ ++ if ( ( channel < 0 ) || ( DMA_MaxChannel < channel ) ) ++ { ++ Error = DMA_ChannelOutOfRange; ++ status = DMA_Error; ++ } ++ else if ( DMA_PortInfo[ channel ].Valid == INVALID ) ++ { ++ Error = DMA_InvalidChannel; ++ status = DMA_Error; ++ } ++ ++ DMA_SetErrorCode( Error ); ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DMA_SetupTransfer ++ ++ Programs the specified DMA channel to transfer data. ++---------------------------------------------------------------------*/ ++ ++int DMA_SetupTransfer ++ ( ++ int channel, ++ char *address, ++ int length, ++ int mode ++ ) ++ ++ { ++ DMA_PORT *Port; ++ int addr; ++ int ChannelSelect; ++ int Page; ++ int HiByte; ++ int LoByte; ++ int TransferLength; ++ int status; ++ ++ status = DMA_VerifyChannel( channel ); ++ ++ if ( status == DMA_Ok ) ++ { ++ Port = &DMA_PortInfo[ channel ]; ++ ChannelSelect = channel & 0x3; ++ ++ addr = ( int )address; ++ ++ if ( Port->Width == WORD ) ++ { ++ Page = ( addr >> 16 ) & 255; ++ HiByte = ( addr >> 9 ) & 255; ++ LoByte = ( addr >> 1 ) & 255; ++ ++ // Convert the length in bytes to the length in words ++ TransferLength = ( length + 1 ) >> 1; ++ ++ // The length is always one less the number of bytes or words ++ // that we're going to send ++ TransferLength--; ++ } ++ else ++ { ++ Page = ( addr >> 16 ) & 255; ++ HiByte = ( addr >> 8 ) & 255; ++ LoByte = addr & 255; ++ ++ // The length is always one less the number of bytes or words ++ // that we're going to send ++ TransferLength = length - 1; ++ } ++ ++ // Mask off DMA channel ++ outp( Port->Mask, 4 | ChannelSelect ); ++ ++ // Clear flip-flop to lower byte with any data ++ outp( Port->Clear, 0 ); ++ ++ // Set DMA mode ++ switch( mode ) ++ { ++ case DMA_SingleShotRead : ++ outp( Port->Mode, 0x48 | ChannelSelect ); ++ break; ++ ++ case DMA_SingleShotWrite : ++ outp( Port->Mode, 0x44 | ChannelSelect ); ++ break; ++ ++ case DMA_AutoInitRead : ++ outp( Port->Mode, 0x58 | ChannelSelect ); ++ break; ++ ++ case DMA_AutoInitWrite : ++ outp( Port->Mode, 0x54 | ChannelSelect ); ++ break; ++ } ++ ++ // Send address ++ outp( Port->Address, LoByte ); ++ outp( Port->Address, HiByte ); ++ ++ // Send page ++ outp( Port->Page, Page ); ++ ++ // Send length ++ outp( Port->Length, TransferLength ); ++ outp( Port->Length, TransferLength >> 8 ); ++ ++ // enable DMA channel ++ outp( Port->Mask, ChannelSelect ); ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DMA_EndTransfer ++ ++ Ends use of the specified DMA channel. ++---------------------------------------------------------------------*/ ++ ++int DMA_EndTransfer ++ ( ++ int channel ++ ) ++ ++ { ++ DMA_PORT *Port; ++ int ChannelSelect; ++ int status; ++ ++ status = DMA_VerifyChannel( channel ); ++ if ( status == DMA_Ok ) ++ { ++ Port = &DMA_PortInfo[ channel ]; ++ ChannelSelect = channel & 0x3; ++ ++ // Mask off DMA channel ++ outp( Port->Mask, 4 | ChannelSelect ); ++ ++ // Clear flip-flop to lower byte with any data ++ outp( Port->Clear, 0 ); ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DMA_GetCurrentPos ++ ++ Returns the position of the specified DMA transfer. ++---------------------------------------------------------------------*/ ++ ++char *DMA_GetCurrentPos ++ ( ++ int channel ++ ) ++ ++ { ++ DMA_PORT *Port; ++ unsigned long addr; ++ int status; ++ ++ addr = NULL; ++ status = DMA_VerifyChannel( channel ); ++ ++ if ( status == DMA_Ok ) ++ { ++ Port = &DMA_PortInfo[ channel ]; ++ ++ if ( Port->Width == WORD ) ++ { ++ // Get address ++ addr = inp( Port->Address ) << 1; ++ addr |= inp( Port->Address ) << 9; ++ ++ // Get page ++ addr |= inp( Port->Page ) << 16; ++ } ++ else ++ { ++ // Get address ++ addr = inp( Port->Address ); ++ addr |= inp( Port->Address ) << 8; ++ ++ // Get page ++ addr |= inp( Port->Page ) << 16; ++ } ++ } ++ ++ return( ( char * )addr ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DMA_GetTransferCount ++ ++ Returns how many bytes are left in the DMA's transfer. ++---------------------------------------------------------------------*/ ++ ++int DMA_GetTransferCount ++ ( ++ int channel ++ ) ++ ++ { ++ DMA_PORT *Port; ++ int count; ++ int status; ++ ++ status = DMA_Ok; ++ ++ count = 0; ++ ++ if ( ( channel < 0 ) || ( DMA_MaxChannel < channel ) ) ++ { ++ status = DMA_ChannelOutOfRange; ++ } ++ else if ( DMA_PortInfo[ channel ].Valid == INVALID ) ++ { ++ status = DMA_InvalidChannel; ++ } ++ ++ if ( status == DMA_Ok ) ++ { ++ Port = &DMA_PortInfo[ channel ]; ++ ++ outp( Port->Clear, 0 ); ++ count = inp( Port->Length ); ++ count += inp( Port->Length ) << 8; ++ ++ if ( Port->Width == WORD ) ++ { ++ count <<= 1; ++ } ++ } ++ ++ DMA_SetErrorCode( status ); ++ ++ return( count ); ++ } +diff -urN rott-1.0/rott/audiolib/dma.h trunk/rott/audiolib/dma.h +--- rott-1.0/rott/audiolib/dma.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/dma.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,83 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ file: DMA.H ++ ++ author: James R. Dose ++ date: February 4, 1994 ++ ++ Public header file for DMA.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __DMA_H ++#define __DMA_H ++ ++enum DMA_ERRORS ++ { ++ DMA_Error = -1, ++ DMA_Ok = 0, ++ DMA_ChannelOutOfRange, ++ DMA_InvalidChannel ++ }; ++ ++enum DMA_Modes ++ { ++ DMA_SingleShotRead, ++ DMA_SingleShotWrite, ++ DMA_AutoInitRead, ++ DMA_AutoInitWrite ++ }; ++ ++char *DMA_ErrorString ++ ( ++ int ErrorNumber ++ ); ++ ++int DMA_VerifyChannel ++ ( ++ int channel ++ ); ++ ++int DMA_SetupTransfer ++ ( ++ int channel, ++ char *address, ++ int length, ++ int mode ++ ); ++ ++int DMA_EndTransfer ++ ( ++ int channel ++ ); ++ ++char *DMA_GetCurrentPos ++ ( ++ int channel ++ ); ++ ++int DMA_GetTransferCount ++ ( ++ int channel ++ ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/dpmi.c trunk/rott/audiolib/dpmi.c +--- rott-1.0/rott/audiolib/dpmi.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/dpmi.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,250 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: DPMI.C ++ ++ author: James R. Dose ++ date: April 8, 1994 ++ ++ Functions for performing DPMI calls. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include "dpmi.h" ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++static union REGS Regs; ++static struct SREGS SegRegs; ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_GetRealModeVector ++ ++ Returns the vector of a real mode interrupt. ++---------------------------------------------------------------------*/ ++ ++unsigned long DPMI_GetRealModeVector ++ ( ++ int num ++ ) ++ ++ { ++ unsigned long vector; ++ ++ Regs.x.eax = 0x0200; ++ Regs.h.bl = num; ++ int386( 0x31, &Regs, &Regs ); ++ ++ vector = Regs.w.cx & 0xffff; ++ vector <<= 16; ++ vector |= Regs.w.dx & 0xffff; ++ ++ return( vector ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_SetRealModeVector ++ ++ Sets the vector of a real mode interrupt. ++---------------------------------------------------------------------*/ ++ ++void DPMI_SetRealModeVector ++ ( ++ int num, ++ unsigned long vector ++ ) ++ ++ { ++ Regs.x.eax = 0x0201; ++ Regs.h.bl = num; ++ Regs.w.dx = vector & 0xffff; ++ Regs.w.cx = ( vector >> 16 ) & 0xffff; ++ ++ int386( 0x31, &Regs, &Regs ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_CallRealModeFunction ++ ++ Performs a call to a real mode function. ++---------------------------------------------------------------------*/ ++ ++int DPMI_CallRealModeFunction ++ ( ++ dpmi_regs *callregs ++ ) ++ ++ { ++ // Setup our registers to call DPMI ++ Regs.w.ax = 0x0301; ++ Regs.h.bl = 0; ++ Regs.h.bh = 0; ++ Regs.w.cx = 0; ++ ++ SegRegs.es = FP_SEG( callregs ); ++ Regs.x.edi = FP_OFF( callregs ); ++ ++ // Call Real-mode procedure with Far Return Frame ++ int386x( 0x31, &Regs, &Regs, &SegRegs ); ++ ++ if ( Regs.x.cflag ) ++ { ++ return( DPMI_Error ); ++ } ++ ++ return( DPMI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_LockMemory ++ ++ Locks a region of memory to keep the virtual memory manager from ++ paging the region out. ++---------------------------------------------------------------------*/ ++ ++int DPMI_LockMemory ++ ( ++ void *address, ++ unsigned length ++ ) ++ ++ { ++ unsigned linear; ++ ++ // Thanks to DOS/4GW's zero-based flat memory model, converting ++ // a pointer of any type to a linear address is trivial. ++ ++ linear = (unsigned) address; ++ ++ // DPMI Lock Linear Region ++ Regs.w.ax = 0x600; ++ ++ // Linear address in BX:CX ++ Regs.w.bx = (linear >> 16); ++ Regs.w.cx = (linear & 0xFFFF); ++ ++ // Length in SI:DI ++ Regs.w.si = (length >> 16); ++ Regs.w.di = (length & 0xFFFF); ++ ++ int386 (0x31, &Regs, &Regs); ++ ++ // Return 0 if can't lock ++ if ( Regs.w.cflag ) ++ { ++ return( DPMI_Error ); ++ } ++ ++ return ( DPMI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_LockMemoryRegion ++ ++ Locks a region of memory to keep the virtual memory manager from ++ paging the region out. ++---------------------------------------------------------------------*/ ++ ++int DPMI_LockMemoryRegion ++ ( ++ void *start, ++ void *end ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_LockMemory( start, ( char * )end - ( char * )start ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_UnlockMemory ++ ++ Unlocks a region of memory that was previously locked. ++---------------------------------------------------------------------*/ ++ ++int DPMI_UnlockMemory ++ ( ++ void *address, ++ unsigned length ++ ) ++ ++ { ++ unsigned linear; ++ ++ // Thanks to DOS/4GW's zero-based flat memory model, converting ++ // a pointer of any type to a linear address is trivial. ++ ++ linear = (unsigned) address; ++ ++ // DPMI Unlock Linear Region ++ Regs.w.ax = 0x601; ++ ++ // Linear address in BX:CX ++ Regs.w.bx = (linear >> 16); ++ Regs.w.cx = (linear & 0xFFFF); ++ ++ // Length in SI:DI ++ Regs.w.si = (length >> 16); ++ Regs.w.di = (length & 0xFFFF); ++ ++ int386 (0x31, &Regs, &Regs); ++ ++ // Return 0 if can't unlock ++ if ( Regs.w.cflag ) ++ { ++ return( DPMI_Error ); ++ } ++ ++ return ( DPMI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_UnlockMemoryRegion ++ ++ Unlocks a region of memory that was previously locked. ++---------------------------------------------------------------------*/ ++ ++int DPMI_UnlockMemoryRegion ++ ( ++ void *start, ++ void *end ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_UnlockMemory( start, ( char * )end - ( char * )start ); ++ ++ return( status ); ++ } +diff -urN rott-1.0/rott/audiolib/dpmi.h trunk/rott/audiolib/dpmi.h +--- rott-1.0/rott/audiolib/dpmi.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/dpmi.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,102 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: DPMI.H ++ ++ author: James R. Dose ++ date: March 31, 1994 ++ ++ Inline functions for performing DPMI calls. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __DPMI_H ++#define __DPMI_H ++ ++enum DPMI_Errors ++ { ++ DPMI_Warning = -2, ++ DPMI_Error = -1, ++ DPMI_Ok = 0 ++ }; ++ ++typedef struct ++ { ++ unsigned long EDI; ++ unsigned long ESI; ++ unsigned long EBP; ++ unsigned long Reserved; ++ unsigned long EBX; ++ unsigned long EDX; ++ unsigned long ECX; ++ unsigned long EAX; ++ unsigned short Flags; ++ unsigned short ES; ++ unsigned short DS; ++ unsigned short FS; ++ unsigned short GS; ++ unsigned short IP; ++ unsigned short CS; ++ unsigned short SP; ++ unsigned short SS; ++ } dpmi_regs; ++ ++unsigned long DPMI_GetRealModeVector( int num ); ++void DPMI_SetRealModeVector( int num, unsigned long vector ); ++int DPMI_CallRealModeFunction( dpmi_regs *callregs ); ++int DPMI_GetDOSMemory( void **ptr, int *descriptor, unsigned length ); ++int DPMI_FreeDOSMemory( int descriptor ); ++int DPMI_LockMemory( void *address, unsigned length ); ++int DPMI_LockMemoryRegion( void *start, void *end ); ++int DPMI_UnlockMemory( void *address, unsigned length ); ++int DPMI_UnlockMemoryRegion( void *start, void *end ); ++ ++#define DPMI_Lock( variable ) \ ++ ( DPMI_LockMemory( (void *) &( variable ), sizeof( variable ) ) ) ++ ++#define DPMI_Unlock( variable ) \ ++ ( DPMI_UnlockMemory( (void *) &( variable ), sizeof( variable ) ) ) ++ ++#ifdef PLAT_DOS ++#pragma aux DPMI_GetDOSMemory = \ ++ "mov eax, 0100h", \ ++ "add ebx, 15", \ ++ "shr ebx, 4", \ ++ "int 31h", \ ++ "jc DPMI_Exit", \ ++ "movzx eax, ax", \ ++ "shl eax, 4", \ ++ "mov [ esi ], eax", \ ++ "mov [ edi ], edx", \ ++ "sub eax, eax", \ ++ "DPMI_Exit:", \ ++ parm [ esi ] [ edi ] [ ebx ] modify exact [ eax ebx edx ]; ++ ++#pragma aux DPMI_FreeDOSMemory = \ ++ "mov eax, 0101h", \ ++ "int 31h", \ ++ "jc DPMI_Exit", \ ++ "sub eax, eax", \ ++ "DPMI_Exit:", \ ++ parm [ edx ] modify exact [ eax ]; ++#endif ++ ++#endif +diff -urN rott-1.0/rott/audiolib/dsl.c trunk/rott/audiolib/dsl.c +--- rott-1.0/rott/audiolib/dsl.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/dsl.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,235 @@ ++#include ++#include ++ ++#include "dsl.h" ++#include "util.h" ++ ++#include "SDL.h" ++#include "SDL_mixer.h" ++ ++extern volatile int MV_MixPage; ++ ++static int DSL_ErrorCode = DSL_Ok; ++ ++static int mixer_initialized; ++ ++static void ( *_CallBackFunc )( void ); ++static volatile char *_BufferStart; ++static int _BufferSize; ++static int _NumDivisions; ++static int _SampleRate; ++static int _remainder; ++ ++static Mix_Chunk *blank; ++static unsigned char *blank_buf; ++ ++/* ++possible todo ideas: cache sdl/sdl mixer error messages. ++*/ ++ ++char *DSL_ErrorString( int ErrorNumber ) ++{ ++ char *ErrorString; ++ ++ switch (ErrorNumber) { ++ case DSL_Warning: ++ case DSL_Error: ++ ErrorString = DSL_ErrorString(DSL_ErrorCode); ++ break; ++ ++ case DSL_Ok: ++ ErrorString = "SDL Driver ok."; ++ break; ++ ++ case DSL_SDLInitFailure: ++ ErrorString = "SDL Audio initialization failed."; ++ break; ++ ++ case DSL_MixerActive: ++ ErrorString = "SDL Mixer already initialized."; ++ break; ++ ++ case DSL_MixerInitFailure: ++ ErrorString = "SDL Mixer initialization failed."; ++ break; ++ ++ default: ++ ErrorString = "Unknown SDL Driver error."; ++ break; ++ } ++ ++ return ErrorString; ++} ++ ++static void DSL_SetErrorCode(int ErrorCode) ++{ ++ DSL_ErrorCode = ErrorCode; ++} ++ ++int DSL_Init( void ) ++{ ++ DSL_SetErrorCode(DSL_Ok); ++ ++ if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { ++ DSL_SetErrorCode(DSL_SDLInitFailure); ++ ++ return DSL_Error; ++ } ++ ++ return DSL_Ok; ++} ++ ++void DSL_Shutdown( void ) ++{ ++ DSL_StopPlayback(); ++} ++ ++static void mixer_callback(int chan, void *stream, int len, void *udata) ++{ ++ Uint8 *stptr; ++ Uint8 *fxptr; ++ int copysize; ++ ++ /* len should equal _BufferSize, else this is screwed up */ ++ ++ stptr = (Uint8 *)stream; ++ ++ if (_remainder > 0) { ++ copysize = min(len, _remainder); ++ ++ fxptr = (Uint8 *)(&_BufferStart[MV_MixPage * ++ _BufferSize]); ++ ++ memcpy(stptr, fxptr+(_BufferSize-_remainder), copysize); ++ ++ len -= copysize; ++ _remainder -= copysize; ++ ++ stptr += copysize; ++ } ++ ++ while (len > 0) { ++ /* new buffer */ ++ ++ _CallBackFunc(); ++ ++ fxptr = (Uint8 *)(&_BufferStart[MV_MixPage * ++ _BufferSize]); ++ ++ copysize = min(len, _BufferSize); ++ ++ memcpy(stptr, fxptr, copysize); ++ ++ len -= copysize; ++ ++ stptr += copysize; ++ } ++ ++ _remainder = len; ++} ++ ++int DSL_BeginBufferedPlayback( char *BufferStart, ++ int BufferSize, int NumDivisions, unsigned SampleRate, ++ int MixMode, void ( *CallBackFunc )( void ) ) ++{ ++ Uint16 format; ++ Uint8 *tmp; ++ int channels; ++ int chunksize; ++ ++ if (mixer_initialized) { ++ DSL_SetErrorCode(DSL_MixerActive); ++ ++ return DSL_Error; ++ } ++ ++ _CallBackFunc = CallBackFunc; ++ _BufferStart = BufferStart; ++ _BufferSize = (BufferSize / NumDivisions); ++ _NumDivisions = NumDivisions; ++ _SampleRate = SampleRate; ++ ++ _remainder = 0; ++ ++ format = (MixMode & SIXTEEN_BIT) ? AUDIO_S16SYS : AUDIO_U8; ++ channels = (MixMode & STEREO) ? 2 : 1; ++ ++/* ++ 23ms is typically ideal (11025,22050,44100) ++ 46ms isn't bad ++*/ ++ ++ chunksize = 512; ++ ++ if (SampleRate >= 16000) chunksize *= 2; ++ if (SampleRate >= 32000) chunksize *= 2; ++ ++/* ++// SDL mixer does this already ++ if (MixMode & SIXTEEN_BIT) chunksize *= 2; ++ if (MixMode & STEREO) chunksize *= 2; ++*/ ++ ++ if (Mix_OpenAudio(SampleRate, format, channels, chunksize) < 0) { ++ DSL_SetErrorCode(DSL_MixerInitFailure); ++ ++ return DSL_Error; ++ } ++ ++/* ++ Mix_SetPostMix(mixer_callback, NULL); ++*/ ++ /* have to use a channel because postmix will overwrite the music... */ ++ Mix_RegisterEffect(0, mixer_callback, NULL, NULL); ++ ++ /* create a dummy sample just to allocate that channel */ ++ blank_buf = (Uint8 *)malloc(4096); ++ memset(blank_buf, 0, 4096); ++ ++ blank = Mix_QuickLoad_RAW(blank_buf, 4096); ++ ++ Mix_PlayChannel(0, blank, -1); ++ ++ mixer_initialized = 1; ++ ++ return DSL_Ok; ++} ++ ++void DSL_StopPlayback( void ) ++{ ++ if (mixer_initialized) { ++ Mix_HaltChannel(0); ++ } ++ ++ if (blank != NULL) { ++ Mix_FreeChunk(blank); ++ } ++ ++ blank = NULL; ++ ++ if (blank_buf != NULL) { ++ free(blank_buf); ++ } ++ ++ blank_buf = NULL; ++ ++ if (mixer_initialized) { ++ Mix_CloseAudio(); ++ } ++ ++ mixer_initialized = 0; ++} ++ ++unsigned DSL_GetPlaybackRate( void ) ++{ ++ return _SampleRate; ++} ++ ++unsigned long DisableInterrupts( void ) ++{ ++ return 0; ++} ++ ++void RestoreInterrupts( unsigned long flags ) ++{ ++} +diff -urN rott-1.0/rott/audiolib/dsl.h trunk/rott/audiolib/dsl.h +--- rott-1.0/rott/audiolib/dsl.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/dsl.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,28 @@ ++#ifndef AUDIOLIB__DSL_H ++#define AUDIOLIB__DSL_H ++ ++#define MONO_8BIT 0 ++#define STEREO 1 ++#define SIXTEEN_BIT 2 ++#define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) ++ ++enum DSL_ERRORS ++ { ++ DSL_Warning = -2, ++ DSL_Error = -1, ++ DSL_Ok = 0, ++ DSL_SDLInitFailure, ++ DSL_MixerActive, ++ DSL_MixerInitFailure ++ }; ++ ++char *DSL_ErrorString( int ErrorNumber ); ++int DSL_Init( void ); ++void DSL_StopPlayback( void ); ++unsigned DSL_GetPlaybackRate( void ); ++int DSL_BeginBufferedPlayback( char *BufferStart, ++ int BufferSize, int NumDivisions, unsigned SampleRate, ++ int MixMode, void ( *CallBackFunc )( void ) ); ++void DSL_Shutdown( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/fx_man.c trunk/rott/audiolib/fx_man.c +--- rott-1.0/rott/audiolib/fx_man.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/fx_man.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,1376 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: FX_MAN.C ++ ++ author: James R. Dose ++ date: March 17, 1994 ++ ++ Device independant sound effect routines. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include "sndcards.h" ++#include "multivoc.h" ++ ++#ifdef PLAT_DOS ++#include "blaster.h" ++#include "pas16.h" ++#include "sndscape.h" ++#include "guswave.h" ++#include "sndsrc.h" ++#else ++#include "dsl.h" ++#endif ++ ++#include "ll_man.h" ++#include "user.h" ++#include "fx_man.h" ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++static unsigned FX_MixRate; ++ ++int FX_SoundDevice = -1; ++int FX_ErrorCode = FX_Ok; ++int FX_Installed = FALSE; ++ ++#define FX_SetErrorCode( status ) \ ++ FX_ErrorCode = ( status ); ++ ++/*--------------------------------------------------------------------- ++ Function: FX_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *FX_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case FX_Warning : ++ case FX_Error : ++ ErrorString = FX_ErrorString( FX_ErrorCode ); ++ break; ++ ++ case FX_Ok : ++ ErrorString = "Fx ok."; ++ break; ++ ++ case FX_ASSVersion : ++ ErrorString = "Apogee Sound System Version " ASS_VERSION_STRING " " ++ "Programmed by Jim Dose\n" ++ "(c) Copyright 1995 James R. Dose. All Rights Reserved.\n"; ++ break; ++ ++#ifdef PLAT_DOS ++ case FX_BlasterError : ++ ErrorString = BLASTER_ErrorString( BLASTER_Error ); ++ break; ++#endif ++ ++ case FX_SoundCardError : ++#ifdef PLAT_DOS ++ switch( FX_SoundDevice ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ ErrorString = BLASTER_ErrorString( BLASTER_Error ); ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ ErrorString = PAS_ErrorString( PAS_Error ); ++ break; ++ ++ case SoundScape : ++ ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_Error ); ++ break; ++ ++ case UltraSound : ++ ErrorString = GUSWAVE_ErrorString( GUSWAVE_Error ); ++ break; ++ ++ case SoundSource : ++ case TandySoundSource : ++ ErrorString = SS_ErrorString( SS_Error ); ++ break; ++ } ++#else ++ ErrorString = DSL_ErrorString( DSL_Error ); ++#endif ++ break; ++ ++ case FX_InvalidCard : ++ ErrorString = "Invalid Sound Fx device."; ++ break; ++ ++ case FX_MultiVocError : ++ ErrorString = MV_ErrorString( MV_Error ); ++ break; ++ ++ case FX_DPMI_Error : ++ ErrorString = "DPMI Error in FX_MAN."; ++ break; ++ ++ default : ++ ErrorString = "Unknown Fx error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetupCard ++ ++ Sets the configuration of a sound device. ++---------------------------------------------------------------------*/ ++ ++int FX_SetupCard ++ ( ++ int SoundCard, ++ fx_device *device ++ ) ++ ++ { ++ int status; ++ int DeviceStatus; ++ ++ if ( USER_CheckParameter( "ASSVER" ) ) ++ { ++ FX_SetErrorCode( FX_ASSVersion ); ++ return( FX_Error ); ++ } ++ ++ FX_SoundDevice = SoundCard; ++ ++ status = FX_Ok; ++ FX_SetErrorCode( FX_Ok ); ++ ++#ifdef PLAT_DOS ++ switch( SoundCard ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ DeviceStatus = BLASTER_Init(); ++ if ( DeviceStatus != BLASTER_Ok ) ++ { ++ FX_SetErrorCode( FX_SoundCardError ); ++ status = FX_Error; ++ break; ++ } ++ ++ device->MaxVoices = 32; ++ BLASTER_GetCardInfo( &device->MaxSampleBits, &device->MaxChannels ); ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ DeviceStatus = PAS_Init(); ++ if ( DeviceStatus != PAS_Ok ) ++ { ++ FX_SetErrorCode( FX_SoundCardError ); ++ status = FX_Error; ++ break; ++ } ++ ++ device->MaxVoices = 32; ++ PAS_GetCardInfo( &device->MaxSampleBits, &device->MaxChannels ); ++ break; ++ ++ case GenMidi : ++ case SoundCanvas : ++ case WaveBlaster : ++ device->MaxVoices = 0; ++ device->MaxSampleBits = 0; ++ device->MaxChannels = 0; ++ break; ++ ++ case SoundScape : ++ device->MaxVoices = 32; ++ DeviceStatus = SOUNDSCAPE_GetCardInfo( &device->MaxSampleBits, ++ &device->MaxChannels ); ++ if ( DeviceStatus != SOUNDSCAPE_Ok ) ++ { ++ FX_SetErrorCode( FX_SoundCardError ); ++ status = FX_Error; ++ } ++ break; ++ ++ case UltraSound : ++ if ( GUSWAVE_Init( 8 ) != GUSWAVE_Ok ) ++ { ++ FX_SetErrorCode( FX_SoundCardError ); ++ status = FX_Error; ++ break; ++ } ++ ++ device->MaxVoices = 8; ++ device->MaxSampleBits = 0; ++ device->MaxChannels = 0; ++ break; ++ ++ case SoundSource : ++ case TandySoundSource : ++ DeviceStatus = SS_Init( SoundCard ); ++ if ( DeviceStatus != SS_Ok ) ++ { ++ FX_SetErrorCode( FX_SoundCardError ); ++ status = FX_Error; ++ break; ++ } ++ SS_Shutdown(); ++ device->MaxVoices = 32; ++ device->MaxSampleBits = 8; ++ device->MaxChannels = 1; ++ break; ++ default : ++ FX_SetErrorCode( FX_InvalidCard ); ++ status = FX_Error; ++ } ++#else ++ DeviceStatus = DSL_Init(); ++ if ( DeviceStatus != DSL_Ok ) ++ { ++ FX_SetErrorCode( FX_SoundCardError ); ++ status = FX_Error; ++ } ++ else ++ { ++ device->MaxVoices = 32; ++ device->MaxSampleBits = 0; ++ device->MaxChannels = 0; ++ } ++#endif ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_GetBlasterSettings ++ ++ Returns the current BLASTER environment variable settings. ++---------------------------------------------------------------------*/ ++ ++int FX_GetBlasterSettings ++ ( ++ fx_blaster_config *blaster ++ ) ++ ++ { ++#ifdef PLAT_DOS ++ int status; ++ BLASTER_CONFIG Blaster; ++ ++ FX_SetErrorCode( FX_Ok ); ++ ++ status = BLASTER_GetEnv( &Blaster ); ++ if ( status != BLASTER_Ok ) ++ { ++ FX_SetErrorCode( FX_BlasterError ); ++ return( FX_Error ); ++ } ++ ++ blaster->Type = Blaster.Type; ++ blaster->Address = Blaster.Address; ++ blaster->Interrupt = Blaster.Interrupt; ++ blaster->Dma8 = Blaster.Dma8; ++ blaster->Dma16 = Blaster.Dma16; ++ blaster->Midi = Blaster.Midi; ++ blaster->Emu = Blaster.Emu; ++#endif ++ ++ return( FX_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetupSoundBlaster ++ ++ Handles manual setup of the Sound Blaster information. ++---------------------------------------------------------------------*/ ++ ++int FX_SetupSoundBlaster ++ ( ++ fx_blaster_config blaster, ++ int *MaxVoices, ++ int *MaxSampleBits, ++ int *MaxChannels ++ ) ++ ++ { ++#ifdef PLAT_DOS ++ int DeviceStatus; ++ BLASTER_CONFIG Blaster; ++ ++ FX_SetErrorCode( FX_Ok ); ++ ++ FX_SoundDevice = SoundBlaster; ++ ++ Blaster.Type = blaster.Type; ++ Blaster.Address = blaster.Address; ++ Blaster.Interrupt = blaster.Interrupt; ++ Blaster.Dma8 = blaster.Dma8; ++ Blaster.Dma16 = blaster.Dma16; ++ Blaster.Midi = blaster.Midi; ++ Blaster.Emu = blaster.Emu; ++ ++ BLASTER_SetCardSettings( Blaster ); ++ ++ DeviceStatus = BLASTER_Init(); ++ if ( DeviceStatus != BLASTER_Ok ) ++ { ++ FX_SetErrorCode( FX_SoundCardError ); ++ return( FX_Error ); ++ } ++ ++ *MaxVoices = 8; ++ BLASTER_GetCardInfo( MaxSampleBits, MaxChannels ); ++#endif ++ ++ return( FX_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_Init ++ ++ Selects which sound device to use. ++---------------------------------------------------------------------*/ ++ ++int FX_Init ++ ( ++ int SoundCard, ++ int numvoices, ++ int numchannels, ++ int samplebits, ++ unsigned mixrate ++ ) ++ ++ { ++ int status; ++ int devicestatus; ++ ++ if ( FX_Installed ) ++ { ++ FX_Shutdown(); ++ } ++ ++ if ( USER_CheckParameter( "ASSVER" ) ) ++ { ++ FX_SetErrorCode( FX_ASSVersion ); ++ return( FX_Error ); ++ } ++ ++ status = LL_LockMemory(); ++ if ( status != LL_Ok ) ++ { ++ FX_SetErrorCode( FX_DPMI_Error ); ++ return( FX_Error ); ++ } ++ ++ FX_MixRate = mixrate; ++ ++ status = FX_Ok; ++ FX_SoundDevice = SoundCard; ++ switch( SoundCard ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ case SoundScape : ++ case SoundSource : ++ case TandySoundSource : ++ case UltraSound : ++ devicestatus = MV_Init( SoundCard, FX_MixRate, numvoices, ++ numchannels, samplebits ); ++ if ( devicestatus != MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ status = FX_Error; ++ } ++ break; ++ ++ default : ++ FX_SetErrorCode( FX_InvalidCard ); ++ status = FX_Error; ++ } ++ ++ if ( status != FX_Ok ) ++ { ++ LL_UnlockMemory(); ++ } ++ else ++ { ++ FX_Installed = TRUE; ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_Shutdown ++ ++ Terminates use of sound device. ++---------------------------------------------------------------------*/ ++ ++int FX_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ if ( !FX_Installed ) ++ { ++ return( FX_Ok ); ++ } ++ ++ status = FX_Ok; ++ switch( FX_SoundDevice ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ case SoundScape : ++ case SoundSource : ++ case TandySoundSource : ++ case UltraSound : ++ status = MV_Shutdown(); ++ if ( status != MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ status = FX_Error; ++ } ++ break; ++ ++ default : ++ FX_SetErrorCode( FX_InvalidCard ); ++ status = FX_Error; ++ } ++ ++ FX_Installed = FALSE; ++ LL_UnlockMemory(); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetCallback ++ ++ Sets the function to call when a voice is done. ++---------------------------------------------------------------------*/ ++ ++int FX_SetCallBack ++ ( ++ void ( *function )( unsigned long ) ++ ) ++ ++ { ++ int status; ++ ++ status = FX_Ok; ++ ++ switch( FX_SoundDevice ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ case SoundScape : ++ case SoundSource : ++ case TandySoundSource : ++ case UltraSound : ++ MV_SetCallBack( function ); ++ break; ++ ++ default : ++ FX_SetErrorCode( FX_InvalidCard ); ++ status = FX_Error; ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetVolume ++ ++ Sets the volume of the current sound device. ++---------------------------------------------------------------------*/ ++ ++void FX_SetVolume ++ ( ++ int volume ++ ) ++ ++ { ++ int status; ++ ++#ifdef PLAT_DOS ++ switch( FX_SoundDevice ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ if ( BLASTER_CardHasMixer() ) ++ { ++ BLASTER_SetVoiceVolume( volume ); ++ } ++ else ++ { ++ MV_SetVolume( volume ); ++ } ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ status = PAS_SetPCMVolume( volume ); ++ if ( status != PAS_Ok ) ++ { ++ MV_SetVolume( volume ); ++ } ++ break; ++ ++ case GenMidi : ++ case SoundCanvas : ++ case WaveBlaster : ++ break; ++ ++ case SoundScape : ++ MV_SetVolume( volume ); ++ break; ++ ++ case UltraSound : ++ GUSWAVE_SetVolume( volume ); ++ break; ++ ++ case SoundSource : ++ case TandySoundSource : ++ MV_SetVolume( volume ); ++ break; ++ } ++#else ++ MV_SetVolume( volume ); ++#endif ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_GetVolume ++ ++ Returns the volume of the current sound device. ++---------------------------------------------------------------------*/ ++ ++int FX_GetVolume ++ ( ++ void ++ ) ++ ++ { ++ int volume; ++ ++#ifdef PLAT_DOS ++ switch( FX_SoundDevice ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ if ( BLASTER_CardHasMixer() ) ++ { ++ volume = BLASTER_GetVoiceVolume(); ++ } ++ else ++ { ++ volume = MV_GetVolume(); ++ } ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ volume = PAS_GetPCMVolume(); ++ if ( volume == PAS_Error ) ++ { ++ volume = MV_GetVolume(); ++ } ++ break; ++ ++ case GenMidi : ++ case SoundCanvas : ++ case WaveBlaster : ++ volume = 255; ++ break; ++ ++ case SoundScape : ++ volume = MV_GetVolume(); ++ break; ++ ++ case UltraSound : ++ volume = GUSWAVE_GetVolume(); ++ break; ++ ++ case SoundSource : ++ case TandySoundSource : ++ volume = MV_GetVolume(); ++ break; ++ ++ default : ++ volume = 0; ++ } ++#else ++ volume = MV_GetVolume(); ++#endif ++ ++ return( volume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetReverseStereo ++ ++ Set the orientation of the left and right channels. ++---------------------------------------------------------------------*/ ++ ++void FX_SetReverseStereo ++ ( ++ int setting ++ ) ++ ++ { ++ MV_SetReverseStereo( setting ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_GetReverseStereo ++ ++ Returns the orientation of the left and right channels. ++---------------------------------------------------------------------*/ ++ ++int FX_GetReverseStereo ++ ( ++ void ++ ) ++ ++ { ++ return MV_GetReverseStereo(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetReverb ++ ++ Sets the reverb level. ++---------------------------------------------------------------------*/ ++ ++void FX_SetReverb ++ ( ++ int reverb ++ ) ++ ++ { ++ MV_SetReverb( reverb ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetFastReverb ++ ++ Sets the reverb level. ++---------------------------------------------------------------------*/ ++ ++void FX_SetFastReverb ++ ( ++ int reverb ++ ) ++ ++ { ++ MV_SetFastReverb( reverb ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_GetMaxReverbDelay ++ ++ Returns the maximum delay time for reverb. ++---------------------------------------------------------------------*/ ++ ++int FX_GetMaxReverbDelay ++ ( ++ void ++ ) ++ ++ { ++ return MV_GetMaxReverbDelay(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_GetReverbDelay ++ ++ Returns the current delay time for reverb. ++---------------------------------------------------------------------*/ ++ ++int FX_GetReverbDelay ++ ( ++ void ++ ) ++ ++ { ++ return MV_GetReverbDelay(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetReverbDelay ++ ++ Sets the delay level of reverb to add to mix. ++---------------------------------------------------------------------*/ ++ ++void FX_SetReverbDelay ++ ( ++ int delay ++ ) ++ ++ { ++ MV_SetReverbDelay( delay ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_VoiceAvailable ++ ++ Checks if a voice can be play at the specified priority. ++---------------------------------------------------------------------*/ ++ ++int FX_VoiceAvailable ++ ( ++ int priority ++ ) ++ ++ { ++ return MV_VoiceAvailable( priority ); ++ } ++ ++/*--------------------------------------------------------------------- ++ Function: FX_EndLooping ++ ++ Stops the voice associated with the specified handle from looping ++ without stoping the sound. ++---------------------------------------------------------------------*/ ++ ++int FX_EndLooping ++ ( ++ int handle ++ ) ++ ++ { ++ int status; ++ ++ status = MV_EndLooping( handle ); ++ if ( status == MV_Error ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ status = FX_Warning; ++ } ++ ++ return( status ); ++ } ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetPan ++ ++ Sets the stereo and mono volume level of the voice associated ++ with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int FX_SetPan ++ ( ++ int handle, ++ int vol, ++ int left, ++ int right ++ ) ++ ++ { ++ int status; ++ ++ status = MV_SetPan( handle, vol, left, right ); ++ if ( status == MV_Error ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ status = FX_Warning; ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetPitch ++ ++ Sets the pitch of the voice associated with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int FX_SetPitch ++ ( ++ int handle, ++ int pitchoffset ++ ) ++ ++ { ++ int status; ++ ++ status = MV_SetPitch( handle, pitchoffset ); ++ if ( status == MV_Error ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ status = FX_Warning; ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SetFrequency ++ ++ Sets the frequency of the voice associated with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int FX_SetFrequency ++ ( ++ int handle, ++ int frequency ++ ) ++ ++ { ++ int status; ++ ++ status = MV_SetFrequency( handle, frequency ); ++ if ( status == MV_Error ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ status = FX_Warning; ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_PlayVOC ++ ++ Begin playback of sound data with the given volume and priority. ++---------------------------------------------------------------------*/ ++ ++int FX_PlayVOC ++ ( ++ char *ptr, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int handle; ++ ++ handle = MV_PlayVOC( ptr, pitchoffset, vol, left, right, ++ priority, callbackval ); ++ if ( handle < MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ handle = FX_Warning; ++ } ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_PlayLoopedVOC ++ ++ Begin playback of sound data with the given volume and priority. ++---------------------------------------------------------------------*/ ++ ++int FX_PlayLoopedVOC ++ ( ++ char *ptr, ++ long loopstart, ++ long loopend, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int handle; ++ ++ handle = MV_PlayLoopedVOC( ptr, loopstart, loopend, pitchoffset, ++ vol, left, right, priority, callbackval ); ++ if ( handle < MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ handle = FX_Warning; ++ } ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_PlayWAV ++ ++ Begin playback of sound data with the given volume and priority. ++---------------------------------------------------------------------*/ ++ ++int FX_PlayWAV ++ ( ++ char *ptr, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int handle; ++ ++ handle = MV_PlayWAV( ptr, pitchoffset, vol, left, right, ++ priority, callbackval ); ++ if ( handle < MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ handle = FX_Warning; ++ } ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_PlayWAV ++ ++ Begin playback of sound data with the given volume and priority. ++---------------------------------------------------------------------*/ ++ ++int FX_PlayLoopedWAV ++ ( ++ char *ptr, ++ long loopstart, ++ long loopend, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int handle; ++ ++ handle = MV_PlayLoopedWAV( ptr, loopstart, loopend, ++ pitchoffset, vol, left, right, priority, callbackval ); ++ if ( handle < MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ handle = FX_Warning; ++ } ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_PlayVOC3D ++ ++ Begin playback of sound data at specified angle and distance ++ from listener. ++---------------------------------------------------------------------*/ ++ ++int FX_PlayVOC3D ++ ( ++ char *ptr, ++ int pitchoffset, ++ int angle, ++ int distance, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int handle; ++ ++ handle = MV_PlayVOC3D( ptr, pitchoffset, angle, distance, ++ priority, callbackval ); ++ if ( handle < MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ handle = FX_Warning; ++ } ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_PlayWAV3D ++ ++ Begin playback of sound data at specified angle and distance ++ from listener. ++---------------------------------------------------------------------*/ ++ ++int FX_PlayWAV3D ++ ( ++ char *ptr, ++ int pitchoffset, ++ int angle, ++ int distance, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int handle; ++ ++ handle = MV_PlayWAV3D( ptr, pitchoffset, angle, distance, ++ priority, callbackval ); ++ if ( handle < MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ handle = FX_Warning; ++ } ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_PlayRaw ++ ++ Begin playback of raw sound data with the given volume and priority. ++---------------------------------------------------------------------*/ ++ ++int FX_PlayRaw ++ ( ++ char *ptr, ++ unsigned long length, ++ unsigned rate, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int handle; ++ ++ handle = MV_PlayRaw( ptr, length, rate, pitchoffset, ++ vol, left, right, priority, callbackval ); ++ if ( handle < MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ handle = FX_Warning; ++ } ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_PlayLoopedRaw ++ ++ Begin playback of raw sound data with the given volume and priority. ++---------------------------------------------------------------------*/ ++ ++int FX_PlayLoopedRaw ++ ( ++ char *ptr, ++ unsigned long length, ++ char *loopstart, ++ char *loopend, ++ unsigned rate, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int handle; ++ ++ handle = MV_PlayLoopedRaw( ptr, length, loopstart, loopend, ++ rate, pitchoffset, vol, left, right, priority, callbackval ); ++ if ( handle < MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ handle = FX_Warning; ++ } ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_Pan3D ++ ++ Set the angle and distance from the listener of the voice associated ++ with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int FX_Pan3D ++ ( ++ int handle, ++ int angle, ++ int distance ++ ) ++ ++ { ++ int status; ++ ++ status = MV_Pan3D( handle, angle, distance ); ++ if ( status != MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ status = FX_Warning; ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SoundActive ++ ++ Tests if the specified sound is currently playing. ++---------------------------------------------------------------------*/ ++ ++int FX_SoundActive ++ ( ++ int handle ++ ) ++ ++ { ++ return( MV_VoicePlaying( handle ) ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_SoundsPlaying ++ ++ Reports the number of voices playing. ++---------------------------------------------------------------------*/ ++ ++int FX_SoundsPlaying ++ ( ++ void ++ ) ++ ++ { ++ return( MV_VoicesPlaying() ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_StopSound ++ ++ Halts playback of a specific voice ++---------------------------------------------------------------------*/ ++ ++int FX_StopSound ++ ( ++ int handle ++ ) ++ ++ { ++ int status; ++ ++ status = MV_Kill( handle ); ++ if ( status != MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ return( FX_Warning ); ++ } ++ ++ return( FX_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_StopAllSounds ++ ++ Halts playback of all sounds. ++---------------------------------------------------------------------*/ ++ ++int FX_StopAllSounds ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = MV_KillAllVoices(); ++ if ( status != MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ return( FX_Warning ); ++ } ++ ++ return( FX_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_StartDemandFeedPlayback ++ ++ Plays a digitized sound from a user controlled buffering system. ++---------------------------------------------------------------------*/ ++ ++int FX_StartDemandFeedPlayback ++ ( ++ void ( *function )( char **ptr, unsigned long *length ), ++ int rate, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int handle; ++ ++ handle = MV_StartDemandFeedPlayback( function, rate, ++ pitchoffset, vol, left, right, priority, callbackval ); ++ if ( handle < MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ handle = FX_Warning; ++ } ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_StartRecording ++ ++ Starts the sound recording engine. ++---------------------------------------------------------------------*/ ++ ++int FX_StartRecording ++ ( ++ int MixRate, ++ void ( *function )( char *ptr, int length ) ++ ) ++ ++ { ++ int status; ++ ++#ifdef PLAT_DOS ++ switch( FX_SoundDevice ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ status = MV_StartRecording( MixRate, function ); ++ if ( status != MV_Ok ) ++ { ++ FX_SetErrorCode( FX_MultiVocError ); ++ status = FX_Warning; ++ } ++ else ++ { ++ status = FX_Ok; ++ } ++ break; ++ ++ default : ++ FX_SetErrorCode( FX_InvalidCard ); ++ status = FX_Warning; ++ break; ++ } ++#else ++ FX_SetErrorCode( FX_InvalidCard ); ++ status = FX_Warning; ++#endif ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: FX_StopRecord ++ ++ Stops the sound record engine. ++---------------------------------------------------------------------*/ ++ ++void FX_StopRecord ++ ( ++ void ++ ) ++ ++ { ++#ifdef PLAT_DOS ++ // Stop sound playback ++ switch( FX_SoundDevice ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ MV_StopRecord(); ++ break; ++ } ++#endif ++ } +diff -urN rott-1.0/rott/audiolib/fx_man.h trunk/rott/audiolib/fx_man.h +--- rott-1.0/rott/audiolib/fx_man.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/fx_man.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,135 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: FX_MAN.H ++ ++ author: James R. Dose ++ date: March 17, 1994 ++ ++ Public header for FX_MAN.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __FX_MAN_H ++#define __FX_MAN_H ++ ++#include "sndcards.h" ++ ++typedef struct ++ { ++ int MaxVoices; ++ int MaxSampleBits; ++ int MaxChannels; ++ } fx_device; ++ ++#define MonoFx 1 ++#define StereoFx 2 ++ ++typedef struct ++ { ++ unsigned long Address; ++ unsigned long Type; ++ unsigned long Interrupt; ++ unsigned long Dma8; ++ unsigned long Dma16; ++ unsigned long Midi; ++ unsigned long Emu; ++ } fx_blaster_config; ++ ++enum FX_ERRORS ++ { ++ FX_Warning = -2, ++ FX_Error = -1, ++ FX_Ok = 0, ++ FX_ASSVersion, ++ FX_BlasterError, ++ FX_SoundCardError, ++ FX_InvalidCard, ++ FX_MultiVocError, ++ FX_DPMI_Error ++ }; ++ ++enum fx_BLASTER_Types ++ { ++ fx_SB = 1, ++ fx_SBPro = 2, ++ fx_SB20 = 3, ++ fx_SBPro2 = 4, ++ fx_SB16 = 6 ++ }; ++ ++ ++char *FX_ErrorString( int ErrorNumber ); ++int FX_SetupCard( int SoundCard, fx_device *device ); ++int FX_GetBlasterSettings( fx_blaster_config *blaster ); ++int FX_SetupSoundBlaster( fx_blaster_config blaster, int *MaxVoices, int *MaxSampleBits, int *MaxChannels ); ++int FX_Init( int SoundCard, int numvoices, int numchannels, int samplebits, unsigned mixrate ); ++int FX_Shutdown( void ); ++int FX_SetCallBack( void ( *function )( unsigned long ) ); ++void FX_SetVolume( int volume ); ++int FX_GetVolume( void ); ++ ++void FX_SetReverseStereo( int setting ); ++int FX_GetReverseStereo( void ); ++void FX_SetReverb( int reverb ); ++void FX_SetFastReverb( int reverb ); ++int FX_GetMaxReverbDelay( void ); ++int FX_GetReverbDelay( void ); ++void FX_SetReverbDelay( int delay ); ++ ++int FX_VoiceAvailable( int priority ); ++int FX_EndLooping( int handle ); ++int FX_SetPan( int handle, int vol, int left, int right ); ++int FX_SetPitch( int handle, int pitchoffset ); ++int FX_SetFrequency( int handle, int frequency ); ++ ++int FX_PlayVOC( char *ptr, int pitchoffset, int vol, int left, int right, ++ int priority, unsigned long callbackval ); ++int FX_PlayLoopedVOC( char *ptr, long loopstart, long loopend, ++ int pitchoffset, int vol, int left, int right, int priority, ++ unsigned long callbackval ); ++int FX_PlayWAV( char *ptr, int pitchoffset, int vol, int left, int right, ++ int priority, unsigned long callbackval ); ++int FX_PlayLoopedWAV( char *ptr, long loopstart, long loopend, ++ int pitchoffset, int vol, int left, int right, int priority, ++ unsigned long callbackval ); ++int FX_PlayVOC3D( char *ptr, int pitchoffset, int angle, int distance, ++ int priority, unsigned long callbackval ); ++int FX_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance, ++ int priority, unsigned long callbackval ); ++int FX_PlayRaw( char *ptr, unsigned long length, unsigned rate, ++ int pitchoffset, int vol, int left, int right, int priority, ++ unsigned long callbackval ); ++int FX_PlayLoopedRaw( char *ptr, unsigned long length, char *loopstart, ++ char *loopend, unsigned rate, int pitchoffset, int vol, int left, ++ int right, int priority, unsigned long callbackval ); ++int FX_Pan3D( int handle, int angle, int distance ); ++int FX_SoundActive( int handle ); ++int FX_SoundsPlaying( void ); ++int FX_StopSound( int handle ); ++int FX_StopAllSounds( void ); ++int FX_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ), ++ int rate, int pitchoffset, int vol, int left, int right, ++ int priority, unsigned long callbackval ); ++int FX_StartRecording( int MixRate, void ( *function )( char *ptr, int length ) ); ++void FX_StopRecord( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/gmtimbre.c trunk/rott/audiolib/gmtimbre.c +--- rott-1.0/rott/audiolib/gmtimbre.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/gmtimbre.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,290 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++typedef struct ++ { ++ unsigned char SAVEK[ 2 ]; ++ unsigned char Level[ 2 ]; ++ unsigned char Env1[ 2 ]; ++ unsigned char Env2[ 2 ]; ++ unsigned char Wave[ 2 ]; ++ unsigned char Feedback; ++ signed char Transpose; ++ signed char Velocity; ++ } TIMBRE; ++ ++TIMBRE ADLIB_TimbreBank[ 256 ] = ++ { ++ { { 33, 33 }, { 143, 6 }, { 242, 242 }, { 69, 118 }, { 0, 0 }, 8, 0 }, ++ { { 49, 33 }, { 75, 0 }, { 242, 242 }, { 84, 86 }, { 0, 0 }, 8, 0 }, ++ { { 49, 33 }, { 73, 0 }, { 242, 242 }, { 85, 118 }, { 0, 0 }, 8, 0 }, ++ { { 177, 97 }, { 14, 0 }, { 242, 243 }, { 59, 11 }, { 0, 0 }, 6, 0 }, ++ { { 1, 33 }, { 87, 0 }, { 241, 241 }, { 56, 40 }, { 0, 0 }, 0, 0 }, ++ { { 1, 33 }, { 147, 0 }, { 241, 241 }, { 56, 40 }, { 0, 0 }, 0, 0 }, ++ { { 33, 54 }, { 128, 14 }, { 162, 241 }, { 1, 213 }, { 0, 0 }, 8, 0 }, ++ { { 1, 1 }, { 146, 0 }, { 194, 194 }, { 168, 88 }, { 0, 0 }, 10, 0 }, ++ { { 12, 129 }, { 92, 0 }, { 246, 243 }, { 84, 181 }, { 0, 0 }, 0, 0 }, ++ { { 7, 17 }, { 151, 128 }, { 246, 245 }, { 50, 17 }, { 0, 0 }, 2, 0 }, ++ { { 23, 1 }, { 33, 0 }, { 86, 246 }, { 4, 4 }, { 0, 0 }, 2, 0 }, ++ { { 24, 129 }, { 98, 0 }, { 243, 242 }, { 230, 246 }, { 0, 0 }, 0, 0 }, ++ { { 24, 33 }, { 35, 0 }, { 247, 229 }, { 85, 216 }, { 0, 0 }, 0, 0 }, ++ { { 21, 1 }, { 145, 0 }, { 246, 246 }, { 166, 230 }, { 0, 0 }, 4, 0 }, ++ { { 69, 129 }, { 89, 128 }, { 211, 163 }, { 130, 227 }, { 0, 0 }, 12, 0 }, ++ { { 3, 129 }, { 73, 128 }, { 116, 179 }, { 85, 5 }, { 1, 0 }, 4, 0 }, ++ { { 113, 49 }, { 146, 0 }, { 246, 241 }, { 20, 7 }, { 0, 0 }, 2, 0 }, ++ { { 114, 48 }, { 20, 0 }, { 199, 199 }, { 88, 8 }, { 0, 0 }, 2, 0 }, ++ { { 112, 177 }, { 68, 0 }, { 170, 138 }, { 24, 8 }, { 0, 0 }, 4, 0 }, ++ { { 35, 177 }, { 147, 0 }, { 151, 85 }, { 35, 20 }, { 1, 0 }, 4, 0 }, ++ { { 97, 177 }, { 19, 128 }, { 151, 85 }, { 4, 4 }, { 1, 0 }, 0, 0 }, ++ { { 36, 177 }, { 72, 0 }, { 152, 70 }, { 42, 26 }, { 1, 0 }, 12, 0 }, ++ { { 97, 33 }, { 19, 0 }, { 145, 97 }, { 6, 7 }, { 1, 0 }, 10, 0 }, ++ { { 33, 161 }, { 19, 137 }, { 113, 97 }, { 6, 7 }, { 0, 0 }, 6, 0 }, ++ { { 2, 65 }, { 156, 128 }, { 243, 243 }, { 148, 200 }, { 1, 0 }, 12, 0 }, ++ { { 3, 17 }, { 84, 0 }, { 243, 241 }, { 154, 231 }, { 1, 0 }, 12, 0 }, ++ { { 35, 33 }, { 95, 0 }, { 241, 242 }, { 58, 248 }, { 0, 0 }, 0, 0 }, ++ { { 3, 33 }, { 135, 128 }, { 246, 243 }, { 34, 243 }, { 1, 0 }, 6, 0 }, ++ { { 3, 33 }, { 71, 0 }, { 249, 246 }, { 84, 58 }, { 0, 0 }, 0, 0 }, ++ { { 35, 33 }, { 72, 0 }, { 149, 132 }, { 25, 25 }, { 1, 0 }, 8, 0 }, ++ { { 35, 33 }, { 74, 0 }, { 149, 148 }, { 25, 25 }, { 1, 0 }, 8, 0 }, ++ { { 9, 132 }, { 161, 128 }, { 32, 209 }, { 79, 248 }, { 0, 0 }, 8, 0 }, ++ { { 33, 162 }, { 30, 0 }, { 148, 195 }, { 6, 166 }, { 0, 0 }, 2, 0 }, ++ { { 49, 49 }, { 18, 0 }, { 241, 241 }, { 40, 24 }, { 0, 0 }, 10, 0 }, ++ { { 49, 49 }, { 141, 0 }, { 241, 241 }, { 232, 120 }, { 0, 0 }, 10, 0 }, ++ { { 49, 50 }, { 91, 0 }, { 81, 113 }, { 40, 72 }, { 0, 0 }, 12, 0 }, ++ { { 1, 33 }, { 139, 64 }, { 161, 242 }, { 154, 223 }, { 0, 0 }, 8, 0 }, ++ { { 1, 33 }, { 137, 64 }, { 161, 242 }, { 154, 223 }, { 0, 0 }, 8, 0 }, ++ { { 49, 49 }, { 139, 0 }, { 244, 241 }, { 232, 120 }, { 0, 0 }, 10, 0 }, ++ { { 49, 49 }, { 18, 0 }, { 241, 241 }, { 40, 24 }, { 0, 0 }, 10, 0 }, ++ { { 49, 33 }, { 21, 0 }, { 221, 86 }, { 19, 38 }, { 1, 0 }, 8, 0 }, ++ { { 49, 33 }, { 22, 0 }, { 221, 102 }, { 19, 6 }, { 1, 0 }, 8, 0 }, ++ { { 113, 49 }, { 73, 0 }, { 209, 97 }, { 28, 12 }, { 1, 0 }, 8, 0 }, ++ { { 33, 35 }, { 77, 128 }, { 113, 114 }, { 18, 6 }, { 1, 0 }, 2, 0 }, ++ { { 241, 225 }, { 64, 0 }, { 241, 111 }, { 33, 22 }, { 1, 0 }, 2, 0 }, ++ { { 2, 1 }, { 26, 128 }, { 245, 133 }, { 117, 53 }, { 1, 0 }, 0, 0 }, ++ { { 2, 1 }, { 29, 128 }, { 245, 243 }, { 117, 244 }, { 1, 0 }, 0, 0 }, ++ { { 16, 17 }, { 65, 0 }, { 245, 242 }, { 5, 195 }, { 1, 0 }, 2, 0 }, ++ { { 33, 162 }, { 155, 1 }, { 177, 114 }, { 37, 8 }, { 1, 0 }, 14, 0 }, ++ { { 161, 33 }, { 152, 0 }, { 127, 63 }, { 3, 7 }, { 1, 1 }, 0, 0 }, ++ { { 161, 97 }, { 147, 0 }, { 193, 79 }, { 18, 5 }, { 0, 0 }, 10, 0 }, ++ { { 33, 97 }, { 24, 0 }, { 193, 79 }, { 34, 5 }, { 0, 0 }, 12, 0 }, ++ { { 49, 114 }, { 91, 131 }, { 244, 138 }, { 21, 5 }, { 0, 0 }, 0, 0 }, ++ { { 161, 97 }, { 144, 0 }, { 116, 113 }, { 57, 103 }, { 0, 0 }, 0, 0 }, ++ { { 113, 114 }, { 87, 0 }, { 84, 122 }, { 5, 5 }, { 0, 0 }, 12, 0 }, ++ { { 144, 65 }, { 0, 0 }, { 84, 165 }, { 99, 69 }, { 0, 0 }, 8, 0 }, ++ { { 33, 33 }, { 146, 1 }, { 133, 143 }, { 23, 9 }, { 0, 0 }, 12, 0 }, ++ { { 33, 33 }, { 148, 5 }, { 117, 143 }, { 23, 9 }, { 0, 0 }, 12, 0 }, ++ { { 33, 97 }, { 148, 0 }, { 118, 130 }, { 21, 55 }, { 0, 0 }, 12, 0 }, ++ { { 49, 33 }, { 67, 0 }, { 158, 98 }, { 23, 44 }, { 1, 1 }, 2, 0 }, ++ { { 33, 33 }, { 155, 0 }, { 97, 127 }, { 106, 10 }, { 0, 0 }, 2, 0 }, ++ { { 97, 34 }, { 138, 6 }, { 117, 116 }, { 31, 15 }, { 0, 0 }, 8, 0 }, ++ { { 161, 33 }, { 134, 13 }, { 114, 113 }, { 85, 24 }, { 1, 0 }, 0, 0 }, ++ { { 33, 33 }, { 77, 0 }, { 84, 166 }, { 60, 28 }, { 0, 0 }, 8, 0 }, ++ { { 49, 97 }, { 143, 0 }, { 147, 114 }, { 2, 11 }, { 1, 0 }, 8, 0 }, ++ { { 49, 97 }, { 142, 0 }, { 147, 114 }, { 3, 9 }, { 1, 0 }, 8, 0 }, ++ { { 49, 97 }, { 145, 0 }, { 147, 130 }, { 3, 9 }, { 1, 0 }, 10, 0 }, ++ { { 49, 97 }, { 142, 0 }, { 147, 114 }, { 15, 15 }, { 1, 0 }, 10, 0 }, ++ { { 33, 33 }, { 75, 0 }, { 170, 143 }, { 22, 10 }, { 1, 0 }, 8, 0 }, ++ { { 49, 33 }, { 144, 0 }, { 126, 139 }, { 23, 12 }, { 1, 1 }, 6, 0 }, ++ { { 49, 50 }, { 129, 0 }, { 117, 97 }, { 25, 25 }, { 1, 0 }, 0, 0 }, ++ { { 50, 33 }, { 144, 0 }, { 155, 114 }, { 33, 23 }, { 0, 0 }, 4, 0 }, ++ { { 225, 225 }, { 31, 0 }, { 133, 101 }, { 95, 26 }, { 0, 0 }, 0, 0 }, ++ { { 225, 225 }, { 70, 0 }, { 136, 101 }, { 95, 26 }, { 0, 0 }, 0, 0 }, ++ { { 161, 33 }, { 156, 0 }, { 117, 117 }, { 31, 10 }, { 0, 0 }, 2, 0 }, ++ { { 49, 33 }, { 139, 0 }, { 132, 101 }, { 88, 26 }, { 0, 0 }, 0, 0 }, ++ { { 225, 161 }, { 76, 0 }, { 102, 101 }, { 86, 38 }, { 0, 0 }, 0, 0 }, ++ { { 98, 161 }, { 203, 0 }, { 118, 85 }, { 70, 54 }, { 0, 0 }, 0, 0 }, ++ { { 98, 161 }, { 153, 0 }, { 87, 86 }, { 7, 7 }, { 0, 0 }, 11, 0 }, ++ { { 98, 161 }, { 147, 0 }, { 119, 118 }, { 7, 7 }, { 0, 0 }, 11, 0 }, ++ { { 34, 33 }, { 89, 0 }, { 255, 255 }, { 3, 15 }, { 2, 0 }, 0, 0 }, ++ { { 33, 33 }, { 14, 0 }, { 255, 255 }, { 15, 15 }, { 1, 1 }, 0, 0 }, ++ { { 34, 33 }, { 70, 128 }, { 134, 100 }, { 85, 24 }, { 0, 0 }, 0, 0 }, ++ { { 33, 161 }, { 69, 0 }, { 102, 150 }, { 18, 10 }, { 0, 0 }, 0, 0 }, ++ { { 33, 34 }, { 139, 0 }, { 146, 145 }, { 42, 42 }, { 1, 0 }, 0, 0 }, ++ { { 162, 97 }, { 158, 64 }, { 223, 111 }, { 5, 7 }, { 0, 0 }, 2, 0 }, ++ { { 32, 96 }, { 26, 0 }, { 239, 143 }, { 1, 6 }, { 0, 2 }, 0, 0 }, ++ { { 33, 33 }, { 143, 128 }, { 241, 244 }, { 41, 9 }, { 0, 0 }, 10, 0 }, ++ { { 119, 161 }, { 165, 0 }, { 83, 160 }, { 148, 5 }, { 0, 0 }, 2, 0 }, ++ { { 97, 177 }, { 31, 128 }, { 168, 37 }, { 17, 3 }, { 0, 0 }, 10, 0 }, ++ { { 97, 97 }, { 23, 0 }, { 145, 85 }, { 52, 22 }, { 0, 0 }, 12, 0 }, ++ { { 113, 114 }, { 93, 0 }, { 84, 106 }, { 1, 3 }, { 0, 0 }, 0, 0 }, ++ { { 33, 162 }, { 151, 0 }, { 33, 66 }, { 67, 53 }, { 0, 0 }, 8, 0 }, ++ { { 161, 33 }, { 28, 0 }, { 161, 49 }, { 119, 71 }, { 1, 1 }, 0, 0 }, ++ { { 33, 97 }, { 137, 3 }, { 17, 66 }, { 51, 37 }, { 0, 0 }, 10, 0 }, ++ { { 161, 33 }, { 21, 0 }, { 17, 207 }, { 71, 7 }, { 1, 0 }, 0, 0 }, ++ { { 58, 81 }, { 206, 0 }, { 248, 134 }, { 246, 2 }, { 0, 0 }, 2, 0 }, ++ { { 33, 33 }, { 21, 0 }, { 33, 65 }, { 35, 19 }, { 1, 0 }, 0, 0 }, ++ { { 6, 1 }, { 91, 0 }, { 116, 165 }, { 149, 114 }, { 0, 0 }, 0, 0 }, ++ { { 34, 97 }, { 146, 131 }, { 177, 242 }, { 129, 38 }, { 0, 0 }, 12, 0 }, ++ { { 65, 66 }, { 77, 0 }, { 241, 242 }, { 81, 245 }, { 1, 0 }, 0, 0 }, ++ { { 97, 163 }, { 148, 128 }, { 17, 17 }, { 81, 19 }, { 1, 0 }, 6, 0 }, ++ { { 97, 161 }, { 140, 128 }, { 17, 29 }, { 49, 3 }, { 0, 0 }, 6, 0 }, ++ { { 164, 97 }, { 76, 0 }, { 243, 129 }, { 115, 35 }, { 1, 0 }, 4, 0 }, ++ { { 2, 7 }, { 133, 3 }, { 210, 242 }, { 83, 246 }, { 0, 1 }, 0, 0 }, ++ { { 17, 19 }, { 12, 128 }, { 163, 162 }, { 17, 229 }, { 1, 0 }, 0, 0 }, ++ { { 17, 17 }, { 6, 0 }, { 246, 242 }, { 65, 230 }, { 1, 2 }, 4, 0 }, ++ { { 147, 145 }, { 145, 0 }, { 212, 235 }, { 50, 17 }, { 0, 1 }, 8, 0 }, ++ { { 4, 1 }, { 79, 0 }, { 250, 194 }, { 86, 5 }, { 0, 0 }, 12, 0 }, ++ { { 33, 34 }, { 73, 0 }, { 124, 111 }, { 32, 12 }, { 0, 1 }, 6, 0 }, ++ { { 49, 33 }, { 133, 0 }, { 221, 86 }, { 51, 22 }, { 1, 0 }, 10, 0 }, ++ { { 32, 33 }, { 4, 129 }, { 218, 143 }, { 5, 11 }, { 2, 0 }, 6, 0 }, ++ { { 5, 3 }, { 106, 128 }, { 241, 195 }, { 229, 229 }, { 0, 0 }, 6, 0 }, ++ { { 7, 2 }, { 21, 0 }, { 236, 248 }, { 38, 22 }, { 0, 0 }, 10, 0 }, ++ { { 5, 1 }, { 157, 0 }, { 103, 223 }, { 53, 5 }, { 0, 0 }, 8, 0 }, ++ { { 24, 18 }, { 150, 0 }, { 250, 248 }, { 40, 229 }, { 0, 0 }, 10, 0 }, ++ { { 16, 0 }, { 134, 3 }, { 168, 250 }, { 7, 3 }, { 0, 0 }, 6, 0 }, ++ { { 17, 16 }, { 65, 3 }, { 248, 243 }, { 71, 3 }, { 2, 0 }, 4, 0 }, ++ { { 1, 16 }, { 142, 0 }, { 241, 243 }, { 6, 2 }, { 2, 0 }, 14, 0 }, ++ { { 14, 192 }, { 0, 0 }, { 31, 31 }, { 0, 255 }, { 0, 3 }, 14, 0 }, ++ { { 6, 3 }, { 128, 136 }, { 248, 86 }, { 36, 132 }, { 0, 2 }, 14, 0 }, ++ { { 14, 208 }, { 0, 5 }, { 248, 52 }, { 0, 4 }, { 0, 3 }, 14, 0 }, ++ { { 14, 192 }, { 0, 0 }, { 246, 31 }, { 0, 2 }, { 0, 3 }, 14, 0 }, ++ { { 213, 218 }, { 149, 64 }, { 55, 86 }, { 163, 55 }, { 0, 0 }, 0, 0 }, ++ { { 53, 20 }, { 92, 8 }, { 178, 244 }, { 97, 21 }, { 2, 0 }, 10, 0 }, ++ { { 14, 208 }, { 0, 0 }, { 246, 79 }, { 0, 245 }, { 0, 3 }, 14, 0 }, ++ { { 38, 228 }, { 0, 0 }, { 255, 18 }, { 1, 22 }, { 0, 1 }, 14, 0 }, ++ { { 0, 0 }, { 0, 0 }, { 243, 246 }, { 240, 201 }, { 0, 2 }, 14, 0 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 0, 0 }, { 0, 0 }, { 252, 250 }, { 5, 23 }, { 2, 0 }, 14, 52 }, ++ { { 0, 1 }, { 2, 0 }, { 255, 255 }, { 7, 8 }, { 0, 0 }, 0, 48 }, ++ { { 0, 0 }, { 0, 0 }, { 252, 250 }, { 5, 23 }, { 2, 0 }, 14, 58 }, ++ { { 0, 0 }, { 0, 0 }, { 246, 246 }, { 12, 6 }, { 0, 0 }, 4, 60 }, ++ { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 47 }, ++ { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43 }, ++ { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 49 }, ++ { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43 }, ++ { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 51 }, ++ { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43 }, ++ { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 54 }, ++ { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 57 }, ++ { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 72 }, ++ { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 60 }, ++ { { 14, 208 }, { 0, 10 }, { 245, 159 }, { 48, 2 }, { 0, 0 }, 14, 76 }, ++ { { 14, 7 }, { 10, 93 }, { 228, 245 }, { 228, 229 }, { 3, 1 }, 6, 84 }, ++ { { 2, 5 }, { 3, 10 }, { 180, 151 }, { 4, 247 }, { 0, 0 }, 14, 36 }, ++ { { 78, 158 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 14, 76 }, ++ { { 17, 16 }, { 69, 8 }, { 248, 243 }, { 55, 5 }, { 2, 0 }, 8, 84 }, ++ { { 14, 208 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 14, 83 }, ++ { { 128, 16 }, { 0, 13 }, { 255, 255 }, { 3, 20 }, { 3, 0 }, 12, 84 }, ++ { { 14, 7 }, { 8, 81 }, { 248, 244 }, { 66, 228 }, { 0, 3 }, 14, 24 }, ++ { { 14, 208 }, { 0, 10 }, { 245, 159 }, { 48, 2 }, { 0, 0 }, 14, 77 }, ++ { { 1, 2 }, { 0, 0 }, { 250, 200 }, { 191, 151 }, { 0, 0 }, 7, 60 }, ++ { { 1, 1 }, { 81, 0 }, { 250, 250 }, { 135, 183 }, { 0, 0 }, 6, 65 }, ++ { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 59 }, ++ { { 1, 2 }, { 89, 0 }, { 250, 248 }, { 136, 182 }, { 0, 0 }, 6, 51 }, ++ { { 1, 0 }, { 0, 0 }, { 249, 250 }, { 10, 6 }, { 3, 0 }, 14, 45 }, ++ { { 0, 0 }, { 128, 0 }, { 249, 246 }, { 137, 108 }, { 3, 0 }, 14, 71 }, ++ { { 3, 12 }, { 128, 8 }, { 248, 246 }, { 136, 182 }, { 3, 0 }, 15, 60 }, ++ { { 3, 12 }, { 133, 0 }, { 248, 246 }, { 136, 182 }, { 3, 0 }, 15, 58 }, ++ { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 53 }, ++ { { 14, 3 }, { 64, 0 }, { 200, 155 }, { 73, 105 }, { 0, 2 }, 14, 64 }, ++ { { 215, 199 }, { 220, 0 }, { 173, 141 }, { 5, 5 }, { 3, 0 }, 14, 71 }, ++ { { 215, 199 }, { 220, 0 }, { 168, 136 }, { 4, 4 }, { 3, 0 }, 14, 61 }, ++ { { 128, 17 }, { 0, 0 }, { 246, 103 }, { 6, 23 }, { 3, 3 }, 14, 61 }, ++ { { 128, 17 }, { 0, 9 }, { 245, 70 }, { 5, 22 }, { 2, 3 }, 14, 48 }, ++ { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 48 }, ++ { { 6, 18 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 3, 0 }, 0, 69 }, ++ { { 6, 18 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 68 }, ++ { { 1, 2 }, { 88, 0 }, { 103, 117 }, { 231, 7 }, { 0, 0 }, 0, 63 }, ++ { { 65, 66 }, { 69, 8 }, { 248, 117 }, { 72, 5 }, { 0, 0 }, 0, 74 }, ++ { { 10, 30 }, { 64, 78 }, { 224, 255 }, { 240, 5 }, { 3, 0 }, 8, 60 }, ++ { { 10, 30 }, { 124, 82 }, { 224, 255 }, { 240, 2 }, { 3, 0 }, 8, 80 }, ++ { { 14, 0 }, { 64, 8 }, { 122, 123 }, { 74, 27 }, { 0, 2 }, 14, 64 }, ++ { { 14, 7 }, { 10, 64 }, { 228, 85 }, { 228, 57 }, { 3, 1 }, 6, 69 }, ++ { { 5, 4 }, { 5, 64 }, { 249, 214 }, { 50, 165 }, { 3, 0 }, 14, 73 }, ++ { { 2, 21 }, { 63, 0 }, { 0, 247 }, { 243, 245 }, { 3, 0 }, 8, 75 }, ++ { { 1, 2 }, { 79, 0 }, { 250, 248 }, { 141, 181 }, { 0, 0 }, 7, 68 }, ++ { { 0, 0 }, { 0, 0 }, { 246, 246 }, { 12, 6 }, { 0, 0 }, 4, 48 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 53 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 } ++ }; +diff -urN rott-1.0/rott/audiolib/gus.c trunk/rott/audiolib/gus.c +--- rott-1.0/rott/audiolib/gus.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/gus.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,283 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ file: GUS.C ++ ++ author: James R. Dose ++ date: September 7, 1994 ++ ++ Gravis Ultrasound initialization routines. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "usrhooks.h" ++#include "interrup.h" ++#include "newgf1.h" ++#include "gusmidi.h" ++#include "guswave.h" ++#include "_guswave.h" ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++// size of DMA buffer for patch loading ++#define DMABUFFSIZE 2048U ++ ++struct gf1_dma_buff GUS_HoldBuffer; ++static int HoldBufferAllocated = FALSE; ++ ++static int GUS_Installed = 0; ++ ++extern VoiceNode GUSWAVE_Voices[ VOICES ]; ++extern int GUSWAVE_Installed; ++ ++unsigned long GUS_TotalMemory; ++int GUS_MemConfig; ++ ++int GUS_AuxError = 0; ++ ++int GUS_ErrorCode = GUS_Ok; ++ ++#define GUS_SetErrorCode( status ) \ ++ GUS_ErrorCode = ( status ); ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUS_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *GUS_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case GUS_Warning : ++ case GUS_Error : ++ ErrorString = GUS_ErrorString( GUS_ErrorCode ); ++ break; ++ ++ case GUS_Ok : ++ ErrorString = "Ultrasound music ok."; ++ break; ++ ++ case GUS_OutOfMemory : ++ ErrorString = "Out of memory in GusMidi."; ++ break; ++ ++ case GUS_OutOfDosMemory : ++ ErrorString = "Out of conventional (640K) memory in GusMidi."; ++ break; ++ ++ case GUS_GF1Error : ++ ErrorString = gf1_error_str( GUS_AuxError ); ++ break; ++ ++ case GUS_InvalidIrq : ++ ErrorString = "Ultrasound IRQ must be 7 or less."; ++ break; ++ ++ case GUS_ULTRADIRNotSet : ++ ErrorString = "ULTRADIR environment variable not set."; ++ break; ++ ++ case GUS_MissingConfig : ++// ErrorString = "Can't find GUSMIDI.INI file."; ++ ErrorString = "Can't find ULTRAMID.INI file."; ++ break; ++ ++ case GUS_FileError : ++ ErrorString = strerror( GUS_AuxError ); ++ break; ++ ++ default : ++ ErrorString = "Unknown Ultrasound error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++ ++/*--------------------------------------------------------------------- ++ Function: D32DosMemAlloc ++ ++ Allocate a block of Conventional memory. ++---------------------------------------------------------------------*/ ++ ++void *D32DosMemAlloc ++ ( ++ unsigned size ++ ) ++ ++ { ++ union REGS r; ++ ++ // DPMI allocate DOS memory ++ r.x.eax = 0x0100; ++ ++ // Number of paragraphs requested ++ r.x.ebx = ( size + 15 ) >> 4; ++ int386( 0x31, &r, &r ); ++ if ( r.x.cflag ) ++ { ++ // Failed ++ return( NULL ); ++ } ++ ++ return( ( void * )( ( r.x.eax & 0xFFFF ) << 4 ) ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUS_Init ++ ++ Initializes the Gravis Ultrasound for sound and music playback. ++---------------------------------------------------------------------*/ ++ ++int GUS_Init ++ ( ++ void ++ ) ++ ++ { ++ struct load_os os; ++ int ret; ++ ++ if ( GUS_Installed > 0 ) ++ { ++ GUS_Installed++; ++ return( GUS_Ok ); ++ } ++ ++ GUS_SetErrorCode( GUS_Ok ); ++ ++ GUS_Installed = 0; ++ ++ GetUltraCfg( &os ); ++ ++ if ( os.forced_gf1_irq > 7 ) ++ { ++ GUS_SetErrorCode( GUS_InvalidIrq ); ++ return( GUS_Error ); ++ } ++ ++ if ( !HoldBufferAllocated ) ++ { ++ GUS_HoldBuffer.vptr = D32DosMemAlloc( DMABUFFSIZE ); ++ if ( GUS_HoldBuffer.vptr == NULL ) ++ { ++ GUS_SetErrorCode( GUS_OutOfDosMemory ); ++ return( GUS_Error ); ++ } ++ GUS_HoldBuffer.paddr = ( unsigned long )GUS_HoldBuffer.vptr; ++ ++ HoldBufferAllocated = TRUE; ++ } ++ ++ os.voices = 24; ++ ret = gf1_load_os( &os ); ++ if ( ret ) ++ { ++ GUS_AuxError = ret; ++ GUS_SetErrorCode( GUS_GF1Error ); ++ return( GUS_Error ); ++ } ++ ++ GUS_TotalMemory = gf1_mem_avail(); ++ GUS_MemConfig = ( GUS_TotalMemory - 1 ) >> 18; ++ ++ GUS_Installed = 1; ++ return( GUS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUS_Shutdown ++ ++ Ends use of the Gravis Ultrasound. Must be called the same number ++ of times as GUS_Init. ++---------------------------------------------------------------------*/ ++ ++void GUS_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ if ( GUS_Installed > 0 ) ++ { ++ GUS_Installed--; ++ if ( GUS_Installed == 0 ) ++ { ++ gf1_unload_os(); ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_Shutdown ++ ++ Terminates use of the Gravis Ultrasound for digitized sound playback. ++---------------------------------------------------------------------*/ ++ ++void GUSWAVE_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ int i; ++ ++ if ( GUSWAVE_Installed ) ++ { ++ GUSWAVE_KillAllVoices(); ++ ++ // free memory ++ for ( i = 0; i < VOICES; i++ ) ++ { ++ if ( GUSWAVE_Voices[ i ].mem != NULL ) ++ { ++ gf1_free( GUSWAVE_Voices[ i ].mem ); ++ GUSWAVE_Voices[ i ].mem = NULL; ++ } ++ } ++ ++ GUS_Shutdown(); ++ GUSWAVE_Installed = FALSE; ++ } ++ } +diff -urN rott-1.0/rott/audiolib/gusmidi.c trunk/rott/audiolib/gusmidi.c +--- rott-1.0/rott/audiolib/gusmidi.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/gusmidi.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,561 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/*********** *********************************************************** ++ file: GUSMIDI.C ++ ++ author: James R. Dose ++ date: March 23, 1994 ++ ++ General MIDI playback functions for the Gravis Ultrasound ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++// Module MUST be compiled with structure allignment set to a maximum ++// of 1 byte ( zp1 ). ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "usrhooks.h" ++#include "interrup.h" ++#include "newgf1.h" ++#include "gusmidi.h" ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++// size of DMA buffer for patch loading ++#define DMABUFFSIZE 2048U ++ ++#define MAX_MEM_CONFIG 3 ++ ++// size of patch array (128 perc, 128 melodic) ++#define NUM_PATCHES 256 ++ ++// size of largest patch name ++#define BIGGEST_NAME 9 ++ ++#define UNUSED_PATCH -1 ++ ++static struct patch Patch[ NUM_PATCHES ]; ++static unsigned char *PatchWaves[ NUM_PATCHES ]; ++ ++static int PatchMap[ NUM_PATCHES ][ MAX_MEM_CONFIG + 1 ]; ++static char ProgramName[ NUM_PATCHES ][ BIGGEST_NAME ]; ++static char PatchLoaded[ NUM_PATCHES ]; ++ ++static char ConfigFileName[] = "ULTRAMID.INI"; ++static char ConfigDirectory[ 80 ] = { '\0' }; ++ ++// The name of the configuration directory ++static char InstrumentDirectory[ 80 ]; ++ ++extern struct gf1_dma_buff GUS_HoldBuffer; ++ ++extern unsigned long GUS_TotalMemory; ++extern int GUS_MemConfig; ++ ++static int GUSMIDI_Volume = 255; ++ ++extern int GUS_AuxError; ++extern int GUS_ErrorCode; ++ ++int GUSMIDI_Installed = FALSE; ++ ++#define GUS_SetErrorCode( status ) \ ++ GUS_ErrorCode = ( status ); ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUS_GetPatchMap ++ ++ Reads the patch map from disk. ++---------------------------------------------------------------------*/ ++ ++int GUS_GetPatchMap ++ ( ++ char *name ++ ) ++ ++ { ++ char text[ 80 ]; ++ char *ud; ++ int index; ++ int ignore; ++ FILE *fp; ++ ++ for( index = 0; index < NUM_PATCHES; index++ ) ++ { ++ PatchMap[ index ][ 0 ] = UNUSED_PATCH; ++ PatchMap[ index ][ 1 ] = UNUSED_PATCH; ++ PatchMap[ index ][ 2 ] = UNUSED_PATCH; ++ PatchMap[ index ][ 3 ] = UNUSED_PATCH; ++ ProgramName[ index ][ 0 ] = 0; ++ } ++ ++ ud = getenv( "ULTRADIR" ); ++ if ( ud == NULL ) ++ { ++ GUS_SetErrorCode( GUS_ULTRADIRNotSet ); ++ return( GUS_Error ); ++ } ++ ++ strcpy( InstrumentDirectory, ud ); ++ strcat( InstrumentDirectory, "\\midi\\" ); ++ strcpy( ConfigDirectory, ud ); ++ strcat( ConfigDirectory, "\\midi\\" ); ++ strcpy( text, name ); ++ ++ fp = fopen( text, "r" ); ++ if ( fp == NULL ) ++ { ++ strcpy( text, InstrumentDirectory ); ++ strcat( text, name ); ++ ++ fp = fopen( text, "r" ); ++ if ( fp == NULL ) ++ { ++ GUS_SetErrorCode( GUS_MissingConfig ); ++ return( GUS_Error ); ++ } ++ } ++ ++ while( 1 ) ++ { ++ if ( fgets( text, 80, fp ) == NULL ) ++ { ++ break; ++ } ++ ++ if ( text[ 0 ] == '#' ) ++ { ++ continue; ++ } ++ ++ if ( sscanf( text, "%d", &index ) != 1 ) ++ { ++ continue; ++ } ++ ++ sscanf( text, "%d, %d, %d, %d, %d, %s\n", &ignore, ++ &PatchMap[ index ][ 0 ], ++ &PatchMap[ index ][ 1 ], ++ &PatchMap[ index ][ 2 ], ++ &PatchMap[ index ][ 3 ], ++ ProgramName[ index ] ); ++ } ++ ++ fclose( fp ); ++ ++ return( GUS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_UnloadPatch ++ ++ Unloads a patch from the GUS's memory. ++---------------------------------------------------------------------*/ ++ ++int GUSMIDI_UnloadPatch ++ ( ++ int prognum ++ ) ++ ++ { ++ int prog; ++ unsigned flags; ++ ++ prog = PatchMap[ prognum ][ GUS_MemConfig ]; ++ ++ if ( PatchLoaded[ prog ] ) ++ { ++ flags = DisableInterrupts(); ++ ++ gf1_unload_patch( &Patch[ prog ] ); ++ if ( PatchWaves[ prog ] != NULL ) ++ { ++ USRHOOKS_FreeMem( PatchWaves[ prog ] ); ++ PatchWaves[ prog ] = NULL; ++ } ++ ++ // just in case sequence is still playing ++ Patch[ prog ].nlayers = 0; ++ PatchLoaded[ prog ] = FALSE; ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ return( GUS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_LoadPatch ++ ++ Loads a patch into the GUS's memory. ++---------------------------------------------------------------------*/ ++ ++int GUSMIDI_LoadPatch ++ ( ++ int prognum ++ ) ++ ++ { ++ int prog; ++ char text[ 80 ]; ++ int ret; ++ unsigned char *wave_buff; ++ struct patchinfo patchi; ++ int status; ++ ++ prog = PatchMap[ prognum ][ GUS_MemConfig ]; ++ ++ if ( ( PatchLoaded[ prog ] ) || ( prog == UNUSED_PATCH ) ) ++ { ++ return( GUS_Ok ); ++ } ++ ++ if ( !ProgramName[ prog ][ 0 ] ) ++ { ++ return( GUS_Ok ); ++ } ++ ++ strcpy( text, InstrumentDirectory ); ++ strcat( text, ProgramName[ prog ] ); ++ strcat( text, ".pat" ); ++ ++ ret = gf1_get_patch_info( text, &patchi ); ++ if ( ret != OK ) ++ { ++ GUS_AuxError = ret; ++ GUS_SetErrorCode( GUS_GF1Error ); ++ return( GUS_Error ); ++ } ++ ++ status = USRHOOKS_GetMem( &wave_buff, patchi.header.wave_forms * ++ sizeof( struct wave_struct ) ); ++ if ( status != USRHOOKS_Ok ) ++ { ++ GUS_SetErrorCode( GUS_OutOfMemory ); ++ return( GUS_Error ); ++ } ++ ++ ret = gf1_load_patch( text, &patchi, &Patch[ prog ], &GUS_HoldBuffer, ++ DMABUFFSIZE, ( unsigned char * )wave_buff, PATCH_LOAD_8_BIT ); ++ ++ if ( ret != OK ) ++ { ++ USRHOOKS_FreeMem( wave_buff ); ++ GUS_AuxError = ret; ++ GUS_SetErrorCode( GUS_GF1Error ); ++ return( GUS_Error ); ++ } ++ ++ PatchWaves[ prog ] = wave_buff; ++ PatchLoaded[ prog ] = TRUE; ++ ++ return( GUS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_ProgramChange ++ ++ Selects the instrument to use on the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++void GUSMIDI_ProgramChange ++ ( ++ int channel, ++ int prognum ++ ) ++ ++ { ++ int prog; ++ ++ prog = PatchMap[ prognum ][ GUS_MemConfig ]; ++ ++ if ( PatchLoaded[ prog ] ) ++ { ++ gf1_midi_change_program( &Patch[ prog ], channel ); ++ } ++ else ++ { ++ gf1_midi_change_program( NULL, channel ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_NoteOn ++ ++ Plays a note on the specified channel. ++---------------------------------------------------------------------*/ ++ ++void GUSMIDI_NoteOn ++ ( ++ int chan, ++ int note, ++ int velocity ++ ) ++ ++ { ++ int prog; ++ ++ if ( chan == 9 ) ++ { ++ prog = PatchMap[ note + 128 ][ GUS_MemConfig ]; ++ ++ if ( PatchLoaded[ prog ] ) ++ { ++ gf1_midi_note_on( &Patch[ note + 128 ], 1, ++ note, velocity, 9 ); ++ } ++ } ++ else ++ { ++ gf1_midi_note_on( 0L, 1, note, velocity, chan ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_NoteOff ++ ++ Turns off a note on the specified channel. ++---------------------------------------------------------------------*/ ++#pragma warn -par ++void GUSMIDI_NoteOff ++ ( ++ int chan, ++ int note, ++ int velocity ++ ) ++ ++ { ++ gf1_midi_note_off( note, chan ); ++ } ++#pragma warn .par ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_ControlChange ++ ++ Sets the value of a controller on the specified channel. ++---------------------------------------------------------------------*/ ++ ++void GUSMIDI_ControlChange ++ ( ++ int channel, ++ int number, ++ int value ++ ) ++ ++ { ++ gf1_midi_parameter( channel, number, value ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_PitchBend ++ ++ Sets the pitch bend on the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++void GUSMIDI_PitchBend ++ ( ++ int channel, ++ int lsb, ++ int msb ++ ) ++ ++ { ++ gf1_midi_pitch_bend( channel, lsb, msb ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_ReleasePatches ++ ++ Removes all the instruments from the GUS's memory. ++---------------------------------------------------------------------*/ ++ ++void GUSMIDI_ReleasePatches ++ ( ++ void ++ ) ++ ++ { ++ int i; ++ ++ for( i = 0; i < 256; i++ ) ++ { ++ GUSMIDI_UnloadPatch( i ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_SetVolume ++ ++ Sets the total music volume. ++---------------------------------------------------------------------*/ ++ ++void GUSMIDI_SetVolume ++ ( ++ int volume ++ ) ++ ++ { ++ // Set the minimum to 2 because 0 has a tremolo problem ++ volume = max( 2, volume ); ++ volume = min( volume, 255 ); ++ ++ GUSMIDI_Volume = volume; ++ ++ // range = 0 to 127 ++ gf1_midi_synth_volume( 0, volume >> 1 ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_GetVolume ++ ++ Returns the total music volume. ++---------------------------------------------------------------------*/ ++ ++int GUSMIDI_GetVolume ++ ( ++ void ++ ) ++ ++ { ++ return( GUSMIDI_Volume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_Init ++ ++ Initializes the Gravis Ultrasound for music playback. ++---------------------------------------------------------------------*/ ++ ++int GUSMIDI_Init ++ ( ++ void ++ ) ++ ++ { ++ int ret; ++ int i; ++ int startmem; ++// unsigned long mem; ++ extern int GUSWAVE_Installed; ++ ++ if ( GUSMIDI_Installed ) ++ { ++ GUSMIDI_Shutdown(); ++ } ++ ++ ret = GUS_Init(); ++ if ( ret != GUS_Ok ) ++ { ++ return( ret ); ++ } ++ ++ if ( GUS_MemConfig < 0 ) ++ { ++ GUS_MemConfig = 0; ++ } ++ ++ if ( GUS_MemConfig > MAX_MEM_CONFIG ) ++ { ++ GUS_MemConfig = MAX_MEM_CONFIG; ++ } ++ ++ for( i = 0; i < NUM_PATCHES; i++ ) ++ { ++ ProgramName[ i ][ 0 ] = '\0'; ++ PatchWaves[ i ] = NULL; ++ PatchLoaded[ i ] = FALSE; ++ } ++ ++ GUSMIDI_SetVolume( 255 ); ++ ++ GUSMIDI_Installed = TRUE; ++ ++ ret = GUS_GetPatchMap( ConfigFileName ); ++ if ( ret != GUS_Ok ) ++ { ++ GUSMIDI_Shutdown(); ++ return( ret ); ++ } ++ ++// if ( !GUSWAVE_Installed ) ++// { ++// mem = gf1_malloc( 8192 ); ++// } ++ ++ startmem = gf1_mem_avail(); ++ for( i = 0; i < NUM_PATCHES; i++ ) ++ { ++ ret = GUSMIDI_LoadPatch( i ); ++ if ( ret != GUS_Ok ) ++ { ++ } ++// if ( ret != GUS_Ok ) ++// { ++// return( ret ); ++// } ++ } ++ ++// if ( !GUSWAVE_Installed ) ++// { ++// gf1_free( mem ); ++// } ++ ++ GUSMIDI_Installed = TRUE; ++ ++ return( GUS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSMIDI_Shutdown ++ ++ Ends use of the Gravis Ultrasound for music playback. ++---------------------------------------------------------------------*/ ++ ++void GUSMIDI_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ GUSMIDI_ReleasePatches(); ++ GUS_Shutdown(); ++ GUSMIDI_Installed = FALSE; ++ } +diff -urN rott-1.0/rott/audiolib/gusmidi.h trunk/rott/audiolib/gusmidi.h +--- rott-1.0/rott/audiolib/gusmidi.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/gusmidi.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,59 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++#ifndef __GUSMIDI_H ++#define __GUSMIDI_H ++ ++extern struct gf1_dma_buff GUS_HoldBuffer; ++ ++enum GUS_Errors ++ { ++ GUS_Warning = -2, ++ GUS_Error = -1, ++ GUS_Ok = 0, ++ GUS_OutOfMemory, ++ GUS_OutOfDosMemory, ++ GUS_OutOfDRAM, ++ GUS_GF1Error, ++ GUS_InvalidIrq, ++ GUS_ULTRADIRNotSet, ++ GUS_MissingConfig, ++ GUS_FileError ++ }; ++ ++char *GUS_ErrorString( int ErrorNumber ); ++int GUS_GetPatchMap( char *name ); ++int GUSMIDI_UnloadPatch( int prog ); ++int GUSMIDI_LoadPatch( int prog ); ++void GUSMIDI_ProgramChange( int channel, int prog ); ++void GUSMIDI_NoteOn( int chan, int note, int velocity ); ++void GUSMIDI_NoteOff( int chan, int note, int velocity ); ++void GUSMIDI_ControlChange( int channel, int number, int value ); ++void GUSMIDI_PitchBend( int channel, int lsb, int msb ); ++void GUSMIDI_ReleasePatches( void ); ++void GUSMIDI_SetVolume( int volume ); ++int GUSMIDI_GetVolume( void ); ++int GUS_Init( void ); ++void GUS_Shutdown( void ); ++#pragma aux GUS_Shutdown frame; ++int GUSMIDI_Init( void ); ++void GUSMIDI_Shutdown( void ); ++void *D32DosMemAlloc( unsigned size ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/guswave.c trunk/rott/audiolib/guswave.c +--- rott-1.0/rott/audiolib/guswave.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/guswave.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,1773 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ file: GUSWAVE.C ++ ++ author: James R. Dose ++ date: March 23, 1994 ++ ++ Digitized sound playback routines for the Gravis Ultrasound. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "debugio.h" ++#include "interrup.h" ++#include "ll_man.h" ++#include "pitch.h" ++#include "user.h" ++#include "multivoc.h" ++#include "_guswave.h" ++#include "newgf1.h" ++#include "gusmidi.h" ++#include "guswave.h" ++ ++#define ATR_INDEX 0x3c0 ++#define STATUS_REGISTER_1 0x3da ++ ++#define SetBorderColor(color) \ ++ { \ ++ inp (STATUS_REGISTER_1); \ ++ outp (ATR_INDEX,0x31); \ ++ outp (ATR_INDEX,color); \ ++ } ++ ++static const int GUSWAVE_PanTable[ 32 ] = ++ { ++ 8, 9, 10, 11, 11, 12, 13, 14, ++ 15, 14, 13, 12, 11, 10, 9, 8, ++ 7, 6, 5, 4, 4, 3, 2, 1, ++ 0, 1, 2, 3, 4, 5, 6, 7 ++ }; ++ ++static voicelist VoiceList; ++static voicelist VoicePool; ++ ++static voicestatus VoiceStatus[ MAX_VOICES ]; ++//static ++VoiceNode GUSWAVE_Voices[ VOICES ]; ++ ++static int GUSWAVE_VoiceHandle = GUSWAVE_MinVoiceHandle; ++static int GUSWAVE_MaxVoices = VOICES; ++//static ++int GUSWAVE_Installed = FALSE; ++ ++static void ( *GUSWAVE_CallBackFunc )( unsigned long ) = NULL; ++ ++// current volume for dig audio - from 0 to 4095 ++static int GUSWAVE_Volume = MAX_VOLUME; ++ ++static int GUSWAVE_SwapLeftRight = FALSE; ++ ++static int GUS_Debug = FALSE; ++ ++extern int GUSMIDI_Installed; ++ ++int GUSWAVE_ErrorCode = GUSWAVE_Ok; ++ ++#define GUSWAVE_SetErrorCode( status ) \ ++ GUSWAVE_ErrorCode = ( status ); ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *GUSWAVE_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case GUSWAVE_Warning : ++ case GUSWAVE_Error : ++ ErrorString = GUSWAVE_ErrorString( GUSWAVE_ErrorCode ); ++ break; ++ ++ case GUSWAVE_Ok : ++ ErrorString = "GUSWAVE ok."; ++ break; ++ ++ case GUSWAVE_GUSError : ++ ErrorString = GUS_ErrorString( GUS_Error ); ++ break; ++ ++ case GUSWAVE_NotInstalled : ++ ErrorString = "GUSWAVE not installed."; ++ break; ++ ++ case GUSWAVE_NoVoices : ++ ErrorString = "No free voices available to GUSWAVE."; ++ break; ++ ++ case GUSWAVE_UltraNoMem : ++ ErrorString = "Not enough Ultrasound memory available for GUSWAVE."; ++ break; ++ ++ case GUSWAVE_UltraNoMemMIDI : ++ ErrorString = "Not enough Ultrasound memory available for GUSWAVE. " ++ "Try initializing Sound FX before Music."; ++ break; ++ ++ case GUSWAVE_VoiceNotFound : ++ ErrorString = "No voice with matching handle found."; ++ break; ++ ++ case GUSWAVE_InvalidVOCFile : ++ ErrorString = "Invalid VOC file passed in to GUSWAVE."; ++ break; ++ ++ case GUSWAVE_InvalidWAVFile : ++ ErrorString = "Invalid WAV file passed in to GUSWAVE."; ++ break; ++ ++ default : ++ ErrorString = "Unknown GUSWAVE error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_CallBack ++ ++ GF1 callback service routine. ++---------------------------------------------------------------------*/ ++ ++char GUS_Silence8[ 1024 ] = //256 ] = ++ { ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, ++ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 ++ ++ ++ }; ++ ++//unsigned short GUS_Silence16[ 128 ] = ++unsigned short GUS_Silence16[ 512 ] = ++ { ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ ++ ++ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ++ }; ++ ++static int LOADDS GUSWAVE_CallBack ++ ( ++ int reason, ++ int voice, ++ unsigned char **buf, ++ unsigned long *size ++ ) ++ ++ { ++ VoiceNode *Voice; ++ playbackstatus status; ++ ++ // this function is called from an interrupt ++ // remember not to make any DOS or BIOS calls from here ++ // also don't call any C library functions unless you are sure that ++ // they are reentrant ++ // restore our DS register ++ ++ if ( VoiceStatus[ voice ].playing == FALSE ) ++ { ++ return( DIG_DONE ); ++ } ++ ++ if ( reason == DIG_MORE_DATA ) ++ { ++// SetBorderColor(16); ++ Voice = VoiceStatus[ voice ].Voice; ++ ++ if ( ( Voice != NULL ) && ( Voice->Playing ) ) ++/* ++ { ++ *buf = ( unsigned char * )GUS_Silence16; ++ *size = 1024; ++ ++ SetBorderColor(0); ++ return( DIG_MORE_DATA ); ++ } ++ */ ++ { ++ status = Voice->GetSound( Voice ); ++ if ( status != SoundDone ) ++ { ++ if ( ( Voice->sound == NULL ) || ( status == NoMoreData ) ) ++ { ++ if ( Voice->bits == 8 ) ++ { ++ *buf = GUS_Silence8; ++ } ++ else ++ { ++ *buf = ( unsigned char * )GUS_Silence16; ++ } ++ *size = 256; ++ } ++ else ++ { ++ *buf = Voice->sound; ++ *size = Voice->length; ++ } ++ return( DIG_MORE_DATA ); ++ } ++ } ++// SetBorderColor(16); ++ return( DIG_DONE ); ++ } ++ ++ if ( reason == DIG_DONE ) ++ { ++ Voice = VoiceStatus[ voice ].Voice; ++ VoiceStatus[ voice ].playing = FALSE; ++ ++ if ( Voice != NULL ) ++ { ++ Voice->Active = FALSE; ++ Voice->Playing = FALSE; ++ ++// I'm commenting this out because a -1 could cause a crash if it ++// is sent to the GF1 code. This shouldn't be necessary since ++// Active should be false when GF1voice is -1, but this is just ++// a precaution. Adjust the pan on the wrong voice is a lot ++// more pleasant than a crash! ++// Voice->GF1voice = -1; ++ ++ LL_Remove( VoiceNode, &VoiceList, Voice ); ++ LL_AddToTail( VoiceNode, &VoicePool, Voice ); ++ } ++ ++ if ( GUSWAVE_CallBackFunc ) ++ { ++ GUSWAVE_CallBackFunc( Voice->callbackval ); ++ } ++ } ++ ++ return( DIG_DONE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_DebugCallBack ++ ++ GF1 callback service routine with debugging info. ++---------------------------------------------------------------------*/ ++ ++static int LOADDS GUSWAVE_DebugCallBack ++ ( ++ int reason, ++ int voice, ++ unsigned char **buf, ++ unsigned long *size ++ ) ++ ++ { ++ VoiceNode *Voice; ++ ++ // this function is called from an interrupt ++ // remember not to make any DOS or BIOS calls from here ++ // also don't call any C library functions unless you are sure that ++ // they are reentrant ++ // restore our DS register ++ ++ if ( VoiceStatus[ voice ].playing == FALSE ) ++ { ++// DB_printf( "GUS Voice %d not playing.\n", voice ); ++ DB_printf( "GUS Voice " ); ++ DB_PrintNum( voice ); ++ DB_printf( " not playing.\n" ); ++ return( DIG_DONE ); ++ } ++ ++ if ( reason == DIG_MORE_DATA ) ++ { ++ Voice = VoiceStatus[ voice ].Voice; ++ ++// DB_printf( "Voice %d : More data -- ", Voice ); ++ DB_printf( "Voice " ); ++ DB_PrintNum( voice ); ++ DB_printf( " : More data -- " ); ++ if ( Voice != NULL ) ++ { ++ if ( Voice->Playing ) ++ { ++ GUSWAVE_GetNextVOCBlock( Voice ); ++ if ( Voice->Playing ) ++ { ++// DB_printf( "More data -- size = %u blocklength = %u\n", ++// Voice->length, Voice->BlockLength ); ++ DB_printf( "More data -- size = " ); ++ DB_PrintNum( Voice->length ); ++ DB_printf( " blocklength = " ); ++ DB_PrintNum( Voice->BlockLength ); ++ DB_printf( "\n" ); ++ *buf = Voice->sound; ++ *size = Voice->length; ++ return( DIG_MORE_DATA ); ++ } ++ else ++ { ++ DB_printf( "Voice done.\n" ); ++ } ++ } ++ else ++ { ++ DB_printf( "Voice not active.\n" ); ++ } ++ } ++ else ++ { ++ DB_printf( " NULL Voice\n" ); ++ } ++ ++ return( DIG_DONE ); ++ } ++ ++ if ( reason == DIG_DONE ) ++ { ++ VoiceStatus[ voice ].playing = FALSE; ++ Voice = VoiceStatus[ voice ].Voice; ++// DB_printf( "Voice %d : Done -- ", Voice ); ++ DB_printf( "Voice " ); ++ DB_PrintNum( voice ); ++ DB_printf( " : Done -- " ); ++ ++ if ( Voice != NULL ) ++ { ++ DB_printf( "Ok\n" ); ++ ++ Voice->Active = FALSE; ++ Voice->Playing = FALSE; ++ ++// I'm commenting this out because a -1 could cause a crash if it ++// is sent to the GF1 code. This shouldn't be necessary since ++// Active should be false when GF1voice is -1, but this is just ++// a precaution. Adjust the pan on the wrong voice is a lot ++// more pleasant than a crash! ++// Voice->GF1voice = -1; ++ ++ LL_Remove( VoiceNode, &VoiceList, Voice ); ++ LL_AddToTail( VoiceNode, &VoicePool, Voice ); ++ } ++ else ++ { ++ DB_printf( "Null voice\n" ); ++ } ++ ++ if ( GUSWAVE_CallBackFunc ) ++ { ++ GUSWAVE_CallBackFunc( Voice->callbackval ); ++ } ++ } ++ ++ return( DIG_DONE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_GetVoice ++ ++ Locates the voice with the specified handle. ++---------------------------------------------------------------------*/ ++ ++static VoiceNode *GUSWAVE_GetVoice ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ voice = VoiceList.start; ++ ++ while( voice != NULL ) ++ { ++ if ( handle == voice->handle ) ++ { ++ break; ++ } ++ ++ voice = voice->next; ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( voice == NULL ) ++ { ++ GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound ); ++ } ++ ++ return( voice ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_VoicePlaying ++ ++ Checks if the voice associated with the specified handle is ++ playing. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_VoicePlaying ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ voice = GUSWAVE_GetVoice( handle ); ++ if ( voice != NULL ) ++ { ++ return( voice->Active ); ++ } ++ ++ return( FALSE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_VoicesPlaying ++ ++ Determines the number of currently active voices. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_VoicesPlaying ++ ( ++ void ++ ) ++ ++ { ++ int index; ++ int NumVoices = 0; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ for( index = 0; index < GUSWAVE_MaxVoices; index++ ) ++ { ++ if ( GUSWAVE_Voices[ index ].Active ) ++ { ++ NumVoices++; ++ } ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( GUS_Debug ) ++ { ++ DB_printf( "Number of voices = %d.\n", NumVoices ); ++ } ++ ++ return( NumVoices ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_Kill ++ ++ Stops output of the voice associated with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_Kill ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ voice = GUSWAVE_GetVoice( handle ); ++ ++ if ( voice == NULL ) ++ { ++ RestoreInterrupts( flags ); ++ GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound ); ++ ++ if ( GUS_Debug ) ++ { ++ DB_printf( "Could not find voice to kill.\n" ); ++ } ++ ++ return( GUSWAVE_Warning ); ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( !GUS_Debug ) ++ { ++ if ( voice->Active ) ++ { ++ gf1_stop_digital( voice->GF1voice ); ++ } ++ } ++ else ++ { ++ DB_printf( "Kill - GUS Voice %d ", voice->GF1voice ); ++ if ( voice->Active ) ++ { ++ DB_printf( "active\n" ); ++ gf1_stop_digital( voice->GF1voice ); ++ } ++ else ++ { ++ DB_printf( "inactive\n" ); ++ } ++ } ++ ++// RestoreInterrupts( flags ); ++ ++ return( GUSWAVE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_KillAllVoices ++ ++ Stops output of all currently active voices. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_KillAllVoices ++ ( ++ void ++ ) ++ ++ { ++ int i; ++ unsigned flags; ++ ++ if ( !GUSWAVE_Installed ) ++ { ++ return( GUSWAVE_Ok ); ++ } ++ ++ if ( GUS_Debug ) ++ { ++ DB_printf( "Kill All Voices\n" ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ // Remove all the voices from the list ++ for( i = 0; i < GUSWAVE_MaxVoices; i++ ) ++ { ++ if ( GUSWAVE_Voices[ i ].Active ) ++ { ++// GUSWAVE_Kill( GUSWAVE_Voices[ i ].handle ); ++ ++ gf1_stop_digital( GUSWAVE_Voices[ i ].GF1voice ); ++ } ++ } ++ ++ for( i = 0; i < MAX_VOICES; i++ ) ++ { ++ VoiceStatus[ i ].playing = FALSE; ++ VoiceStatus[ i ].Voice = NULL; ++ } ++ ++ VoicePool.start = NULL; ++ VoicePool.end = NULL; ++ VoiceList.start = NULL; ++ VoiceList.end = NULL; ++ ++ for( i = 0; i < GUSWAVE_MaxVoices; i++ ) ++ { ++ GUSWAVE_Voices[ i ].Active = FALSE; ++ if ( GUSWAVE_Voices[ i ].mem != NULL ) ++ { ++ LL_AddToTail( VoiceNode, &VoicePool, &GUSWAVE_Voices[ i ] ); ++ } ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ return( GUSWAVE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_SetPitch ++ ++ Sets the pitch for the voice associated with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_SetPitch ++ ( ++ int handle, ++ int pitchoffset ++ ) ++ ++ { ++ VoiceNode *voice; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ voice = GUSWAVE_GetVoice( handle ); ++ ++ if ( voice == NULL ) ++ { ++ RestoreInterrupts( flags ); ++ ++ GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound ); ++ return( GUSWAVE_Warning ); ++ } ++ ++ if ( voice->Active ) ++ { ++ voice->PitchScale = PITCH_GetScale( pitchoffset ); ++ voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) >> 16; ++ gf1_dig_set_freq( voice->GF1voice, voice->RateScale ); ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ return( GUSWAVE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_SetPan3D ++ ++ Sets the pan position of the voice with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_SetPan3D ++ ( ++ int handle, ++ int angle, ++ int distance ++ ) ++ ++ { ++ VoiceNode *voice; ++ int pan; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ voice = GUSWAVE_GetVoice( handle ); ++ ++ if ( voice == NULL ) ++ { ++ RestoreInterrupts( flags ); ++ ++ GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound ); ++ return( GUSWAVE_Warning ); ++ } ++ ++ if ( voice->Active ) ++ { ++ angle &= 31; ++ ++ pan = GUSWAVE_PanTable[ angle ]; ++ if ( GUSWAVE_SwapLeftRight ) ++ { ++ pan = 15 - pan; ++ } ++ ++ distance = max( 0, distance ); ++ distance = min( 255, distance ); ++ ++ voice->Volume = 255 - distance; ++ voice->Pan = pan; ++ ++ gf1_dig_set_pan( voice->GF1voice, pan ); ++ gf1_dig_set_vol( voice->GF1voice, GUSWAVE_Volume - distance * 4 ); ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ return( GUSWAVE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_SetVolume ++ ++ Sets the total volume of the digitized sounds. ++---------------------------------------------------------------------*/ ++ ++void GUSWAVE_SetVolume ++ ( ++ int volume ++ ) ++ ++ { ++ int i; ++ ++ volume = max( 0, volume ); ++ volume = min( 255, volume ); ++ GUSWAVE_Volume = MAX_VOLUME - ( 255 - volume ) * 4; ++ ++ for( i = 0; i < GUSWAVE_MaxVoices; i++ ) ++ { ++ if ( GUSWAVE_Voices[ i ].Active ) ++ { ++ gf1_dig_set_vol( GUSWAVE_Voices[ i ].GF1voice, ++ GUSWAVE_Volume - ( 255 - GUSWAVE_Voices[ i ].Volume ) * 4 ); ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_GetVolume ++ ++ Returns the total volume of the digitized sounds. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_GetVolume ++ ( ++ void ++ ) ++ ++ { ++ return( 255 - ( ( MAX_VOLUME - GUSWAVE_Volume ) / 4 ) ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_AllocVoice ++ ++ Retrieve an inactive or lower priority voice for output. ++---------------------------------------------------------------------*/ ++ ++static VoiceNode *GUSWAVE_AllocVoice ++ ( ++ int priority ++ ) ++ ++ { ++ VoiceNode *voice; ++ VoiceNode *node; ++ unsigned flags; ++ ++ // If we don't have any free voices, check if we have a higher ++ // priority than one that is playing. ++ if ( GUSWAVE_VoicesPlaying() >= GUSWAVE_MaxVoices ) ++ { ++ flags = DisableInterrupts(); ++ ++ node = VoiceList.start; ++ voice = node; ++ while( node != NULL ) ++ { ++ if ( node->priority < voice->priority ) ++ { ++ voice = node; ++ } ++ ++ node = node->next; ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( priority >= voice->priority ) ++ { ++ GUSWAVE_Kill( voice->handle ); ++ } ++ } ++ ++ // Check if any voices are in the voice pool ++ flags = DisableInterrupts(); ++ ++ voice = VoicePool.start; ++ if ( voice != NULL ) ++ { ++ LL_Remove( VoiceNode, &VoicePool, voice ); ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( voice != NULL ) ++ { ++ do ++ { ++ GUSWAVE_VoiceHandle++; ++ if ( GUSWAVE_VoiceHandle < GUSWAVE_MinVoiceHandle ) ++ { ++ GUSWAVE_VoiceHandle = GUSWAVE_MinVoiceHandle; ++ } ++ } ++ while( GUSWAVE_VoicePlaying( GUSWAVE_VoiceHandle ) ); ++ ++ voice->handle = GUSWAVE_VoiceHandle; ++ } ++ ++ return( voice ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_VoiceAvailable ++ ++ Checks if a voice can be play at the specified priority. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_VoiceAvailable ++ ( ++ int priority ++ ) ++ ++ { ++ VoiceNode *voice; ++ VoiceNode *node; ++ unsigned flags; ++ ++ if ( GUSWAVE_VoicesPlaying() < GUSWAVE_MaxVoices ) ++ { ++ return( TRUE ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ node = VoiceList.start; ++ voice = node; ++ while( node != NULL ) ++ { ++ if ( node->priority < voice->priority ) ++ { ++ voice = node; ++ } ++ ++ node = node->next; ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( priority >= voice->priority ) ++ { ++ return( TRUE ); ++ } ++ ++ return( FALSE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_GetNextVOCBlock ++ ++ Interperate the information of a VOC format sound file. ++---------------------------------------------------------------------*/ ++ ++playbackstatus GUSWAVE_GetNextVOCBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ unsigned char *ptr; ++ int blocktype; ++ int lastblocktype; ++ unsigned long blocklength; ++ unsigned long samplespeed; ++ unsigned int tc; ++ int packtype; ++ int voicemode; ++ int done; ++ unsigned BitsPerSample; ++ unsigned Channels; ++ unsigned Format; ++ ++ if ( voice->BlockLength > 0 ) ++ { ++ voice->sound += MAX_BLOCK_LENGTH; ++ voice->length = min( voice->BlockLength, MAX_BLOCK_LENGTH ); ++ voice->BlockLength -= voice->length; ++ return( KeepPlaying ); ++ } ++ ++ ptr = ( unsigned char * )voice->NextBlock; ++ ++ voice->Playing = TRUE; ++ ++ voicemode = 0; ++ lastblocktype = 0; ++ packtype = 0; ++ ++ done = FALSE; ++ while( !done ) ++ { ++ // Stop playing if we get a NULL pointer ++ if ( ptr == NULL ) ++ { ++ voice->Playing = FALSE; ++ done = TRUE; ++ break; ++ } ++ ++ blocktype = ( int )*ptr; ++ blocklength = ( *( unsigned long * )( ptr + 1 ) ) & 0x00ffffff; ++ ptr += 4; ++ ++ switch( blocktype ) ++ { ++ case 0 : ++ // End of data ++ voice->Playing = FALSE; ++ done = TRUE; ++ break; ++ ++ case 1 : ++ // Sound data block ++ voice->bits = 8; ++ if ( lastblocktype != 8 ) ++ { ++ tc = ( unsigned int )*ptr << 8; ++ packtype = *( ptr + 1 ); ++ } ++ ++ ptr += 2; ++ blocklength -= 2; ++ ++ samplespeed = 256000000L / ( 65536 - tc ); ++ ++ // Skip packed or stereo data ++ if ( ( packtype != 0 ) || ( voicemode != 0 ) ) ++ { ++ ptr += blocklength; ++ } ++ else ++ { ++ done = TRUE; ++ } ++ voicemode = 0; ++ break; ++ ++ case 2 : ++ // Sound continuation block ++ samplespeed = voice->SamplingRate; ++ done = TRUE; ++ break; ++ ++ case 3 : ++ // Silence ++ // Not implimented. ++ ptr += blocklength; ++ break; ++ ++ case 4 : ++ // Marker ++ // Not implimented. ++ ptr += blocklength; ++ break; ++ ++ case 5 : ++ // ASCII string ++ // Not implimented. ++ ptr += blocklength; ++ break; ++ ++ case 6 : ++ // Repeat begin ++ voice->LoopCount = *( unsigned short * )ptr; ++ ptr += blocklength; ++ voice->LoopStart = ptr; ++ break; ++ ++ case 7 : ++ // Repeat end ++ ptr += blocklength; ++ if ( lastblocktype == 6 ) ++ { ++ voice->LoopCount = 0; ++ } ++ else ++ { ++ if ( ( voice->LoopCount > 0 ) && ( voice->LoopStart != NULL ) ) ++ { ++ ptr = voice->LoopStart; ++ if ( voice->LoopCount < 0xffff ) ++ { ++ voice->LoopCount--; ++ if ( voice->LoopCount == 0 ) ++ { ++ voice->LoopStart = NULL; ++ } ++ } ++ } ++ } ++ break; ++ ++ case 8 : ++ // Extended block ++ voice->bits = 8; ++ tc = *( unsigned short * )ptr; ++ packtype = *( ptr + 2 ); ++ voicemode = *( ptr + 3 ); ++ ptr += blocklength; ++ break; ++ ++ case 9 : ++ // New sound data block ++ samplespeed = *( unsigned long * )ptr; ++ BitsPerSample = ( unsigned )*( ptr + 4 ); ++ Channels = ( unsigned )*( ptr + 5 ); ++ Format = ( unsigned )*( unsigned short * )( ptr + 6 ); ++ ++ if ( ( BitsPerSample == 8 ) && ( Channels == 1 ) && ++ ( Format == VOC_8BIT ) ) ++ { ++ ptr += 12; ++ blocklength -= 12; ++ voice->bits = 8; ++ done = TRUE; ++ } ++ else if ( ( BitsPerSample == 16 ) && ( Channels == 1 ) && ++ ( Format == VOC_16BIT ) ) ++ { ++ ptr += 12; ++ blocklength -= 12; ++ voice->bits = 16; ++ done = TRUE; ++ } ++ else ++ { ++ ptr += blocklength; ++ } ++ break; ++ ++ default : ++ // Unknown data. Probably not a VOC file. ++ voice->Playing = FALSE; ++ done = TRUE; ++ break; ++ } ++ ++ lastblocktype = blocktype; ++ } ++ ++ if ( voice->Playing ) ++ { ++ voice->NextBlock = ptr + blocklength; ++ voice->sound = ptr; ++ ++ voice->SamplingRate = samplespeed; ++ voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) >> 16; ++ ++ voice->length = min( blocklength, MAX_BLOCK_LENGTH ); ++ voice->BlockLength = blocklength - voice->length; ++ ++ return( KeepPlaying ); ++ } ++ ++ return( SoundDone ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_GetNextWAVBlock ++ ++ Controls playback of demand fed data. ++---------------------------------------------------------------------*/ ++ ++playbackstatus GUSWAVE_GetNextWAVBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ if ( voice->BlockLength <= 0 ) ++ { ++ if ( voice->LoopStart == NULL ) ++ { ++ voice->Playing = FALSE; ++ return( SoundDone ); ++ } ++ ++ voice->BlockLength = voice->LoopSize; ++ voice->NextBlock = voice->LoopStart; ++ voice->length = 0; ++ } ++ ++ voice->sound = voice->NextBlock; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->NextBlock += voice->length; ++ voice->BlockLength -= voice->length; ++ ++ return( KeepPlaying ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_GetNextDemandFeedBlock ++ ++ Controls playback of demand fed data. ++---------------------------------------------------------------------*/ ++ ++playbackstatus GUSWAVE_GetNextDemandFeedBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ if ( voice->BlockLength > 0 ) ++ { ++ voice->sound += voice->length; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ ++ return( KeepPlaying ); ++ } ++ ++ if ( voice->DemandFeed == NULL ) ++ { ++ return( SoundDone ); ++ } ++ ++ ( voice->DemandFeed )( &voice->sound, &voice->BlockLength ); ++// voice->sound = GUS_Silence16; ++// voice->BlockLength = 256; ++ ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ ++ if ( ( voice->length > 0 ) && ( voice->sound != NULL ) ) ++ { ++ return( KeepPlaying ); ++ } ++ return( NoMoreData ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_Play ++ ++ Begins playback of digitized sound. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_Play ++ ( ++ VoiceNode *voice, ++ int angle, ++ int volume, ++ int channels ++ ) ++ ++ { ++ int VoiceNumber; ++ int type; ++ int pan; ++ unsigned flags; ++ int ( *servicefunction )( int reason, int voice, unsigned char **buf, unsigned long *size ); ++ ++ type = 0; ++ if ( channels != 1 ) ++ { ++ type |= TYPE_STEREO; ++ } ++ ++ if ( voice->bits == 8 ) ++ { ++ type |= TYPE_8BIT; ++ type |= TYPE_INVERT_MSB; ++ } ++ ++ voice->GF1voice = -1; ++ ++ angle &= 31; ++ pan = GUSWAVE_PanTable[ angle ]; ++ if ( GUSWAVE_SwapLeftRight ) ++ { ++ pan = 15 - pan; ++ } ++ ++ voice->Pan = pan; ++ ++ volume = max( 0, volume ); ++ volume = min( 255, volume ); ++ voice->Volume = volume; ++ ++ if ( !GUS_Debug ) ++ { ++ servicefunction = GUSWAVE_CallBack; ++ } ++ else ++ { ++ servicefunction = GUSWAVE_DebugCallBack; ++ } ++ ++ VoiceNumber = gf1_play_digital( 0, voice->sound, voice->length, ++ voice->mem, GUSWAVE_Volume - ( 255 - volume ) * 4, pan, ++ voice->RateScale, type, &GUS_HoldBuffer, servicefunction ); ++ ++ if ( VoiceNumber == NO_MORE_VOICES ) ++ { ++ if ( GUS_Debug ) ++ { ++ DB_printf( "Out of voices.\n" ); ++ } ++ ++ flags = DisableInterrupts(); ++ LL_AddToTail( VoiceNode, &VoicePool, voice ); ++ RestoreInterrupts( flags ); ++ ++ GUSWAVE_SetErrorCode( GUSWAVE_NoVoices ); ++ return( GUSWAVE_Warning ); ++ } ++ ++ flags = DisableInterrupts(); ++ voice->GF1voice = VoiceNumber; ++ voice->Active = TRUE; ++ LL_AddToTail( VoiceNode, &VoiceList, voice ); ++ VoiceStatus[ VoiceNumber ].playing = TRUE; ++ VoiceStatus[ VoiceNumber ].Voice = voice; ++ ++ if ( GUS_Debug ) ++ { ++ DB_printf( "GUS voice %d playing\n", VoiceNumber ); ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ return( voice->handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_PlayVOC ++ ++ Begins playback of digitized sound. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_PlayVOC ++ ( ++ char *sample, ++ int pitchoffset, ++ int angle, ++ int volume, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int handle; ++ int status; ++ playbackstatus soundstatus; ++ VoiceNode *voice; ++ unsigned flags; ++ ++ // Make sure it's a valid VOC file. ++ status = strncmp( sample, "Creative Voice File", 19 ); ++ if ( status != 0 ) ++ { ++ // Tell multivoc that we had a bad VOC file ++ MV_ErrorCode = MV_InvalidVOCFile; ++ ++ GUSWAVE_SetErrorCode( GUSWAVE_InvalidVOCFile ); ++ return( GUSWAVE_Error ); ++ } ++ ++ // Request a voice from the voice pool ++ voice = GUSWAVE_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ if ( GUS_Debug ) ++ { ++ DB_printf( "No more voices. Skipping sound.\n" ); ++ } ++ GUSWAVE_SetErrorCode( GUSWAVE_NoVoices ); ++ return( GUSWAVE_Warning ); ++ } ++ ++ voice->NextBlock = sample + *( unsigned short int * )( sample + 0x14 ); ++ voice->LoopStart = NULL; ++ voice->LoopCount = 0; ++ voice->BlockLength = 0; ++ voice->PitchScale = PITCH_GetScale( pitchoffset ); ++ voice->wavetype = VOC; ++ voice->bits = 8; ++ voice->GetSound = GUSWAVE_GetNextVOCBlock; ++ voice->length = 0; ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ ++ soundstatus = GUSWAVE_GetNextVOCBlock( voice ); ++ if ( soundstatus == SoundDone ) ++ { ++ flags = DisableInterrupts(); ++ LL_AddToTail( VoiceNode, &VoicePool, voice ); ++ RestoreInterrupts( flags ); ++ ++ if ( GUS_Debug ) ++ { ++ DB_printf( "Voice ended before playback.\n" ); ++ } ++ ++ // Tell multivoc that we had a bad VOC file ++ MV_ErrorCode = MV_InvalidVOCFile; ++ ++ GUSWAVE_SetErrorCode( GUSWAVE_InvalidVOCFile ); ++ return( GUSWAVE_Error ); ++ } ++ ++ handle = GUSWAVE_Play( voice, angle, volume, 1 ); ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_PlayWAV ++ ++ Begins playback of digitized sound. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_PlayWAV ++ ( ++ char *sample, ++ int pitchoffset, ++ int angle, ++ int volume, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ VoiceNode *voice; ++ int handle; ++ int channels; ++ int bits; ++ int length; ++ riff_header *riff; ++ format_header *format; ++ data_header *data; ++ ++ riff = ( riff_header * )sample; ++ ++ if ( ( strncmp( riff->RIFF, "RIFF", 4 ) != 0 ) || ++ ( strncmp( riff->WAVE, "WAVE", 4 ) != 0 ) || ++ ( strncmp( riff->fmt, "fmt ", 4) != 0 ) ) ++ { ++ GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile ); ++ return( GUSWAVE_Error ); ++ } ++ ++ format = ( format_header * )( riff + 1 ); ++ data = ( data_header * )( ( ( char * )format ) + riff->format_size ); ++ ++ if ( format->wFormatTag != 1 ) ++ { ++ GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile ); ++ return( GUSWAVE_Error ); ++ } ++ ++ channels = format->nChannels; ++ if ( ( channels != 1 ) && ( channels != 2 ) ) ++ { ++ GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile ); ++ return( GUSWAVE_Error ); ++ } ++ ++ bits = format->nBitsPerSample; ++ if ( ( bits != 8 ) && ( bits != 16 ) ) ++ { ++ GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile ); ++ return( GUSWAVE_Error ); ++ } ++ ++ if ( strncmp( data->DATA, "data", 4 ) != 0 ) ++ { ++ GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile ); ++ return( GUSWAVE_Error ); ++ } ++ ++ // Request a voice from the voice pool ++ voice = GUSWAVE_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ if ( GUS_Debug ) ++ { ++ DB_printf( "No more voices. Skipping sound.\n" ); ++ } ++ GUSWAVE_SetErrorCode( GUSWAVE_NoVoices ); ++ return( GUSWAVE_Warning ); ++ } ++ ++ voice->wavetype = WAV; ++ voice->bits = bits; ++ voice->GetSound = GUSWAVE_GetNextWAVBlock; ++ ++ length = data->size; ++ ++ voice->Playing = TRUE; ++ voice->DemandFeed = NULL; ++ voice->LoopStart = NULL; ++ voice->LoopCount = 0; ++ voice->length = min( length, 0x8000 ); ++ voice->BlockLength = length - voice->length;// min( loopend + 1, data->size ); ++ voice->sound = ( char * )( data + 1 ); ++ voice->NextBlock = voice->sound + voice->length; ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ voice->LoopStart = NULL;// voice->NextBlock + loopstart; ++ voice->LoopEnd = NULL;//voice->NextBlock + min( loopend, data->size - 1 ); ++ voice->LoopSize = 0;//( voice->LoopEnd - voice->LoopStart ) + 1; ++ voice->PitchScale = PITCH_GetScale( pitchoffset ); ++ voice->SamplingRate = format->nSamplesPerSec; ++ voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) >> 16; ++ ++ handle = GUSWAVE_Play( voice, angle, volume, channels ); ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_StartDemandFeedPlayback ++ ++ Begins playback of digitized sound. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_StartDemandFeedPlayback ++ ( ++ void ( *function )( char **ptr, unsigned long *length ), ++ int channels, ++ int bits, ++ int rate, ++ int pitchoffset, ++ int angle, ++ int volume, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ VoiceNode *voice; ++ int handle; ++ ++ // Request a voice from the voice pool ++ voice = GUSWAVE_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ if ( GUS_Debug ) ++ { ++ DB_printf( "No more voices. Skipping sound.\n" ); ++ } ++ GUSWAVE_SetErrorCode( GUSWAVE_NoVoices ); ++ return( GUSWAVE_Warning ); ++ } ++ ++ voice->wavetype = DemandFeed; ++ voice->bits = bits; ++ voice->GetSound = GUSWAVE_GetNextDemandFeedBlock; ++ voice->Playing = TRUE; ++ voice->DemandFeed = function; ++ voice->LoopStart = NULL; ++ voice->LoopCount = 0; ++ voice->BlockLength = 0; ++ voice->length = 256; ++ voice->sound = ( bits == 8 ) ? GUS_Silence8 : ( char * )GUS_Silence16; ++ voice->NextBlock = NULL; ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ voice->PitchScale = PITCH_GetScale( pitchoffset ); ++ voice->SamplingRate = rate; ++ voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) >> 16; ++ ++ handle = GUSWAVE_Play( voice, angle, volume, channels ); ++ ++ return( handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_SetReverseStereo ++ ++ Set the orientation of the left and right channels. ++---------------------------------------------------------------------*/ ++ ++void GUSWAVE_SetReverseStereo ++ ( ++ int setting ++ ) ++ ++ { ++ GUSWAVE_SwapLeftRight = setting; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_GetReverseStereo ++ ++ Returns the orientation of the left and right channels. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_GetReverseStereo ++ ( ++ void ++ ) ++ ++ { ++ return( GUSWAVE_SwapLeftRight ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_InitVoices ++ ++ Begins playback of digitized sound. ++---------------------------------------------------------------------*/ ++ ++static int GUSWAVE_InitVoices ++ ( ++ void ++ ) ++ ++ { ++ int i; ++ ++ for( i = 0; i < MAX_VOICES; i++ ) ++ { ++ VoiceStatus[ i ].playing = FALSE; ++ VoiceStatus[ i ].Voice = NULL; ++ } ++ ++ VoicePool.start = NULL; ++ VoicePool.end = NULL; ++ VoiceList.start = NULL; ++ VoiceList.end = NULL; ++ ++ for( i = 0; i < VOICES; i++ ) ++ { ++ GUSWAVE_Voices[ i ].num = -1; ++ GUSWAVE_Voices[ i ].Active = FALSE; ++ GUSWAVE_Voices[ i ].GF1voice = -1; ++ GUSWAVE_Voices[ i ].mem = NULL; ++ } ++ ++ for( i = 0; i < VOICES; i++ ) ++ { ++ GUSWAVE_Voices[ i ].num = i; ++ GUSWAVE_Voices[ i ].Active = FALSE; ++ GUSWAVE_Voices[ i ].GF1voice = 0; ++ ++ GUSWAVE_Voices[ i ].mem = gf1_malloc( GF1BSIZE ); ++ if ( GUSWAVE_Voices[ i ].mem == NULL ) ++ { ++ GUSWAVE_MaxVoices = i; ++ if ( i < 1 ) ++ { ++ if ( GUSMIDI_Installed ) ++ { ++ GUSWAVE_SetErrorCode( GUSWAVE_UltraNoMemMIDI ); ++ } ++ else ++ { ++ GUSWAVE_SetErrorCode( GUSWAVE_UltraNoMem ); ++ } ++ return( GUSWAVE_Error ); ++ } ++ ++ break; ++ } ++ ++ LL_AddToTail( VoiceNode, &VoicePool, &GUSWAVE_Voices[ i ] ); ++ } ++ ++ return( GUSWAVE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_SetCallBack ++ ++ Set the function to call when a voice stops. ++---------------------------------------------------------------------*/ ++ ++void GUSWAVE_SetCallBack ++ ( ++ void ( *function )( unsigned long ) ++ ) ++ ++ { ++ GUSWAVE_CallBackFunc = function; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: GUSWAVE_Init ++ ++ Initializes the Gravis Ultrasound for digitized sound playback. ++---------------------------------------------------------------------*/ ++ ++int GUSWAVE_Init ++ ( ++ int numvoices ++ ) ++ ++ { ++ int status; ++ ++ if ( GUSWAVE_Installed ) ++ { ++ GUSWAVE_Shutdown(); ++ } ++ ++ GUSWAVE_SetErrorCode( GUSWAVE_Ok ); ++ ++ status = GUS_Init(); ++ if ( status != GUS_Ok ) ++ { ++ GUSWAVE_SetErrorCode( GUSWAVE_GUSError ); ++ return( GUSWAVE_Error ); ++ } ++ ++ GUS_Debug = USER_CheckParameter( "DEBUGGUS" ); ++ ++ GUSWAVE_MaxVoices = min( numvoices, VOICES ); ++ GUSWAVE_MaxVoices = max( GUSWAVE_MaxVoices, 0 ); ++ ++ status = GUSWAVE_InitVoices(); ++ if ( status != GUSWAVE_Ok ) ++ { ++ GUS_Shutdown(); ++ return( status ); ++ } ++ ++ GUSWAVE_SetReverseStereo( FALSE ); ++ ++ GUSWAVE_CallBackFunc = NULL; ++ GUSWAVE_Installed = TRUE; ++ ++ return( GUSWAVE_Ok ); ++ } +diff -urN rott-1.0/rott/audiolib/guswave.h trunk/rott/audiolib/guswave.h +--- rott-1.0/rott/audiolib/guswave.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/guswave.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,75 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: GUSWAVE.H ++ ++ author: James R. Dose ++ date: March 23, 1994 ++ ++ Public header for for GUSWAVE.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __GUSWAVE_H ++#define __GUSWAVE_H ++ ++#define GUSWAVE_MinVoiceHandle 1 ++ ++enum GUSWAVE_Errors ++ { ++ GUSWAVE_Warning = -2, ++ GUSWAVE_Error = -1, ++ GUSWAVE_Ok = 0, ++ GUSWAVE_GUSError, ++ GUSWAVE_NotInstalled, ++ GUSWAVE_NoVoices, ++ GUSWAVE_UltraNoMem, ++ GUSWAVE_UltraNoMemMIDI, ++ GUSWAVE_VoiceNotFound, ++ GUSWAVE_InvalidVOCFile, ++ GUSWAVE_InvalidWAVFile ++ }; ++ ++char *GUSWAVE_ErrorString( int ErrorNumber ); ++int GUSWAVE_VoicePlaying( int handle ); ++int GUSWAVE_VoicesPlaying( void ); ++int GUSWAVE_Kill( int handle ); ++int GUSWAVE_KillAllVoices( void ); ++int GUSWAVE_SetPitch( int handle, int pitchoffset ); ++int GUSWAVE_SetPan3D( int handle, int angle, int distance ); ++void GUSWAVE_SetVolume( int volume ); ++int GUSWAVE_GetVolume( void ); ++int GUSWAVE_VoiceAvailable( int priority ); ++int GUSWAVE_PlayVOC( char *sample, int pitchoffset, int angle, int volume, ++ int priority, unsigned long callbackval ); ++int GUSWAVE_PlayWAV( char *sample, int pitchoffset, int angle, int volume, ++ int priority, unsigned long callbackval ); ++int GUSWAVE_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ), ++ int channels, int bits, int rate, int pitchoffset, int angle, ++ int volume, int priority, unsigned long callbackval ); ++void GUSWAVE_SetCallBack( void ( *function )( unsigned long ) ); ++void GUSWAVE_SetReverseStereo( int setting ); ++int GUSWAVE_GetReverseStereo( void ); ++int GUSWAVE_Init( int numvoices ); ++void GUSWAVE_Shutdown( void ); ++#pragma aux GUSWAVE_Shutdown frame; ++ ++#endif +diff -urN rott-1.0/rott/audiolib/interrup.h trunk/rott/audiolib/interrup.h +--- rott-1.0/rott/audiolib/interrup.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/interrup.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,50 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: INTERRUP.H ++ ++ author: James R. Dose ++ date: March 31, 1994 ++ ++ Inline functions for disabling and restoring the interrupt flag. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __INTERRUPT_H ++#define __INTERRUPT_H ++ ++unsigned long DisableInterrupts( void ); ++void RestoreInterrupts( unsigned long flags ); ++ ++#ifdef PLAT_DOS ++#pragma aux DisableInterrupts = \ ++ "pushfd", \ ++ "pop eax", \ ++ "cli" \ ++ modify [ eax ]; ++ ++#pragma aux RestoreInterrupts = \ ++ "push eax", \ ++ "popfd" \ ++ parm [ eax ]; ++#endif ++ ++#endif +diff -urN rott-1.0/rott/audiolib/irq.c trunk/rott/audiolib/irq.c +--- rott-1.0/rott/audiolib/irq.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/irq.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,325 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: IRQ.C ++ ++ author: James R. Dose ++ date: August 26, 1994 ++ ++ Low level routines to set and restore IRQ's through DPMI. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include "irq.h" ++ ++#define D32RealSeg(P) ( ( ( ( unsigned long )( P ) ) >> 4 ) & 0xFFFF ) ++#define D32RealOff(P) ( ( ( unsigned long )( P ) ) & 0xF ) ++ ++typedef struct ++ { ++ unsigned long drdi; ++ unsigned long drsi; ++ unsigned long drbp; ++ unsigned long drxx; ++ unsigned long drbx; ++ unsigned long drdx; ++ unsigned long drcx; ++ unsigned long drax; ++ ++ unsigned short drflags; ++ unsigned short dres; ++ unsigned short drds; ++ unsigned short drfs; ++ unsigned short drgs; ++ unsigned short drip; ++ unsigned short drcs; ++ unsigned short drsp; ++ unsigned short drss; ++ } DPMI_REGS; ++ ++static DPMI_REGS rmregs = { 0 }; ++static void ( __interrupt __far *IRQ_Callback )( void ) = NULL; ++ ++static char *IRQ_RealModeCode = NULL; ++ ++static unsigned short IRQ_CallBackSegment; ++static unsigned short IRQ_CallBackOffset; ++static unsigned short IRQ_RealModeSegment; ++static unsigned short IRQ_RealModeOffset; ++static unsigned long IRQ_ProtectedModeOffset; ++static unsigned short IRQ_ProtectedModeSelector; ++ ++static union REGS Regs; ++static struct SREGS SegRegs; ++ ++static void *D32DosMemAlloc ++ ( ++ unsigned long size ++ ) ++ ++ { ++ // DPMI allocate DOS memory ++ Regs.x.eax = 0x0100; ++ ++ // Number of paragraphs requested ++ Regs.x.ebx = ( size + 15 ) >> 4; ++ ++ int386( 0x31, &Regs, &Regs ); ++ ++ if ( Regs.x.cflag != 0 ) ++ { ++ // Failed ++ return ( ( unsigned long )0 ); ++ } ++ ++ return( ( void * )( ( Regs.x.eax & 0xFFFF ) << 4 ) ); ++ } ++ ++// Intermediary function: DPMI calls this, making it ++// easier to write in C ++// handle 16-bit incoming stack ++ ++void fixebp ++ ( ++ void ++ ); ++ ++#pragma aux fixebp = \ ++ "mov bx, ss" \ ++ "lar ebx, ebx" \ ++ "bt ebx, 22" \ ++ "jc bigstk" \ ++ "movzx esp, sp" \ ++ "mov ebp, esp" \ ++ "bigstk:" \ ++modify exact [ ebx ]; ++ ++#pragma aux rmcallback parm []; ++ ++void rmcallback ++ ( ++ unsigned short _far *stkp ++ ) ++ ++ { ++ // "Pop" the real mode return frame so we ++ // can resume where we left off ++ rmregs.drip = *stkp++; ++ rmregs.drcs = *stkp++; ++ ++ rmregs.drsp = FP_OFF(stkp); ++ ++ // Call protected-mode handler ++ IRQ_Callback(); ++ } ++ ++static void _interrupt _cdecl callback_x ++ ( ++ // regs pushed in this order by prologue ++ ++ int rgs, ++ int rfs, ++ int res, ++ int rds, ++ int rdi, ++ int rsi, ++ int rbp, ++ int rsp, ++ int rbx, ++ int rdx, ++ int rcx, ++ int rax ++ ) ++ ++ { ++// unsigned short _far *stkp; ++// return; ++ ++ fixebp(); ++ rmcallback (MK_FP(rds, rsi)); ++ } ++ ++/* ++static void _interrupt _cdecl callback_x ++ ( ++ // regs pushed in this order by prologue ++ ++ int rgs, ++ int rfs, ++ int res, ++ int rds, ++ int rdi, ++ int rsi, ++ int rbp, ++ int rsp, ++ int rbx, ++ int rdx, ++ int rcx, ++ int rax ++ ) ++ ++ { ++ unsigned short _far *stkp; ++ ++ fixebp(); ++ stkp = MK_FP(rds, rsi); ++ ++ // "Pop" the real mode return frame so we ++ // can resume where we left off ++ rmregs.drip = *stkp++; ++ rmregs.drcs = *stkp++; ++ ++ rmregs.drsp = FP_OFF(stkp); ++ ++ // Call protected-mode handler ++ IRQ_Callback(); ++ } ++*/ ++ ++ ++int IRQ_SetVector ++ ( ++ int vector, ++ void ( __interrupt __far *function )( void ) ++ ) ++ ++ { ++ void far *fp; ++ ++ IRQ_Callback = function; ++ ++ // Save the starting real-mode and protected-mode handler addresses ++ ++ // DPMI get protected mode vector */ ++ Regs.w.ax = 0x0204; ++ Regs.w.bx = vector; ++ int386( 0x31, &Regs, &Regs ); ++ IRQ_ProtectedModeSelector = Regs.w.cx; ++ IRQ_ProtectedModeOffset = Regs.x.edx; ++ ++ // DPMI get real mode vector ++ Regs.w.ax = 0x0200; ++ Regs.w.bx = vector; ++ int386( 0x31, &Regs, &Regs ); ++ IRQ_RealModeSegment = Regs.w.cx; ++ IRQ_RealModeOffset = Regs.w.dx; ++ ++ // Set up callback ++ // DPMI allocate real mode callback ++ Regs.w.ax = 0x0303; ++ fp = ( void far * )callback_x; ++ SegRegs.ds = FP_SEG( fp ); ++ Regs.x.esi = FP_OFF( fp ); ++ fp = ( void _far * )&rmregs; ++ SegRegs.es = FP_SEG( fp ); ++ Regs.x.edi = FP_OFF( fp ); ++ int386x( 0x31, &Regs, &Regs, &SegRegs ); ++ ++ IRQ_CallBackSegment = Regs.w.cx; ++ IRQ_CallBackOffset = Regs.w.dx; ++ ++ if ( Regs.x.cflag != 0 ) ++ { ++ return( IRQ_Error ); ++ } ++ ++ if ( IRQ_RealModeCode == NULL ) ++ { ++ // Allocate 6 bytes of low memory for real mode interrupt handler ++ IRQ_RealModeCode = D32DosMemAlloc( 6 ); ++ if ( IRQ_RealModeCode == NULL ) ++ { ++ // Free callback ++ Regs.w.ax = 0x304; ++ Regs.w.cx = IRQ_CallBackSegment; ++ Regs.w.dx = IRQ_CallBackOffset; ++ int386x( 0x31, &Regs, &Regs, &SegRegs ); ++ ++ return( IRQ_Error ); ++ } ++ } ++ ++ // Poke code (to call callback) into real mode handler ++ ++ // CALL FAR PTR (callback) ++ IRQ_RealModeCode[ 0 ] = '\x9A'; ++ *( ( unsigned short * )&IRQ_RealModeCode[ 1 ] ) = IRQ_CallBackOffset; ++ *( ( unsigned short * )&IRQ_RealModeCode[ 3 ] ) = IRQ_CallBackSegment; ++ ++ // IRET ++ IRQ_RealModeCode[ 5 ] = '\xCF'; ++ ++ // Install protected mode handler ++ // DPMI set protected mode vector ++ Regs.w.ax = 0x0205; ++ Regs.w.bx = vector; ++ fp = function; ++ ++ Regs.w.cx = FP_SEG( fp ); ++ Regs.x.edx = FP_OFF( fp ); ++ int386( 0x31, &Regs, &Regs ); ++ ++ // Install callback address as real mode handler ++ // DPMI set real mode vector ++ Regs.w.ax = 0x0201; ++ Regs.w.bx = vector; ++ Regs.w.cx = D32RealSeg( IRQ_RealModeCode ); ++ Regs.w.dx = D32RealOff( IRQ_RealModeCode ); ++ int386( 0x31, &Regs, &Regs ); ++ ++ return( IRQ_Ok ); ++ } ++ ++int IRQ_RestoreVector ++ ( ++ int vector ++ ) ++ ++ { ++ // Restore original interrupt handlers ++ // DPMI set real mode vector ++ Regs.w.ax = 0x0201; ++ Regs.w.bx = vector; ++ Regs.w.cx = IRQ_RealModeSegment; ++ Regs.w.dx = IRQ_RealModeOffset; ++ int386( 0x31, &Regs, &Regs ); ++ ++ Regs.w.ax = 0x0205; ++ Regs.w.bx = vector; ++ Regs.w.cx = IRQ_ProtectedModeSelector; ++ Regs.x.edx = IRQ_ProtectedModeOffset; ++ int386( 0x31, &Regs, &Regs ); ++ ++ // Free callback ++ Regs.w.ax = 0x304; ++ Regs.w.cx = IRQ_CallBackSegment; ++ Regs.w.dx = IRQ_CallBackOffset; ++ int386x( 0x31, &Regs, &Regs, &SegRegs ); ++ ++ if ( Regs.x.cflag ) ++ { ++ return( IRQ_Error ); ++ } ++ ++ return( IRQ_Ok ); ++ } +diff -urN rott-1.0/rott/audiolib/irq.h trunk/rott/audiolib/irq.h +--- rott-1.0/rott/audiolib/irq.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/irq.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,54 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: IRQ.H ++ ++ author: James R. Dose ++ date: August 8, 1994 ++ ++ Public header for IRQ.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __IRQ_H ++#define __IRQ_H ++ ++enum IRQ_ERRORS ++ { ++ IRQ_Warning = -2, ++ IRQ_Error = -1, ++ IRQ_Ok = 0, ++ }; ++ ++#define VALID_IRQ( irq ) ( ( ( irq ) >= 0 ) && ( ( irq ) <= 15 ) ) ++ ++int IRQ_SetVector ++ ( ++ int vector, ++ void ( __interrupt *function )( void ) ++ ); ++int IRQ_RestoreVector ++ ( ++ int vector ++ ); ++ ++ ++#endif +diff -urN rott-1.0/rott/audiolib/leetimbr.c trunk/rott/audiolib/leetimbr.c +--- rott-1.0/rott/audiolib/leetimbr.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/leetimbr.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,290 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++typedef struct ++ { ++ unsigned char SAVEK[ 2 ]; ++ unsigned char Level[ 2 ]; ++ unsigned char Env1[ 2 ]; ++ unsigned char Env2[ 2 ]; ++ unsigned char Wave[ 2 ]; ++ unsigned char Feedback; ++ signed char Transpose; ++ signed char Velocity; ++ } TIMBRE; ++ ++TIMBRE ADLIB_TimbreBank[ 256 ] = ++ { ++ { { 33, 49 }, { 79, 0 }, { 242, 210 }, { 82, 115 }, { 0, 0 }, 6, 0 }, ++ { { 19, 17 }, { 198, 10 }, { 242, 241 }, { 245, 245 }, { 1, 0 }, 0, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 3, 18 }, { 48, 16 }, { 246, 242 }, { 25, 244 }, { 0, 0 }, 15, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 24, 129 }, { 98, 0 }, { 243, 242 }, { 230, 246 }, { 0, 0 }, 0, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 23, 2 }, { 79, 16 }, { 242, 242 }, { 96, 114 }, { 0, 0 }, 8, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 178, 176 }, { 192, 134 }, { 159, 148 }, { 6, 15 }, { 1, 1 }, 9, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 178, 176 }, { 192, 128 }, { 159, 148 }, { 6, 15 }, { 1, 1 }, 9, 0 }, ++ { { 130, 128 }, { 192, 134 }, { 145, 145 }, { 246, 246 }, { 1, 1 }, 9, 0 }, ++ { { 36, 49 }, { 79, 27 }, { 242, 82 }, { 11, 11 }, { 0, 0 }, 14, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 35, 33 }, { 72, 0 }, { 149, 132 }, { 25, 25 }, { 1, 0 }, 8, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 19, 49 }, { 150, 128 }, { 254, 242 }, { 33, 148 }, { 0, 0 }, 10, 0 }, ++ { { 1, 17 }, { 77, 0 }, { 242, 245 }, { 83, 116 }, { 1, 1 }, 8, 0 }, ++ { { 33, 40 }, { 1, 9 }, { 148, 148 }, { 25, 9 }, { 0, 0 }, 6, 0 }, ++ { { 33, 40 }, { 1, 19 }, { 148, 148 }, { 25, 9 }, { 0, 0 }, 6, 0 }, ++ { { 36, 194 }, { 138, 3 }, { 250, 145 }, { 111, 248 }, { 0, 0 }, 8, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 33 }, { 26, 0 }, { 241, 246 }, { 207, 72 }, { 0, 0 }, 10, 0 }, ++ { { 1, 34 }, { 29, 0 }, { 183, 196 }, { 34, 55 }, { 0, 0 }, 14, 0 }, ++ { { 49, 34 }, { 30, 0 }, { 242, 241 }, { 239, 104 }, { 0, 0 }, 14, 0 }, ++ { { 49, 34 }, { 30, 0 }, { 242, 245 }, { 239, 120 }, { 0, 0 }, 14, 0 }, ++ { { 49, 34 }, { 30, 0 }, { 242, 245 }, { 239, 120 }, { 0, 0 }, 14, 0 }, ++ { { 17, 49 }, { 5, 9 }, { 249, 241 }, { 37, 52 }, { 0, 0 }, 10, 0 }, ++ { { 17, 49 }, { 5, 0 }, { 249, 241 }, { 37, 52 }, { 0, 0 }, 10, 0 }, ++ { { 49, 114 }, { 138, 0 }, { 213, 97 }, { 25, 27 }, { 0, 0 }, 12, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 17, 17 }, { 150, 128 }, { 165, 245 }, { 85, 179 }, { 2, 1 }, 12, 0 }, ++ { { 1, 17 }, { 156, 128 }, { 128, 240 }, { 5, 6 }, { 0, 0 }, 0, 0 }, ++ { { 17, 17 }, { 150, 128 }, { 165, 245 }, { 85, 179 }, { 2, 1 }, 12, 0 }, ++ { { 2, 1 }, { 153, 128 }, { 245, 246 }, { 85, 83 }, { 0, 0 }, 0, 0 }, ++ { { 192, 0 }, { 13, 0 }, { 165, 212 }, { 67, 35 }, { 2, 1 }, 0, 0 }, ++ { { 33, 32 }, { 88, 0 }, { 194, 97 }, { 227, 22 }, { 1, 3 }, 0, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 34 }, { 22, 0 }, { 176, 179 }, { 129, 44 }, { 0, 1 }, 12, 0 }, ++ { { 49, 114 }, { 91, 131 }, { 244, 138 }, { 21, 5 }, { 0, 0 }, 0, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 33 }, { 29, 0 }, { 113, 129 }, { 174, 158 }, { 0, 0 }, 14, 0 }, ++ { { 49, 97 }, { 28, 128 }, { 65, 146 }, { 11, 59 }, { 0, 0 }, 14, 0 }, ++ { { 49, 241 }, { 28, 0 }, { 65, 146 }, { 11, 27 }, { 0, 0 }, 10, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 33 }, { 155, 0 }, { 97, 127 }, { 106, 10 }, { 0, 0 }, 2, 0 }, ++ { { 225, 226 }, { 21, 3 }, { 113, 129 }, { 174, 158 }, { 0, 0 }, 14, 0 }, ++ { { 33, 33 }, { 29, 0 }, { 113, 129 }, { 174, 158 }, { 0, 0 }, 14, 0 }, ++ { { 33, 33 }, { 77, 0 }, { 84, 166 }, { 60, 28 }, { 0, 0 }, 8, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 50 }, { 79, 0 }, { 113, 82 }, { 83, 76 }, { 0, 0 }, 10, 0 }, ++ { { 33, 50 }, { 79, 0 }, { 113, 82 }, { 83, 76 }, { 0, 0 }, 10, 0 }, ++ { { 32, 49 }, { 78, 0 }, { 113, 82 }, { 104, 94 }, { 0, 0 }, 10, 0 }, ++ { { 33, 33 }, { 75, 0 }, { 170, 143 }, { 22, 10 }, { 1, 0 }, 8, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 50, 97 }, { 154, 130 }, { 81, 162 }, { 27, 59 }, { 0, 0 }, 12, 0 }, ++ { { 50, 33 }, { 192, 0 }, { 155, 114 }, { 33, 7 }, { 0, 0 }, 4, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 162 }, { 131, 141 }, { 116, 101 }, { 23, 23 }, { 0, 0 }, 7, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 225, 98 }, { 236, 0 }, { 110, 101 }, { 143, 42 }, { 0, 0 }, 14, 0 }, ++ { { 50, 33 }, { 144, 0 }, { 155, 114 }, { 33, 23 }, { 0, 0 }, 4, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 245, 242 }, { 154, 128 }, { 12, 96 }, { 199, 165 }, { 0, 0 }, 13, 0 }, ++ { { 98, 161 }, { 147, 0 }, { 119, 118 }, { 7, 7 }, { 0, 0 }, 11, 0 }, ++ { { 34, 33 }, { 89, 8 }, { 255, 255 }, { 3, 15 }, { 2, 0 }, 0, 0 }, ++ { { 33, 33 }, { 29, 0 }, { 113, 129 }, { 14, 14 }, { 0, 0 }, 14, 0 }, ++ { { 34, 33 }, { 70, 128 }, { 134, 100 }, { 85, 24 }, { 0, 0 }, 0, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 113, 114 }, { 93, 0 }, { 84, 106 }, { 1, 3 }, { 0, 0 }, 0, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 0, 17 }, { 13, 128 }, { 241, 80 }, { 255, 255 }, { 0, 0 }, 6, 0 }, ++ { { 33, 97 }, { 137, 3 }, { 17, 66 }, { 51, 37 }, { 0, 0 }, 10, 0 }, ++ { { 0, 49 }, { 16, 128 }, { 17, 176 }, { 239, 15 }, { 0, 0 }, 10, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 164, 97 }, { 76, 16 }, { 243, 129 }, { 115, 35 }, { 1, 0 }, 4, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 1, 1 }, { 0, 0 }, { 255, 255 }, { 7, 7 }, { 0, 0 }, 7, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 1, 221 }, { 0, 0 }, { 246, 31 }, { 0, 6 }, { 2, 3 }, 12, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 36 }, ++ { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 36 }, ++ { { 3, 15 }, { 0, 0 }, { 251, 245 }, { 43, 11 }, { 2, 0 }, 15, 36 }, ++ { { 33, 0 }, { 128, 0 }, { 255, 249 }, { 7, 7 }, { 0, 1 }, 14, 36 }, ++ { { 240, 229 }, { 192, 0 }, { 255, 251 }, { 255, 240 }, { 3, 0 }, 14, 48 }, ++ { { 33, 0 }, { 128, 0 }, { 255, 248 }, { 10, 25 }, { 0, 1 }, 14, 36 }, ++ { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 48 }, ++ { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 69 }, ++ { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 52 }, ++ { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 48 }, ++ { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 55 }, ++ { { 2, 5 }, { 3, 10 }, { 180, 151 }, { 4, 247 }, { 0, 0 }, 14, 57 }, ++ { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 58 }, ++ { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 60 }, ++ { { 1, 221 }, { 12, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 12, 62 }, ++ { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 63 }, ++ { { 12, 18 }, { 0, 0 }, { 246, 203 }, { 2, 67 }, { 0, 2 }, 10, 70 }, ++ { { 12, 18 }, { 0, 0 }, { 246, 203 }, { 2, 19 }, { 0, 2 }, 10, 70 }, ++ { { 14, 7 }, { 6, 68 }, { 248, 244 }, { 66, 228 }, { 3, 3 }, 14, 53 }, ++ { { 14, 0 }, { 64, 8 }, { 150, 183 }, { 79, 24 }, { 0, 2 }, 14, 48 }, ++ { { 1, 221 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 2, 3 }, 12, 84 }, ++ { { 2, 9 }, { 27, 0 }, { 245, 246 }, { 118, 214 }, { 2, 0 }, 4, 43 }, ++ { { 0, 223 }, { 9, 0 }, { 246, 147 }, { 0, 67 }, { 0, 2 }, 14, 56 }, ++ { { 128, 144 }, { 13, 0 }, { 248, 159 }, { 0, 4 }, { 2, 3 }, 14, 24 }, ++ { { 12, 18 }, { 0, 0 }, { 246, 203 }, { 2, 67 }, { 0, 2 }, 10, 65 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 48 }, ++ { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 51 }, ++ { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 54 }, ++ { { 2, 4 }, { 0, 0 }, { 250, 200 }, { 191, 151 }, { 0, 0 }, 11, 42 }, ++ { { 2, 4 }, { 0, 0 }, { 250, 200 }, { 191, 151 }, { 0, 0 }, 11, 39 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 64 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 128, 17 }, { 0, 0 }, { 255, 111 }, { 6, 22 }, { 3, 0 }, 14, 52 }, ++ { { 128, 17 }, { 0, 0 }, { 255, 79 }, { 6, 22 }, { 3, 0 }, 14, 52 }, ++ { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 60 }, ++ { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 66 }, ++ { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 59 }, ++ { { 65, 66 }, { 69, 0 }, { 252, 105 }, { 69, 5 }, { 0, 0 }, 0, 91 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 23, 2 }, { 79, 16 }, { 242, 242 }, { 96, 114 }, { 0, 0 }, 8, 109 }, ++ { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 64 }, ++ { { 133, 132 }, { 5, 64 }, { 249, 214 }, { 50, 165 }, { 3, 0 }, 14, 79 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, ++ { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 } ++ }; +diff -urN rott-1.0/rott/audiolib/linklist.h trunk/rott/audiolib/linklist.h +--- rott-1.0/rott/audiolib/linklist.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/linklist.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,118 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++#ifndef __linklist_h ++#define __linklist_h ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++#define NewNode(type) ((type*)SafeMalloc(sizeof(type))) ++ ++ ++#define LL_CreateNewLinkedList(rootnode,type,next,prev) \ ++ { \ ++ (rootnode) = NewNode(type); \ ++ (rootnode)->prev = (rootnode); \ ++ (rootnode)->next = (rootnode); \ ++ } ++ ++ ++ ++#define LL_AddNode(rootnode, newnode, next, prev) \ ++ { \ ++ (newnode)->next = (rootnode); \ ++ (newnode)->prev = (rootnode)->prev; \ ++ (rootnode)->prev->next = (newnode); \ ++ (rootnode)->prev = (newnode); \ ++ } ++ ++#define LL_TransferList(oldroot,newroot,next,prev) \ ++ { \ ++ if ((oldroot)->prev != (oldroot)) \ ++ { \ ++ (oldroot)->prev->next = (newroot); \ ++ (oldroot)->next->prev = (newroot)->prev; \ ++ (newroot)->prev->next = (oldroot)->next; \ ++ (newroot)->prev = (oldroot)->prev; \ ++ (oldroot)->next = (oldroot); \ ++ (oldroot)->prev = (oldroot); \ ++ } \ ++ } ++ ++#define LL_ReverseList(root,type,next,prev) \ ++ { \ ++ type *newend,*trav,*tprev; \ ++ \ ++ newend = (root)->next; \ ++ for(trav = (root)->prev; trav != newend; trav = tprev) \ ++ { \ ++ tprev = trav->prev; \ ++ LL_MoveNode(trav,newend,next,prev); \ ++ } \ ++ } ++ ++ ++#define LL_RemoveNode(node,next,prev) \ ++ { \ ++ (node)->prev->next = (node)->next; \ ++ (node)->next->prev = (node)->prev; \ ++ (node)->next = (node); \ ++ (node)->prev = (node); \ ++ } ++ ++ ++#define LL_SortedInsertion(rootnode,insertnode,next,prev,type,sortparm) \ ++ { \ ++ type *hoya; \ ++ \ ++ hoya = (rootnode)->next; \ ++ while((hoya != (rootnode)) && ((insertnode)->sortparm > hoya->sortparm)) \ ++ { \ ++ hoya = hoya->next; \ ++ } \ ++ LL_AddNode(hoya,(insertnode),next,prev); \ ++ } ++ ++#define LL_MoveNode(node,newroot,next,prev) \ ++ { \ ++ LL_RemoveNode((node),next,prev); \ ++ LL_AddNode((newroot),(node),next,prev); \ ++ } ++ ++#define LL_ListEmpty(list,next,prev) \ ++ ( \ ++ ((list)->next == (list)) && \ ++ ((list)->prev == (list)) \ ++ ) ++ ++#define LL_Free(list) SafeFree(list) ++#define LL_Reset(list,next,prev) (list)->next = (list)->prev = (list) ++#define LL_New LL_CreateNewLinkedList ++#define LL_Remove LL_RemoveNode ++#define LL_Add LL_AddNode ++#define LL_Empty LL_ListEmpty ++#define LL_Move LL_MoveNode ++ ++ ++#ifdef __cplusplus ++}; ++#endif ++#endif +diff -urN rott-1.0/rott/audiolib/ll_man.c trunk/rott/audiolib/ll_man.c +--- rott-1.0/rott/audiolib/ll_man.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/ll_man.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,173 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: LL_MAN.C ++ ++ author: James R. Dose ++ date: January 1, 1994 ++ ++ Linked list management routines. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#define LOCKMEMORY ++ ++#include ++#include "ll_man.h" ++ ++#ifdef LOCKMEMORY ++#include "dpmi.h" ++#endif ++ ++#define OFFSET( structure, offset ) \ ++ ( *( ( char ** )&( structure )[ offset ] ) ) ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define LL_LockStart LL_AddNode ++ ++ ++void LL_AddNode ++ ( ++ char *item, ++ char **head, ++ char **tail, ++ int next, ++ int prev ++ ) ++ ++ { ++ OFFSET( item, prev ) = NULL; ++ OFFSET( item, next ) = *head; ++ ++ if ( *head ) ++ { ++ OFFSET( *head, prev ) = item; ++ } ++ else ++ { ++ *tail = item; ++ } ++ ++ *head = item; ++ } ++ ++void LL_RemoveNode ++ ( ++ char *item, ++ char **head, ++ char **tail, ++ int next, ++ int prev ++ ) ++ ++ { ++ if ( OFFSET( item, prev ) == NULL ) ++ { ++ *head = OFFSET( item, next ); ++ } ++ else ++ { ++ OFFSET( OFFSET( item, prev ), next ) = OFFSET( item, next ); ++ } ++ ++ if ( OFFSET( item, next ) == NULL ) ++ { ++ *tail = OFFSET( item, prev ); ++ } ++ else ++ { ++ OFFSET( OFFSET( item, next ), prev ) = OFFSET( item, prev ); ++ } ++ ++ OFFSET( item, next ) = NULL; ++ OFFSET( item, prev ) = NULL; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: LL_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void LL_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: LL_UnlockMemory ++ ++ Unlocks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++void LL_UnlockMemory ++ ( ++ void ++ ) ++ ++ { ++#ifdef LOCKMEMORY ++ ++ DPMI_UnlockMemoryRegion( LL_LockStart, LL_LockEnd ); ++ ++#endif ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: LL_LockMemory ++ ++ Locks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++int LL_LockMemory ++ ( ++ void ++ ) ++ ++ { ++ ++#ifdef LOCKMEMORY ++ ++ int status; ++ ++ status = DPMI_LockMemoryRegion( LL_LockStart, LL_LockEnd ); ++ if ( status != DPMI_Ok ) ++ { ++ return( LL_Error ); ++ } ++ ++#endif ++ ++ return( LL_Ok ); ++ } +diff -urN rott-1.0/rott/audiolib/ll_man.h trunk/rott/audiolib/ll_man.h +--- rott-1.0/rott/audiolib/ll_man.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/ll_man.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,76 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: LL_MAN.H ++ ++ author: James R. Dose ++ date: February 4, 1994 ++ ++ Public header for LL_MAN.C. Linked list management routines. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __LL_MAN_H ++#define __LL_MAN_H ++ ++enum LL_Errors ++ { ++ LL_Warning = -2, ++ LL_Error = -1, ++ LL_Ok = 0 ++ }; ++ ++typedef struct list ++ { ++ void *start; ++ void *end; ++ } list; ++ ++void LL_AddNode( char *node, char **head, char **tail, int next, int prev ); ++void LL_RemoveNode( char *node, char **head, char **tail, int next, int prev ); ++void LL_UnlockMemory( void ); ++int LL_LockMemory( void ); ++ ++#define LL_AddToHead( type, listhead, node ) \ ++ LL_AddNode( ( char * )( node ), \ ++ ( char ** )&( ( listhead )->start ), \ ++ ( char ** )&( ( listhead )->end ), \ ++ ( int )&( ( type * ) 0 )->next, \ ++ ( int )&( ( type * ) 0 )->prev ) ++ ++#define LL_AddToTail( type, listhead, node ) \ ++ LL_AddNode( ( char * )( node ), \ ++ ( char ** )&( ( listhead )->end ), \ ++ ( char ** )&( ( listhead )->start ), \ ++ ( int )&( ( type * ) 0 )->prev, \ ++ ( int )&( ( type * ) 0 )->next ) ++ ++#define LL_Remove( type, listhead, node ) \ ++ LL_RemoveNode( ( char * )( node ), \ ++ ( char ** )&( ( listhead )->start ), \ ++ ( char ** )&( ( listhead )->end ), \ ++ ( int )&( ( type * ) 0 )->next, \ ++ ( int )&( ( type * ) 0 )->prev ) ++ ++#define LL_NextNode( node ) ( ( node )->next ) ++#define LL_PreviousNode( node ) ( ( node )->prev ) ++ ++#endif +diff -urN rott-1.0/rott/audiolib/midi.c trunk/rott/audiolib/midi.c +--- rott-1.0/rott/audiolib/midi.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/midi.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,2265 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: MIDI.C ++ ++ author: James R. Dose ++ date: May 25, 1994 ++ ++ Midi song file playback routines. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include "sndcards.h" ++#include "interrup.h" ++#include "dpmi.h" ++#include "standard.h" ++#include "task_man.h" ++#include "ll_man.h" ++#include "usrhooks.h" ++#include "music.h" ++#include "_midi.h" ++#include "midi.h" ++#include "debugio.h" ++ ++extern int MUSIC_SoundDevice; ++ ++static const int _MIDI_CommandLengths[ NUM_MIDI_CHANNELS ] = ++ { ++ 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 ++ }; ++ ++static int cdecl ( *_MIDI_RerouteFunctions[ NUM_MIDI_CHANNELS ] ) ++ ( ++ int event, ++ int c1, ++ int c2 ++ ) = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; ++ ++static track *_MIDI_TrackPtr = NULL; ++static int _MIDI_TrackMemSize; ++static int _MIDI_NumTracks; ++ ++static int _MIDI_SongActive = FALSE; ++static int _MIDI_SongLoaded = FALSE; ++static int _MIDI_Loop = FALSE; ++ ++static task *_MIDI_PlayRoutine = NULL; ++ ++static int _MIDI_Division; ++static int _MIDI_Tick = 0; ++static int _MIDI_Beat = 1; ++static int _MIDI_Measure = 1; ++static unsigned _MIDI_Time; ++static int _MIDI_BeatsPerMeasure; ++static int _MIDI_TicksPerBeat; ++static int _MIDI_TimeBase; ++static long _MIDI_FPSecondsPerTick; ++static unsigned _MIDI_TotalTime; ++static int _MIDI_TotalTicks; ++static int _MIDI_TotalBeats; ++static int _MIDI_TotalMeasures; ++ ++static unsigned long _MIDI_PositionInTicks; ++ ++static int _MIDI_Context; ++ ++static int _MIDI_ActiveTracks; ++static int _MIDI_TotalVolume = MIDI_MaxVolume; ++ ++static int _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ]; ++static int _MIDI_UserChannelVolume[ NUM_MIDI_CHANNELS ] = ++ { ++ 256, 256, 256, 256, 256, 256, 256, 256, ++ 256, 256, 256, 256, 256, 256, 256, 256 ++ }; ++ ++static midifuncs *_MIDI_Funcs = NULL; ++ ++static int Reset = FALSE; ++ ++int MIDI_Tempo = 120; ++ ++char MIDI_PatchMap[ 128 ]; ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define MIDI_LockStart _MIDI_ReadNumber ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_ReadNumber ++ ++ Reads a variable length number from a MIDI track. ++---------------------------------------------------------------------*/ ++ ++static long _MIDI_ReadNumber ++ ( ++ void *from, ++ size_t size ++ ) ++ ++ { ++ unsigned char *FromPtr; ++ long value; ++ ++ if ( size > 4 ) ++ { ++ size = 4; ++ } ++ ++ FromPtr = ( unsigned char * )from; ++ ++ value = 0; ++ while( size-- ) ++ { ++ value <<= 8; ++ value += *FromPtr++; ++ } ++ ++ return( value ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_ReadDelta ++ ++ Reads a variable length encoded delta delay time from the MIDI data. ++---------------------------------------------------------------------*/ ++ ++static long _MIDI_ReadDelta ++ ( ++ track *ptr ++ ) ++ ++ { ++ long value; ++ unsigned char c; ++ ++ GET_NEXT_EVENT( ptr, value ); ++ ++ if ( value & 0x80 ) ++ { ++ value &= 0x7f; ++ do ++ { ++ GET_NEXT_EVENT( ptr, c ); ++ value = ( value << 7 ) + ( c & 0x7f ); ++ } ++ while ( c & 0x80 ); ++ } ++ ++ return( value ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_ResetTracks ++ ++ Sets the track pointers to the beginning of the song. ++---------------------------------------------------------------------*/ ++ ++static void _MIDI_ResetTracks ++ ( ++ void ++ ) ++ ++ { ++ int i; ++ track *ptr; ++ ++ _MIDI_Tick = 0; ++ _MIDI_Beat = 1; ++ _MIDI_Measure = 1; ++ _MIDI_Time = 0; ++ _MIDI_BeatsPerMeasure = 4; ++ _MIDI_TicksPerBeat = _MIDI_Division; ++ _MIDI_TimeBase = 4; ++ ++ _MIDI_PositionInTicks = 0; ++ _MIDI_ActiveTracks = 0; ++ _MIDI_Context = 0; ++ ++ ptr = _MIDI_TrackPtr; ++ for( i = 0; i < _MIDI_NumTracks; i++ ) ++ { ++ ptr->pos = ptr->start; ++ ptr->delay = _MIDI_ReadDelta( ptr ); ++ ptr->active = ptr->EMIDI_IncludeTrack; ++ ptr->RunningStatus = 0; ++ ptr->currentcontext = 0; ++ ptr->context[ 0 ].loopstart = ptr->start; ++ ptr->context[ 0 ].loopcount = 0; ++ ++ if ( ptr->active ) ++ { ++ _MIDI_ActiveTracks++; ++ } ++ ++ ptr++; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_AdvanceTick ++ ++ Increment tick counters. ++---------------------------------------------------------------------*/ ++ ++static void _MIDI_AdvanceTick ++ ( ++ void ++ ) ++ ++ { ++ _MIDI_PositionInTicks++; ++ _MIDI_Time += _MIDI_FPSecondsPerTick; ++ ++ _MIDI_Tick++; ++ while( _MIDI_Tick > _MIDI_TicksPerBeat ) ++ { ++ _MIDI_Tick -= _MIDI_TicksPerBeat; ++ _MIDI_Beat++; ++ } ++ while( _MIDI_Beat > _MIDI_BeatsPerMeasure ) ++ { ++ _MIDI_Beat -= _MIDI_BeatsPerMeasure; ++ _MIDI_Measure++; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_SysEx ++ ++ Interpret SysEx Event. ++---------------------------------------------------------------------*/ ++ ++static void _MIDI_SysEx ++ ( ++ track *Track ++ ) ++ ++ { ++ int length; ++ ++ length = _MIDI_ReadDelta( Track ); ++ Track->pos += length; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_MetaEvent ++ ++ Interpret Meta Event. ++---------------------------------------------------------------------*/ ++ ++static void _MIDI_MetaEvent ++ ( ++ track *Track ++ ) ++ ++ { ++ int command; ++ int length; ++ int denominator; ++ long tempo; ++ ++ GET_NEXT_EVENT( Track, command ); ++ GET_NEXT_EVENT( Track, length ); ++ ++ switch( command ) ++ { ++ case MIDI_END_OF_TRACK : ++ Track->active = FALSE; ++ ++ _MIDI_ActiveTracks--; ++ break; ++ ++ case MIDI_TEMPO_CHANGE : ++ tempo = 60000000L / _MIDI_ReadNumber( Track->pos, 3 ); ++ MIDI_SetTempo( tempo ); ++ break; ++ ++ case MIDI_TIME_SIGNATURE : ++ if ( ( _MIDI_Tick > 0 ) || ( _MIDI_Beat > 1 ) ) ++ { ++ _MIDI_Measure++; ++ } ++ ++ _MIDI_Tick = 0; ++ _MIDI_Beat = 1; ++ ++ _MIDI_BeatsPerMeasure = (int)*Track->pos; ++ denominator = (int)*( Track->pos + 1 ); ++ _MIDI_TimeBase = 1; ++ while( denominator > 0 ) ++ { ++ _MIDI_TimeBase += _MIDI_TimeBase; ++ denominator--; ++ } ++ _MIDI_TicksPerBeat = ( _MIDI_Division * 4 ) / _MIDI_TimeBase; ++ break; ++ } ++ ++ Track->pos += length; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_InterpretControllerInfo ++ ++ Interprets the MIDI controller info. ++---------------------------------------------------------------------*/ ++ ++static int _MIDI_InterpretControllerInfo ++ ( ++ track *Track, ++ int TimeSet, ++ int channel, ++ int c1, ++ int c2 ++ ) ++ ++ { ++ track *trackptr; ++ int tracknum; ++ int loopcount; ++ ++ switch( c1 ) ++ { ++ case MIDI_MONO_MODE_ON : ++ Track->pos++; ++ break; ++ ++ case MIDI_VOLUME : ++ if ( !Track->EMIDI_VolumeChange ) ++ { ++ _MIDI_SetChannelVolume( channel, c2 ); ++ } ++ break; ++ ++ case EMIDI_INCLUDE_TRACK : ++ case EMIDI_EXCLUDE_TRACK : ++ break; ++ ++ case EMIDI_PROGRAM_CHANGE : ++ if ( Track->EMIDI_ProgramChange ) ++ { ++ _MIDI_Funcs->ProgramChange( channel, MIDI_PatchMap[ c2 & 0x7f ] ); ++ } ++ break; ++ ++ case EMIDI_VOLUME_CHANGE : ++ if ( Track->EMIDI_VolumeChange ) ++ { ++ _MIDI_SetChannelVolume( channel, c2 ); ++ } ++ break; ++ ++ case EMIDI_CONTEXT_START : ++ break; ++ ++ case EMIDI_CONTEXT_END : ++ if ( ( Track->currentcontext == _MIDI_Context ) || ++ ( _MIDI_Context < 0 ) || ++ ( Track->context[ _MIDI_Context ].pos == NULL ) ) ++ { ++ break; ++ } ++ ++ Track->currentcontext = _MIDI_Context; ++ Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart; ++ Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount; ++ Track->pos = Track->context[ _MIDI_Context ].pos; ++ Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus; ++ ++ if ( TimeSet ) ++ { ++ break; ++ } ++ ++ _MIDI_Time = Track->context[ _MIDI_Context ].time; ++ _MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick; ++ _MIDI_Tick = Track->context[ _MIDI_Context ].tick; ++ _MIDI_Beat = Track->context[ _MIDI_Context ].beat; ++ _MIDI_Measure = Track->context[ _MIDI_Context ].measure; ++ _MIDI_BeatsPerMeasure = Track->context[ _MIDI_Context ].BeatsPerMeasure; ++ _MIDI_TicksPerBeat = Track->context[ _MIDI_Context ].TicksPerBeat; ++ _MIDI_TimeBase = Track->context[ _MIDI_Context ].TimeBase; ++ TimeSet = TRUE; ++ break; ++ ++ case EMIDI_LOOP_START : ++ case EMIDI_SONG_LOOP_START : ++ if ( c2 == 0 ) ++ { ++ loopcount = EMIDI_INFINITE; ++ } ++ else ++ { ++ loopcount = c2; ++ } ++ ++ if ( c1 == EMIDI_SONG_LOOP_START ) ++ { ++ trackptr = _MIDI_TrackPtr; ++ tracknum = _MIDI_NumTracks; ++ } ++ else ++ { ++ trackptr = Track; ++ tracknum = 1; ++ } ++ ++ while( tracknum > 0 ) ++ { ++ trackptr->context[ 0 ].loopcount = loopcount; ++ trackptr->context[ 0 ].pos = trackptr->pos; ++ trackptr->context[ 0 ].loopstart = trackptr->pos; ++ trackptr->context[ 0 ].RunningStatus = trackptr->RunningStatus; ++ trackptr->context[ 0 ].active = trackptr->active; ++ trackptr->context[ 0 ].delay = trackptr->delay; ++ trackptr->context[ 0 ].time = _MIDI_Time; ++ trackptr->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick; ++ trackptr->context[ 0 ].tick = _MIDI_Tick; ++ trackptr->context[ 0 ].beat = _MIDI_Beat; ++ trackptr->context[ 0 ].measure = _MIDI_Measure; ++ trackptr->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure; ++ trackptr->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat; ++ trackptr->context[ 0 ].TimeBase = _MIDI_TimeBase; ++ trackptr++; ++ tracknum--; ++ } ++ break; ++ ++ case EMIDI_LOOP_END : ++ case EMIDI_SONG_LOOP_END : ++ if ( ( c2 != EMIDI_END_LOOP_VALUE ) || ++ ( Track->context[ 0 ].loopstart == NULL ) || ++ ( Track->context[ 0 ].loopcount == 0 ) ) ++ { ++ break; ++ } ++ ++ if ( c1 == EMIDI_SONG_LOOP_END ) ++ { ++ trackptr = _MIDI_TrackPtr; ++ tracknum = _MIDI_NumTracks; ++ _MIDI_ActiveTracks = 0; ++ } ++ else ++ { ++ trackptr = Track; ++ tracknum = 1; ++ _MIDI_ActiveTracks--; ++ } ++ ++ while( tracknum > 0 ) ++ { ++ if ( trackptr->context[ 0 ].loopcount != EMIDI_INFINITE ) ++ { ++ trackptr->context[ 0 ].loopcount--; ++ } ++ ++ trackptr->pos = trackptr->context[ 0 ].loopstart; ++ trackptr->RunningStatus = trackptr->context[ 0 ].RunningStatus; ++ trackptr->delay = trackptr->context[ 0 ].delay; ++ trackptr->active = trackptr->context[ 0 ].active; ++ if ( trackptr->active ) ++ { ++ _MIDI_ActiveTracks++; ++ } ++ ++ if ( !TimeSet ) ++ { ++ _MIDI_Time = trackptr->context[ 0 ].time; ++ _MIDI_FPSecondsPerTick = trackptr->context[ 0 ].FPSecondsPerTick; ++ _MIDI_Tick = trackptr->context[ 0 ].tick; ++ _MIDI_Beat = trackptr->context[ 0 ].beat; ++ _MIDI_Measure = trackptr->context[ 0 ].measure; ++ _MIDI_BeatsPerMeasure = trackptr->context[ 0 ].BeatsPerMeasure; ++ _MIDI_TicksPerBeat = trackptr->context[ 0 ].TicksPerBeat; ++ _MIDI_TimeBase = trackptr->context[ 0 ].TimeBase; ++ TimeSet = TRUE; ++ } ++ ++ trackptr++; ++ tracknum--; ++ } ++ break; ++ ++ default : ++ if ( _MIDI_Funcs->ControlChange ) ++ { ++ _MIDI_Funcs->ControlChange( channel, c1, c2 ); ++ } ++ } ++ ++ return TimeSet; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_ServiceRoutine ++ ++ Task that interperates the MIDI data. ++---------------------------------------------------------------------*/ ++// NOTE: We have to use a stack frame here because of a strange bug ++// that occurs with Watcom. This means that we cannot access Task! ++//Turned off to test if it works with Watcom 10a ++//#pragma aux _MIDI_ServiceRoutine frame; ++/* ++static void test ++ ( ++ task *Task ++ ) ++ { ++ _MIDI_ServiceRoutine( Task ); ++ _MIDI_ServiceRoutine( Task ); ++ _MIDI_ServiceRoutine( Task ); ++ _MIDI_ServiceRoutine( Task ); ++ } ++*/ ++static void _MIDI_ServiceRoutine ++ ( ++ task *Task ++ ) ++ ++ { ++ int event; ++ int channel; ++ int command; ++ track *Track; ++ int tracknum; ++ int status; ++ int c1; ++ int c2; ++ int TimeSet = FALSE; ++ ++ if ( !_MIDI_SongActive ) ++ { ++ return; ++ } ++ ++ Track = _MIDI_TrackPtr; ++ tracknum = 0; ++ while( tracknum < _MIDI_NumTracks ) ++ { ++ while ( ( Track->active ) && ( Track->delay == 0 ) ) ++ { ++ GET_NEXT_EVENT( Track, event ); ++ ++ if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL ) ++ { ++ switch( event ) ++ { ++ case MIDI_SYSEX : ++ case MIDI_SYSEX_CONTINUE : ++ _MIDI_SysEx( Track ); ++ break; ++ ++ case MIDI_META_EVENT : ++ _MIDI_MetaEvent( Track ); ++ break; ++ } ++ ++ if ( Track->active ) ++ { ++ Track->delay = _MIDI_ReadDelta( Track ); ++ } ++ ++ continue; ++ } ++ ++ if ( event & MIDI_RUNNING_STATUS ) ++ { ++ Track->RunningStatus = event; ++ } ++ else ++ { ++ event = Track->RunningStatus; ++ Track->pos--; ++ } ++ ++ channel = GET_MIDI_CHANNEL( event ); ++ command = GET_MIDI_COMMAND( event ); ++ ++ if ( _MIDI_CommandLengths[ command ] > 0 ) ++ { ++ GET_NEXT_EVENT( Track, c1 ); ++ if ( _MIDI_CommandLengths[ command ] > 1 ) ++ { ++ GET_NEXT_EVENT( Track, c2 ); ++ } ++ } ++ ++ if ( _MIDI_RerouteFunctions[ channel ] != NULL ) ++ { ++ status = _MIDI_RerouteFunctions[ channel ]( event, c1, c2 ); ++ ++ if ( status == MIDI_DONT_PLAY ) ++ { ++ Track->delay = _MIDI_ReadDelta( Track ); ++ continue; ++ } ++ } ++ ++ switch ( command ) ++ { ++ case MIDI_NOTE_OFF : ++ if ( _MIDI_Funcs->NoteOff ) ++ { ++ _MIDI_Funcs->NoteOff( channel, c1, c2 ); ++ } ++ break; ++ ++ case MIDI_NOTE_ON : ++ if ( _MIDI_Funcs->NoteOn ) ++ { ++ _MIDI_Funcs->NoteOn( channel, c1, c2 ); ++ } ++ break; ++ ++ case MIDI_POLY_AFTER_TCH : ++ if ( _MIDI_Funcs->PolyAftertouch ) ++ { ++ _MIDI_Funcs->PolyAftertouch( channel, c1, c2 ); ++ } ++ break; ++ ++ case MIDI_CONTROL_CHANGE : ++ TimeSet = _MIDI_InterpretControllerInfo( Track, TimeSet, ++ channel, c1, c2 ); ++ break; ++ ++ case MIDI_PROGRAM_CHANGE : ++ if ( ( _MIDI_Funcs->ProgramChange ) && ++ ( !Track->EMIDI_ProgramChange ) ) ++ { ++ _MIDI_Funcs->ProgramChange( channel, MIDI_PatchMap[ c1 & 0x7f ] ); ++ } ++ break; ++ ++ case MIDI_AFTER_TOUCH : ++ if ( _MIDI_Funcs->ChannelAftertouch ) ++ { ++ _MIDI_Funcs->ChannelAftertouch( channel, c1 ); ++ } ++ break; ++ ++ case MIDI_PITCH_BEND : ++ if ( _MIDI_Funcs->PitchBend ) ++ { ++ _MIDI_Funcs->PitchBend( channel, c1, c2 ); ++ } ++ break; ++ ++ default : ++ break; ++ } ++ ++ Track->delay = _MIDI_ReadDelta( Track ); ++ } ++ ++ Track->delay--; ++ Track++; ++ tracknum++; ++ ++ if ( _MIDI_ActiveTracks == 0 ) ++ { ++ _MIDI_ResetTracks(); ++ if ( _MIDI_Loop ) ++ { ++ tracknum = 0; ++ Track = _MIDI_TrackPtr; ++ } ++ else ++ { ++ _MIDI_SongActive = FALSE; ++ break; ++ } ++ } ++ } ++ ++ _MIDI_AdvanceTick(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_SendControlChange ++ ++ Sends a control change to the proper device ++---------------------------------------------------------------------*/ ++ ++static int _MIDI_SendControlChange ++ ( ++ int channel, ++ int c1, ++ int c2 ++ ) ++ ++ { ++ int status; ++ ++ if ( _MIDI_RerouteFunctions[ channel ] != NULL ) ++ { ++ status = _MIDI_RerouteFunctions[ channel ]( 0xB0 + channel, ++ c1, c2 ); ++ if ( status == MIDI_DONT_PLAY ) ++ { ++ return( MIDI_Ok ); ++ } ++ } ++ ++ if ( _MIDI_Funcs == NULL ) ++ { ++ return( MIDI_Error ); ++ } ++ ++ if ( _MIDI_Funcs->ControlChange == NULL ) ++ { ++ return( MIDI_Error ); ++ } ++ ++ _MIDI_Funcs->ControlChange( channel, c1, c2 ); ++ ++ return( MIDI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_RerouteMidiChannel ++ ++ Sets callback function to reroute MIDI commands from specified ++ function. ++---------------------------------------------------------------------*/ ++ ++void MIDI_RerouteMidiChannel ++ ( ++ int channel, ++ int cdecl ( *function )( int event, int c1, int c2 ) ++ ) ++ ++ { ++ if ( ( channel >= 1 ) && ( channel <= 16 ) ) ++ { ++ _MIDI_RerouteFunctions[ channel - 1 ] = function; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_AllNotesOff ++ ++ Sends all notes off commands on all midi channels. ++---------------------------------------------------------------------*/ ++ ++int MIDI_AllNotesOff ++ ( ++ void ++ ) ++ ++ { ++ int channel; ++ ++ for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ ) ++ { ++ _MIDI_SendControlChange( channel, 0x40, 0 ); ++ _MIDI_SendControlChange( channel, MIDI_ALL_NOTES_OFF, 0 ); ++ _MIDI_SendControlChange( channel, 0x78, 0 ); ++ } ++ ++ return( MIDI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_SetChannelVolume ++ ++ Sets the volume of the specified midi channel. ++---------------------------------------------------------------------*/ ++ ++static void _MIDI_SetChannelVolume ++ ( ++ int channel, ++ int volume ++ ) ++ ++ { ++ int status; ++ int remotevolume; ++ ++ _MIDI_ChannelVolume[ channel ] = volume; ++ ++ if ( _MIDI_RerouteFunctions[ channel ] != NULL ) ++ { ++ remotevolume = volume * _MIDI_TotalVolume; ++ remotevolume *= _MIDI_UserChannelVolume[ channel ]; ++ remotevolume /= MIDI_MaxVolume; ++ remotevolume >>= 8; ++ ++ status = _MIDI_RerouteFunctions[ channel ]( 0xB0 + channel, ++ MIDI_VOLUME, remotevolume ); ++ if ( status == MIDI_DONT_PLAY ) ++ { ++ return; ++ } ++ } ++ ++ if ( _MIDI_Funcs == NULL ) ++ { ++ return; ++ } ++ ++ if ( _MIDI_Funcs->ControlChange == NULL ) ++ { ++ return; ++ } ++ ++ // For user volume ++ volume *= _MIDI_UserChannelVolume[ channel ]; ++ ++ if ( _MIDI_Funcs->SetVolume == NULL ) ++ { ++ volume *= _MIDI_TotalVolume; ++ volume /= MIDI_MaxVolume; ++ } ++ ++ // For user volume ++ volume >>= 8; ++ ++ _MIDI_Funcs->ControlChange( channel, MIDI_VOLUME, volume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_SetUserChannelVolume ++ ++ Sets the volume of the specified midi channel. ++---------------------------------------------------------------------*/ ++ ++void MIDI_SetUserChannelVolume ++ ( ++ int channel, ++ int volume ++ ) ++ ++ { ++ // Convert channel from 1-16 to 0-15 ++ channel--; ++ ++ volume = max( 0, volume ); ++ volume = min( volume, 256 ); ++ ++ if ( ( channel >= 0 ) && ( channel < NUM_MIDI_CHANNELS ) ) ++ { ++ _MIDI_UserChannelVolume[ channel ] = volume; ++ _MIDI_SetChannelVolume( channel, _MIDI_ChannelVolume[ channel ] ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_ResetUserChannelVolume ++ ++ Sets the volume of the specified midi channel. ++---------------------------------------------------------------------*/ ++ ++void MIDI_ResetUserChannelVolume ++ ( ++ void ++ ) ++ ++ { ++ int channel; ++ ++ for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ ) ++ { ++ _MIDI_UserChannelVolume[ channel ] = 256; ++ } ++ ++ _MIDI_SendChannelVolumes(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_SendChannelVolumes ++ ++ Sets the volume on all the midi channels. ++---------------------------------------------------------------------*/ ++ ++static void _MIDI_SendChannelVolumes ++ ( ++ void ++ ) ++ ++ { ++ int channel; ++ ++ for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ ) ++ { ++ _MIDI_SetChannelVolume( channel, _MIDI_ChannelVolume[ channel ] ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_Reset ++ ++ Resets the MIDI device to General Midi defaults. ++---------------------------------------------------------------------*/ ++ ++int MIDI_Reset ++ ( ++ void ++ ) ++ ++ { ++ int channel; ++ long time; ++ unsigned flags; ++ ++ MIDI_AllNotesOff(); ++ ++ flags = DisableInterrupts(); ++ _enable(); ++ time = clock() + CLOCKS_PER_SEC/24; ++ while(clock() < time) ++ ; ++ ++ RestoreInterrupts( flags ); ++ ++ for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ ) ++ { ++ _MIDI_SendControlChange( channel, MIDI_RESET_ALL_CONTROLLERS, 0 ); ++ _MIDI_SendControlChange( channel, MIDI_RPN_MSB, MIDI_PITCHBEND_MSB ); ++ _MIDI_SendControlChange( channel, MIDI_RPN_LSB, MIDI_PITCHBEND_LSB ); ++ _MIDI_SendControlChange( channel, MIDI_DATAENTRY_MSB, 2 ); /* Pitch Bend Sensitivity MSB */ ++ _MIDI_SendControlChange( channel, MIDI_DATAENTRY_LSB, 0 ); /* Pitch Bend Sensitivity LSB */ ++ _MIDI_ChannelVolume[ channel ] = GENMIDI_DefaultVolume; ++ } ++ ++ _MIDI_SendChannelVolumes(); ++ ++ Reset = TRUE; ++ ++ return( MIDI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_SetVolume ++ ++ Sets the total volume of the music. ++---------------------------------------------------------------------*/ ++ ++int MIDI_SetVolume ++ ( ++ int volume ++ ) ++ ++ { ++ int i; ++ ++ if ( _MIDI_Funcs == NULL ) ++ { ++ return( MIDI_NullMidiModule ); ++ } ++ ++ volume = min( MIDI_MaxVolume, volume ); ++ volume = max( 0, volume ); ++ ++ _MIDI_TotalVolume = volume; ++ ++ if ( _MIDI_Funcs->SetVolume ) ++ { ++ _MIDI_Funcs->SetVolume( volume ); ++ ++ for( i = 0; i < NUM_MIDI_CHANNELS; i++ ) ++ { ++ if ( _MIDI_RerouteFunctions[ i ] != NULL ) ++ { ++ _MIDI_SetChannelVolume( i, _MIDI_ChannelVolume[ i ] ); ++ } ++ } ++ } ++ else ++ { ++ _MIDI_SendChannelVolumes(); ++ } ++ ++ return( MIDI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_GetVolume ++ ++ Returns the total volume of the music. ++---------------------------------------------------------------------*/ ++ ++int MIDI_GetVolume ++ ( ++ void ++ ) ++ ++ { ++ int volume; ++ ++ if ( _MIDI_Funcs == NULL ) ++ { ++ return( MIDI_NullMidiModule ); ++ } ++ ++ if ( _MIDI_Funcs->GetVolume ) ++ { ++ volume = _MIDI_Funcs->GetVolume(); ++ } ++ else ++ { ++ volume = _MIDI_TotalVolume; ++ } ++ ++ return( volume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_SetContext ++ ++ Sets the song context. ++---------------------------------------------------------------------*/ ++ ++void MIDI_SetContext ++ ( ++ int context ++ ) ++ ++ { ++ if ( ( context > 0 ) && ( context < EMIDI_NUM_CONTEXTS ) ) ++ { ++ _MIDI_Context = context; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_GetContext ++ ++ Returns the current song context. ++---------------------------------------------------------------------*/ ++ ++int MIDI_GetContext ++ ( ++ void ++ ) ++ ++ { ++ return _MIDI_Context; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_SetLoopFlag ++ ++ Sets whether the song should loop when finished or not. ++---------------------------------------------------------------------*/ ++ ++void MIDI_SetLoopFlag ++ ( ++ int loopflag ++ ) ++ ++ { ++ _MIDI_Loop = loopflag; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_ContinueSong ++ ++ Continues playback of a paused song. ++---------------------------------------------------------------------*/ ++ ++void MIDI_ContinueSong ++ ( ++ void ++ ) ++ ++ { ++ if ( _MIDI_SongLoaded ) ++ { ++ _MIDI_SongActive = TRUE; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_PauseSong ++ ++ Pauses playback of the current song. ++---------------------------------------------------------------------*/ ++ ++void MIDI_PauseSong ++ ( ++ void ++ ) ++ ++ { ++ if ( _MIDI_SongLoaded ) ++ { ++ _MIDI_SongActive = FALSE; ++ MIDI_AllNotesOff(); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_SongPlaying ++ ++ Returns whether a song is playing or not. ++---------------------------------------------------------------------*/ ++ ++int MIDI_SongPlaying ++ ( ++ void ++ ) ++ ++ { ++ return( _MIDI_SongActive ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_SetMidiFuncs ++ ++ Selects the routines that send the MIDI data to the music device. ++---------------------------------------------------------------------*/ ++ ++void MIDI_SetMidiFuncs ++ ( ++ midifuncs *funcs ++ ) ++ ++ { ++ _MIDI_Funcs = funcs; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_StopSong ++ ++ Stops playback of the currently playing song. ++---------------------------------------------------------------------*/ ++ ++void MIDI_StopSong ++ ( ++ void ++ ) ++ ++ { ++ if ( _MIDI_SongLoaded ) ++ { ++ TS_Terminate( _MIDI_PlayRoutine ); ++ ++ _MIDI_PlayRoutine = NULL; ++ _MIDI_SongActive = FALSE; ++ _MIDI_SongLoaded = FALSE; ++ ++ MIDI_Reset(); ++ _MIDI_ResetTracks(); ++ ++ if ( _MIDI_Funcs->ReleasePatches ) ++ { ++ _MIDI_Funcs->ReleasePatches(); ++ } ++ ++ DPMI_UnlockMemory( _MIDI_TrackPtr, _MIDI_TrackMemSize ); ++ USRHOOKS_FreeMem( _MIDI_TrackPtr ); ++ ++ _MIDI_TrackPtr = NULL; ++ _MIDI_NumTracks = 0; ++ _MIDI_TrackMemSize = 0; ++ ++ _MIDI_TotalTime = 0; ++ _MIDI_TotalTicks = 0; ++ _MIDI_TotalBeats = 0; ++ _MIDI_TotalMeasures = 0; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_PlaySong ++ ++ Begins playback of a MIDI song. ++---------------------------------------------------------------------*/ ++ ++int MIDI_PlaySong ++ ( ++ unsigned char *song, ++ int loopflag ++ ) ++ ++ { ++ int numtracks; ++ int format; ++ long headersize; ++ long tracklength; ++ track *CurrentTrack; ++ unsigned char *ptr; ++ int status; ++ ++ if ( _MIDI_SongLoaded ) ++ { ++ MIDI_StopSong(); ++ } ++ ++ _MIDI_Loop = loopflag; ++ ++ if ( _MIDI_Funcs == NULL ) ++ { ++ return( MIDI_NullMidiModule ); ++ } ++ ++ if ( *( unsigned long * )song != MIDI_HEADER_SIGNATURE ) ++ { ++ return( MIDI_InvalidMidiFile ); ++ } ++ ++ song += 4; ++ ++ headersize = _MIDI_ReadNumber( song, 4 ); ++ song += 4; ++ format = _MIDI_ReadNumber( song, 2 ); ++ _MIDI_NumTracks = _MIDI_ReadNumber( song + 2, 2 ); ++ _MIDI_Division = _MIDI_ReadNumber( song + 4, 2 ); ++ if ( _MIDI_Division < 0 ) ++ { ++ // If a SMPTE time division is given, just set to 96 so no errors occur ++ _MIDI_Division = 96; ++ } ++ ++ if ( format > MAX_FORMAT ) ++ { ++ return( MIDI_UnknownMidiFormat ); ++ } ++ ++ ptr = song + headersize; ++ ++ if ( _MIDI_NumTracks == 0 ) ++ { ++ return( MIDI_NoTracks ); ++ } ++ ++ _MIDI_TrackMemSize = _MIDI_NumTracks * sizeof( track ); ++ status = USRHOOKS_GetMem( &_MIDI_TrackPtr, _MIDI_TrackMemSize ); ++ if ( status != USRHOOKS_Ok ) ++ { ++ return( MIDI_NoMemory ); ++ } ++ ++ status = DPMI_LockMemory( _MIDI_TrackPtr, _MIDI_TrackMemSize ); ++ if ( status != DPMI_Ok ) ++ { ++ USRHOOKS_FreeMem( _MIDI_TrackPtr ); ++ ++ _MIDI_TrackPtr = NULL; ++ _MIDI_TrackMemSize = 0; ++ _MIDI_NumTracks = 0; ++// MIDI_SetErrorCode( MIDI_DPMI_Error ); ++ return( MIDI_Error ); ++ } ++ ++ CurrentTrack = _MIDI_TrackPtr; ++ numtracks = _MIDI_NumTracks; ++ while( numtracks-- ) ++ { ++ if ( *( unsigned long * )ptr != MIDI_TRACK_SIGNATURE ) ++ { ++ DPMI_UnlockMemory( _MIDI_TrackPtr, _MIDI_TrackMemSize ); ++ ++ USRHOOKS_FreeMem( _MIDI_TrackPtr ); ++ ++ _MIDI_TrackPtr = NULL; ++ _MIDI_TrackMemSize = 0; ++ ++ return( MIDI_InvalidTrack ); ++ } ++ ++ tracklength = _MIDI_ReadNumber( ptr + 4, 4 ); ++ ptr += 8; ++ CurrentTrack->start = ptr; ++ ptr += tracklength; ++ CurrentTrack++; ++ } ++ ++ if ( _MIDI_Funcs->GetVolume != NULL ) ++ { ++ _MIDI_TotalVolume = _MIDI_Funcs->GetVolume(); ++ } ++ ++ _MIDI_InitEMIDI(); ++ ++ if ( _MIDI_Funcs->LoadPatch ) ++ { ++ MIDI_LoadTimbres(); ++ } ++ ++ _MIDI_ResetTracks(); ++ ++ if ( !Reset ) ++ { ++ MIDI_Reset(); ++ } ++ ++ Reset = FALSE; ++ ++ _MIDI_PlayRoutine = TS_ScheduleTask( _MIDI_ServiceRoutine, 100, 1, NULL ); ++// _MIDI_PlayRoutine = TS_ScheduleTask( test, 100, 1, NULL ); ++ MIDI_SetTempo( 120 ); ++ TS_Dispatch(); ++ ++ _MIDI_SongLoaded = TRUE; ++ _MIDI_SongActive = TRUE; ++ ++ return( MIDI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_SetTempo ++ ++ Sets the song tempo. ++---------------------------------------------------------------------*/ ++ ++void MIDI_SetTempo ++ ( ++ int tempo ++ ) ++ ++ { ++ long tickspersecond; ++ ++ MIDI_Tempo = tempo; ++ tickspersecond = ( tempo * _MIDI_Division ) / 60; ++ if ( _MIDI_PlayRoutine != NULL ) ++ { ++ TS_SetTaskRate( _MIDI_PlayRoutine, tickspersecond ); ++// TS_SetTaskRate( _MIDI_PlayRoutine, tickspersecond / 4 ); ++ } ++ _MIDI_FPSecondsPerTick = ( 1 << TIME_PRECISION ) / tickspersecond; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_GetTempo ++ ++ Returns the song tempo. ++---------------------------------------------------------------------*/ ++ ++int MIDI_GetTempo ++ ( ++ void ++ ) ++ ++ { ++ return( MIDI_Tempo ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: _MIDI_ProcessNextTick ++ ++ Sets the position of the song pointer. ++---------------------------------------------------------------------*/ ++ ++static int _MIDI_ProcessNextTick ++ ( ++ void ++ ) ++ ++ { ++ int event; ++ int channel; ++ int command; ++ track *Track; ++ int tracknum; ++ int status; ++ int c1; ++ int c2; ++ int TimeSet = FALSE; ++ ++ Track = _MIDI_TrackPtr; ++ tracknum = 0; ++ while( ( tracknum < _MIDI_NumTracks ) && ( Track != NULL ) ) ++ { ++ while ( ( Track->active ) && ( Track->delay == 0 ) ) ++ { ++ GET_NEXT_EVENT( Track, event ); ++ ++ if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL ) ++ { ++ switch( event ) ++ { ++ case MIDI_SYSEX : ++ case MIDI_SYSEX_CONTINUE : ++ _MIDI_SysEx( Track ); ++ break; ++ ++ case MIDI_META_EVENT : ++ _MIDI_MetaEvent( Track ); ++ break; ++ } ++ ++ if ( Track->active ) ++ { ++ Track->delay = _MIDI_ReadDelta( Track ); ++ } ++ ++ continue; ++ } ++ ++ if ( event & MIDI_RUNNING_STATUS ) ++ { ++ Track->RunningStatus = event; ++ } ++ else ++ { ++ event = Track->RunningStatus; ++ Track->pos--; ++ } ++ ++ channel = GET_MIDI_CHANNEL( event ); ++ command = GET_MIDI_COMMAND( event ); ++ ++ if ( _MIDI_CommandLengths[ command ] > 0 ) ++ { ++ GET_NEXT_EVENT( Track, c1 ); ++ if ( _MIDI_CommandLengths[ command ] > 1 ) ++ { ++ GET_NEXT_EVENT( Track, c2 ); ++ } ++ } ++ ++ if ( _MIDI_RerouteFunctions[ channel ] != NULL ) ++ { ++ status = _MIDI_RerouteFunctions[ channel ]( event, c1, c2 ); ++ ++ if ( status == MIDI_DONT_PLAY ) ++ { ++ Track->delay = _MIDI_ReadDelta( Track ); ++ continue; ++ } ++ } ++ ++ switch ( command ) ++ { ++ case MIDI_NOTE_OFF : ++ break; ++ ++ case MIDI_NOTE_ON : ++ break; ++ ++ case MIDI_POLY_AFTER_TCH : ++ if ( _MIDI_Funcs->PolyAftertouch ) ++ { ++ _MIDI_Funcs->PolyAftertouch( channel, c1, c2 ); ++ } ++ break; ++ ++ case MIDI_CONTROL_CHANGE : ++ TimeSet = _MIDI_InterpretControllerInfo( Track, TimeSet, ++ channel, c1, c2 ); ++ break; ++ ++ case MIDI_PROGRAM_CHANGE : ++ if ( ( _MIDI_Funcs->ProgramChange ) && ++ ( !Track->EMIDI_ProgramChange ) ) ++ { ++ _MIDI_Funcs->ProgramChange( channel, c1 ); ++ } ++ break; ++ ++ case MIDI_AFTER_TOUCH : ++ if ( _MIDI_Funcs->ChannelAftertouch ) ++ { ++ _MIDI_Funcs->ChannelAftertouch( channel, c1 ); ++ } ++ break; ++ ++ case MIDI_PITCH_BEND : ++ if ( _MIDI_Funcs->PitchBend ) ++ { ++ _MIDI_Funcs->PitchBend( channel, c1, c2 ); ++ } ++ break; ++ ++ default : ++ break; ++ } ++ ++ Track->delay = _MIDI_ReadDelta( Track ); ++ } ++ ++ Track->delay--; ++ Track++; ++ tracknum++; ++ ++ if ( _MIDI_ActiveTracks == 0 ) ++ { ++ break; ++ } ++ } ++ ++ _MIDI_AdvanceTick(); ++ ++ return( TimeSet ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_SetSongTick ++ ++ Sets the position of the song pointer. ++---------------------------------------------------------------------*/ ++ ++void MIDI_SetSongTick ++ ( ++ unsigned long PositionInTicks ++ ) ++ ++ { ++ if ( !_MIDI_SongLoaded ) ++ { ++ return; ++ } ++ ++ MIDI_PauseSong(); ++ ++ if ( PositionInTicks < _MIDI_PositionInTicks ) ++ { ++ _MIDI_ResetTracks(); ++ MIDI_Reset(); ++ } ++ ++ while( _MIDI_PositionInTicks < PositionInTicks ) ++ { ++ if ( _MIDI_ProcessNextTick() ) ++ { ++ break; ++ } ++ if ( _MIDI_ActiveTracks == 0 ) ++ { ++ _MIDI_ResetTracks(); ++ if ( !_MIDI_Loop ) ++ { ++ return; ++ } ++ break; ++ } ++ } ++ ++ MIDI_SetVolume( _MIDI_TotalVolume ); ++ MIDI_ContinueSong(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_SetSongTime ++ ++ Sets the position of the song pointer. ++---------------------------------------------------------------------*/ ++ ++void MIDI_SetSongTime ++ ( ++ unsigned long milliseconds ++ ) ++ ++ { ++ unsigned long mil; ++ unsigned long sec; ++ unsigned long newtime; ++ ++ if ( !_MIDI_SongLoaded ) ++ { ++ return; ++ } ++ ++ MIDI_PauseSong(); ++ ++ mil = ( ( milliseconds % 1000 ) << TIME_PRECISION ) / 1000; ++ sec = ( milliseconds / 1000 ) << TIME_PRECISION; ++ newtime = sec + mil; ++ ++ if ( newtime < _MIDI_Time ) ++ { ++ _MIDI_ResetTracks(); ++ MIDI_Reset(); ++ } ++ ++ while( _MIDI_Time < newtime ) ++ { ++ if ( _MIDI_ProcessNextTick() ) ++ { ++ break; ++ } ++ if ( _MIDI_ActiveTracks == 0 ) ++ { ++ _MIDI_ResetTracks(); ++ if ( !_MIDI_Loop ) ++ { ++ return; ++ } ++ break; ++ } ++ } ++ ++ MIDI_SetVolume( _MIDI_TotalVolume ); ++ MIDI_ContinueSong(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_SetSongPosition ++ ++ Sets the position of the song pointer. ++---------------------------------------------------------------------*/ ++ ++void MIDI_SetSongPosition ++ ( ++ int measure, ++ int beat, ++ int tick ++ ) ++ ++ { ++ unsigned long pos; ++ ++ if ( !_MIDI_SongLoaded ) ++ { ++ return; ++ } ++ ++ MIDI_PauseSong(); ++ ++ pos = RELATIVE_BEAT( measure, beat, tick ); ++ ++ if ( pos < RELATIVE_BEAT( _MIDI_Measure, _MIDI_Beat, _MIDI_Tick ) ) ++ { ++ _MIDI_ResetTracks(); ++ MIDI_Reset(); ++ } ++ ++ while( RELATIVE_BEAT( _MIDI_Measure, _MIDI_Beat, _MIDI_Tick ) < pos ) ++ { ++ if ( _MIDI_ProcessNextTick() ) ++ { ++ break; ++ } ++ if ( _MIDI_ActiveTracks == 0 ) ++ { ++ _MIDI_ResetTracks(); ++ if ( !_MIDI_Loop ) ++ { ++ return; ++ } ++ break; ++ } ++ } ++ ++ MIDI_SetVolume( _MIDI_TotalVolume ); ++ MIDI_ContinueSong(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_GetSongPosition ++ ++ Returns the position of the song pointer in Measures, beats, ticks. ++---------------------------------------------------------------------*/ ++ ++void MIDI_GetSongPosition ++ ( ++ songposition *pos ++ ) ++ ++ { ++ unsigned long mil; ++ unsigned long sec; ++ ++ mil = ( _MIDI_Time & ( ( 1 << TIME_PRECISION ) - 1 ) ) * 1000; ++ sec = _MIDI_Time >> TIME_PRECISION; ++ pos->milliseconds = ( mil >> TIME_PRECISION ) + ( sec * 1000 ); ++ pos->tickposition = _MIDI_PositionInTicks; ++ pos->measure = _MIDI_Measure; ++ pos->beat = _MIDI_Beat; ++ pos->tick = _MIDI_Tick; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_GetSongLength ++ ++ Returns the length of the song. ++---------------------------------------------------------------------*/ ++ ++void MIDI_GetSongLength ++ ( ++ songposition *pos ++ ) ++ ++ { ++ unsigned long mil; ++ unsigned long sec; ++ ++ mil = ( _MIDI_TotalTime & ( ( 1 << TIME_PRECISION ) - 1 ) ) * 1000; ++ sec = _MIDI_TotalTime >> TIME_PRECISION; ++ ++ pos->milliseconds = ( mil >> TIME_PRECISION ) + ( sec * 1000 ); ++ pos->measure = _MIDI_TotalMeasures; ++ pos->beat = _MIDI_TotalBeats; ++ pos->tick = _MIDI_TotalTicks; ++ pos->tickposition = 0; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_InitEMIDI ++ ++ Sets up the EMIDI ++---------------------------------------------------------------------*/ ++ ++static void _MIDI_InitEMIDI ++ ( ++ void ++ ) ++ ++ { ++ int event; ++ int command; ++ int channel; ++ int length; ++ int IncludeFound; ++ track *Track; ++ int tracknum; ++ int type; ++ int c1; ++ int c2; ++ ++ type = EMIDI_GeneralMIDI; ++ switch( MUSIC_SoundDevice ) ++ { ++ case SoundBlaster : ++ type = EMIDI_SoundBlaster; ++ break; ++ ++ case ProAudioSpectrum : ++ type = EMIDI_ProAudio; ++ break; ++ ++ case SoundMan16 : ++ type = EMIDI_SoundMan16; ++ break; ++ ++ case Adlib : ++ type = EMIDI_Adlib; ++ break; ++ ++ case GenMidi : ++ type = EMIDI_GeneralMIDI; ++ break; ++ ++ case SoundCanvas : ++ type = EMIDI_SoundCanvas; ++ break; ++ ++ case Awe32 : ++ type = EMIDI_AWE32; ++ break; ++ ++ case WaveBlaster : ++ type = EMIDI_WaveBlaster; ++ break; ++ ++ case SoundScape : ++ type = EMIDI_Soundscape; ++ break; ++ ++ case UltraSound : ++ type = EMIDI_Ultrasound; ++ break; ++ } ++ ++ _MIDI_ResetTracks(); ++ ++ _MIDI_TotalTime = 0; ++ _MIDI_TotalTicks = 0; ++ _MIDI_TotalBeats = 0; ++ _MIDI_TotalMeasures = 0; ++ ++ Track = _MIDI_TrackPtr; ++ tracknum = 0; ++ while( ( tracknum < _MIDI_NumTracks ) && ( Track != NULL ) ) ++ { ++ _MIDI_Tick = 0; ++ _MIDI_Beat = 1; ++ _MIDI_Measure = 1; ++ _MIDI_Time = 0; ++ _MIDI_BeatsPerMeasure = 4; ++ _MIDI_TicksPerBeat = _MIDI_Division; ++ _MIDI_TimeBase = 4; ++ ++ _MIDI_PositionInTicks = 0; ++ _MIDI_ActiveTracks = 0; ++ _MIDI_Context = -1; ++ ++ Track->RunningStatus = 0; ++ Track->active = TRUE; ++ ++ Track->EMIDI_ProgramChange = FALSE; ++ Track->EMIDI_VolumeChange = FALSE; ++ Track->EMIDI_IncludeTrack = TRUE; ++ ++ memset( Track->context, 0, sizeof( Track->context ) ); ++ ++ while( Track->delay > 0 ) ++ { ++ _MIDI_AdvanceTick(); ++ Track->delay--; ++ } ++ ++ IncludeFound = FALSE; ++ while ( Track->active ) ++ { ++ GET_NEXT_EVENT( Track, event ); ++ ++ if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL ) ++ { ++ switch( event ) ++ { ++ case MIDI_SYSEX : ++ case MIDI_SYSEX_CONTINUE : ++ _MIDI_SysEx( Track ); ++ break; ++ ++ case MIDI_META_EVENT : ++ _MIDI_MetaEvent( Track ); ++ break; ++ } ++ ++ if ( Track->active ) ++ { ++ Track->delay = _MIDI_ReadDelta( Track ); ++ while( Track->delay > 0 ) ++ { ++ _MIDI_AdvanceTick(); ++ Track->delay--; ++ } ++ } ++ ++ continue; ++ } ++ ++ if ( event & MIDI_RUNNING_STATUS ) ++ { ++ Track->RunningStatus = event; ++ } ++ else ++ { ++ event = Track->RunningStatus; ++ Track->pos--; ++ } ++ ++ channel = GET_MIDI_CHANNEL( event ); ++ command = GET_MIDI_COMMAND( event ); ++ length = _MIDI_CommandLengths[ command ]; ++ ++ if ( command == MIDI_CONTROL_CHANGE ) ++ { ++ if ( *Track->pos == MIDI_MONO_MODE_ON ) ++ { ++ length++; ++ } ++ GET_NEXT_EVENT( Track, c1 ); ++ GET_NEXT_EVENT( Track, c2 ); ++ length -= 2; ++ ++ switch( c1 ) ++ { ++ case EMIDI_LOOP_START : ++ case EMIDI_SONG_LOOP_START : ++ if ( c2 == 0 ) ++ { ++ Track->context[ 0 ].loopcount = EMIDI_INFINITE; ++ } ++ else ++ { ++ Track->context[ 0 ].loopcount = c2; ++ } ++ ++ Track->context[ 0 ].pos = Track->pos; ++ Track->context[ 0 ].loopstart = Track->pos; ++ Track->context[ 0 ].RunningStatus = Track->RunningStatus; ++ Track->context[ 0 ].time = _MIDI_Time; ++ Track->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick; ++ Track->context[ 0 ].tick = _MIDI_Tick; ++ Track->context[ 0 ].beat = _MIDI_Beat; ++ Track->context[ 0 ].measure = _MIDI_Measure; ++ Track->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure; ++ Track->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat; ++ Track->context[ 0 ].TimeBase = _MIDI_TimeBase; ++ break; ++ ++ case EMIDI_LOOP_END : ++ case EMIDI_SONG_LOOP_END : ++ if ( c2 == EMIDI_END_LOOP_VALUE ) ++ { ++ Track->context[ 0 ].loopstart = NULL; ++ Track->context[ 0 ].loopcount = 0; ++ } ++ break; ++ ++ case EMIDI_INCLUDE_TRACK : ++ if ( EMIDI_AffectsCurrentCard( c2, type ) ) ++ { ++ //printf( "Include track %d on card %d\n", tracknum, c2 ); ++ IncludeFound = TRUE; ++ Track->EMIDI_IncludeTrack = TRUE; ++ } ++ else if ( !IncludeFound ) ++ { ++ //printf( "Track excluded %d on card %d\n", tracknum, c2 ); ++ IncludeFound = TRUE; ++ Track->EMIDI_IncludeTrack = FALSE; ++ } ++ break; ++ ++ case EMIDI_EXCLUDE_TRACK : ++ if ( EMIDI_AffectsCurrentCard( c2, type ) ) ++ { ++ //printf( "Exclude track %d on card %d\n", tracknum, c2 ); ++ Track->EMIDI_IncludeTrack = FALSE; ++ } ++ break; ++ ++ case EMIDI_PROGRAM_CHANGE : ++ if ( !Track->EMIDI_ProgramChange ) ++ //printf( "Program change on track %d\n", tracknum ); ++ Track->EMIDI_ProgramChange = TRUE; ++ break; ++ ++ case EMIDI_VOLUME_CHANGE : ++ if ( !Track->EMIDI_VolumeChange ) ++ //printf( "Volume change on track %d\n", tracknum ); ++ Track->EMIDI_VolumeChange = TRUE; ++ break; ++ ++ case EMIDI_CONTEXT_START : ++ if ( ( c2 > 0 ) && ( c2 < EMIDI_NUM_CONTEXTS ) ) ++ { ++ Track->context[ c2 ].pos = Track->pos; ++ Track->context[ c2 ].loopstart = Track->context[ 0 ].loopstart; ++ Track->context[ c2 ].loopcount = Track->context[ 0 ].loopcount; ++ Track->context[ c2 ].RunningStatus = Track->RunningStatus; ++ Track->context[ c2 ].time = _MIDI_Time; ++ Track->context[ c2 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick; ++ Track->context[ c2 ].tick = _MIDI_Tick; ++ Track->context[ c2 ].beat = _MIDI_Beat; ++ Track->context[ c2 ].measure = _MIDI_Measure; ++ Track->context[ c2 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure; ++ Track->context[ c2 ].TicksPerBeat = _MIDI_TicksPerBeat; ++ Track->context[ c2 ].TimeBase = _MIDI_TimeBase; ++ } ++ break; ++ ++ case EMIDI_CONTEXT_END : ++ break; ++ } ++ } ++ ++ Track->pos += length; ++ Track->delay = _MIDI_ReadDelta( Track ); ++ ++ while( Track->delay > 0 ) ++ { ++ _MIDI_AdvanceTick(); ++ Track->delay--; ++ } ++ } ++ ++ _MIDI_TotalTime = max( _MIDI_TotalTime, _MIDI_Time ); ++ if ( RELATIVE_BEAT( _MIDI_Measure, _MIDI_Beat, _MIDI_Tick ) > ++ RELATIVE_BEAT( _MIDI_TotalMeasures, _MIDI_TotalBeats, ++ _MIDI_TotalTicks ) ) ++ { ++ _MIDI_TotalTicks = _MIDI_Tick; ++ _MIDI_TotalBeats = _MIDI_Beat; ++ _MIDI_TotalMeasures = _MIDI_Measure; ++ } ++ ++ Track++; ++ tracknum++; ++ } ++ ++ _MIDI_ResetTracks(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_LoadTimbres ++ ++ Preloads the timbres on cards that use patch-caching. ++---------------------------------------------------------------------*/ ++ ++void MIDI_LoadTimbres ++ ( ++ void ++ ) ++ ++ { ++ int event; ++ int command; ++ int channel; ++ int length; ++ int Finished; ++ track *Track; ++ int tracknum; ++ ++ Track = _MIDI_TrackPtr; ++ tracknum = 0; ++ while( ( tracknum < _MIDI_NumTracks ) && ( Track != NULL ) ) ++ { ++ Finished = FALSE; ++ while ( !Finished ) ++ { ++ GET_NEXT_EVENT( Track, event ); ++ ++ if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL ) ++ { ++ switch( event ) ++ { ++ case MIDI_SYSEX : ++ case MIDI_SYSEX_CONTINUE : ++ length = _MIDI_ReadDelta( Track ); ++ Track->pos += length; ++ break; ++ ++ case MIDI_META_EVENT : ++ GET_NEXT_EVENT( Track, command ); ++ GET_NEXT_EVENT( Track, length ); ++ ++ if ( command == MIDI_END_OF_TRACK ) ++ { ++ Finished = TRUE; ++ } ++ ++ Track->pos += length; ++ break; ++ } ++ ++ if ( !Finished ) ++ { ++ _MIDI_ReadDelta( Track ); ++ } ++ ++ continue; ++ } ++ ++ if ( event & MIDI_RUNNING_STATUS ) ++ { ++ Track->RunningStatus = event; ++ } ++ else ++ { ++ event = Track->RunningStatus; ++ Track->pos--; ++ } ++ ++ channel = GET_MIDI_CHANNEL( event ); ++ command = GET_MIDI_COMMAND( event ); ++ length = _MIDI_CommandLengths[ command ]; ++ ++ if ( command == MIDI_CONTROL_CHANGE ) ++ { ++ if ( *Track->pos == MIDI_MONO_MODE_ON ) ++ { ++ length++; ++ } ++ ++ if ( *Track->pos == EMIDI_PROGRAM_CHANGE ) ++ { ++ _MIDI_Funcs->LoadPatch( *( Track->pos + 1 ) ); ++ } ++ } ++ ++ if ( channel == MIDI_RHYTHM_CHANNEL ) ++ { ++ if ( command == MIDI_NOTE_ON ) ++ { ++ _MIDI_Funcs->LoadPatch( 128 + *Track->pos ); ++ } ++ } ++ else ++ { ++ if ( command == MIDI_PROGRAM_CHANGE ) ++ { ++ _MIDI_Funcs->LoadPatch( *Track->pos ); ++ } ++ } ++ Track->pos += length; ++ _MIDI_ReadDelta( Track ); ++ } ++ Track++; ++ tracknum++; ++ } ++ ++ _MIDI_ResetTracks(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void MIDI_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_UnlockMemory ++ ++ Unlocks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++void MIDI_UnlockMemory ++ ( ++ void ++ ) ++ ++ { ++ DPMI_UnlockMemoryRegion( MIDI_LockStart, MIDI_LockEnd ); ++ DPMI_UnlockMemory( ( void * )&_MIDI_CommandLengths[ 0 ], ++ sizeof( _MIDI_CommandLengths ) ); ++ DPMI_Unlock( _MIDI_TrackPtr ); ++ DPMI_Unlock( _MIDI_NumTracks ); ++ DPMI_Unlock( _MIDI_SongActive ); ++ DPMI_Unlock( _MIDI_SongLoaded ); ++ DPMI_Unlock( _MIDI_Loop ); ++ DPMI_Unlock( _MIDI_PlayRoutine ); ++ DPMI_Unlock( _MIDI_Division ); ++ DPMI_Unlock( _MIDI_ActiveTracks ); ++ DPMI_Unlock( _MIDI_TotalVolume ); ++ DPMI_Unlock( _MIDI_ChannelVolume ); ++ DPMI_Unlock( _MIDI_Funcs ); ++ DPMI_Unlock( _MIDI_PositionInTicks ); ++ DPMI_Unlock( _MIDI_Division ); ++ DPMI_Unlock( _MIDI_Tick ); ++ DPMI_Unlock( _MIDI_Beat ); ++ DPMI_Unlock( _MIDI_Measure ); ++ DPMI_Unlock( _MIDI_Time ); ++ DPMI_Unlock( _MIDI_BeatsPerMeasure ); ++ DPMI_Unlock( _MIDI_TicksPerBeat ); ++ DPMI_Unlock( _MIDI_TimeBase ); ++ DPMI_Unlock( _MIDI_FPSecondsPerTick ); ++ DPMI_Unlock( _MIDI_Context ); ++ DPMI_Unlock( _MIDI_TotalTime ); ++ DPMI_Unlock( _MIDI_TotalTicks ); ++ DPMI_Unlock( _MIDI_TotalBeats ); ++ DPMI_Unlock( _MIDI_TotalMeasures ); ++ DPMI_Unlock( MIDI_Tempo ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MIDI_LockMemory ++ ++ Locks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++int MIDI_LockMemory ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_LockMemoryRegion( MIDI_LockStart, MIDI_LockEnd ); ++ status |= DPMI_LockMemory( ( void * )&_MIDI_CommandLengths[ 0 ], ++ sizeof( _MIDI_CommandLengths ) ); ++ status |= DPMI_Lock( _MIDI_TrackPtr ); ++ status |= DPMI_Lock( _MIDI_NumTracks ); ++ status |= DPMI_Lock( _MIDI_SongActive ); ++ status |= DPMI_Lock( _MIDI_SongLoaded ); ++ status |= DPMI_Lock( _MIDI_Loop ); ++ status |= DPMI_Lock( _MIDI_PlayRoutine ); ++ status |= DPMI_Lock( _MIDI_Division ); ++ status |= DPMI_Lock( _MIDI_ActiveTracks ); ++ status |= DPMI_Lock( _MIDI_TotalVolume ); ++ status |= DPMI_Lock( _MIDI_ChannelVolume ); ++ status |= DPMI_Lock( _MIDI_Funcs ); ++ status |= DPMI_Lock( _MIDI_PositionInTicks ); ++ status |= DPMI_Lock( _MIDI_Division ); ++ status |= DPMI_Lock( _MIDI_Tick ); ++ status |= DPMI_Lock( _MIDI_Beat ); ++ status |= DPMI_Lock( _MIDI_Measure ); ++ status |= DPMI_Lock( _MIDI_Time ); ++ status |= DPMI_Lock( _MIDI_BeatsPerMeasure ); ++ status |= DPMI_Lock( _MIDI_TicksPerBeat ); ++ status |= DPMI_Lock( _MIDI_TimeBase ); ++ status |= DPMI_Lock( _MIDI_FPSecondsPerTick ); ++ status |= DPMI_Lock( _MIDI_Context ); ++ status |= DPMI_Lock( _MIDI_TotalTime ); ++ status |= DPMI_Lock( _MIDI_TotalTicks ); ++ status |= DPMI_Lock( _MIDI_TotalBeats ); ++ status |= DPMI_Lock( _MIDI_TotalMeasures ); ++ status |= DPMI_Lock( MIDI_Tempo ); ++ ++ if ( status != DPMI_Ok ) ++ { ++ MIDI_UnlockMemory(); ++// MIDI_SetErrorCode( MIDI_DPMI_Error ); ++ return( MIDI_Error ); ++ } ++ ++ return( MIDI_Ok ); ++ } +diff -urN rott-1.0/rott/audiolib/midi.h trunk/rott/audiolib/midi.h +--- rott-1.0/rott/audiolib/midi.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/midi.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,98 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: MIDI.H ++ ++ author: James R. Dose ++ date: May 25, 1994 ++ ++ Public header for MIDI.C. Midi song file playback routines. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __MIDI_H ++#define __MIDI_H ++ ++enum MIDI_Errors ++ { ++ MIDI_Warning = -2, ++ MIDI_Error = -1, ++ MIDI_Ok = 0, ++ MIDI_NullMidiModule, ++ MIDI_InvalidMidiFile, ++ MIDI_UnknownMidiFormat, ++ MIDI_NoTracks, ++ MIDI_InvalidTrack, ++ MIDI_NoMemory, ++ MIDI_DPMI_Error ++ }; ++ ++ ++#define MIDI_PASS_THROUGH 1 ++#define MIDI_DONT_PLAY 0 ++ ++#define MIDI_MaxVolume 255 ++ ++extern char MIDI_PatchMap[ 128 ]; ++ ++typedef struct ++ { ++ void ( *NoteOff )( int channel, int key, int velocity ); ++ void ( *NoteOn )( int channel, int key, int velocity ); ++ void ( *PolyAftertouch )( int channel, int key, int pressure ); ++ void ( *ControlChange )( int channel, int number, int value ); ++ void ( *ProgramChange )( int channel, int program ); ++ void ( *ChannelAftertouch )( int channel, int pressure ); ++ void ( *PitchBend )( int channel, int lsb, int msb ); ++ void ( *ReleasePatches )( void ); ++ void ( *LoadPatch )( int number ); ++ void ( *SetVolume )( int volume ); ++ int ( *GetVolume )( void ); ++ } midifuncs; ++ ++void MIDI_RerouteMidiChannel( int channel, int cdecl ( *function )( int event, int c1, int c2 ) ); ++int MIDI_AllNotesOff( void ); ++void MIDI_SetUserChannelVolume( int channel, int volume ); ++void MIDI_ResetUserChannelVolume( void ); ++int MIDI_Reset( void ); ++int MIDI_SetVolume( int volume ); ++int MIDI_GetVolume( void ); ++void MIDI_SetMidiFuncs( midifuncs *funcs ); ++void MIDI_SetContext( int context ); ++int MIDI_GetContext( void ); ++void MIDI_SetLoopFlag( int loopflag ); ++void MIDI_ContinueSong( void ); ++void MIDI_PauseSong( void ); ++int MIDI_SongPlaying( void ); ++void MIDI_StopSong( void ); ++int MIDI_PlaySong( unsigned char *song, int loopflag ); ++void MIDI_SetTempo( int tempo ); ++int MIDI_GetTempo( void ); ++void MIDI_SetSongTick( unsigned long PositionInTicks ); ++void MIDI_SetSongTime( unsigned long milliseconds ); ++void MIDI_SetSongPosition( int measure, int beat, int tick ); ++void MIDI_GetSongPosition( songposition *pos ); ++void MIDI_GetSongLength( songposition *pos ); ++void MIDI_LoadTimbres( void ); ++void MIDI_UnlockMemory( void ); ++int MIDI_LockMemory( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/mpu401.c trunk/rott/audiolib/mpu401.c +--- rott-1.0/rott/audiolib/mpu401.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/mpu401.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,451 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: MPU401.C ++ ++ author: James R. Dose ++ date: January 1, 1994 ++ ++ Low level routines to support sending of MIDI data to MPU401 ++ compatible MIDI interfaces. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include "dpmi.h" ++#include "user.h" ++#include "mpu401.h" ++ ++#define MIDI_NOTE_OFF 0x80 ++#define MIDI_NOTE_ON 0x90 ++#define MIDI_POLY_AFTER_TCH 0xA0 ++#define MIDI_CONTROL_CHANGE 0xB0 ++#define MIDI_PROGRAM_CHANGE 0xC0 ++#define MIDI_AFTER_TOUCH 0xD0 ++#define MIDI_PITCH_BEND 0xE0 ++#define MIDI_META_EVENT 0xFF ++#define MIDI_END_OF_TRACK 0x2F ++#define MIDI_TEMPO_CHANGE 0x51 ++#define MIDI_MONO_MODE_ON 0x7E ++#define MIDI_ALL_NOTES_OFF 0x7B ++ ++int MPU_BaseAddr = MPU_DefaultAddress; ++ ++//unsigned MPU_Delay = 500; ++//unsigned MPU_Delay = 5000; ++unsigned MPU_Delay = 0x5000; ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define MPU_LockStart MPU_SendMidi ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_SendMidi ++ ++ Sends a byte of MIDI data to the music device. ++---------------------------------------------------------------------*/ ++ ++void MPU_SendMidi ++ ( ++ int data ++ ) ++ ++ { ++ int port = MPU_BaseAddr + 1; ++ unsigned count; ++ ++ count = MPU_Delay; ++ while( count > 0 ) ++ { ++ // check if status port says we're ready for write ++ if ( !( inp( port ) & MPU_ReadyToWrite ) ) ++ { ++ break; ++ } ++ ++ count--; ++ } ++ ++ port--; ++ ++ // Send the midi data ++ outp( port, data ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_NoteOff ++ ++ Sends a full MIDI note off event out to the music device. ++---------------------------------------------------------------------*/ ++ ++void MPU_NoteOff ++ ( ++ int channel, ++ int key, ++ int velocity ++ ) ++ ++ { ++ MPU_SendMidi( MIDI_NOTE_OFF | channel ); ++ MPU_SendMidi( key ); ++ MPU_SendMidi( velocity ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_NoteOn ++ ++ Sends a full MIDI note on event out to the music device. ++---------------------------------------------------------------------*/ ++ ++void MPU_NoteOn ++ ( ++ int channel, ++ int key, ++ int velocity ++ ) ++ ++ { ++ MPU_SendMidi( MIDI_NOTE_ON | channel ); ++ MPU_SendMidi( key ); ++ MPU_SendMidi( velocity ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_PolyAftertouch ++ ++ Sends a full MIDI polyphonic aftertouch event out to the music device. ++---------------------------------------------------------------------*/ ++ ++void MPU_PolyAftertouch ++ ( ++ int channel, ++ int key, ++ int pressure ++ ) ++ ++ { ++ MPU_SendMidi( MIDI_POLY_AFTER_TCH | channel ); ++ MPU_SendMidi( key ); ++ MPU_SendMidi( pressure ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_ControlChange ++ ++ Sends a full MIDI control change event out to the music device. ++---------------------------------------------------------------------*/ ++ ++void MPU_ControlChange ++ ( ++ int channel, ++ int number, ++ int value ++ ) ++ ++ { ++ MPU_SendMidi( MIDI_CONTROL_CHANGE | channel ); ++ MPU_SendMidi( number ); ++ MPU_SendMidi( value ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_ProgramChange ++ ++ Sends a full MIDI program change event out to the music device. ++---------------------------------------------------------------------*/ ++ ++void MPU_ProgramChange ++ ( ++ int channel, ++ int program ++ ) ++ ++ { ++ MPU_SendMidi( MIDI_PROGRAM_CHANGE | channel ); ++ MPU_SendMidi( program ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_ChannelAftertouch ++ ++ Sends a full MIDI channel aftertouch event out to the music device. ++---------------------------------------------------------------------*/ ++ ++void MPU_ChannelAftertouch ++ ( ++ int channel, ++ int pressure ++ ) ++ ++ { ++ MPU_SendMidi( MIDI_AFTER_TOUCH | channel ); ++ MPU_SendMidi( pressure ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_PitchBend ++ ++ Sends a full MIDI pitch bend event out to the music device. ++---------------------------------------------------------------------*/ ++ ++void MPU_PitchBend ++ ( ++ int channel, ++ int lsb, ++ int msb ++ ) ++ ++ { ++ MPU_SendMidi( MIDI_PITCH_BEND | channel ); ++ MPU_SendMidi( lsb ); ++ MPU_SendMidi( msb ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_SendCommand ++ ++ Sends a command to the MPU401 card. ++---------------------------------------------------------------------*/ ++ ++void MPU_SendCommand ++ ( ++ int data ++ ) ++ ++ { ++ int port = MPU_BaseAddr + 1; ++ unsigned count; ++ ++ count = 0xffff; ++ while( count > 0 ) ++ { ++ // check if status port says we're ready for write ++ if ( !( inp( port ) & MPU_ReadyToWrite ) ) ++ { ++ break; ++ } ++ count--; ++ } ++ ++ outp( port, data ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_Reset ++ ++ Resets the MPU401 card. ++---------------------------------------------------------------------*/ ++ ++int MPU_Reset ++ ( ++ void ++ ) ++ ++ { ++ int port = MPU_BaseAddr + 1; ++ unsigned count; ++ ++ // Output "Reset" command via Command port ++ MPU_SendCommand( MPU_CmdReset ); ++ ++ // Wait for status port to be ready for read ++ count = 0xffff; ++ while( count > 0 ) ++ { ++ if ( !( inp( port ) & MPU_ReadyToRead ) ) ++ { ++ port--; ++ ++ // Check for a successful reset ++ if ( inp( port ) == MPU_CmdAcknowledge ) ++ { ++ return( MPU_Ok ); ++ } ++ ++ port++; ++ } ++ count--; ++ } ++ ++ // Failed to reset : MPU-401 not detected ++ return( MPU_NotFound ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_EnterUART ++ ++ Sets the MPU401 card to operate in UART mode. ++---------------------------------------------------------------------*/ ++ ++int MPU_EnterUART ++ ( ++ void ++ ) ++ ++ { ++ int port = MPU_BaseAddr + 1; ++ unsigned count; ++ ++ // Output "Enter UART" command via Command port ++ MPU_SendCommand( MPU_CmdEnterUART ); ++ ++ // Wait for status port to be ready for read ++ count = 0xffff; ++ while( count > 0 ) ++ { ++ if ( !( inp( port ) & MPU_ReadyToRead ) ) ++ { ++ port--; ++ ++ // Check for a successful reset ++ if ( inp( port ) == MPU_CmdAcknowledge ) ++ { ++ return( MPU_Ok ); ++ } ++ ++ port++; ++ } ++ count--; ++ } ++ ++ // Failed to reset : MPU-401 not detected ++ return( MPU_UARTFailed ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_Init ++ ++ Detects and initializes the MPU401 card. ++---------------------------------------------------------------------*/ ++ ++int MPU_Init ++ ( ++ int addr ++ ) ++ ++ { ++ int status; ++ int count; ++ char *ptr; ++ ++ ptr = USER_GetText( "MPUDELAY" ); ++ if ( ptr != NULL ) ++ { ++ MPU_Delay = ( unsigned )atol( ptr ); ++ } ++ ++ MPU_BaseAddr = addr; ++ ++ count = 4; ++ while( count > 0 ) ++ { ++ status = MPU_Reset(); ++ if ( status == MPU_Ok ) ++ { ++ return( MPU_EnterUART() ); ++ } ++ count--; ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void MPU_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_UnlockMemory ++ ++ Locks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++void MPU_UnlockMemory ++ ( ++ void ++ ) ++ ++ { ++ DPMI_UnlockMemoryRegion( MPU_LockStart, MPU_LockEnd ); ++ DPMI_Unlock( MPU_BaseAddr ); ++ DPMI_Unlock( MPU_Delay ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MPU_LockMemory ++ ++ Locks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++int MPU_LockMemory ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_LockMemoryRegion( MPU_LockStart, MPU_LockEnd ); ++ status |= DPMI_Lock( MPU_BaseAddr ); ++ status |= DPMI_Lock( MPU_Delay ); ++ ++ if ( status != DPMI_Ok ) ++ { ++ MPU_UnlockMemory(); ++ return( MPU_Error ); ++ } ++ ++ return( MPU_Ok ); ++ } +diff -urN rott-1.0/rott/audiolib/mpu401.h trunk/rott/audiolib/mpu401.h +--- rott-1.0/rott/audiolib/mpu401.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/mpu401.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,61 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++#ifndef __MPU401_H ++#define __MPU401_H ++ ++#define MPU_DefaultAddress 0x330 ++ ++enum MPU_ERRORS ++ { ++ MPU_Warning = -2, ++ MPU_Error = -1, ++ MPU_Ok = 0, ++ MPU_DPMI_Error ++ }; ++ ++#define MPU_NotFound -1 ++#define MPU_UARTFailed -2 ++ ++#define MPU_ReadyToWrite 0x40 ++#define MPU_ReadyToRead 0x80 ++#define MPU_CmdEnterUART 0x3f ++#define MPU_CmdReset 0xff ++#define MPU_CmdAcknowledge 0xfe ++ ++extern int MPU_BaseAddr; ++extern unsigned MPU_Delay; ++ ++void MPU_SendCommand( int data ); ++void MPU_SendMidi( int data ); ++int MPU_Reset( void ); ++int MPU_EnterUART( void ); ++int MPU_Init( int addr ); ++void MPU_ResetMidi( void ); ++void MPU_NoteOff( int channel, int key, int velocity ); ++void MPU_NoteOn( int channel, int key, int velocity ); ++void MPU_PolyAftertouch( int channel, int key, int pressure ); ++void MPU_ControlChange( int channel, int number, int value ); ++void MPU_ProgramChange( int channel, int program ); ++void MPU_ChannelAftertouch( int channel, int pressure ); ++void MPU_PitchBend( int channel, int lsb, int msb ); ++void MPU_UnlockMemory( void ); ++int MPU_LockMemory( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/multivoc.c trunk/rott/audiolib/multivoc.c +--- rott-1.0/rott/audiolib/multivoc.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/multivoc.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,3555 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: MULTIVOC.C ++ ++ author: James R. Dose ++ date: December 20, 1993 ++ ++ Routines to provide multichannel digitized sound playback for ++ Sound Blaster compatible sound cards. ++ ++ (c) Copyright 1993 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef PLAT_DOS ++#include ++#include ++#endif ++ ++#include "util.h" ++#include "dpmi.h" ++#include "usrhooks.h" ++#include "interrup.h" ++#include "dma.h" ++#include "linklist.h" ++#include "sndcards.h" ++ ++#ifdef PLAT_DOS ++#include "blaster.h" ++#include "sndscape.h" ++#include "sndsrc.h" ++#include "pas16.h" ++#include "guswave.h" ++#else ++#include "dsl.h" ++#endif ++ ++#include "pitch.h" ++#include "multivoc.h" ++#include "_multivc.h" ++#include "debugio.h" ++ ++#define RoundFixed( fixedval, bits ) \ ++ ( \ ++ ( \ ++ (fixedval) + ( 1 << ( (bits) - 1 ) )\ ++ ) >> (bits) \ ++ ) ++ ++#define IS_QUIET( ptr ) ( ( void * )( ptr ) == ( void * )&MV_VolumeTable[ 0 ] ) ++ ++static int MV_ReverbLevel; ++static int MV_ReverbDelay; ++static VOLUME16 *MV_ReverbTable = NULL; ++ ++//static signed short MV_VolumeTable[ MV_MaxVolume + 1 ][ 256 ]; ++static signed short MV_VolumeTable[ 63 + 1 ][ 256 ]; ++ ++//static Pan MV_PanTable[ MV_NumPanPositions ][ MV_MaxVolume + 1 ]; ++static Pan MV_PanTable[ MV_NumPanPositions ][ 63 + 1 ]; ++ ++static int MV_Installed = FALSE; ++static int MV_SoundCard = SoundBlaster; ++static int MV_TotalVolume = MV_MaxTotalVolume; ++static int MV_MaxVoices = 1; ++static int MV_Recording; ++ ++static int MV_BufferSize = MixBufferSize; ++static int MV_BufferLength; ++ ++static int MV_NumberOfBuffers = NumberOfBuffers; ++ ++static int MV_MixMode = MONO_8BIT; ++static int MV_Channels = 1; ++static int MV_Bits = 8; ++ ++static int MV_Silence = SILENCE_8BIT; ++static int MV_SwapLeftRight = FALSE; ++ ++static int MV_RequestedMixRate; ++static int MV_MixRate; ++ ++static int MV_DMAChannel = -1; ++static int MV_BuffShift; ++ ++static int MV_TotalMemory; ++ ++static int MV_BufferDescriptor; ++static int MV_BufferEmpty[ NumberOfBuffers ]; ++char *MV_MixBuffer[ NumberOfBuffers + 1 ]; ++ ++static VoiceNode *MV_Voices = NULL; ++ ++static volatile VoiceNode VoiceList; ++static volatile VoiceNode VoicePool; ++ ++/*static*/ int MV_MixPage = 0; ++static int MV_VoiceHandle = MV_MinVoiceHandle; ++ ++static void ( *MV_CallBackFunc )( unsigned long ) = NULL; ++static void ( *MV_RecordFunc )( char *ptr, int length ) = NULL; ++static void ( *MV_MixFunction )( VoiceNode *voice, int buffer ); ++ ++static int MV_MaxVolume = 63; ++ ++char *MV_HarshClipTable; ++char *MV_MixDestination; ++short *MV_LeftVolume; ++short *MV_RightVolume; ++int MV_SampleSize = 1; ++int MV_RightChannelOffset; ++ ++unsigned long MV_MixPosition; ++ ++int MV_ErrorCode = MV_Ok; ++ ++#define MV_SetErrorCode( status ) \ ++ MV_ErrorCode = ( status ); ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *MV_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case MV_Warning : ++ case MV_Error : ++ ErrorString = MV_ErrorString( MV_ErrorCode ); ++ break; ++ ++ case MV_Ok : ++ ErrorString = "Multivoc ok."; ++ break; ++ ++ case MV_UnsupportedCard : ++ ErrorString = "Selected sound card is not supported by Multivoc."; ++ break; ++ ++ case MV_NotInstalled : ++ ErrorString = "Multivoc not installed."; ++ break; ++ ++ case MV_NoVoices : ++ ErrorString = "No free voices available to Multivoc."; ++ break; ++ ++ case MV_NoMem : ++ ErrorString = "Out of memory in Multivoc."; ++ break; ++ ++ case MV_VoiceNotFound : ++ ErrorString = "No voice with matching handle found."; ++ break; ++ ++#ifdef PLAT_DOS ++ case MV_BlasterError : ++ ErrorString = BLASTER_ErrorString( BLASTER_Error ); ++ break; ++ ++ case MV_PasError : ++ ErrorString = PAS_ErrorString( PAS_Error ); ++ break; ++ ++ case MV_SoundScapeError : ++ ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_Error ); ++ break; ++ ++ #ifndef SOUNDSOURCE_OFF ++ case MV_SoundSourceError : ++ ErrorString = SS_ErrorString( SS_Error ); ++ break; ++ #endif ++#endif ++ ++ case MV_DPMI_Error : ++ ErrorString = "DPMI Error in Multivoc."; ++ break; ++ ++ case MV_InvalidVOCFile : ++ ErrorString = "Invalid VOC file passed in to Multivoc."; ++ break; ++ ++ case MV_InvalidWAVFile : ++ ErrorString = "Invalid WAV file passed in to Multivoc."; ++ break; ++ ++ case MV_InvalidMixMode : ++ ErrorString = "Invalid mix mode request in Multivoc."; ++ break; ++ ++ case MV_SoundSourceFailure : ++ ErrorString = "Sound Source playback failed."; ++ break; ++ ++ case MV_IrqFailure : ++ ErrorString = "Playback failed, possibly due to an invalid or conflicting IRQ."; ++ break; ++ ++ case MV_DMAFailure : ++ ErrorString = "Playback failed, possibly due to an invalid or conflicting DMA channel."; ++ break; ++ ++ case MV_DMA16Failure : ++ ErrorString = "Playback failed, possibly due to an invalid or conflicting DMA channel. \n" ++ "Make sure the 16-bit DMA channel is correct."; ++ break; ++ ++ case MV_NullRecordFunction : ++ ErrorString = "Null record function passed to MV_StartRecording."; ++ break; ++ ++ default : ++ ErrorString = "Unknown Multivoc error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define MV_LockStart MV_Mix ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_Mix ++ ++ Mixes the sound into the buffer. ++---------------------------------------------------------------------*/ ++ ++static void MV_Mix ++ ( ++ VoiceNode *voice, ++ int buffer ++ ) ++ ++ { ++ char *start; ++ int length; ++ long voclength; ++ unsigned long position; ++ unsigned long rate; ++ unsigned long FixedPointBufferSize; ++ ++ if ( ( voice->length == 0 ) && ++ ( voice->GetSound != NULL ) && ++ ( voice->GetSound( voice ) != KeepPlaying ) ) ++ { ++ return; ++ } ++ ++ length = MixBufferSize; ++ FixedPointBufferSize = voice->FixedPointBufferSize; ++ ++ MV_MixDestination = MV_MixBuffer[ buffer ]; ++ MV_LeftVolume = voice->LeftVolume; ++ MV_RightVolume = voice->RightVolume; ++ ++ if ( ( MV_Channels == 2 ) && ( IS_QUIET( MV_LeftVolume ) ) ) ++ { ++ MV_LeftVolume = MV_RightVolume; ++ MV_MixDestination += MV_RightChannelOffset; ++ } ++ ++ // Add this voice to the mix ++ while( length > 0 ) ++ { ++ start = voice->sound; ++ rate = voice->RateScale; ++ position = voice->position; ++ ++ // Check if the last sample in this buffer would be ++ // beyond the length of the sample block ++ if ( ( position + FixedPointBufferSize ) >= voice->length ) ++ { ++ if ( position < voice->length ) ++ { ++ voclength = ( voice->length - position + rate - 1 ) / rate; ++ } ++ else ++ { ++ voice->GetSound( voice ); ++ return; ++ } ++ } ++ else ++ { ++ voclength = length; ++ } ++ ++ voice->mix( position, rate, start, voclength ); ++ ++ if ( voclength & 1 ) ++ { ++ MV_MixPosition += rate; ++ voclength -= 1; ++ } ++ voice->position = MV_MixPosition; ++ ++ length -= voclength; ++ ++ if ( voice->position >= voice->length ) ++ { ++ // Get the next block of sound ++ if ( voice->GetSound( voice ) != KeepPlaying ) ++ { ++ return; ++ } ++ ++ if ( length > 0 ) ++ { ++ // Get the position of the last sample in the buffer ++ FixedPointBufferSize = voice->RateScale * ( length - 1 ); ++ } ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayVoice ++ ++ Adds a voice to the play list. ++---------------------------------------------------------------------*/ ++ ++void MV_PlayVoice ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ LL_SortedInsertion( &VoiceList, voice, prev, next, VoiceNode, priority ); ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StopVoice ++ ++ Removes the voice from the play list and adds it to the free list. ++---------------------------------------------------------------------*/ ++ ++void MV_StopVoice ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ // move the voice from the play list to the free list ++ LL_Remove( voice, next, prev ); ++ LL_Add( (VoiceNode *)&VoicePool, voice, next, prev ); ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_ServiceVoc ++ ++ Starts playback of the waiting buffer and mixes the next one. ++---------------------------------------------------------------------*/ ++ ++// static int backcolor = 1; ++ ++void MV_ServiceVoc ++ ( ++ void ++ ) ++ ++ { ++ VoiceNode *voice; ++ VoiceNode *next; ++ char *buffer; ++ ++#ifdef PLAT_DOS ++ if ( MV_DMAChannel >= 0 ) ++ { ++ // Get the currently playing buffer ++ buffer = ( char * )DMA_GetCurrentPos( MV_DMAChannel ); ++ MV_MixPage = ( unsigned )( buffer - MV_MixBuffer[ 0 ] ); ++ MV_MixPage >>= MV_BuffShift; ++ } ++#endif ++ ++ // Toggle which buffer we'll mix next ++ MV_MixPage++; ++ if ( MV_MixPage >= MV_NumberOfBuffers ) ++ { ++ MV_MixPage -= MV_NumberOfBuffers; ++ } ++ ++ if ( MV_ReverbLevel == 0 ) ++ { ++ // Initialize buffer ++ //Commented out so that the buffer is always cleared. ++ //This is so the guys at Echo Speech can mix into the ++ //buffer even when no sounds are playing. ++ //if ( !MV_BufferEmpty[ MV_MixPage ] ) ++ { ++ ClearBuffer_DW( MV_MixBuffer[ MV_MixPage ], MV_Silence, MV_BufferSize >> 2 ); ++ if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) ++ { ++ ClearBuffer_DW( MV_MixBuffer[ MV_MixPage ] + MV_RightChannelOffset, ++ MV_Silence, MV_BufferSize >> 2 ); ++ } ++ MV_BufferEmpty[ MV_MixPage ] = TRUE; ++ } ++ } ++ else ++ { ++ char *end; ++ char *source; ++ char *dest; ++ int count; ++ int length; ++ ++ end = MV_MixBuffer[ 0 ] + MV_BufferLength;; ++ dest = MV_MixBuffer[ MV_MixPage ]; ++ source = MV_MixBuffer[ MV_MixPage ] - MV_ReverbDelay; ++ if ( source < MV_MixBuffer[ 0 ] ) ++ { ++ source += MV_BufferLength; ++ } ++ ++ length = MV_BufferSize; ++ while( length > 0 ) ++ { ++ count = length; ++ if ( source + count > end ) ++ { ++ count = end - source; ++ } ++ ++ if ( MV_Bits == 16 ) ++ { ++ if ( MV_ReverbTable != NULL ) ++ { ++ MV_16BitReverb( source, dest, (const VOLUME16 *)MV_ReverbTable, count / 2 ); ++ if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) ++ { ++ MV_16BitReverb( source + MV_RightChannelOffset, ++ dest + MV_RightChannelOffset, (const VOLUME16 *)MV_ReverbTable, count / 2 ); ++ } ++ } ++ else ++ { ++ MV_16BitReverbFast( source, dest, count / 2, MV_ReverbLevel ); ++ if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) ++ { ++ MV_16BitReverbFast( source + MV_RightChannelOffset, ++ dest + MV_RightChannelOffset, count / 2, MV_ReverbLevel ); ++ } ++ } ++ } ++ else ++ { ++ if ( MV_ReverbTable != NULL ) ++ { ++ MV_8BitReverb( source, dest, (const VOLUME16 *)MV_ReverbTable, count ); ++ if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) ++ { ++ MV_8BitReverb( source + MV_RightChannelOffset, ++ dest + MV_RightChannelOffset, (const VOLUME16 *)MV_ReverbTable, count ); ++ } ++ } ++ else ++ { ++ MV_8BitReverbFast( source, dest, count, MV_ReverbLevel ); ++ if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) ++ { ++ MV_8BitReverbFast( source + MV_RightChannelOffset, ++ dest + MV_RightChannelOffset, count, MV_ReverbLevel ); ++ } ++ } ++ } ++ ++ // if we go through the loop again, it means that we've wrapped around the buffer ++ source = MV_MixBuffer[ 0 ]; ++ dest += count; ++ length -= count; ++ } ++ } ++ ++ // Play any waiting voices ++ for( voice = VoiceList.next; voice != &VoiceList; voice = next ) ++ { ++// if ( ( voice < &MV_Voices[ 0 ] ) || ( voice > &MV_Voices[ 8 ] ) ) ++// { ++// SetBorderColor(backcolor++); ++// break; ++// } ++ ++ MV_BufferEmpty[ MV_MixPage ] = FALSE; ++ ++ MV_MixFunction( voice, MV_MixPage ); ++ ++ next = voice->next; ++ ++ // Is this voice done? ++ if ( !voice->Playing ) ++ { ++ MV_StopVoice( voice ); ++ ++ if ( MV_CallBackFunc ) ++ { ++ MV_CallBackFunc( voice->callbackval ); ++ } ++ } ++ } ++ } ++ ++ ++int leftpage = -1; ++int rightpage = -1; ++ ++void MV_ServiceGus( char **ptr, unsigned long *length ) ++ { ++ if ( leftpage == MV_MixPage ) ++ { ++ MV_ServiceVoc(); ++ } ++ ++ leftpage = MV_MixPage; ++ ++ *ptr = MV_MixBuffer[ MV_MixPage ]; ++ *length = MV_BufferSize; ++ } ++ ++void MV_ServiceRightGus( char **ptr, unsigned long *length ) ++ { ++ if ( rightpage == MV_MixPage ) ++ { ++ MV_ServiceVoc(); ++ } ++ ++ rightpage = MV_MixPage; ++ ++ *ptr = MV_MixBuffer[ MV_MixPage ] + MV_RightChannelOffset; ++ *length = MV_BufferSize; ++ } ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetNextVOCBlock ++ ++ Interperate the information of a VOC format sound file. ++---------------------------------------------------------------------*/ ++static __inline unsigned int get_le32(void *p0) ++{ ++ //unsigned char *p = p0; ++ //return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); ++ unsigned int val = *((unsigned int *) p0); ++ return(BUILDSWAP_INTEL32(val)); ++} ++ ++static __inline unsigned int get_le16(void *p0) ++{ ++ //unsigned char *p = p0; ++ //return p[0] | (p[1]<<8); ++ unsigned short val = *((unsigned short *) p0); ++ return( (unsigned int) (BUILDSWAP_INTEL16(val)) ); ++} ++ ++playbackstatus MV_GetNextVOCBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ unsigned char *ptr; ++ int blocktype=0; ++ int lastblocktype=0; ++ unsigned long blocklength=0l; ++ unsigned long samplespeed=0l; ++ unsigned int tc=0; ++ int packtype=0; ++ int voicemode=0; ++ int done=0; ++ unsigned BitsPerSample; ++ unsigned Channels; ++ unsigned Format; ++ ++ if ( voice->BlockLength > 0 ) ++ { ++ voice->position -= voice->length; ++ voice->sound += voice->length >> 16; ++ if ( voice->bits == 16 ) ++ { ++ voice->sound += voice->length >> 16; ++ } ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ return( KeepPlaying ); ++ } ++ ++ if ( ( voice->length > 0 ) && ( voice->LoopEnd != NULL ) && ++ ( voice->LoopStart != NULL ) ) ++ { ++ voice->BlockLength = voice->LoopSize; ++ voice->sound = voice->LoopStart; ++ voice->position = 0; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ return( KeepPlaying ); ++ } ++ ++ ptr = ( unsigned char * )voice->NextBlock; ++ ++ voice->Playing = TRUE; ++ ++ voicemode = 0; ++ lastblocktype = 0; ++ packtype = 0; ++ ++ done = FALSE; ++ while( !done ) ++ { ++ // Stop playing if we get a NULL pointer ++ if ( ptr == NULL ) ++ { ++ voice->Playing = FALSE; ++ done = TRUE; ++ break; ++ } ++ ++ { ++ unsigned tmp = get_le32(ptr); ++ blocktype = tmp&255; ++ blocklength = tmp>>8; ++ } ++ ptr += 4; ++ ++ switch( blocktype ) ++ { ++ case 0 : ++ // End of data ++ if ( ( voice->LoopStart == NULL ) || ++ ( (unsigned char *)voice->LoopStart >= ( ptr - 4 ) ) ) ++ { ++ voice->Playing = FALSE; ++ done = TRUE; ++ } ++ else ++ { ++ voice->BlockLength = ( ptr - 4 ) - (unsigned char *)voice->LoopStart; ++ voice->sound = voice->LoopStart; ++ voice->position = 0; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ return( KeepPlaying ); ++ } ++ break; ++ ++ case 1 : ++ // Sound data block ++ voice->bits = 8; ++ if ( lastblocktype != 8 ) ++ { ++ tc = ( unsigned int )*ptr << 8; ++ packtype = *( ptr + 1 ); ++ } ++ ++ ptr += 2; ++ blocklength -= 2; ++ ++ samplespeed = 256000000L / ( 65536 - tc ); ++ ++ // Skip packed or stereo data ++ if ( ( packtype != 0 ) || ( voicemode != 0 ) ) ++ { ++ ptr += blocklength; ++ } ++ else ++ { ++ done = TRUE; ++ } ++ voicemode = 0; ++ break; ++ ++ case 2 : ++ // Sound continuation block ++ samplespeed = voice->SamplingRate; ++ done = TRUE; ++ break; ++ ++ case 3 : ++ // Silence ++ // Not implimented. ++ ptr += blocklength; ++ break; ++ ++ case 4 : ++ // Marker ++ // Not implimented. ++ ptr += blocklength; ++ break; ++ ++ case 5 : ++ // ASCII string ++ // Not implimented. ++ ptr += blocklength; ++ break; ++ ++ case 6 : ++ // Repeat begin ++ if ( voice->LoopEnd == NULL ) ++ { ++ voice->LoopCount = get_le16(ptr); ++ voice->LoopStart = ptr + blocklength; ++ } ++ ptr += blocklength; ++ break; ++ ++ case 7 : ++ // Repeat end ++ ptr += blocklength; ++ if ( lastblocktype == 6 ) ++ { ++ voice->LoopCount = 0; ++ } ++ else ++ { ++ if ( ( voice->LoopCount > 0 ) && ( voice->LoopStart != NULL ) ) ++ { ++ ptr = voice->LoopStart; ++ if ( voice->LoopCount < 0xffff ) ++ { ++ voice->LoopCount--; ++ if ( voice->LoopCount == 0 ) ++ { ++ voice->LoopStart = NULL; ++ } ++ } ++ } ++ } ++ break; ++ ++ case 8 : ++ // Extended block ++ voice->bits = 8; ++ tc = get_le16(ptr); ++ packtype = *( ptr + 2 ); ++ voicemode = *( ptr + 3 ); ++ ptr += blocklength; ++ break; ++ ++ case 9 : ++ // New sound data block ++ samplespeed = get_le32(ptr); ++ BitsPerSample = ptr[4]; ++ Channels = ptr[5]; ++ Format = get_le16(ptr+6); ++ ++ if ( ( BitsPerSample == 8 ) && ( Channels == 1 ) && ++ ( Format == VOC_8BIT ) ) ++ { ++ ptr += 12; ++ blocklength -= 12; ++ voice->bits = 8; ++ done = TRUE; ++ } ++ else if ( ( BitsPerSample == 16 ) && ( Channels == 1 ) && ++ ( Format == VOC_16BIT ) ) ++ { ++ ptr += 12; ++ blocklength -= 12; ++ voice->bits = 16; ++ done = TRUE; ++ } ++ else ++ { ++ ptr += blocklength; ++ } ++ break; ++ ++ default : ++ // Unknown data. Probably not a VOC file. ++ voice->Playing = FALSE; ++ done = TRUE; ++ break; ++ } ++ ++ lastblocktype = blocktype; ++ } ++ ++ if ( voice->Playing ) ++ { ++ voice->NextBlock = ptr + blocklength; ++ voice->sound = ptr; ++ ++ voice->SamplingRate = samplespeed; ++ voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate; ++ ++ // Multiply by MixBufferSize - 1 ++ voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) - ++ voice->RateScale; ++ ++ if ( voice->LoopEnd != NULL ) ++ { ++ if ( blocklength > ( unsigned long )voice->LoopEnd ) ++ { ++ blocklength = ( unsigned long )voice->LoopEnd; ++ } ++ else ++ { ++ voice->LoopEnd = ( char * )blocklength; ++ } ++ ++ voice->LoopStart = voice->sound + ( unsigned long )voice->LoopStart; ++ voice->LoopEnd = voice->sound + ( unsigned long )voice->LoopEnd; ++ voice->LoopSize = voice->LoopEnd - voice->LoopStart; ++ } ++ ++ if ( voice->bits == 16 ) ++ { ++ blocklength /= 2; ++ } ++ ++ voice->position = 0; ++ voice->length = min( blocklength, 0x8000 ); ++ voice->BlockLength = blocklength - voice->length; ++ voice->length <<= 16; ++ ++ MV_SetVoiceMixMode( voice ); ++ ++ return( KeepPlaying ); ++ } ++ ++ return( NoMoreData ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetNextDemandFeedBlock ++ ++ Controls playback of demand fed data. ++---------------------------------------------------------------------*/ ++ ++playbackstatus MV_GetNextDemandFeedBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ if ( voice->BlockLength > 0 ) ++ { ++ voice->position -= voice->length; ++ voice->sound += voice->length >> 16; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ ++ return( KeepPlaying ); ++ } ++ ++ if ( voice->DemandFeed == NULL ) ++ { ++ return( NoMoreData ); ++ } ++ ++ voice->position = 0; ++ ( voice->DemandFeed )( &voice->sound, &voice->BlockLength ); ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ ++ if ( ( voice->length > 0 ) && ( voice->sound != NULL ) ) ++ { ++ return( KeepPlaying ); ++ } ++ return( NoMoreData ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetNextRawBlock ++ ++ Controls playback of demand fed data. ++---------------------------------------------------------------------*/ ++ ++playbackstatus MV_GetNextRawBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ if ( voice->BlockLength <= 0 ) ++ { ++ if ( voice->LoopStart == NULL ) ++ { ++ voice->Playing = FALSE; ++ return( NoMoreData ); ++ } ++ ++ voice->BlockLength = voice->LoopSize; ++ voice->NextBlock = voice->LoopStart; ++ voice->length = 0; ++ voice->position = 0; ++ } ++ ++ voice->sound = voice->NextBlock; ++ voice->position -= voice->length; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->NextBlock += voice->length; ++ if ( voice->bits == 16 ) ++ { ++ voice->NextBlock += voice->length; ++ } ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ ++ return( KeepPlaying ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetNextWAVBlock ++ ++ Controls playback of demand fed data. ++---------------------------------------------------------------------*/ ++ ++playbackstatus MV_GetNextWAVBlock ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ if ( voice->BlockLength <= 0 ) ++ { ++ if ( voice->LoopStart == NULL ) ++ { ++ voice->Playing = FALSE; ++ return( NoMoreData ); ++ } ++ ++ voice->BlockLength = voice->LoopSize; ++ voice->NextBlock = voice->LoopStart; ++ voice->length = 0; ++ voice->position = 0; ++ } ++ ++ voice->sound = voice->NextBlock; ++ voice->position -= voice->length; ++ voice->length = min( voice->BlockLength, 0x8000 ); ++ voice->NextBlock += voice->length; ++ if ( voice->bits == 16 ) ++ { ++ voice->NextBlock += voice->length; ++ } ++ voice->BlockLength -= voice->length; ++ voice->length <<= 16; ++ ++ return( KeepPlaying ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_ServiceRecord ++ ++ Starts recording of the waiting buffer. ++---------------------------------------------------------------------*/ ++ ++static void MV_ServiceRecord ++ ( ++ void ++ ) ++ ++ { ++ if ( MV_RecordFunc ) ++ { ++ MV_RecordFunc( MV_MixBuffer[ 0 ] + MV_MixPage * MixBufferSize, ++ MixBufferSize ); ++ } ++ ++ // Toggle which buffer we'll mix next ++ MV_MixPage++; ++ if ( MV_MixPage >= NumberOfBuffers ) ++ { ++ MV_MixPage = 0; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetVoice ++ ++ Locates the voice with the specified handle. ++---------------------------------------------------------------------*/ ++ ++VoiceNode *MV_GetVoice ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ for( voice = VoiceList.next; voice != &VoiceList; voice = voice->next ) ++ { ++ if ( handle == voice->handle ) ++ { ++ break; ++ } ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( voice == &VoiceList ) ++ { ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ ++ // SBF - should this return null? ++ return NULL; ++ } ++ ++ return( voice ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_VoicePlaying ++ ++ Checks if the voice associated with the specified handle is ++ playing. ++---------------------------------------------------------------------*/ ++ ++int MV_VoicePlaying ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( FALSE ); ++ } ++ ++ voice = MV_GetVoice( handle ); ++ ++ if ( voice == NULL ) ++ { ++ return( FALSE ); ++ } ++ ++ return( TRUE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_KillAllVoices ++ ++ Stops output of all currently active voices. ++---------------------------------------------------------------------*/ ++ ++int MV_KillAllVoices ++ ( ++ void ++ ) ++ ++ { ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ // Remove all the voices from the list ++ while( VoiceList.next != &VoiceList ) ++ { ++ MV_Kill( VoiceList.next->handle ); ++ } ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_Kill ++ ++ Stops output of the voice associated with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int MV_Kill ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ unsigned flags; ++ unsigned long callbackval; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ voice = MV_GetVoice( handle ); ++ if ( voice == NULL ) ++ { ++ RestoreInterrupts( flags ); ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ return( MV_Error ); ++ } ++ ++ callbackval = voice->callbackval; ++ ++ MV_StopVoice( voice ); ++ ++ RestoreInterrupts( flags ); ++ ++ if ( MV_CallBackFunc ) ++ { ++ MV_CallBackFunc( callbackval ); ++ } ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_VoicesPlaying ++ ++ Determines the number of currently active voices. ++---------------------------------------------------------------------*/ ++ ++int MV_VoicesPlaying ++ ( ++ void ++ ) ++ ++ { ++ VoiceNode *voice; ++ int NumVoices = 0; ++ unsigned flags; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( 0 ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ for( voice = VoiceList.next; voice != &VoiceList; voice = voice->next ) ++ { ++ NumVoices++; ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ return( NumVoices ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_AllocVoice ++ ++ Retrieve an inactive or lower priority voice for output. ++---------------------------------------------------------------------*/ ++ ++VoiceNode *MV_AllocVoice ++ ( ++ int priority ++ ) ++ ++ { ++ VoiceNode *voice; ++ VoiceNode *node; ++ unsigned flags; ++ ++//return( NULL ); ++ if ( MV_Recording ) ++ { ++ return( NULL ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ // Check if we have any free voices ++ if ( LL_Empty( &VoicePool, next, prev ) ) ++ { ++ // check if we have a higher priority than a voice that is playing. ++ voice = VoiceList.next; ++ for( node = voice->next; node != &VoiceList; node = node->next ) ++ { ++ if ( node->priority < voice->priority ) ++ { ++ voice = node; ++ } ++ } ++ ++ if ( priority >= voice->priority ) ++ { ++ MV_Kill( voice->handle ); ++ } ++ } ++ ++ // Check if any voices are in the voice pool ++ if ( LL_Empty( &VoicePool, next, prev ) ) ++ { ++ // No free voices ++ RestoreInterrupts( flags ); ++ return( NULL ); ++ } ++ ++ voice = VoicePool.next; ++ LL_Remove( voice, next, prev ); ++ RestoreInterrupts( flags ); ++ ++ // Find a free voice handle ++ do ++ { ++ MV_VoiceHandle++; ++ if ( MV_VoiceHandle < MV_MinVoiceHandle ) ++ { ++ MV_VoiceHandle = MV_MinVoiceHandle; ++ } ++ } ++ while( MV_VoicePlaying( MV_VoiceHandle ) ); ++ ++ voice->handle = MV_VoiceHandle; ++ ++ return( voice ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_VoiceAvailable ++ ++ Checks if a voice can be play at the specified priority. ++---------------------------------------------------------------------*/ ++ ++int MV_VoiceAvailable ++ ( ++ int priority ++ ) ++ ++ { ++ VoiceNode *voice; ++ VoiceNode *node; ++ unsigned flags; ++ ++ // Check if we have any free voices ++ if ( !LL_Empty( &VoicePool, next, prev ) ) ++ { ++ return( TRUE ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ // check if we have a higher priority than a voice that is playing. ++ voice = VoiceList.next; ++ for( node = VoiceList.next; node != &VoiceList; node = node->next ) ++ { ++ if ( node->priority < voice->priority ) ++ { ++ voice = node; ++ } ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( ( voice != &VoiceList ) && ( priority >= voice->priority ) ) ++ { ++ return( TRUE ); ++ } ++ ++ return( FALSE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetVoicePitch ++ ++ Sets the pitch for the specified voice. ++---------------------------------------------------------------------*/ ++ ++void MV_SetVoicePitch ++ ( ++ VoiceNode *voice, ++ unsigned long rate, ++ int pitchoffset ++ ) ++ ++ { ++ voice->SamplingRate = rate; ++ voice->PitchScale = PITCH_GetScale( pitchoffset ); ++ voice->RateScale = ( rate * voice->PitchScale ) / MV_MixRate; ++ ++ // Multiply by MixBufferSize - 1 ++ voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) - ++ voice->RateScale; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetPitch ++ ++ Sets the pitch for the voice associated with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int MV_SetPitch ++ ( ++ int handle, ++ int pitchoffset ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ voice = MV_GetVoice( handle ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ return( MV_Error ); ++ } ++ ++ MV_SetVoicePitch( voice, voice->SamplingRate, pitchoffset ); ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetFrequency ++ ++ Sets the frequency for the voice associated with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int MV_SetFrequency ++ ( ++ int handle, ++ int frequency ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ voice = MV_GetVoice( handle ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ return( MV_Error ); ++ } ++ ++ MV_SetVoicePitch( voice, frequency, 0 ); ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetVolumeTable ++ ++ Returns a pointer to the volume table associated with the specified ++ volume. ++---------------------------------------------------------------------*/ ++ ++static short *MV_GetVolumeTable ++ ( ++ int vol ++ ) ++ ++ { ++ int volume; ++ short *table; ++ ++ volume = MIX_VOLUME( vol ); ++ ++ table = (short *)&MV_VolumeTable[ volume ]; ++ ++ return( table ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetVoiceMixMode ++ ++ Selects which method should be used to mix the voice. ++---------------------------------------------------------------------*/ ++ ++static void MV_SetVoiceMixMode ++ ( ++ VoiceNode *voice ++ ) ++ ++ { ++ unsigned flags; ++ int test; ++ ++ flags = DisableInterrupts(); ++ ++ test = T_DEFAULT; ++ if ( MV_Bits == 8 ) ++ { ++ test |= T_8BITS; ++ } ++ ++ if ( voice->bits == 16 ) ++ { ++ test |= T_16BITSOURCE; ++ } ++ ++ if ( MV_Channels == 1 ) ++ { ++ test |= T_MONO; ++ } ++ else ++ { ++ if ( IS_QUIET( voice->RightVolume ) ) ++ { ++ test |= T_RIGHTQUIET; ++ } ++ else if ( IS_QUIET( voice->LeftVolume ) ) ++ { ++ test |= T_LEFTQUIET; ++ } ++ } ++ ++ // Default case ++ voice->mix = MV_Mix8BitMono; ++ ++ switch( test ) ++ { ++ case T_8BITS | T_MONO | T_16BITSOURCE : ++ voice->mix = MV_Mix8BitMono16; ++ break; ++ ++ case T_8BITS | T_MONO : ++ voice->mix = MV_Mix8BitMono; ++ break; ++ ++ case T_8BITS | T_16BITSOURCE | T_LEFTQUIET : ++ MV_LeftVolume = MV_RightVolume; ++ voice->mix = MV_Mix8BitMono16; ++ break; ++ ++ case T_8BITS | T_LEFTQUIET : ++ MV_LeftVolume = MV_RightVolume; ++ voice->mix = MV_Mix8BitMono; ++ break; ++ ++ case T_8BITS | T_16BITSOURCE | T_RIGHTQUIET : ++ voice->mix = MV_Mix8BitMono16; ++ break; ++ ++ case T_8BITS | T_RIGHTQUIET : ++ voice->mix = MV_Mix8BitMono; ++ break; ++ ++ case T_8BITS | T_16BITSOURCE : ++ voice->mix = MV_Mix8BitStereo16; ++ break; ++ ++ case T_8BITS : ++ voice->mix = MV_Mix8BitStereo; ++ break; ++ ++ case T_MONO | T_16BITSOURCE : ++ voice->mix = MV_Mix16BitMono16; ++ break; ++ ++ case T_MONO : ++ voice->mix = MV_Mix16BitMono; ++ break; ++ ++ case T_16BITSOURCE | T_LEFTQUIET : ++ MV_LeftVolume = MV_RightVolume; ++ voice->mix = MV_Mix16BitMono16; ++ break; ++ ++ case T_LEFTQUIET : ++ MV_LeftVolume = MV_RightVolume; ++ voice->mix = MV_Mix16BitMono; ++ break; ++ ++ case T_16BITSOURCE | T_RIGHTQUIET : ++ voice->mix = MV_Mix16BitMono16; ++ break; ++ ++ case T_RIGHTQUIET : ++ voice->mix = MV_Mix16BitMono; ++ break; ++ ++ case T_16BITSOURCE : ++ voice->mix = MV_Mix16BitStereo16; ++ break; ++ ++ case T_SIXTEENBIT_STEREO : ++ voice->mix = MV_Mix16BitStereo; ++ break; ++ ++ default : ++ voice->mix = MV_Mix8BitMono; ++ } ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetVoiceVolume ++ ++ Sets the stereo and mono volume level of the voice associated ++ with the specified handle. ++---------------------------------------------------------------------*/ ++ ++void MV_SetVoiceVolume ++ ( ++ VoiceNode *voice, ++ int vol, ++ int left, ++ int right ++ ) ++ ++ { ++ if ( MV_Channels == 1 ) ++ { ++ left = vol; ++ right = vol; ++ } ++ ++ if ( MV_SwapLeftRight ) ++ { ++ // SBPro uses reversed panning ++ voice->LeftVolume = MV_GetVolumeTable( right ); ++ voice->RightVolume = MV_GetVolumeTable( left ); ++ } ++ else ++ { ++ voice->LeftVolume = MV_GetVolumeTable( left ); ++ voice->RightVolume = MV_GetVolumeTable( right ); ++ } ++ ++ MV_SetVoiceMixMode( voice ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_EndLooping ++ ++ Stops the voice associated with the specified handle from looping ++ without stoping the sound. ++---------------------------------------------------------------------*/ ++ ++int MV_EndLooping ++ ( ++ int handle ++ ) ++ ++ { ++ VoiceNode *voice; ++ unsigned flags; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ voice = MV_GetVoice( handle ); ++ if ( voice == NULL ) ++ { ++ RestoreInterrupts( flags ); ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ return( MV_Warning ); ++ } ++ ++ voice->LoopCount = 0; ++ voice->LoopStart = NULL; ++ voice->LoopEnd = NULL; ++ ++ RestoreInterrupts( flags ); ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetPan ++ ++ Sets the stereo and mono volume level of the voice associated ++ with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int MV_SetPan ++ ( ++ int handle, ++ int vol, ++ int left, ++ int right ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ voice = MV_GetVoice( handle ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_VoiceNotFound ); ++ return( MV_Warning ); ++ } ++ ++ MV_SetVoiceVolume( voice, vol, left, right ); ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_Pan3D ++ ++ Set the angle and distance from the listener of the voice associated ++ with the specified handle. ++---------------------------------------------------------------------*/ ++ ++int MV_Pan3D ++ ( ++ int handle, ++ int angle, ++ int distance ++ ) ++ ++ { ++ int left; ++ int right; ++ int mid; ++ int volume; ++ int status; ++ ++ if ( distance < 0 ) ++ { ++ distance = -distance; ++ angle += MV_NumPanPositions / 2; ++ } ++ ++ volume = MIX_VOLUME( distance ); ++ ++ // Ensure angle is within 0 - 31 ++ angle &= MV_MaxPanPosition; ++ ++ left = MV_PanTable[ angle ][ volume ].left; ++ right = MV_PanTable[ angle ][ volume ].right; ++ mid = max( 0, 255 - distance ); ++ ++ status = MV_SetPan( handle, mid, left, right ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetReverb ++ ++ Sets the level of reverb to add to mix. ++---------------------------------------------------------------------*/ ++ ++void MV_SetReverb ++ ( ++ int reverb ++ ) ++ ++ { ++ MV_ReverbLevel = MIX_VOLUME( reverb ); ++ MV_ReverbTable = &MV_VolumeTable[ MV_ReverbLevel ]; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetFastReverb ++ ++ Sets the level of reverb to add to mix. ++---------------------------------------------------------------------*/ ++ ++void MV_SetFastReverb ++ ( ++ int reverb ++ ) ++ ++ { ++ MV_ReverbLevel = max( 0, min( 16, reverb ) ); ++ MV_ReverbTable = NULL; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetMaxReverbDelay ++ ++ Returns the maximum delay time for reverb. ++---------------------------------------------------------------------*/ ++ ++int MV_GetMaxReverbDelay ++ ( ++ void ++ ) ++ ++ { ++ int maxdelay; ++ ++ maxdelay = MixBufferSize * MV_NumberOfBuffers; ++ ++ return maxdelay; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetReverbDelay ++ ++ Returns the current delay time for reverb. ++---------------------------------------------------------------------*/ ++ ++int MV_GetReverbDelay ++ ( ++ void ++ ) ++ ++ { ++ return MV_ReverbDelay / MV_SampleSize; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetReverbDelay ++ ++ Sets the delay level of reverb to add to mix. ++---------------------------------------------------------------------*/ ++ ++void MV_SetReverbDelay ++ ( ++ int delay ++ ) ++ ++ { ++ int maxdelay; ++ ++ maxdelay = MV_GetMaxReverbDelay(); ++ MV_ReverbDelay = max( MixBufferSize, min( delay, maxdelay ) ); ++ MV_ReverbDelay *= MV_SampleSize; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetMixMode ++ ++ Prepares Multivoc to play stereo of mono digitized sounds. ++---------------------------------------------------------------------*/ ++ ++int MV_SetMixMode ++ ( ++ int numchannels, ++ int samplebits ++ ) ++ ++ { ++ int mode; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ mode = 0; ++ if ( numchannels == 2 ) ++ { ++ mode |= STEREO; ++ } ++ if ( samplebits == 16 ) ++ { ++ mode |= SIXTEEN_BIT; ++ } ++ ++#ifdef PLAT_DOS ++ switch( MV_SoundCard ) ++ { ++ case UltraSound : ++ MV_MixMode = mode; ++ break; ++ ++ case SoundBlaster : ++ case Awe32 : ++ MV_MixMode = BLASTER_SetMixMode( mode ); ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ MV_MixMode = PAS_SetMixMode( mode ); ++ break; ++ ++ case SoundScape : ++ MV_MixMode = SOUNDSCAPE_SetMixMode( mode ); ++ break; ++ ++ #ifndef SOUNDSOURCE_OFF ++ case SoundSource : ++ case TandySoundSource : ++ MV_MixMode = SS_SetMixMode( mode ); ++ break; ++ #endif ++ } ++#else ++ MV_MixMode = mode; ++#endif ++ ++ MV_Channels = 1; ++ if ( MV_MixMode & STEREO ) ++ { ++ MV_Channels = 2; ++ } ++ ++ MV_Bits = 8; ++ if ( MV_MixMode & SIXTEEN_BIT ) ++ { ++ MV_Bits = 16; ++ } ++ ++ MV_BuffShift = 7 + MV_Channels; ++ MV_SampleSize = sizeof( MONO8 ) * MV_Channels; ++ ++ if ( MV_Bits == 8 ) ++ { ++ MV_Silence = SILENCE_8BIT; ++ } ++ else ++ { ++ MV_Silence = SILENCE_16BIT; ++ MV_BuffShift += 1; ++ MV_SampleSize *= 2; ++ } ++ ++ MV_BufferSize = MixBufferSize * MV_SampleSize; ++ MV_NumberOfBuffers = TotalBufferSize / MV_BufferSize; ++ MV_BufferLength = TotalBufferSize; ++ ++ MV_RightChannelOffset = MV_SampleSize / 2; ++ if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) ++ { ++ MV_SampleSize /= 2; ++ MV_BufferSize /= 2; ++ MV_RightChannelOffset = MV_BufferSize * MV_NumberOfBuffers; ++ MV_BufferLength /= 2; ++ } ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StartPlayback ++ ++ Starts the sound playback engine. ++---------------------------------------------------------------------*/ ++ ++int MV_StartPlayback ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ int buffer; ++ ++ // Initialize the buffers ++ ClearBuffer_DW( MV_MixBuffer[ 0 ], MV_Silence, TotalBufferSize >> 2 ); ++ for( buffer = 0; buffer < MV_NumberOfBuffers; buffer++ ) ++ { ++ MV_BufferEmpty[ buffer ] = TRUE; ++ } ++ ++ // Set the mix buffer variables ++ MV_MixPage = 1; ++ ++ MV_MixFunction = MV_Mix; ++ ++//JIM ++// MV_MixRate = MV_RequestedMixRate; ++// return( MV_Ok ); ++ ++ // Start playback ++#ifdef PLAT_DOS ++ switch( MV_SoundCard ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ status = BLASTER_BeginBufferedPlayback( MV_MixBuffer[ 0 ], ++ TotalBufferSize, MV_NumberOfBuffers, ++ MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc ); ++ ++ if ( status != BLASTER_Ok ) ++ { ++ MV_SetErrorCode( MV_BlasterError ); ++ return( MV_Error ); ++ } ++ ++ MV_MixRate = BLASTER_GetPlaybackRate(); ++ MV_DMAChannel = BLASTER_DMAChannel; ++ break; ++ ++ case UltraSound : ++ ++ status = GUSWAVE_StartDemandFeedPlayback( MV_ServiceGus, 1, ++ MV_Bits, MV_RequestedMixRate, 0, ( MV_Channels == 1 ) ? ++ 0 : 24, 255, 0xffff, 0 ); ++ if ( status < GUSWAVE_Ok ) ++ { ++ MV_SetErrorCode( MV_BlasterError ); ++ return( MV_Error ); ++ } ++ ++ if ( MV_Channels == 2 ) ++ { ++ status = GUSWAVE_StartDemandFeedPlayback( MV_ServiceRightGus, 1, ++ MV_Bits, MV_RequestedMixRate, 0, 8, 255, 0xffff, 0 ); ++ if ( status < GUSWAVE_Ok ) ++ { ++ GUSWAVE_KillAllVoices(); ++ MV_SetErrorCode( MV_BlasterError ); ++ return( MV_Error ); ++ } ++ } ++ ++ MV_MixRate = MV_RequestedMixRate; ++ MV_DMAChannel = -1; ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ status = PAS_BeginBufferedPlayback( MV_MixBuffer[ 0 ], ++ TotalBufferSize, MV_NumberOfBuffers, ++ MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc ); ++ ++ if ( status != PAS_Ok ) ++ { ++ MV_SetErrorCode( MV_PasError ); ++ return( MV_Error ); ++ } ++ ++ MV_MixRate = PAS_GetPlaybackRate(); ++ MV_DMAChannel = PAS_DMAChannel; ++ break; ++ ++ case SoundScape : ++ status = SOUNDSCAPE_BeginBufferedPlayback( MV_MixBuffer[ 0 ], ++ TotalBufferSize, MV_NumberOfBuffers, MV_RequestedMixRate, ++ MV_MixMode, MV_ServiceVoc ); ++ ++ if ( status != SOUNDSCAPE_Ok ) ++ { ++ MV_SetErrorCode( MV_SoundScapeError ); ++ return( MV_Error ); ++ } ++ ++ MV_MixRate = SOUNDSCAPE_GetPlaybackRate(); ++ MV_DMAChannel = SOUNDSCAPE_DMAChannel; ++ break; ++ ++ #ifndef SOUNDSOURCE_OFF ++ case SoundSource : ++ case TandySoundSource : ++ SS_BeginBufferedPlayback( MV_MixBuffer[ 0 ], ++ TotalBufferSize, MV_NumberOfBuffers, ++ MV_ServiceVoc ); ++ MV_MixRate = SS_SampleRate; ++ MV_DMAChannel = -1; ++ break; ++ #endif ++ } ++#else ++ status = DSL_BeginBufferedPlayback( MV_MixBuffer[ 0 ], ++ TotalBufferSize, MV_NumberOfBuffers, ++ MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc ); ++ ++ if ( status != DSL_Ok ) ++ { ++ MV_SetErrorCode( MV_BlasterError ); ++ return( MV_Error ); ++ } ++ ++ MV_MixRate = DSL_GetPlaybackRate(); ++#endif ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StopPlayback ++ ++ Stops the sound playback engine. ++---------------------------------------------------------------------*/ ++ ++void MV_StopPlayback ++ ( ++ void ++ ) ++ ++ { ++ VoiceNode *voice; ++ VoiceNode *next; ++ unsigned flags; ++ ++#ifdef PLAT_DOS ++ // Stop sound playback ++ switch( MV_SoundCard ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ BLASTER_StopPlayback(); ++ break; ++ ++ case UltraSound : ++ GUSWAVE_KillAllVoices(); ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ PAS_StopPlayback(); ++ break; ++ ++ case SoundScape : ++ SOUNDSCAPE_StopPlayback(); ++ break; ++ ++ #ifndef SOUNDSOURCE_OFF ++ case SoundSource : ++ case TandySoundSource : ++ SS_StopPlayback(); ++ break; ++ #endif ++ } ++#else ++ DSL_StopPlayback(); ++#endif ++ ++ // Make sure all callbacks are done. ++ flags = DisableInterrupts(); ++ ++ for( voice = VoiceList.next; voice != &VoiceList; voice = next ) ++ { ++ next = voice->next; ++ ++ MV_StopVoice( voice ); ++ ++ if ( MV_CallBackFunc ) ++ { ++ MV_CallBackFunc( voice->callbackval ); ++ } ++ } ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StartRecording ++ ++ Starts the sound recording engine. ++---------------------------------------------------------------------*/ ++ ++int MV_StartRecording ++ ( ++ int MixRate, ++ void ( *function )( char *ptr, int length ) ++ ) ++ ++ { ++#ifdef PLAT_DOS ++ int status; ++ ++ switch( MV_SoundCard ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ break; ++ ++ default : ++ MV_SetErrorCode( MV_UnsupportedCard ); ++ return( MV_Error ); ++ break; ++ } ++ ++ if ( function == NULL ) ++ { ++ MV_SetErrorCode( MV_NullRecordFunction ); ++ return( MV_Error ); ++ } ++ ++ MV_StopPlayback(); ++ ++ // Initialize the buffers ++ ClearBuffer_DW( MV_MixBuffer[ 0 ], SILENCE_8BIT, TotalBufferSize >> 2 ); ++ ++ // Set the mix buffer variables ++ MV_MixPage = 0; ++ ++ MV_RecordFunc = function; ++ ++ // Start playback ++ switch( MV_SoundCard ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ status = BLASTER_BeginBufferedRecord( MV_MixBuffer[ 0 ], ++ TotalBufferSize, NumberOfBuffers, MixRate, MONO_8BIT, ++ MV_ServiceRecord ); ++ ++ if ( status != BLASTER_Ok ) ++ { ++ MV_SetErrorCode( MV_BlasterError ); ++ return( MV_Error ); ++ } ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ status = PAS_BeginBufferedRecord( MV_MixBuffer[ 0 ], ++ TotalBufferSize, NumberOfBuffers, MixRate, MONO_8BIT, ++ MV_ServiceRecord ); ++ ++ if ( status != PAS_Ok ) ++ { ++ MV_SetErrorCode( MV_PasError ); ++ return( MV_Error ); ++ } ++ break; ++ } ++ ++ MV_Recording = TRUE; ++ return( MV_Ok ); ++#else ++ MV_SetErrorCode( MV_UnsupportedCard ); ++ return( MV_Error ); ++#endif ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StopRecord ++ ++ Stops the sound record engine. ++---------------------------------------------------------------------*/ ++ ++void MV_StopRecord ++ ( ++ void ++ ) ++ ++ { ++#ifdef PLAT_DOS ++ // Stop sound playback ++ switch( MV_SoundCard ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ BLASTER_StopPlayback(); ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ PAS_StopPlayback(); ++ break; ++ } ++ ++ MV_Recording = FALSE; ++ MV_StartPlayback(); ++#endif ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_StartDemandFeedPlayback ++ ++ Plays a digitized sound from a user controlled buffering system. ++---------------------------------------------------------------------*/ ++ ++int MV_StartDemandFeedPlayback ++ ( ++ void ( *function )( char **ptr, unsigned long *length ), ++ int rate, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ // Request a voice from the voice pool ++ voice = MV_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_NoVoices ); ++ return( MV_Error ); ++ } ++ ++ voice->wavetype = DemandFeed; ++ voice->bits = 8; ++ voice->GetSound = MV_GetNextDemandFeedBlock; ++ voice->NextBlock = NULL; ++ voice->DemandFeed = function; ++ voice->LoopStart = NULL; ++ voice->LoopCount = 0; ++ voice->BlockLength = 0; ++ voice->position = 0; ++ voice->sound = NULL; ++ voice->length = 0; ++ voice->BlockLength = 0; ++ voice->Playing = TRUE; ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ ++ MV_SetVoicePitch( voice, rate, pitchoffset ); ++ MV_SetVoiceVolume( voice, vol, left, right ); ++ MV_PlayVoice( voice ); ++ ++ return( voice->handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayRaw ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayRaw ++ ( ++ char *ptr, ++ unsigned long length, ++ unsigned rate, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int status; ++ ++ status = MV_PlayLoopedRaw( ptr, length, NULL, NULL, rate, pitchoffset, ++ vol, left, right, priority, callbackval ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayLoopedRaw ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayLoopedRaw ++ ( ++ char *ptr, ++ unsigned long length, ++ char *loopstart, ++ char *loopend, ++ unsigned rate, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ VoiceNode *voice; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ // Request a voice from the voice pool ++ voice = MV_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_NoVoices ); ++ return( MV_Error ); ++ } ++ ++ voice->wavetype = Raw; ++ voice->bits = 8; ++ voice->GetSound = MV_GetNextRawBlock; ++ voice->Playing = TRUE; ++ voice->NextBlock = ptr; ++ voice->position = 0; ++ voice->BlockLength = length; ++ voice->length = 0; ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ voice->LoopStart = loopstart; ++ voice->LoopEnd = loopend; ++ voice->LoopSize = ( voice->LoopEnd - voice->LoopStart ) + 1; ++ ++ MV_SetVoicePitch( voice, rate, pitchoffset ); ++ MV_SetVoiceVolume( voice, vol, left, right ); ++ MV_PlayVoice( voice ); ++ ++ return( voice->handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayWAV ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayWAV ++ ( ++ char *ptr, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int status; ++ ++ status = MV_PlayLoopedWAV( ptr, -1, -1, pitchoffset, vol, left, right, ++ priority, callbackval ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayWAV3D ++ ++ Begin playback of sound data at specified angle and distance ++ from listener. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayWAV3D ++ ( ++ char *ptr, ++ int pitchoffset, ++ int angle, ++ int distance, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int left; ++ int right; ++ int mid; ++ int volume; ++ int status; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ if ( distance < 0 ) ++ { ++ distance = -distance; ++ angle += MV_NumPanPositions / 2; ++ } ++ ++ volume = MIX_VOLUME( distance ); ++ ++ // Ensure angle is within 0 - 31 ++ angle &= MV_MaxPanPosition; ++ ++ left = MV_PanTable[ angle ][ volume ].left; ++ right = MV_PanTable[ angle ][ volume ].right; ++ mid = max( 0, 255 - distance ); ++ ++ status = MV_PlayWAV( ptr, pitchoffset, mid, left, right, priority, ++ callbackval ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayLoopedWAV ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayLoopedWAV ++ ( ++ char *ptr, ++ long loopstart, ++ long loopend, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ riff_header *riff; ++ format_header *format; ++ data_header *data; ++ VoiceNode *voice; ++ int length; ++ int absloopend; ++ int absloopstart; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ riff = ( riff_header * )ptr; ++ ++ if ( ( strncmp( riff->RIFF, "RIFF", 4 ) != 0 ) || ++ ( strncmp( riff->WAVE, "WAVE", 4 ) != 0 ) || ++ ( strncmp( riff->fmt, "fmt ", 4) != 0 ) ) ++ { ++ MV_SetErrorCode( MV_InvalidWAVFile ); ++ return( MV_Error ); ++ } ++ ++ format = ( format_header * )( riff + 1 ); ++ data = ( data_header * )( ( ( char * )format ) + riff->format_size ); ++ ++ // Check if it's PCM data. ++ if ( format->wFormatTag != 1 ) ++ { ++ MV_SetErrorCode( MV_InvalidWAVFile ); ++ return( MV_Error ); ++ } ++ ++ if ( format->nChannels != 1 ) ++ { ++ MV_SetErrorCode( MV_InvalidWAVFile ); ++ return( MV_Error ); ++ } ++ ++ if ( ( format->nBitsPerSample != 8 ) && ++ ( format->nBitsPerSample != 16 ) ) ++ { ++ MV_SetErrorCode( MV_InvalidWAVFile ); ++ return( MV_Error ); ++ } ++ ++ if ( strncmp( data->DATA, "data", 4 ) != 0 ) ++ { ++ MV_SetErrorCode( MV_InvalidWAVFile ); ++ return( MV_Error ); ++ } ++ ++ // Request a voice from the voice pool ++ voice = MV_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_NoVoices ); ++ return( MV_Error ); ++ } ++ ++ voice->wavetype = WAV; ++ voice->bits = format->nBitsPerSample; ++ voice->GetSound = MV_GetNextWAVBlock; ++ ++ length = data->size; ++ absloopstart = loopstart; ++ absloopend = loopend; ++ if ( voice->bits == 16 ) ++ { ++ loopstart *= 2; ++ data->size &= ~1; ++ loopend *= 2; ++ length /= 2; ++ } ++ ++ loopend = min( loopend, (long)data->size ); ++ absloopend = min( absloopend, length ); ++ ++ voice->Playing = TRUE; ++ voice->DemandFeed = NULL; ++ voice->LoopStart = NULL; ++ voice->LoopCount = 0; ++ voice->position = 0; ++ voice->length = 0; ++ voice->BlockLength = absloopend; ++ voice->NextBlock = ( char * )( data + 1 ); ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ voice->LoopStart = voice->NextBlock + loopstart; ++ voice->LoopEnd = voice->NextBlock + loopend; ++ voice->LoopSize = absloopend - absloopstart; ++ ++ if ( ( loopstart >= (long)data->size ) || ( loopstart < 0 ) ) ++ { ++ voice->LoopStart = NULL; ++ voice->LoopEnd = NULL; ++ voice->BlockLength = length; ++ } ++ ++ MV_SetVoicePitch( voice, format->nSamplesPerSec, pitchoffset ); ++ MV_SetVoiceVolume( voice, vol, left, right ); ++ MV_PlayVoice( voice ); ++ ++ return( voice->handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayVOC3D ++ ++ Begin playback of sound data at specified angle and distance ++ from listener. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayVOC3D ++ ( ++ char *ptr, ++ int pitchoffset, ++ int angle, ++ int distance, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int left; ++ int right; ++ int mid; ++ int volume; ++ int status; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ if ( distance < 0 ) ++ { ++ distance = -distance; ++ angle += MV_NumPanPositions / 2; ++ } ++ ++ volume = MIX_VOLUME( distance ); ++ ++ // Ensure angle is within 0 - 31 ++ angle &= MV_MaxPanPosition; ++ ++ left = MV_PanTable[ angle ][ volume ].left; ++ right = MV_PanTable[ angle ][ volume ].right; ++ mid = max( 0, 255 - distance ); ++ ++ status = MV_PlayVOC( ptr, pitchoffset, mid, left, right, priority, ++ callbackval ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayVOC ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayVOC ++ ( ++ char *ptr, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ int status; ++ ++ status = MV_PlayLoopedVOC( ptr, -1, -1, pitchoffset, vol, left, right, ++ priority, callbackval ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_PlayLoopedVOC ++ ++ Begin playback of sound data with the given sound levels and ++ priority. ++---------------------------------------------------------------------*/ ++ ++int MV_PlayLoopedVOC ++ ( ++ char *ptr, ++ long loopstart, ++ long loopend, ++ int pitchoffset, ++ int vol, ++ int left, ++ int right, ++ int priority, ++ unsigned long callbackval ++ ) ++ ++ { ++ VoiceNode *voice; ++ int status; ++ unsigned short nextpos; ++ ++ if ( !MV_Installed ) ++ { ++ MV_SetErrorCode( MV_NotInstalled ); ++ return( MV_Error ); ++ } ++ ++ // Make sure it's a valid VOC file. ++ status = strncmp( ptr, "Creative Voice File", 19 ); ++ if ( status != 0 ) ++ { ++ MV_SetErrorCode( MV_InvalidVOCFile ); ++ return( MV_Error ); ++ } ++ ++ // Request a voice from the voice pool ++ voice = MV_AllocVoice( priority ); ++ if ( voice == NULL ) ++ { ++ MV_SetErrorCode( MV_NoVoices ); ++ return( MV_Error ); ++ } ++ ++ voice->wavetype = VOC; ++ voice->bits = 8; ++ voice->GetSound = MV_GetNextVOCBlock; ++ ++ nextpos = *( unsigned short * )( ptr + 0x14 ); ++ voice->NextBlock = ptr + BUILDSWAP_INTEL16(nextpos); ++ ++ voice->DemandFeed = NULL; ++ voice->LoopStart = NULL; ++ voice->LoopCount = 0; ++ voice->BlockLength = 0; ++ voice->PitchScale = PITCH_GetScale( pitchoffset ); ++ voice->length = 0; ++ voice->next = NULL; ++ voice->prev = NULL; ++ voice->priority = priority; ++ voice->callbackval = callbackval; ++ voice->LoopStart = ( char * )loopstart; ++ voice->LoopEnd = ( char * )loopend; ++ voice->LoopSize = loopend - loopstart + 1; ++ ++ if ( loopstart < 0 ) ++ { ++ voice->LoopStart = NULL; ++ voice->LoopEnd = NULL; ++ } ++ ++ MV_SetVoiceVolume( voice, vol, left, right ); ++ MV_PlayVoice( voice ); ++ ++ return( voice->handle ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void MV_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_CreateVolumeTable ++ ++ Create the table used to convert sound data to a specific volume ++ level. ++---------------------------------------------------------------------*/ ++ ++void MV_CreateVolumeTable ++ ( ++ int index, ++ int volume, ++ int MaxVolume ++ ) ++ ++ { ++ int val; ++ int level; ++ int i; ++ ++ level = ( volume * MaxVolume ) / MV_MaxTotalVolume; ++ if ( MV_Bits == 16 ) ++ { ++ for( i = 0; i < 65536; i += 256 ) ++ { ++ val = i - 0x8000; ++ val *= level; ++ val /= MV_MaxVolume; ++ MV_VolumeTable[ index ][ i / 256 ] = val; ++ } ++ } ++ else ++ { ++ for( i = 0; i < 256; i++ ) ++ { ++ val = i - 0x80; ++ val *= level; ++ val /= MV_MaxVolume; ++ MV_VolumeTable[ volume ][ i ] = val; ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_CalcVolume ++ ++ Create the table used to convert sound data to a specific volume ++ level. ++---------------------------------------------------------------------*/ ++ ++void MV_CalcVolume ++ ( ++ int MaxVolume ++ ) ++ ++ { ++ int volume; ++ ++ for( volume = 0; volume < 128; volume++ ) ++ { ++ MV_HarshClipTable[ volume ] = 0; ++ MV_HarshClipTable[ volume + 384 ] = 255; ++ } ++ for( volume = 0; volume < 256; volume++ ) ++ { ++ MV_HarshClipTable[ volume + 128 ] = volume; ++ } ++ ++ // For each volume level, create a translation table with the ++ // appropriate volume calculated. ++ for( volume = 0; volume <= MV_MaxVolume; volume++ ) ++ { ++ MV_CreateVolumeTable( volume, volume, MaxVolume ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_CalcPanTable ++ ++ Create the table used to determine the stereo volume level of ++ a sound located at a specific angle and distance from the listener. ++---------------------------------------------------------------------*/ ++ ++void MV_CalcPanTable ++ ( ++ void ++ ) ++ ++ { ++ int level; ++ int angle; ++ int distance; ++ int HalfAngle; ++ int ramp; ++ ++ HalfAngle = ( MV_NumPanPositions / 2 ); ++ ++ for( distance = 0; distance <= MV_MaxVolume; distance++ ) ++ { ++ level = ( 255 * ( MV_MaxVolume - distance ) ) / MV_MaxVolume; ++ for( angle = 0; angle <= HalfAngle / 2; angle++ ) ++ { ++ ramp = level - ( ( level * angle ) / ++ ( MV_NumPanPositions / 4 ) ); ++ ++ MV_PanTable[ angle ][ distance ].left = ramp; ++ MV_PanTable[ HalfAngle - angle ][ distance ].left = ramp; ++ MV_PanTable[ HalfAngle + angle ][ distance ].left = level; ++ MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].left = level; ++ ++ MV_PanTable[ angle ][ distance ].right = level; ++ MV_PanTable[ HalfAngle - angle ][ distance ].right = level; ++ MV_PanTable[ HalfAngle + angle ][ distance ].right = ramp; ++ MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].right = ramp; ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetVolume ++ ++ Sets the volume of digitized sound playback. ++---------------------------------------------------------------------*/ ++ ++void MV_SetVolume ++ ( ++ int volume ++ ) ++ ++ { ++ volume = max( 0, volume ); ++ volume = min( volume, MV_MaxTotalVolume ); ++ ++ MV_TotalVolume = volume; ++ ++ // Calculate volume table ++ MV_CalcVolume( volume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetVolume ++ ++ Returns the volume of digitized sound playback. ++---------------------------------------------------------------------*/ ++ ++int MV_GetVolume ++ ( ++ void ++ ) ++ ++ { ++ return( MV_TotalVolume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetCallBack ++ ++ Set the function to call when a voice stops. ++---------------------------------------------------------------------*/ ++ ++void MV_SetCallBack ++ ( ++ void ( *function )( unsigned long ) ++ ) ++ ++ { ++ MV_CallBackFunc = function; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_SetReverseStereo ++ ++ Set the orientation of the left and right channels. ++---------------------------------------------------------------------*/ ++ ++void MV_SetReverseStereo ++ ( ++ int setting ++ ) ++ ++ { ++ MV_SwapLeftRight = setting; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_GetReverseStereo ++ ++ Returns the orientation of the left and right channels. ++---------------------------------------------------------------------*/ ++ ++int MV_GetReverseStereo ++ ( ++ void ++ ) ++ ++ { ++ return( MV_SwapLeftRight ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_TestPlayback ++ ++ Checks if playback has started. ++---------------------------------------------------------------------*/ ++ ++int MV_TestPlayback ++ ( ++ void ++ ) ++ ++ { ++#ifdef PLAT_DOS ++ unsigned flags; ++ long time; ++ int start; ++ int status; ++ int pos; ++ ++ if ( MV_SoundCard == UltraSound ) ++ { ++ return( MV_Ok ); ++ } ++ ++ flags = DisableInterrupts(); ++ _enable(); ++ ++ status = MV_Error; ++ start = MV_MixPage; ++ time = clock() + CLOCKS_PER_SEC * 2; ++ ++ while( clock() < time ) ++ { ++ if ( MV_MixPage != start ) ++ { ++ status = MV_Ok; ++ } ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ if ( status != MV_Ok ) ++ { ++ // Just in case an error doesn't get reported ++ MV_SetErrorCode( MV_DMAFailure ); ++ ++ switch( MV_SoundCard ) ++ { ++ case SoundBlaster : ++ case Awe32 : ++ pos = BLASTER_GetCurrentPos(); ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ pos = PAS_GetCurrentPos(); ++ break; ++ ++ case SoundScape : ++ pos = SOUNDSCAPE_GetCurrentPos(); ++ break; ++ ++ #ifndef SOUNDSOURCE_OFF ++ case SoundSource : ++ case TandySoundSource : ++ MV_SetErrorCode( MV_SoundSourceFailure ); ++ pos = -1; ++ break; ++ #endif ++ ++ default : ++ MV_SetErrorCode( MV_UnsupportedCard ); ++ pos = -2; ++ break; ++ } ++ ++ if ( pos > 0 ) ++ { ++ MV_SetErrorCode( MV_IrqFailure ); ++ } ++ else if ( pos == 0 ) ++ { ++ if ( MV_Bits == 16 ) ++ { ++ MV_SetErrorCode( MV_DMA16Failure ); ++ } ++ else ++ { ++ MV_SetErrorCode( MV_DMAFailure ); ++ } ++ } ++ } ++ ++ return( status ); ++#else ++ return MV_Ok; ++#endif ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_Init ++ ++ Perform the initialization of variables and memory used by ++ Multivoc. ++---------------------------------------------------------------------*/ ++ ++int MV_Init ++ ( ++ int soundcard, ++ int MixRate, ++ int Voices, ++ int numchannels, ++ int samplebits ++ ) ++ ++ { ++ char *ptr; ++ int status; ++ int buffer; ++ int index; ++ ++ if ( MV_Installed ) ++ { ++ MV_Shutdown(); ++ } ++ ++ MV_SetErrorCode( MV_Ok ); ++ ++ status = MV_LockMemory(); ++ if ( status != MV_Ok ) ++ { ++ return( status ); ++ } ++ ++ MV_TotalMemory = Voices * sizeof( VoiceNode ) + sizeof( HARSH_CLIP_TABLE_8 ); ++ status = USRHOOKS_GetMem( ( void ** )&ptr, MV_TotalMemory ); ++ if ( status != USRHOOKS_Ok ) ++ { ++ MV_UnlockMemory(); ++ MV_SetErrorCode( MV_NoMem ); ++ return( MV_Error ); ++ } ++ ++ status = DPMI_LockMemory( ptr, MV_TotalMemory ); ++ if ( status != DPMI_Ok ) ++ { ++ USRHOOKS_FreeMem( ptr ); ++ MV_UnlockMemory(); ++ MV_SetErrorCode( MV_DPMI_Error ); ++ return( MV_Error ); ++ } ++ ++ MV_Voices = ( VoiceNode * )ptr; ++ MV_HarshClipTable = ptr + ( MV_TotalMemory - sizeof( HARSH_CLIP_TABLE_8 ) ); ++ ++ // Set number of voices before calculating volume table ++ MV_MaxVoices = Voices; ++ ++ LL_Reset( (VoiceNode *)&VoiceList, next, prev ); ++ LL_Reset( (VoiceNode *)&VoicePool, next, prev ); ++ ++ for( index = 0; index < Voices; index++ ) ++ { ++ LL_Add( (VoiceNode *)&VoicePool, &MV_Voices[ index ], next, prev ); ++ } ++ ++ // Allocate mix buffer within 1st megabyte ++ status = DPMI_GetDOSMemory( ( void ** )&ptr, &MV_BufferDescriptor, ++ 2 * TotalBufferSize ); ++ ++ if ( status ) ++ { ++ DPMI_UnlockMemory( MV_Voices, MV_TotalMemory ); ++ USRHOOKS_FreeMem( MV_Voices ); ++ MV_Voices = NULL; ++ MV_TotalMemory = 0; ++ MV_UnlockMemory(); ++ ++ MV_SetErrorCode( MV_NoMem ); ++ return( MV_Error ); ++ } ++ ++ MV_SetReverseStereo( FALSE ); ++ ++ // Initialize the sound card ++#ifdef PLAT_DOS ++ switch( soundcard ) ++ { ++ case UltraSound : ++ status = GUSWAVE_Init( 2 ); ++ if ( status != GUSWAVE_Ok ) ++ { ++ //JIM ++ MV_SetErrorCode( MV_BlasterError ); ++ } ++ break; ++ ++ case SoundBlaster : ++ case Awe32 : ++ status = BLASTER_Init(); ++ if ( status != BLASTER_Ok ) ++ { ++ MV_SetErrorCode( MV_BlasterError ); ++ } ++ ++ if ( ( BLASTER_Config.Type == SBPro ) || ++ ( BLASTER_Config.Type == SBPro2 ) ) ++ { ++ MV_SetReverseStereo( TRUE ); ++ } ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ status = PAS_Init(); ++ if ( status != PAS_Ok ) ++ { ++ MV_SetErrorCode( MV_PasError ); ++ } ++ break; ++ ++ case SoundScape : ++ status = SOUNDSCAPE_Init(); ++ if ( status != SOUNDSCAPE_Ok ) ++ { ++ MV_SetErrorCode( MV_SoundScapeError ); ++ } ++ break; ++ ++ #ifndef SOUNDSOURCE_OFF ++ case SoundSource : ++ case TandySoundSource : ++ status = SS_Init( soundcard ); ++ if ( status != SS_Ok ) ++ { ++ MV_SetErrorCode( MV_SoundSourceError ); ++ } ++ break; ++ #endif ++ ++ default : ++ MV_SetErrorCode( MV_UnsupportedCard ); ++ break; ++ } ++#else ++ status = DSL_Init(); ++ if ( status != DSL_Ok ) ++ { ++ MV_SetErrorCode( MV_BlasterError ); ++ } ++#endif ++ ++ if ( MV_ErrorCode != MV_Ok ) ++ { ++ status = MV_ErrorCode; ++ ++ DPMI_UnlockMemory( MV_Voices, MV_TotalMemory ); ++ USRHOOKS_FreeMem( MV_Voices ); ++ MV_Voices = NULL; ++ MV_TotalMemory = 0; ++ ++ DPMI_FreeDOSMemory( MV_BufferDescriptor ); ++ MV_UnlockMemory(); ++ ++ MV_SetErrorCode( status ); ++ return( MV_Error ); ++ } ++ ++ MV_SoundCard = soundcard; ++ MV_Installed = TRUE; ++ MV_CallBackFunc = NULL; ++ MV_RecordFunc = NULL; ++ MV_Recording = FALSE; ++ MV_ReverbLevel = 0; ++ MV_ReverbTable = NULL; ++ ++ // Set the sampling rate ++ MV_RequestedMixRate = MixRate; ++ ++ // Set Mixer to play stereo digitized sound ++ MV_SetMixMode( numchannels, samplebits ); ++ MV_ReverbDelay = MV_BufferSize * 3; ++ ++#ifdef PLAT_DOS ++ // Make sure we don't cross a physical page ++ if ( ( ( unsigned long )ptr & 0xffff ) + TotalBufferSize > 0x10000 ) ++ { ++ ptr = ( char * )( ( ( unsigned long )ptr & 0xff0000 ) + 0x10000 ); ++ } ++#endif ++ ++ MV_MixBuffer[ MV_NumberOfBuffers ] = ptr; ++ for( buffer = 0; buffer < MV_NumberOfBuffers; buffer++ ) ++ { ++ MV_MixBuffer[ buffer ] = ptr; ++ ptr += MV_BufferSize; ++ } ++ ++ // Calculate pan table ++ MV_CalcPanTable(); ++ ++ MV_SetVolume( MV_MaxTotalVolume ); ++ ++ // Start the playback engine ++ status = MV_StartPlayback(); ++ if ( status != MV_Ok ) ++ { ++ // Preserve error code while we shutdown. ++ status = MV_ErrorCode; ++ MV_Shutdown(); ++ MV_SetErrorCode( status ); ++ return( MV_Error ); ++ } ++ ++ if ( MV_TestPlayback() != MV_Ok ) ++ { ++ status = MV_ErrorCode; ++ MV_Shutdown(); ++ MV_SetErrorCode( status ); ++ return( MV_Error ); ++ } ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_Shutdown ++ ++ Restore any resources allocated by Multivoc back to the system. ++---------------------------------------------------------------------*/ ++ ++int MV_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ int buffer; ++ unsigned flags; ++ ++ if ( !MV_Installed ) ++ { ++ return( MV_Ok ); ++ } ++ ++ flags = DisableInterrupts(); ++ ++ MV_KillAllVoices(); ++ ++ MV_Installed = FALSE; ++ ++ // Stop the sound recording engine ++ if ( MV_Recording ) ++ { ++ MV_StopRecord(); ++ } ++ ++ // Stop the sound playback engine ++ MV_StopPlayback(); ++ ++ // Shutdown the sound card ++#ifdef PLAT_DOS ++ switch( MV_SoundCard ) ++ { ++ case UltraSound : ++ GUSWAVE_Shutdown(); ++ break; ++ ++ case SoundBlaster : ++ case Awe32 : ++ BLASTER_Shutdown(); ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ PAS_Shutdown(); ++ break; ++ ++ case SoundScape : ++ SOUNDSCAPE_Shutdown(); ++ break; ++ ++ #ifndef SOUNDSOURCE_OFF ++ case SoundSource : ++ case TandySoundSource : ++ SS_Shutdown(); ++ break; ++ #endif ++ } ++#else ++ DSL_Shutdown(); ++#endif ++ ++ RestoreInterrupts( flags ); ++ ++ // Free any voices we allocated ++ DPMI_UnlockMemory( MV_Voices, MV_TotalMemory ); ++ USRHOOKS_FreeMem( MV_Voices ); ++ MV_Voices = NULL; ++ MV_TotalMemory = 0; ++ ++ LL_Reset( (VoiceNode *)&VoiceList, next, prev ); ++ LL_Reset( (VoiceNode *)&VoicePool, next, prev ); ++ ++ MV_MaxVoices = 1; ++ ++ // Release the descriptor from our mix buffer ++ DPMI_FreeDOSMemory( MV_BufferDescriptor ); ++ for( buffer = 0; buffer < NumberOfBuffers; buffer++ ) ++ { ++ MV_MixBuffer[ buffer ] = NULL; ++ } ++ ++ return( MV_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_UnlockMemory ++ ++ Unlocks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++void MV_UnlockMemory ++ ( ++ void ++ ) ++ ++ { ++ PITCH_UnlockMemory(); ++ ++ DPMI_UnlockMemoryRegion( MV_LockStart, MV_LockEnd ); ++ DPMI_Unlock( MV_VolumeTable ); ++ DPMI_Unlock( MV_PanTable ); ++ DPMI_Unlock( MV_Installed ); ++ DPMI_Unlock( MV_SoundCard ); ++ DPMI_Unlock( MV_TotalVolume ); ++ DPMI_Unlock( MV_MaxVoices ); ++ DPMI_Unlock( MV_BufferSize ); ++ DPMI_Unlock( MV_BufferLength ); ++ DPMI_Unlock( MV_SampleSize ); ++ DPMI_Unlock( MV_NumberOfBuffers ); ++ DPMI_Unlock( MV_MixMode ); ++ DPMI_Unlock( MV_Channels ); ++ DPMI_Unlock( MV_Bits ); ++ DPMI_Unlock( MV_Silence ); ++ DPMI_Unlock( MV_SwapLeftRight ); ++ DPMI_Unlock( MV_RequestedMixRate ); ++ DPMI_Unlock( MV_MixRate ); ++ DPMI_Unlock( MV_BufferDescriptor ); ++ DPMI_Unlock( MV_MixBuffer ); ++ DPMI_Unlock( MV_BufferEmpty ); ++ DPMI_Unlock( MV_Voices ); ++ DPMI_Unlock( VoiceList ); ++ DPMI_Unlock( VoicePool ); ++ DPMI_Unlock( MV_MixPage ); ++ DPMI_Unlock( MV_VoiceHandle ); ++ DPMI_Unlock( MV_CallBackFunc ); ++ DPMI_Unlock( MV_RecordFunc ); ++ DPMI_Unlock( MV_Recording ); ++ DPMI_Unlock( MV_MixFunction ); ++ DPMI_Unlock( MV_HarshClipTable ); ++ DPMI_Unlock( MV_MixDestination ); ++ DPMI_Unlock( MV_LeftVolume ); ++ DPMI_Unlock( MV_RightVolume ); ++ DPMI_Unlock( MV_MixPosition ); ++ DPMI_Unlock( MV_ErrorCode ); ++ DPMI_Unlock( MV_DMAChannel ); ++ DPMI_Unlock( MV_BuffShift ); ++ DPMI_Unlock( MV_ReverbLevel ); ++ DPMI_Unlock( MV_ReverbDelay ); ++ DPMI_Unlock( MV_ReverbTable ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MV_LockMemory ++ ++ Locks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++int MV_LockMemory ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ int pitchstatus; ++ ++ status = DPMI_LockMemoryRegion( MV_LockStart, MV_LockEnd ); ++ status |= DPMI_Lock( MV_VolumeTable ); ++ status |= DPMI_Lock( MV_PanTable ); ++ status |= DPMI_Lock( MV_Installed ); ++ status |= DPMI_Lock( MV_SoundCard ); ++ status |= DPMI_Lock( MV_TotalVolume ); ++ status |= DPMI_Lock( MV_MaxVoices ); ++ status |= DPMI_Lock( MV_BufferSize ); ++ status |= DPMI_Lock( MV_BufferLength ); ++ status |= DPMI_Lock( MV_SampleSize ); ++ status |= DPMI_Lock( MV_NumberOfBuffers ); ++ status |= DPMI_Lock( MV_MixMode ); ++ status |= DPMI_Lock( MV_Channels ); ++ status |= DPMI_Lock( MV_Bits ); ++ status |= DPMI_Lock( MV_Silence ); ++ status |= DPMI_Lock( MV_SwapLeftRight ); ++ status |= DPMI_Lock( MV_RequestedMixRate ); ++ status |= DPMI_Lock( MV_MixRate ); ++ status |= DPMI_Lock( MV_BufferDescriptor ); ++ status |= DPMI_Lock( MV_MixBuffer ); ++ status |= DPMI_Lock( MV_BufferEmpty ); ++ status |= DPMI_Lock( MV_Voices ); ++ status |= DPMI_Lock( VoiceList ); ++ status |= DPMI_Lock( VoicePool ); ++ status |= DPMI_Lock( MV_MixPage ); ++ status |= DPMI_Lock( MV_VoiceHandle ); ++ status |= DPMI_Lock( MV_CallBackFunc ); ++ status |= DPMI_Lock( MV_RecordFunc ); ++ status |= DPMI_Lock( MV_Recording ); ++ status |= DPMI_Lock( MV_MixFunction ); ++ status |= DPMI_Lock( MV_HarshClipTable ); ++ status |= DPMI_Lock( MV_MixDestination ); ++ status |= DPMI_Lock( MV_LeftVolume ); ++ status |= DPMI_Lock( MV_RightVolume ); ++ status |= DPMI_Lock( MV_MixPosition ); ++ status |= DPMI_Lock( MV_ErrorCode ); ++ status |= DPMI_Lock( MV_DMAChannel ); ++ status |= DPMI_Lock( MV_BuffShift ); ++ status |= DPMI_Lock( MV_ReverbLevel ); ++ status |= DPMI_Lock( MV_ReverbDelay ); ++ status |= DPMI_Lock( MV_ReverbTable ); ++ ++ pitchstatus = PITCH_LockMemory(); ++ if ( ( pitchstatus != PITCH_Ok ) || ( status != DPMI_Ok ) ) ++ { ++ MV_UnlockMemory(); ++ MV_SetErrorCode( MV_DPMI_Error ); ++ return( MV_Error ); ++ } ++ ++ return( MV_Ok ); ++ } ++ ++#ifndef PLAT_DOS ++void ClearBuffer_DW( void *ptr, unsigned data, int length ) ++{ ++ unsigned *d = (unsigned *)ptr; ++ ++ while (length--) { ++ *d = data; ++ ++ d++; ++ } ++} ++#endif +diff -urN rott-1.0/rott/audiolib/multivoc.h trunk/rott/audiolib/multivoc.h +--- rott-1.0/rott/audiolib/multivoc.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/multivoc.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,123 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ file: MULTIVOC.H ++ ++ author: James R. Dose ++ date: December 20, 1993 ++ ++ Public header for MULTIVOC.C ++ ++ (c) Copyright 1993 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __MULTIVOC_H ++#define __MULTIVOC_H ++ ++// platform.h is in buildengine, but I need the byteswapping macros... --ryan. ++#include "platform.h" ++ ++#define MV_MinVoiceHandle 1 ++ ++extern int MV_ErrorCode; ++ ++enum MV_Errors ++ { ++ MV_Warning = -2, ++ MV_Error = -1, ++ MV_Ok = 0, ++ MV_UnsupportedCard, ++ MV_NotInstalled, ++ MV_NoVoices, ++ MV_NoMem, ++ MV_VoiceNotFound, ++ MV_BlasterError, ++ MV_PasError, ++ MV_SoundScapeError, ++ MV_SoundSourceError, ++ MV_DPMI_Error, ++ MV_InvalidVOCFile, ++ MV_InvalidWAVFile, ++ MV_InvalidMixMode, ++ MV_SoundSourceFailure, ++ MV_IrqFailure, ++ MV_DMAFailure, ++ MV_DMA16Failure, ++ MV_NullRecordFunction ++ }; ++ ++char *MV_ErrorString( int ErrorNumber ); ++int MV_VoicePlaying( int handle ); ++int MV_KillAllVoices( void ); ++int MV_Kill( int handle ); ++int MV_VoicesPlaying( void ); ++int MV_VoiceAvailable( int priority ); ++int MV_SetPitch( int handle, int pitchoffset ); ++int MV_SetFrequency( int handle, int frequency ); ++int MV_EndLooping( int handle ); ++int MV_SetPan( int handle, int vol, int left, int right ); ++int MV_Pan3D( int handle, int angle, int distance ); ++void MV_SetReverb( int reverb ); ++void MV_SetFastReverb( int reverb ); ++int MV_GetMaxReverbDelay( void ); ++int MV_GetReverbDelay( void ); ++void MV_SetReverbDelay( int delay ); ++int MV_SetMixMode( int numchannels, int samplebits ); ++int MV_StartPlayback( void ); ++void MV_StopPlayback( void ); ++int MV_StartRecording( int MixRate, void ( *function )( char *ptr, int length ) ); ++void MV_StopRecord( void ); ++int MV_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ), ++ int rate, int pitchoffset, int vol, int left, int right, ++ int priority, unsigned long callbackval ); ++int MV_PlayRaw( char *ptr, unsigned long length, ++ unsigned rate, int pitchoffset, int vol, int left, ++ int right, int priority, unsigned long callbackval ); ++int MV_PlayLoopedRaw( char *ptr, unsigned long length, ++ char *loopstart, char *loopend, unsigned rate, int pitchoffset, ++ int vol, int left, int right, int priority, ++ unsigned long callbackval ); ++int MV_PlayWAV( char *ptr, int pitchoffset, int vol, int left, ++ int right, int priority, unsigned long callbackval ); ++int MV_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance, ++ int priority, unsigned long callbackval ); ++int MV_PlayLoopedWAV( char *ptr, long loopstart, long loopend, ++ int pitchoffset, int vol, int left, int right, int priority, ++ unsigned long callbackval ); ++int MV_PlayVOC3D( char *ptr, int pitchoffset, int angle, int distance, ++ int priority, unsigned long callbackval ); ++int MV_PlayVOC( char *ptr, int pitchoffset, int vol, int left, int right, ++ int priority, unsigned long callbackval ); ++int MV_PlayLoopedVOC( char *ptr, long loopstart, long loopend, ++ int pitchoffset, int vol, int left, int right, int priority, ++ unsigned long callbackval ); ++void MV_CreateVolumeTable( int index, int volume, int MaxVolume ); ++void MV_SetVolume( int volume ); ++int MV_GetVolume( void ); ++void MV_SetCallBack( void ( *function )( unsigned long ) ); ++void MV_SetReverseStereo( int setting ); ++int MV_GetReverseStereo( void ); ++int MV_Init( int soundcard, int MixRate, int Voices, int numchannels, ++ int samplebits ); ++int MV_Shutdown( void ); ++void MV_UnlockMemory( void ); ++int MV_LockMemory( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/music.c trunk/rott/audiolib/music.c +--- rott-1.0/rott/audiolib/music.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/music.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,1035 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: MUSIC.C ++ ++ author: James R. Dose ++ date: March 25, 1994 ++ ++ Device independant music playback routines. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include "task_man.h" ++#include "sndcards.h" ++#include "music.h" ++#include "midi.h" ++#include "al_midi.h" ++#include "pas16.h" ++#include "blaster.h" ++#include "gusmidi.h" ++#include "mpu401.h" ++#include "awe32.h" ++#include "sndscape.h" ++#include "ll_man.h" ++#include "user.h" ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++void TextMode( void ); ++#pragma aux TextMode = \ ++ "mov ax, 0003h", \ ++ "int 10h" \ ++ modify [ ax ]; ++ ++int MUSIC_SoundDevice = -1; ++int MUSIC_ErrorCode = MUSIC_Ok; ++ ++static midifuncs MUSIC_MidiFunctions; ++ ++static int MUSIC_FadeLength; ++static int MUSIC_FadeRate; ++static unsigned MUSIC_CurrentFadeVolume; ++static unsigned MUSIC_LastFadeVolume; ++static int MUSIC_EndingFadeVolume; ++static task *MUSIC_FadeTask = NULL; ++ ++int MUSIC_InitAWE32( midifuncs *Funcs ); ++int MUSIC_InitFM( int card, midifuncs *Funcs ); ++int MUSIC_InitMidi( int card, midifuncs *Funcs, int Address ); ++int MUSIC_InitGUS( midifuncs *Funcs ); ++ ++#define MUSIC_SetErrorCode( status ) \ ++ MUSIC_ErrorCode = ( status ); ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *MUSIC_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case MUSIC_Warning : ++ case MUSIC_Error : ++ ErrorString = MUSIC_ErrorString( MUSIC_ErrorCode ); ++ break; ++ ++ case MUSIC_Ok : ++ ErrorString = "Music ok."; ++ break; ++ ++ case MUSIC_ASSVersion : ++ ErrorString = "Apogee Sound System Version " ASS_VERSION_STRING " " ++ "Programmed by Jim Dose\n" ++ "(c) Copyright 1996 James R. Dose. All Rights Reserved.\n"; ++ break; ++ ++ case MUSIC_SoundCardError : ++ switch( MUSIC_SoundDevice ) ++ { ++ case SoundBlaster : ++ case WaveBlaster : ++ ErrorString = BLASTER_ErrorString( BLASTER_Error ); ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ ErrorString = PAS_ErrorString( PAS_Error ); ++ break; ++ ++ case Adlib : ++ ErrorString = "Adlib error."; ++ break; ++ ++ case GenMidi : ++ case SoundCanvas : ++ ErrorString = "Could not detect MPU-401."; ++ break; ++ ++ case SoundScape : ++ ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_Error ); ++ break; ++ ++ case Awe32 : ++ ErrorString = AWE32_ErrorString( AWE32_Error ); ++ break; ++ ++ case UltraSound : ++ ErrorString = GUS_ErrorString( GUS_Error ); ++ break; ++ ++ default : ++ ErrorString = MUSIC_ErrorString( MUSIC_InvalidCard ); ++ break; ++ } ++ break; ++ ++ case MUSIC_MPU401Error : ++ ErrorString = "Could not detect MPU-401."; ++ break; ++ ++ case MUSIC_InvalidCard : ++ ErrorString = "Invalid Music device."; ++ break; ++ ++ case MUSIC_MidiError : ++ ErrorString = "Error playing MIDI file."; ++ break; ++ ++ case MUSIC_TaskManError : ++ ErrorString = "TaskMan error."; ++ break; ++ ++ case MUSIC_FMNotDetected : ++ ErrorString = "Could not detect FM chip."; ++ break; ++ ++ case MUSIC_DPMI_Error : ++ ErrorString = "DPMI Error in MUSIC."; ++ break; ++ ++ default : ++ ErrorString = "Unknown Music error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_Init ++ ++ Selects which sound device to use. ++---------------------------------------------------------------------*/ ++ ++int MUSIC_Init ++ ( ++ int SoundCard, ++ int Address ++ ) ++ ++ { ++ int i; ++ int status; ++ ++ if ( USER_CheckParameter( "ASSVER" ) ) ++ { ++ MUSIC_SetErrorCode( MUSIC_ASSVersion ); ++ return( MUSIC_Error ); ++ } ++ ++ status = LL_LockMemory(); ++ if ( status != LL_Ok ) ++ { ++ MUSIC_SetErrorCode( MUSIC_DPMI_Error ); ++ return( MUSIC_Error ); ++ } ++ ++ for( i = 0; i < 128; i++ ) ++ { ++ MIDI_PatchMap[ i ] = i; ++ } ++ ++ status = MUSIC_Ok; ++ MUSIC_SoundDevice = SoundCard; ++ ++ switch( SoundCard ) ++ { ++ case SoundBlaster : ++ case Adlib : ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ status = MUSIC_InitFM( SoundCard, &MUSIC_MidiFunctions ); ++ break; ++ ++ case GenMidi : ++ case SoundCanvas : ++ case WaveBlaster : ++ case SoundScape : ++ status = MUSIC_InitMidi( SoundCard, &MUSIC_MidiFunctions, Address ); ++ break; ++ ++ case Awe32 : ++ status = MUSIC_InitAWE32( &MUSIC_MidiFunctions ); ++ break; ++ ++ case UltraSound : ++ status = MUSIC_InitGUS( &MUSIC_MidiFunctions ); ++ break; ++ ++ case SoundSource : ++ case PC : ++ default : ++ MUSIC_SetErrorCode( MUSIC_InvalidCard ); ++ status = MUSIC_Error; ++ } ++ ++ if ( status != MUSIC_Ok ) ++ { ++ LL_UnlockMemory(); ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_Shutdown ++ ++ Terminates use of sound device. ++---------------------------------------------------------------------*/ ++ ++int MUSIC_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = MUSIC_Ok; ++ ++ MIDI_StopSong(); ++ ++ if ( MUSIC_FadeTask != NULL ) ++ { ++ MUSIC_StopFade(); ++ } ++ ++ switch ( MUSIC_SoundDevice ) ++ { ++ case Adlib : ++ AL_Shutdown(); ++ break; ++ ++ case SoundBlaster : ++ AL_Shutdown(); ++ BLASTER_RestoreMidiVolume(); ++ break; ++ ++ case GenMidi : ++ case SoundCanvas : ++ case SoundScape : ++ MPU_Reset(); ++ break; ++ ++ case WaveBlaster : ++ BLASTER_ShutdownWaveBlaster(); ++ MPU_Reset(); ++ BLASTER_RestoreMidiVolume(); ++ break; ++ ++ case Awe32 : ++ AWE32_Shutdown(); ++ BLASTER_RestoreMidiVolume(); ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ AL_Shutdown(); ++ PAS_RestoreMusicVolume(); ++ break; ++ ++ case UltraSound : ++ GUSMIDI_Shutdown(); ++ break; ++ } ++ ++ LL_UnlockMemory(); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_SetMaxFMMidiChannel ++ ++ Sets the maximum MIDI channel that FM cards respond to. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_SetMaxFMMidiChannel ++ ( ++ int channel ++ ) ++ ++ { ++ AL_SetMaxMidiChannel( channel ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_SetVolume ++ ++ Sets the volume of music playback. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_SetVolume ++ ( ++ int volume ++ ) ++ ++ { ++ volume = max( 0, volume ); ++ volume = min( volume, 255 ); ++ ++ if ( MUSIC_SoundDevice != -1 ) ++ { ++ MIDI_SetVolume( volume ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_SetMidiChannelVolume ++ ++ Sets the volume of music playback on the specified MIDI channel. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_SetMidiChannelVolume ++ ( ++ int channel, ++ int volume ++ ) ++ ++ { ++ MIDI_SetUserChannelVolume( channel, volume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_ResetMidiChannelVolumes ++ ++ Sets the volume of music playback on all MIDI channels to full volume. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_ResetMidiChannelVolumes ++ ( ++ void ++ ) ++ ++ { ++ MIDI_ResetUserChannelVolume(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_GetVolume ++ ++ Returns the volume of music playback. ++---------------------------------------------------------------------*/ ++ ++int MUSIC_GetVolume ++ ( ++ void ++ ) ++ ++ { ++ if ( MUSIC_SoundDevice == -1 ) ++ { ++ return( 0 ); ++ } ++ return( MIDI_GetVolume() ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_SetLoopFlag ++ ++ Set whether the music will loop or end when it reaches the end of ++ the song. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_SetLoopFlag ++ ( ++ int loopflag ++ ) ++ ++ { ++ MIDI_SetLoopFlag( loopflag ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_SongPlaying ++ ++ Returns whether there is a song playing. ++---------------------------------------------------------------------*/ ++ ++int MUSIC_SongPlaying ++ ( ++ void ++ ) ++ ++ { ++ return( MIDI_SongPlaying() ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_Continue ++ ++ Continues playback of a paused song. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_Continue ++ ( ++ void ++ ) ++ ++ { ++ MIDI_ContinueSong(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_Pause ++ ++ Pauses playback of a song. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_Pause ++ ( ++ void ++ ) ++ ++ { ++ MIDI_PauseSong(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_StopSong ++ ++ Stops playback of current song. ++---------------------------------------------------------------------*/ ++ ++int MUSIC_StopSong ++ ( ++ void ++ ) ++ ++ { ++ MUSIC_StopFade(); ++ MIDI_StopSong(); ++ MUSIC_SetErrorCode( MUSIC_Ok ); ++ return( MUSIC_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_PlaySong ++ ++ Begins playback of MIDI song. ++---------------------------------------------------------------------*/ ++ ++int MUSIC_PlaySong ++ ( ++ unsigned char *song, ++ int loopflag ++ ) ++ ++ { ++ int status; ++ ++ switch( MUSIC_SoundDevice ) ++ { ++ case SoundBlaster : ++ case Adlib : ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ case GenMidi : ++ case SoundCanvas : ++ case WaveBlaster : ++ case SoundScape : ++ case Awe32 : ++ case UltraSound : ++ MIDI_StopSong(); ++ status = MIDI_PlaySong( song, loopflag ); ++ if ( status != MIDI_Ok ) ++ { ++ MUSIC_SetErrorCode( MUSIC_MidiError ); ++ return( MUSIC_Warning ); ++ } ++ break; ++ ++ case SoundSource : ++ case PC : ++ default : ++ MUSIC_SetErrorCode( MUSIC_InvalidCard ); ++ return( MUSIC_Warning ); ++ break; ++ } ++ ++ return( MUSIC_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_SetContext ++ ++ Sets the song context. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_SetContext ++ ( ++ int context ++ ) ++ ++ { ++ MIDI_SetContext( context ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_GetContext ++ ++ Returns the current song context. ++---------------------------------------------------------------------*/ ++ ++int MUSIC_GetContext ++ ( ++ void ++ ) ++ ++ { ++ return MIDI_GetContext(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_SetSongTick ++ ++ Sets the position of the song pointer. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_SetSongTick ++ ( ++ unsigned long PositionInTicks ++ ) ++ ++ { ++ MIDI_SetSongTick( PositionInTicks ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_SetSongTime ++ ++ Sets the position of the song pointer. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_SetSongTime ++ ( ++ unsigned long milliseconds ++ ) ++ ++ { ++ MIDI_SetSongTime( milliseconds ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_SetSongPosition ++ ++ Sets the position of the song pointer. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_SetSongPosition ++ ( ++ int measure, ++ int beat, ++ int tick ++ ) ++ ++ { ++ MIDI_SetSongPosition( measure, beat, tick ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_GetSongPosition ++ ++ Returns the position of the song pointer. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_GetSongPosition ++ ( ++ songposition *pos ++ ) ++ ++ { ++ MIDI_GetSongPosition( pos ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_GetSongLength ++ ++ Returns the length of the song. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_GetSongLength ++ ( ++ songposition *pos ++ ) ++ ++ { ++ MIDI_GetSongLength( pos ); ++ } ++ ++ ++int MUSIC_InitAWE32 ++ ( ++ midifuncs *Funcs ++ ) ++ ++ { ++ int status; ++ ++ status = AWE32_Init(); ++ if ( status != AWE32_Ok ) ++ { ++ MUSIC_SetErrorCode( MUSIC_SoundCardError ); ++ return( MUSIC_Error ); ++ } ++ ++ Funcs->NoteOff = AWE32_NoteOff; ++ Funcs->NoteOn = AWE32_NoteOn; ++ Funcs->PolyAftertouch = AWE32_PolyAftertouch; ++ Funcs->ControlChange = AWE32_ControlChange; ++ Funcs->ProgramChange = AWE32_ProgramChange; ++ Funcs->ChannelAftertouch = AWE32_ChannelAftertouch; ++ Funcs->PitchBend = AWE32_PitchBend; ++ Funcs->ReleasePatches = NULL; ++ Funcs->LoadPatch = NULL; ++ Funcs->SetVolume = NULL; ++ Funcs->GetVolume = NULL; ++ ++ if ( BLASTER_CardHasMixer() ) ++ { ++ BLASTER_SaveMidiVolume(); ++ Funcs->SetVolume = BLASTER_SetMidiVolume; ++ Funcs->GetVolume = BLASTER_GetMidiVolume; ++ } ++ ++ status = MUSIC_Ok; ++ MIDI_SetMidiFuncs( Funcs ); ++ ++ return( status ); ++ } ++ ++ ++int MUSIC_InitFM ++ ( ++ int card, ++ midifuncs *Funcs ++ ) ++ ++ { ++ int status; ++ int passtatus; ++ ++ status = MIDI_Ok; ++ ++ if ( !AL_DetectFM() ) ++ { ++ MUSIC_SetErrorCode( MUSIC_FMNotDetected ); ++ return( MUSIC_Error ); ++ } ++ ++ // Init the fm routines ++ AL_Init( card ); ++ ++ Funcs->NoteOff = AL_NoteOff; ++ Funcs->NoteOn = AL_NoteOn; ++ Funcs->PolyAftertouch = NULL; ++ Funcs->ControlChange = AL_ControlChange; ++ Funcs->ProgramChange = AL_ProgramChange; ++ Funcs->ChannelAftertouch = NULL; ++ Funcs->PitchBend = AL_SetPitchBend; ++ Funcs->ReleasePatches = NULL; ++ Funcs->LoadPatch = NULL; ++ Funcs->SetVolume = NULL; ++ Funcs->GetVolume = NULL; ++ ++ switch( card ) ++ { ++ case SoundBlaster : ++ if ( BLASTER_CardHasMixer() ) ++ { ++ BLASTER_SaveMidiVolume(); ++ Funcs->SetVolume = BLASTER_SetMidiVolume; ++ Funcs->GetVolume = BLASTER_GetMidiVolume; ++ } ++ else ++ { ++ Funcs->SetVolume = NULL; ++ Funcs->GetVolume = NULL; ++ } ++ break; ++ ++ case Adlib : ++ Funcs->SetVolume = NULL; ++ Funcs->GetVolume = NULL; ++ break; ++ ++ case ProAudioSpectrum : ++ case SoundMan16 : ++ Funcs->SetVolume = NULL; ++ Funcs->GetVolume = NULL; ++ ++ passtatus = PAS_SaveMusicVolume(); ++ if ( passtatus == PAS_Ok ) ++ { ++ Funcs->SetVolume = PAS_SetFMVolume; ++ Funcs->GetVolume = PAS_GetFMVolume; ++ } ++ break; ++ } ++ ++ MIDI_SetMidiFuncs( Funcs ); ++ ++ return( status ); ++ } ++ ++int MUSIC_InitMidi ++ ( ++ int card, ++ midifuncs *Funcs, ++ int Address ++ ) ++ ++ { ++ int status; ++ ++ status = MUSIC_Ok; ++ ++ if ( ( card == WaveBlaster ) || ( card == SoundCanvas ) || ++ ( card == GenMidi ) ) ++ { ++ // Setup WaveBlaster Daughterboard clone ++ // (ie. SoundCanvas DB, TurtleBeach Rio) ++ BLASTER_SetupWaveBlaster(); ++ } ++ ++ if ( card == SoundScape ) ++ { ++ Address = SOUNDSCAPE_GetMIDIPort(); ++ if ( Address < SOUNDSCAPE_Ok ) ++ { ++ MUSIC_SetErrorCode( MUSIC_SoundCardError ); ++ return( MUSIC_Error ); ++ } ++ } ++ ++ if ( MPU_Init( Address ) != MPU_Ok ) ++ { ++ MUSIC_SetErrorCode( MUSIC_MPU401Error ); ++ return( MUSIC_Error ); ++ } ++ ++ Funcs->NoteOff = MPU_NoteOff; ++ Funcs->NoteOn = MPU_NoteOn; ++ Funcs->PolyAftertouch = MPU_PolyAftertouch; ++ Funcs->ControlChange = MPU_ControlChange; ++ Funcs->ProgramChange = MPU_ProgramChange; ++ Funcs->ChannelAftertouch = MPU_ChannelAftertouch; ++ Funcs->PitchBend = MPU_PitchBend; ++ Funcs->ReleasePatches = NULL; ++ Funcs->LoadPatch = NULL; ++ Funcs->SetVolume = NULL; ++ Funcs->GetVolume = NULL; ++ ++ if ( card == WaveBlaster ) ++ { ++ if ( BLASTER_CardHasMixer() ) ++ { ++ BLASTER_SaveMidiVolume(); ++ Funcs->SetVolume = BLASTER_SetMidiVolume; ++ Funcs->GetVolume = BLASTER_GetMidiVolume; ++ } ++ } ++ ++ MIDI_SetMidiFuncs( Funcs ); ++ ++ return( status ); ++ } ++ ++int MUSIC_InitGUS ++ ( ++ midifuncs *Funcs ++ ) ++ ++ { ++ int status; ++ ++ status = MUSIC_Ok; ++ ++ if ( GUSMIDI_Init() != GUS_Ok ) ++ { ++ MUSIC_SetErrorCode( MUSIC_SoundCardError ); ++ return( MUSIC_Error ); ++ } ++ ++ Funcs->NoteOff = GUSMIDI_NoteOff; ++ Funcs->NoteOn = GUSMIDI_NoteOn; ++ Funcs->PolyAftertouch = NULL; ++ Funcs->ControlChange = GUSMIDI_ControlChange; ++ Funcs->ProgramChange = GUSMIDI_ProgramChange; ++ Funcs->ChannelAftertouch = NULL; ++ Funcs->PitchBend = GUSMIDI_PitchBend; ++ Funcs->ReleasePatches = NULL;//GUSMIDI_ReleasePatches; ++ Funcs->LoadPatch = NULL;//GUSMIDI_LoadPatch; ++ Funcs->SetVolume = GUSMIDI_SetVolume; ++ Funcs->GetVolume = GUSMIDI_GetVolume; ++ ++ MIDI_SetMidiFuncs( Funcs ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_FadeRoutine ++ ++ Fades music volume from current level to another over a specified ++ period of time. ++---------------------------------------------------------------------*/ ++ ++static void MUSIC_FadeRoutine ++ ( ++ task *Task ++ ) ++ ++ { ++ int volume; ++ ++ MUSIC_CurrentFadeVolume += MUSIC_FadeRate; ++ if ( MUSIC_FadeLength == 0 ) ++ { ++ MIDI_SetVolume( MUSIC_EndingFadeVolume ); ++ TS_Terminate( Task ); ++ MUSIC_FadeTask = NULL; ++ } ++ else ++ { ++ MUSIC_FadeLength--; ++// if ( ( MUSIC_SoundDevice == GenMidi ) && ++// ( ( MUSIC_FadeLength % 12 ) != 0 ) ) ++// { ++// return; ++// } ++ ++ volume = MUSIC_CurrentFadeVolume >> 7; ++ if ( MUSIC_LastFadeVolume != volume ) ++ { ++ MUSIC_LastFadeVolume = volume; ++ MIDI_SetVolume( volume ); ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_FadeVolume ++ ++ Fades music volume from current level to another over a specified ++ period of time. ++---------------------------------------------------------------------*/ ++ ++int MUSIC_FadeVolume ++ ( ++ int tovolume, ++ int milliseconds ++ ) ++ ++ { ++ int fromvolume; ++ ++ if ( ( MUSIC_SoundDevice == ProAudioSpectrum ) || ++ ( MUSIC_SoundDevice == SoundMan16 ) || ++ ( MUSIC_SoundDevice == GenMidi ) || ++ ( MUSIC_SoundDevice == SoundScape ) || ++ ( MUSIC_SoundDevice == SoundCanvas ) ) ++ { ++ MIDI_SetVolume( tovolume ); ++ return( MUSIC_Ok ); ++ } ++ ++ if ( MUSIC_FadeTask != NULL ) ++ { ++ MUSIC_StopFade(); ++ } ++ ++ tovolume = max( 0, tovolume ); ++ tovolume = min( 255, tovolume ); ++ fromvolume = MUSIC_GetVolume(); ++ ++ MUSIC_FadeLength = milliseconds / 25; ++ MUSIC_FadeRate = ( ( tovolume - fromvolume ) << 7 ) / MUSIC_FadeLength; ++ MUSIC_LastFadeVolume = fromvolume; ++ MUSIC_CurrentFadeVolume = fromvolume << 7; ++ MUSIC_EndingFadeVolume = tovolume; ++ ++ MUSIC_FadeTask = TS_ScheduleTask( MUSIC_FadeRoutine, 40, 1, NULL ); ++ if ( MUSIC_FadeTask == NULL ) ++ { ++ MUSIC_SetErrorCode( MUSIC_TaskManError ); ++ return( MUSIC_Warning ); ++ } ++ ++ TS_Dispatch(); ++ return( MUSIC_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_FadeActive ++ ++ Returns whether the fade routine is active. ++---------------------------------------------------------------------*/ ++ ++int MUSIC_FadeActive ++ ( ++ void ++ ) ++ ++ { ++ return( MUSIC_FadeTask != NULL ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_StopFade ++ ++ Stops fading the music. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_StopFade ++ ( ++ void ++ ) ++ ++ { ++ if ( MUSIC_FadeTask != NULL ) ++ { ++ TS_Terminate( MUSIC_FadeTask ); ++ MUSIC_FadeTask = NULL; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_RerouteMidiChannel ++ ++ Sets callback function to reroute MIDI commands from specified ++ function. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_RerouteMidiChannel ++ ( ++ int channel, ++ int cdecl ( *function )( int event, int c1, int c2 ) ++ ) ++ ++ { ++ MIDI_RerouteMidiChannel( channel, function ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: MUSIC_RegisterTimbreBank ++ ++ Halts playback of all sounds. ++---------------------------------------------------------------------*/ ++ ++void MUSIC_RegisterTimbreBank ++ ( ++ unsigned char *timbres ++ ) ++ ++ { ++ AL_RegisterTimbreBank( timbres ); ++ } +diff -urN rott-1.0/rott/audiolib/music.h trunk/rott/audiolib/music.h +--- rott-1.0/rott/audiolib/music.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/music.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,96 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: MUSIC.H ++ ++ author: James R. Dose ++ date: March 25, 1994 ++ ++ Public header for MUSIC.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __MUSIC_H ++#define __MUSIC_H ++ ++#include "sndcards.h" ++ ++#ifndef PLAT_DOS ++#define cdecl ++#endif ++ ++extern int MUSIC_ErrorCode; ++ ++enum MUSIC_ERRORS ++ { ++ MUSIC_Warning = -2, ++ MUSIC_Error = -1, ++ MUSIC_Ok = 0, ++ MUSIC_ASSVersion, ++ MUSIC_SoundCardError, ++ MUSIC_MPU401Error, ++ MUSIC_InvalidCard, ++ MUSIC_MidiError, ++ MUSIC_TaskManError, ++ MUSIC_FMNotDetected, ++ MUSIC_DPMI_Error ++ }; ++ ++typedef struct ++ { ++ unsigned long tickposition; ++ unsigned long milliseconds; ++ unsigned int measure; ++ unsigned int beat; ++ unsigned int tick; ++ } songposition; ++ ++#define MUSIC_LoopSong ( 1 == 1 ) ++#define MUSIC_PlayOnce ( !MUSIC_LoopSong ) ++ ++char *MUSIC_ErrorString( int ErrorNumber ); ++int MUSIC_Init( int SoundCard, int Address ); ++int MUSIC_Shutdown( void ); ++void MUSIC_SetMaxFMMidiChannel( int channel ); ++void MUSIC_SetVolume( int volume ); ++void MUSIC_SetMidiChannelVolume( int channel, int volume ); ++void MUSIC_ResetMidiChannelVolumes( void ); ++int MUSIC_GetVolume( void ); ++void MUSIC_SetLoopFlag( int loopflag ); ++int MUSIC_SongPlaying( void ); ++void MUSIC_Continue( void ); ++void MUSIC_Pause( void ); ++int MUSIC_StopSong( void ); ++int MUSIC_PlaySong( unsigned char *song, int loopflag ); ++void MUSIC_SetContext( int context ); ++int MUSIC_GetContext( void ); ++void MUSIC_SetSongTick( unsigned long PositionInTicks ); ++void MUSIC_SetSongTime( unsigned long milliseconds ); ++void MUSIC_SetSongPosition( int measure, int beat, int tick ); ++void MUSIC_GetSongPosition( songposition *pos ); ++void MUSIC_GetSongLength( songposition *pos ); ++int MUSIC_FadeVolume( int tovolume, int milliseconds ); ++int MUSIC_FadeActive( void ); ++void MUSIC_StopFade( void ); ++void MUSIC_RerouteMidiChannel( int channel, int cdecl ( *function )( int event, int c1, int c2 ) ); ++void MUSIC_RegisterTimbreBank( unsigned char *timbres ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/mv_mix.asm trunk/rott/audiolib/mv_mix.asm +--- rott-1.0/rott/audiolib/mv_mix.asm 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/mv_mix.asm 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,505 @@ ++ IDEAL ++ ++ p386 ++ MODEL flat ++ ++ dataseg ++ CODESEG ++ ++ MASM ++ ALIGN 4 ++ ++EXTRN _MV_HarshClipTable:DWORD ++EXTRN _MV_MixDestination:DWORD ++EXTRN _MV_MixPosition:DWORD ++EXTRN _MV_LeftVolume:DWORD ++EXTRN _MV_RightVolume:DWORD ++EXTRN _MV_SampleSize:DWORD ++EXTRN _MV_RightChannelOffset:DWORD ++ ++;================ ++; ++; MV_Mix8BitMono ++; ++;================ ++ ++; eax - position ++; edx - rate ++; ebx - start ++; ecx - number of samples to mix ++ ++PROC MV_Mix8BitMono_ ++PUBLIC MV_Mix8BitMono_ ++; Two at once ++ pushad ++ ++ mov ebp, eax ++ ++ mov esi, ebx ; Source pointer ++ ++ ; Sample size ++ mov ebx, _MV_SampleSize ++ mov eax,OFFSET apatch7+2 ; convice tasm to modify code... ++ mov [eax],bl ++ mov eax,OFFSET apatch8+2 ; convice tasm to modify code... ++ mov [eax],bl ++ mov eax,OFFSET apatch9+3 ; convice tasm to modify code... ++ mov [eax],bl ++ ++ ; Volume table ptr ++ mov ebx, _MV_LeftVolume ; Since we're mono, use left volume ++ mov eax,OFFSET apatch1+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET apatch2+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Harsh Clip table ptr ++ mov ebx, _MV_HarshClipTable ++ add ebx, 128 ++ mov eax,OFFSET apatch3+2 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET apatch4+2 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Rate scale ptr ++ mov eax,OFFSET apatch5+2 ; convice tasm to modify code... ++ mov [eax],edx ++ mov eax,OFFSET apatch6+2 ; convice tasm to modify code... ++ mov [eax],edx ++ ++ mov edi, _MV_MixDestination ; Get the position to write to ++ ++ ; Number of samples to mix ++ shr ecx, 1 ; double sample count ++ cmp ecx, 0 ++ je short exit8m ++ ++; eax - scratch ++; ebx - scratch ++; edx - scratch ++; ecx - count ++; edi - destination ++; esi - source ++; ebp - frac pointer ++; apatch1 - volume table ++; apatch2 - volume table ++; apatch3 - harsh clip table ++; apatch4 - harsh clip table ++; apatch5 - sample rate ++; apatch6 - sample rate ++ ++ mov eax,ebp ; begin calculating first sample ++ add ebp,edx ; advance frac pointer ++ shr eax,16 ; finish calculation for first sample ++ ++ mov ebx,ebp ; begin calculating second sample ++ add ebp,edx ; advance frac pointer ++ shr ebx,16 ; finish calculation for second sample ++ ++ movzx eax, byte ptr [esi+eax] ; get first sample ++ movzx ebx, byte ptr [esi+ebx] ; get second sample ++ ++ ALIGN 4 ++mix8Mloop: ++ movzx edx, byte ptr [edi] ; get current sample from destination ++apatch1: ++ movsx eax, byte ptr [2*eax+12345678h] ; volume translate first sample ++apatch2: ++ movsx ebx, byte ptr [2*ebx+12345678h] ; volume translate second sample ++ add eax, edx ; mix first sample ++apatch9: ++ movzx edx, byte ptr [edi + 1] ; get current sample from destination ++apatch3: ++ mov eax, [eax + 12345678h] ; harsh clip new sample ++ add ebx, edx ; mix second sample ++ mov [edi], al ; write new sample to destination ++ mov edx, ebp ; begin calculating third sample ++apatch4: ++ mov ebx, [ebx + 12345678h] ; harsh clip new sample ++apatch5: ++ add ebp,12345678h ; advance frac pointer ++ shr edx, 16 ; finish calculation for third sample ++ mov eax, ebp ; begin calculating fourth sample ++apatch7: ++ add edi, 1 ; move destination to second sample ++ shr eax, 16 ; finish calculation for fourth sample ++ mov [edi], bl ; write new sample to destination ++apatch6: ++ add ebp,12345678h ; advance frac pointer ++ movzx ebx, byte ptr [esi+eax] ; get fourth sample ++ movzx eax, byte ptr [esi+edx] ; get third sample ++apatch8: ++ add edi, 2 ; move destination to third sample ++ dec ecx ; decrement count ++ jnz mix8Mloop ; loop ++ ++ mov _MV_MixDestination, edi ; Store the current write position ++ mov _MV_MixPosition, ebp ; return position ++exit8m: ++ popad ++ ret ++ENDP MV_Mix8BitMono_ ++ ++;================ ++; ++; MV_Mix8BitStereo ++; ++;================ ++ ++; eax - position ++; edx - rate ++; ebx - start ++; ecx - number of samples to mix ++ ++PROC MV_Mix8BitStereo_ ++PUBLIC MV_Mix8BitStereo_ ++ ++ pushad ++ mov ebp, eax ++ ++ mov esi, ebx ; Source pointer ++ ++ ; Sample size ++ mov ebx, _MV_SampleSize ++ mov eax,OFFSET bpatch8+2 ; convice tasm to modify code... ++ mov [eax],bl ++ ++ ; Right channel offset ++ mov ebx, _MV_RightChannelOffset ++ mov eax,OFFSET bpatch6+3 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET bpatch7+2 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Volume table ptr ++ mov ebx, _MV_LeftVolume ++ mov eax,OFFSET bpatch1+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ mov ebx, _MV_RightVolume ++ mov eax,OFFSET bpatch2+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Rate scale ptr ++ mov eax,OFFSET bpatch3+2 ; convice tasm to modify code... ++ mov [eax],edx ++ ++ ; Harsh Clip table ptr ++ mov ebx, _MV_HarshClipTable ++ add ebx,128 ++ mov eax,OFFSET bpatch4+2 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET bpatch5+2 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ mov edi, _MV_MixDestination ; Get the position to write to ++ ++ ; Number of samples to mix ++ cmp ecx, 0 ++ je short exit8S ++ ++; eax - scratch ++; ebx - scratch ++; edx - scratch ++; ecx - count ++; edi - destination ++; esi - source ++; ebp - frac pointer ++; bpatch1 - left volume table ++; bpatch2 - right volume table ++; bpatch3 - sample rate ++; bpatch4 - harsh clip table ++; bpatch5 - harsh clip table ++ ++ mov eax,ebp ; begin calculating first sample ++ shr eax,16 ; finish calculation for first sample ++ ++ movzx ebx, byte ptr [esi+eax] ; get first sample ++ ++ ALIGN 4 ++mix8Sloop: ++bpatch1: ++ movsx eax, byte ptr [2*ebx+12345678h] ; volume translate left sample ++ movzx edx, byte ptr [edi] ; get current sample from destination ++bpatch2: ++ movsx ebx, byte ptr [2*ebx+12345678h] ; volume translate right sample ++ add eax, edx ; mix left sample ++bpatch3: ++ add ebp,12345678h ; advance frac pointer ++bpatch6: ++ movzx edx, byte ptr [edi+12345678h] ; get current sample from destination ++bpatch4: ++ mov eax, [eax + 12345678h] ; harsh clip left sample ++ add ebx, edx ; mix right sample ++ mov [edi], al ; write left sample to destination ++bpatch5: ++ mov ebx, [ebx + 12345678h] ; harsh clip right sample ++ mov edx, ebp ; begin calculating second sample ++bpatch7: ++ mov [edi+12345678h], bl ; write right sample to destination ++ shr edx, 16 ; finish calculation for second sample ++bpatch8: ++ add edi, 2 ; move destination to second sample ++ movzx ebx, byte ptr [esi+edx] ; get second sample ++ dec ecx ; decrement count ++ jnz mix8Sloop ; loop ++ ++ mov _MV_MixDestination, edi ; Store the current write position ++ mov _MV_MixPosition, ebp ; return position ++ ++EXIT8S: ++ popad ++ ret ++ENDP MV_Mix8BitStereo_ ++ ++;================ ++; ++; MV_Mix16BitMono ++; ++;================ ++ ++; eax - position ++; edx - rate ++; ebx - start ++; ecx - number of samples to mix ++ ++PROC MV_Mix16BitMono_ ++PUBLIC MV_Mix16BitMono_ ++; Two at once ++ pushad ++ ++ mov ebp, eax ++ ++ mov esi, ebx ; Source pointer ++ ++ ; Sample size ++ mov ebx, _MV_SampleSize ++ mov eax,OFFSET cpatch5+3 ; convice tasm to modify code... ++ mov [eax],bl ++ mov eax,OFFSET cpatch6+3 ; convice tasm to modify code... ++ mov [eax],bl ++ mov eax,OFFSET cpatch7+2 ; convice tasm to modify code... ++ add bl,bl ++ mov [eax],bl ++ ++ ; Volume table ptr ++ mov ebx, _MV_LeftVolume ++ mov eax,OFFSET cpatch1+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET cpatch2+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Rate scale ptr ++ mov eax,OFFSET cpatch3+2 ; convice tasm to modify code... ++ mov [eax],edx ++ mov eax,OFFSET cpatch4+2 ; convice tasm to modify code... ++ mov [eax],edx ++ ++ mov edi, _MV_MixDestination ; Get the position to write to ++ ++ ; Number of samples to mix ++ shr ecx, 1 ; double sample count ++ cmp ecx, 0 ++ je exit16M ++ ++; eax - scratch ++; ebx - scratch ++; edx - scratch ++; ecx - count ++; edi - destination ++; esi - source ++; ebp - frac pointer ++; cpatch1 - volume table ++; cpatch2 - volume table ++; cpatch3 - sample rate ++; cpatch4 - sample rate ++ ++ mov eax,ebp ; begin calculating first sample ++ add ebp,edx ; advance frac pointer ++ shr eax,16 ; finish calculation for first sample ++ ++ mov ebx,ebp ; begin calculating second sample ++ add ebp,edx ; advance frac pointer ++ shr ebx,16 ; finish calculation for second sample ++ ++ movzx eax, byte ptr [esi+eax] ; get first sample ++ movzx ebx, byte ptr [esi+ebx] ; get second sample ++ ++ ALIGN 4 ++mix16Mloop: ++ movsx edx, word ptr [edi] ; get current sample from destination ++cpatch1: ++ movsx eax, word ptr [2*eax+12345678h] ; volume translate first sample ++cpatch2: ++ movsx ebx, word ptr [2*ebx+12345678h] ; volume translate second sample ++ add eax, edx ; mix first sample ++cpatch5: ++ movsx edx, word ptr [edi + 2] ; get current sample from destination ++ ++ cmp eax, -32768 ; Harsh clip sample ++ jge short m16skip1 ++ mov eax, -32768 ++ jmp short m16skip2 ++m16skip1: ++ cmp eax, 32767 ++ jle short m16skip2 ++ mov eax, 32767 ++m16skip2: ++ add ebx, edx ; mix second sample ++ mov [edi], ax ; write new sample to destination ++ mov edx, ebp ; begin calculating third sample ++ ++ cmp ebx, -32768 ; Harsh clip sample ++ jge short m16skip3 ++ mov ebx, -32768 ++ jmp short m16skip4 ++m16skip3: ++ cmp ebx, 32767 ++ jle short m16skip4 ++ mov ebx, 32767 ++m16skip4: ++cpatch3: ++ add ebp,12345678h ; advance frac pointer ++ shr edx, 16 ; finish calculation for third sample ++ mov eax, ebp ; begin calculating fourth sample ++cpatch6: ++ mov [edi + 2], bx ; write new sample to destination ++ shr eax, 16 ; finish calculation for fourth sample ++ ++cpatch4: ++ add ebp,12345678h ; advance frac pointer ++ movzx ebx, byte ptr [esi+eax] ; get fourth sample ++cpatch7: ++ add edi, 4 ; move destination to third sample ++ movzx eax, byte ptr [esi+edx] ; get third sample ++ dec ecx ; decrement count ++ jnz mix16Mloop ; loop ++ ++ mov _MV_MixDestination, edi ; Store the current write position ++ mov _MV_MixPosition, ebp ; return position ++EXIT16M: ++ popad ++ ret ++ENDP MV_Mix16BitMono_ ++ ++;================ ++; ++; MV_Mix16BitStereo ++; ++;================ ++ ++; eax - position ++; edx - rate ++; ebx - start ++; ecx - number of samples to mix ++ ++PROC MV_Mix16BitStereo_ ++PUBLIC MV_Mix16BitStereo_ ++ ++ pushad ++ mov ebp, eax ++ ++ mov esi, ebx ; Source pointer ++ ++ ; Sample size ++ mov ebx, _MV_SampleSize ++ mov eax,OFFSET dpatch6+2 ; convice tasm to modify code... ++ mov [eax],bl ++ ++ ; Right channel offset ++ mov ebx, _MV_RightChannelOffset ++ mov eax,OFFSET dpatch4+3 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET dpatch5+3 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Volume table ptr ++ mov ebx, _MV_LeftVolume ++ mov eax,OFFSET dpatch1+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ mov ebx, _MV_RightVolume ++ mov eax,OFFSET dpatch2+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Rate scale ptr ++ mov eax,OFFSET dpatch3+2 ; convice tasm to modify code... ++ mov [eax],edx ++ ++ mov edi, _MV_MixDestination ; Get the position to write to ++ ++ ; Number of samples to mix ++ cmp ecx, 0 ++ je exit16S ++ ++; eax - scratch ++; ebx - scratch ++; edx - scratch ++; ecx - count ++; edi - destination ++; esi - source ++; ebp - frac pointer ++; dpatch1 - left volume table ++; dpatch2 - right volume table ++; dpatch3 - sample rate ++ ++ mov eax,ebp ; begin calculating first sample ++ shr eax,16 ; finish calculation for first sample ++ ++ movzx ebx, byte ptr [esi+eax] ; get first sample ++ ++ ALIGN 4 ++mix16Sloop: ++dpatch1: ++ movsx eax, word ptr [2*ebx+12345678h] ; volume translate left sample ++ movsx edx, word ptr [edi] ; get current sample from destination ++dpatch2: ++ movsx ebx, word ptr [2*ebx+12345678h] ; volume translate right sample ++ add eax, edx ; mix left sample ++dpatch3: ++ add ebp,12345678h ; advance frac pointer ++dpatch4: ++ movsx edx, word ptr [edi+12345678h] ; get current sample from destination ++ ++ cmp eax, -32768 ; Harsh clip sample ++ jge short s16skip1 ++ mov eax, -32768 ++ jmp short s16skip2 ++s16skip1: ++ cmp eax, 32767 ++ jle short s16skip2 ++ mov eax, 32767 ++s16skip2: ++ add ebx, edx ; mix right sample ++ mov [edi], ax ; write left sample to destination ++ ++ cmp ebx, -32768 ; Harsh clip sample ++ jge short s16skip3 ++ mov ebx, -32768 ++ jmp short s16skip4 ++s16skip3: ++ cmp ebx, 32767 ++ jle short s16skip4 ++ mov ebx, 32767 ++s16skip4: ++ ++ mov edx, ebp ; begin calculating second sample ++dpatch5: ++ mov [edi+12345678h], bx ; write right sample to destination ++ shr edx, 16 ; finish calculation for second sample ++dpatch6: ++ add edi, 4 ; move destination to second sample ++ movzx ebx, byte ptr [esi+edx] ; get second sample ++ dec ecx ; decrement count ++ jnz mix16Sloop ; loop ++ ++ mov _MV_MixDestination, edi ; Store the current write position ++ mov _MV_MixPosition, ebp ; return position ++exit16S: ++ popad ++ ret ++ENDP MV_Mix16BitStereo_ ++ ++ ENDS ++ ++ END +diff -urN rott-1.0/rott/audiolib/mv_mix.c trunk/rott/audiolib/mv_mix.c +--- rott-1.0/rott/audiolib/mv_mix.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/mv_mix.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,293 @@ ++#include "multivoc.h" ++ ++extern char *MV_MixDestination; ++extern unsigned long MV_MixPosition; ++ ++extern char *MV_LeftVolume; ++extern char *MV_RightVolume; ++ ++extern unsigned char *MV_HarshClipTable; ++ ++extern int MV_RightChannelOffset; ++extern int MV_SampleSize; ++ ++void MV_Mix8BitMono( unsigned long position, unsigned long rate, ++ const char *start, unsigned long length ) ++{ ++ const unsigned char *src; ++ unsigned char *dest; ++ unsigned int i; ++ ++ src = (const unsigned char *)start; ++ dest = (unsigned char *)MV_MixDestination; ++ ++ for (i = 0; i < length; i++) { ++ int s = src[position >> 16]; ++ int d = *dest; ++ ++ s = MV_LeftVolume[s * 2]; ++ ++ s += d; ++ ++ s = MV_HarshClipTable[s + 0x80]; ++ ++ *dest = (s & 0xff); ++ ++ position += rate; ++ dest += MV_SampleSize; ++ } ++ ++ MV_MixPosition = position; ++ MV_MixDestination = (char *)dest; ++} ++ ++void MV_Mix8BitStereo( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ) ++{ ++ const unsigned char *src; ++ unsigned char *dest; ++ unsigned int i; ++ ++ src = (const unsigned char *)start; ++ dest = (unsigned char *)MV_MixDestination; ++ ++ for (i = 0; i < length; i++) { ++ int s = src[(position >> 16)]; ++ int dl = dest[0]; ++ int dr = dest[MV_RightChannelOffset]; ++ ++ dl += MV_LeftVolume[s * 2]; ++ dr += MV_RightVolume[s * 2]; ++ ++ dl = MV_HarshClipTable[dl + 0x80]; ++ dr = MV_HarshClipTable[dr + 0x80]; ++ ++ dest[0] = (dl & 0xff); ++ dest[MV_RightChannelOffset] = (dr & 0xff); ++ ++ position += rate; ++ dest += MV_SampleSize; ++ } ++ ++ MV_MixPosition = position; ++ MV_MixDestination = (char *)dest; ++} ++ ++void MV_Mix16BitMono( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ) ++{ ++ const short *MV_LeftVolumeS; ++ const unsigned char *src; ++ short *dest; ++ unsigned int i; ++ ++ src = (const unsigned char *)start; ++ dest = (short *)MV_MixDestination; ++ ++ MV_LeftVolumeS = (const short *)MV_LeftVolume; ++ ++ for (i = 0; i < length; i++) { ++ int s = src[position >> 16]; ++ int d = dest[0]; ++ ++ s = MV_LeftVolumeS[s]; ++ ++ s += d; ++ ++ if (s < -32768) s = -32768; ++ if (s > 32767) s = 32767; ++ ++ *dest = (short) s; ++ ++ position += rate; ++ dest += MV_SampleSize/2; ++ } ++ ++ MV_MixPosition = position; ++ MV_MixDestination = (char *)dest; ++} ++ ++void MV_Mix16BitStereo( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ) ++{ ++ const short *MV_LeftVolumeS; ++ const short *MV_RightVolumeS; ++ const unsigned char *src; ++ short *dest; ++ unsigned int i; ++ ++ src = (unsigned char *)start; ++ dest = (short *)MV_MixDestination; ++ ++ MV_LeftVolumeS = (const short *)MV_LeftVolume; ++ MV_RightVolumeS = (const short *)MV_RightVolume; ++ ++ for (i = 0; i < length; i++) { ++ int s = src[position >> 16]; ++ int dl = dest[0]; ++ int dr = dest[MV_RightChannelOffset/2]; ++ ++ dl += MV_LeftVolumeS[s]; ++ dr += MV_RightVolumeS[s]; ++ ++ if (dl < -32768) dl = -32768; ++ if (dl > 32767) dl = 32767; ++ if (dr < -32768) dr = -32768; ++ if (dr > 32767) dr = 32767; ++ ++ dest[0] = (short) dl; ++ dest[MV_RightChannelOffset/2] = (short) dr; ++ ++ position += rate; ++ dest += MV_SampleSize/2; ++ } ++ ++ MV_MixPosition = position; ++ MV_MixDestination = (char *)dest; ++} ++ ++void MV_Mix8BitMono16( unsigned long position, unsigned long rate, ++ const char *start, unsigned long length ) ++{ ++ const char *src; ++ unsigned char *dest; ++ unsigned int i; ++ ++ src = (const char *)start + 1; ++ dest = (unsigned char *)MV_MixDestination; ++ ++ for (i = 0; i < length; i++) { ++ int s = (int)src[(position >> 16) * 2] + 0x80; ++ int d = *dest; ++ ++ s = MV_LeftVolume[s * 2]; ++ ++ s += d; ++ ++ s = MV_HarshClipTable[s + 0x80]; ++ ++ *dest = (s & 0xff); ++ ++ position += rate; ++ dest += MV_SampleSize; ++ } ++ ++ MV_MixPosition = position; ++ MV_MixDestination = (char *)dest; ++} ++ ++void MV_Mix8BitStereo16( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ) ++{ ++ const char *src; ++ unsigned char *dest; ++ unsigned int i; ++ ++ src = (const char *)start + 1; ++ dest = (unsigned char *)MV_MixDestination; ++ ++ for (i = 0; i < length; i++) { ++ int s = src[(position >> 16) * 2] + 0x80; ++ int dl = dest[0]; ++ int dr = dest[MV_RightChannelOffset]; ++ ++ dl += MV_LeftVolume[s * 2]; ++ dr += MV_RightVolume[s * 2]; ++ ++ dl = MV_HarshClipTable[dl + 0x80]; ++ dr = MV_HarshClipTable[dr + 0x80]; ++ ++ dest[0] = (dl & 0xff); ++ dest[MV_RightChannelOffset] = (dr & 0xff); ++ ++ position += rate; ++ dest += MV_SampleSize; ++ } ++ ++ MV_MixPosition = position; ++ MV_MixDestination = (char *)dest; ++} ++ ++void MV_Mix16BitMono16( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ) ++{ ++ const short *MV_LeftVolumeS; ++ const unsigned char *src; ++ short *dest; ++ unsigned int i; ++ ++ src = (const unsigned char *)start; ++ dest = (short *)MV_MixDestination; ++ ++ MV_LeftVolumeS = (const short *)MV_LeftVolume; ++ ++ for (i = 0; i < length; i++) { ++ int sl = src[(position >> 16) * 2 + 0]; ++ int sh = src[(position >> 16) * 2 + 1] ^ 0x80; ++ ++ int d = *dest; ++ ++ sl = MV_LeftVolume[sl * 2 + 1]; ++ sh = MV_LeftVolumeS[sh]; ++ ++ d = sl + sh + 0x80 + d; ++ ++ if (d < -32768) d = -32768; ++ if (d > 32767) d = 32767; ++ ++ *dest = (short) d; ++ ++ position += rate; ++ dest += MV_SampleSize/2; ++ } ++ ++ MV_MixPosition = position; ++ MV_MixDestination = (char *)dest; ++} ++ ++void MV_Mix16BitStereo16( unsigned long position, ++ unsigned long rate, const char *start, unsigned long length ) ++{ ++ const short *MV_LeftVolumeS; ++ const short *MV_RightVolumeS; ++ const unsigned char *src; ++ short *dest; ++ unsigned int i; ++ ++ src = (const unsigned char *)start; ++ dest = (short *)MV_MixDestination; ++ ++ MV_LeftVolumeS = (const short *)MV_LeftVolume; ++ MV_RightVolumeS = (const short *)MV_RightVolume; ++ ++ for (i = 0; i < length; i++) { ++ int sl = src[(position >> 16) * 2 + 0]; ++ int sh = src[(position >> 16) * 2 + 1] ^ 0x80; ++ ++ int dl = dest[0]; ++ int dr = dest[MV_RightChannelOffset/2]; ++ ++ int sll = MV_LeftVolume[sl * 2 + 1]; ++ int slh = MV_LeftVolumeS[sh]; ++ ++ int srl = MV_RightVolume[sl * 2 + 1]; ++ int srh = MV_RightVolumeS[sh]; ++ ++ dl = sll + slh + 0x80 + dl; ++ dr = srl + srh + 0x80 + dr; ++ ++ if (dl < -32768) dl = -32768; ++ if (dl > 32767) dl = 32767; ++ if (dr < -32768) dr = -32768; ++ if (dr > 32767) dr = 32767; ++ ++ dest[0] = (short) dl; ++ dest[MV_RightChannelOffset/2] = (short) dr; ++ ++ position += rate; ++ dest += MV_SampleSize/2; ++ } ++ ++ MV_MixPosition = position; ++ MV_MixDestination = (char *)dest; ++} +diff -urN rott-1.0/rott/audiolib/mv_mix16.asm trunk/rott/audiolib/mv_mix16.asm +--- rott-1.0/rott/audiolib/mv_mix16.asm 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/mv_mix16.asm 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,524 @@ ++ IDEAL ++ ++ p386 ++ MODEL flat ++ ++ dataseg ++ CODESEG ++ ++ MASM ++ ALIGN 4 ++ ++EXTRN _MV_HarshClipTable:DWORD ++EXTRN _MV_MixDestination:DWORD ++EXTRN _MV_MixPosition:DWORD ++EXTRN _MV_LeftVolume:DWORD ++EXTRN _MV_RightVolume:DWORD ++EXTRN _MV_SampleSize:DWORD ++EXTRN _MV_RightChannelOffset:DWORD ++ ++;================ ++; ++; MV_Mix8BitMono16 ++; ++;================ ++ ++; eax - position ++; edx - rate ++; ebx - start ++; ecx - number of samples to mix ++ ++PROC MV_Mix8BitMono16_ ++PUBLIC MV_Mix8BitMono16_ ++; Two at once ++ pushad ++ mov ebp, eax ++ ++ mov esi, ebx ; Source pointer ++ inc esi ++ ++ ; Sample size ++ mov ebx, _MV_SampleSize ++ mov eax,OFFSET apatch7+2 ; convice tasm to modify code... ++ mov [eax],bl ++ mov eax,OFFSET apatch8+2 ; convice tasm to modify code... ++ mov [eax],bl ++ mov eax,OFFSET apatch9+3 ; convice tasm to modify code... ++ mov [eax],bl ++ ++ ; Volume table ptr ++ mov ebx, _MV_LeftVolume ; Since we're mono, use left volume ++ mov eax,OFFSET apatch1+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET apatch2+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Harsh Clip table ptr ++ mov ebx, _MV_HarshClipTable ++ add ebx, 128 ++ mov eax,OFFSET apatch3+2 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET apatch4+2 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Rate scale ptr ++ mov eax,OFFSET apatch5+2 ; convice tasm to modify code... ++ mov [eax],edx ++ mov eax,OFFSET apatch6+2 ; convice tasm to modify code... ++ mov [eax],edx ++ ++ mov edi, _MV_MixDestination ; Get the position to write to ++ ++ ; Number of samples to mix ++ shr ecx, 1 ; double sample count ++ cmp ecx, 0 ++ je exit8m ++ ++; eax - scratch ++; ebx - scratch ++; edx - scratch ++; ecx - count ++; edi - destination ++; esi - source ++; ebp - frac pointer ++; apatch1 - volume table ++; apatch2 - volume table ++; apatch3 - harsh clip table ++; apatch4 - harsh clip table ++; apatch5 - sample rate ++; apatch6 - sample rate ++ ++ mov eax,ebp ; begin calculating first sample ++ add ebp,edx ; advance frac pointer ++ shr eax,16 ; finish calculation for first sample ++ ++ mov ebx,ebp ; begin calculating second sample ++ add ebp,edx ; advance frac pointer ++ shr ebx,16 ; finish calculation for second sample ++ ++ movsx eax, byte ptr [esi+2*eax] ; get first sample ++ movsx ebx, byte ptr [esi+2*ebx] ; get second sample ++ add eax, 80h ++ add ebx, 80h ++ ++ ALIGN 4 ++mix8Mloop: ++ movzx edx, byte ptr [edi] ; get current sample from destination ++apatch1: ++ movsx eax, byte ptr [2*eax+12345678h] ; volume translate first sample ++apatch2: ++ movsx ebx, byte ptr [2*ebx+12345678h] ; volume translate second sample ++ add eax, edx ; mix first sample ++apatch9: ++ movzx edx, byte ptr [edi + 1] ; get current sample from destination ++apatch3: ++ mov eax, [eax + 12345678h] ; harsh clip new sample ++ add ebx, edx ; mix second sample ++ mov [edi], al ; write new sample to destination ++ mov edx, ebp ; begin calculating third sample ++apatch4: ++ mov ebx, [ebx + 12345678h] ; harsh clip new sample ++apatch5: ++ add ebp,12345678h ; advance frac pointer ++ shr edx, 16 ; finish calculation for third sample ++ mov eax, ebp ; begin calculating fourth sample ++apatch7: ++ add edi, 2 ; move destination to second sample ++ shr eax, 16 ; finish calculation for fourth sample ++ mov [edi], bl ; write new sample to destination ++apatch6: ++ add ebp,12345678h ; advance frac pointer ++ movsx ebx, byte ptr [esi+2*eax] ; get fourth sample ++ movsx eax, byte ptr [esi+2*edx] ; get third sample ++ add ebx, 80h ++ add eax, 80h ++apatch8: ++ add edi, 2 ; move destination to third sample ++ dec ecx ; decrement count ++ jnz mix8Mloop ; loop ++ ++ mov _MV_MixDestination, edi ; Store the current write position ++ mov _MV_MixPosition, ebp ; return position ++exit8m: ++ popad ++ ret ++ENDP MV_Mix8BitMono16_ ++ ++;================ ++; ++; MV_Mix8BitStereo16 ++; ++;================ ++ ++; eax - position ++; edx - rate ++; ebx - start ++; ecx - number of samples to mix ++ ++PROC MV_Mix8BitStereo16_ ++PUBLIC MV_Mix8BitStereo16_ ++ ++ pushad ++ mov ebp, eax ++ ++ mov esi, ebx ; Source pointer ++ inc esi ++ ++ ; Sample size ++ mov ebx, _MV_SampleSize ++ mov eax,OFFSET bpatch8+2 ; convice tasm to modify code... ++ mov [eax],bl ++ ; mov eax,OFFSET bpatch9+2 ; convice tasm to modify code... ++ ; mov [eax],bl ++ ++ ; Right channel offset ++ mov ebx, _MV_RightChannelOffset ++ mov eax,OFFSET bpatch6+3 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET bpatch7+2 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Volume table ptr ++ mov ebx, _MV_LeftVolume ++ mov eax,OFFSET bpatch1+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ mov ebx, _MV_RightVolume ++ mov eax,OFFSET bpatch2+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Rate scale ptr ++ mov eax,OFFSET bpatch3+2 ; convice tasm to modify code... ++ mov [eax],edx ++ ++ ; Harsh Clip table ptr ++ mov ebx, _MV_HarshClipTable ++ add ebx,128 ++ mov eax,OFFSET bpatch4+2 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET bpatch5+2 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ mov edi, _MV_MixDestination ; Get the position to write to ++ ++ ; Number of samples to mix ++ cmp ecx, 0 ++ je short exit8S ++ ++; eax - scratch ++; ebx - scratch ++; edx - scratch ++; ecx - count ++; edi - destination ++; esi - source ++; ebp - frac pointer ++; bpatch1 - left volume table ++; bpatch2 - right volume table ++; bpatch3 - sample rate ++; bpatch4 - harsh clip table ++; bpatch5 - harsh clip table ++ ++ mov eax,ebp ; begin calculating first sample ++ shr eax,16 ; finish calculation for first sample ++ ++ movsx ebx, byte ptr [esi+2*eax] ; get first sample ++ add ebx, 80h ++ ++ ALIGN 4 ++mix8Sloop: ++bpatch1: ++ movsx eax, byte ptr [2*ebx+12345678h] ; volume translate left sample ++ movzx edx, byte ptr [edi] ; get current sample from destination ++bpatch2: ++ movsx ebx, byte ptr [2*ebx+12345678h] ; volume translate right sample ++ add eax, edx ; mix left sample ++bpatch3: ++ add ebp,12345678h ; advance frac pointer ++bpatch6: ++ movzx edx, byte ptr [edi+12345678h] ; get current sample from destination ++bpatch4: ++ mov eax, [eax + 12345678h] ; harsh clip left sample ++ add ebx, edx ; mix right sample ++ mov [edi], al ; write left sample to destination ++bpatch5: ++ mov ebx, [ebx + 12345678h] ; harsh clip right sample ++ mov edx, ebp ; begin calculating second sample ++bpatch7: ++ mov [edi+12345678h], bl ; write right sample to destination ++ shr edx, 16 ; finish calculation for second sample ++bpatch8: ++ add edi, 1 ; move destination to second sample ++ movsx ebx, byte ptr [esi+2*edx] ; get second sample ++ add ebx, 80h ++ dec ecx ; decrement count ++ jnz mix8Sloop ; loop ++ ++ mov _MV_MixDestination, edi ; Store the current write position ++ mov _MV_MixPosition, ebp ; return position ++ ++EXIT8S: ++ popad ++ ret ++ENDP MV_Mix8BitStereo16_ ++ ++;================ ++; ++; MV_Mix16BitMono16 ++; ++;================ ++ ++; eax - position ++; edx - rate ++; ebx - start ++; ecx - number of samples to mix ++ ++PROC MV_Mix16BitMono16_ ++PUBLIC MV_Mix16BitMono16_ ++ ++ pushad ++ mov ebp, eax ++ ++ mov esi, ebx ; Source pointer ++ ++ ; Sample size ++ mov ebx, _MV_SampleSize ++ mov eax,OFFSET cpatch4+2 ; convice tasm to modify code... ++ mov [eax],bl ++ mov eax,OFFSET cpatch5+3 ; convice tasm to modify code... ++ mov [eax],bl ++ ++ ; Volume table ptr ++ mov ebx, _MV_LeftVolume ++ mov eax,OFFSET cpatch2+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET cpatch1+4 ; convice tasm to modify code... ++ inc ebx ++ mov [eax],ebx ++ ++ ; Rate scale ptr ++ mov eax,OFFSET cpatch3+2 ; convice tasm to modify code... ++ mov [eax],edx ++ ++ mov edi, _MV_MixDestination ; Get the position to write to ++ ++ ; Number of samples to mix ++ cmp ecx, 0 ++ je exit16M ++ ++; eax - scratch ++; ebx - scratch ++; edx - scratch ++; ecx - count ++; edi - destination ++; esi - source ++; ebp - frac pointer ++; cpatch1 - volume table ++; cpatch2 - volume table ++; cpatch3 - sample rate ++; cpatch4 - sample rate ++ ++ mov ebx,ebp ; begin calculating first sample ++ add ebp,edx ; advance frac pointer ++ shr ebx,16 ; finish calculation for first sample ++ movzx eax, word ptr [esi+2*ebx] ; get low byte of sample ++ xor eax, 8000h ++ movzx ebx, ah ++ sub ah, ah ++ ++ movsx edx, word ptr [edi] ; get current sample from destination ++ ++ ALIGN 4 ++mix16Mloop: ++cpatch1: ++ movsx eax, byte ptr [2*eax+12345678h] ; volume translate low byte of sample ++cpatch2: ++ movsx ebx, word ptr [2*ebx+12345678h] ; volume translate high byte of sample ++ lea eax, [ eax + ebx + 80h ] ; mix high byte of sample ++ add eax, edx ; mix low byte of sample ++cpatch5: ++ movsx edx, word ptr [edi + 2] ; get current sample from destination ++ ++ cmp eax, -32768 ; Harsh clip sample ++ jge short m16skip1 ++ mov eax, -32768 ++ jmp short m16skip2 ++m16skip1: ++ cmp eax, 32767 ++ jle short m16skip2 ++ mov eax, 32767 ++m16skip2: ++ mov ebx, ebp ; begin calculating second sample ++ mov [edi], ax ; write new sample to destination ++ ++ shr ebx, 16 ; finish calculation for second sample ++cpatch3: ++ add ebp, 12345678h ; advance frac pointer ++ ++ movzx eax, word ptr [esi+2*ebx] ; get second sample ++cpatch4: ++ add edi, 2 ; move destination to second sample ++ xor eax, 8000h ++ movzx ebx, ah ++ sub ah, ah ++ ++ dec ecx ; decrement count ++ jnz mix16Mloop ; loop ++ ++ mov _MV_MixDestination, edi ; Store the current write position ++ mov _MV_MixPosition, ebp ; return position ++EXIT16M: ++ popad ++ ret ++ENDP MV_Mix16BitMono16_ ++ ++;================ ++; ++; MV_Mix16BitStereo16 ++; ++;================ ++ ++; eax - position ++; edx - rate ++; ebx - start ++; ecx - number of samples to mix ++ ++PROC MV_Mix16BitStereo16_ ++PUBLIC MV_Mix16BitStereo16_ ++ ++ pushad ++ mov ebp, eax ++ ++ mov esi, ebx ; Source pointer ++ ++ ; Sample size ++ mov ebx, _MV_SampleSize ++ mov eax,OFFSET dpatch9+2 ; convice tasm to modify code... ++ mov [eax],bl ++ ++ ; Right channel offset ++ mov ebx, _MV_RightChannelOffset ++ mov eax,OFFSET dpatch7+3 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET dpatch8+3 ; convice tasm to modify code... ++ mov [eax],ebx ++ ++ ; Volume table ptr ++ mov ebx, _MV_LeftVolume ++ mov eax,OFFSET dpatch1+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET dpatch2+4 ; convice tasm to modify code... ++ inc ebx ++ mov [eax],ebx ++ ++ mov ebx, _MV_RightVolume ++ mov eax,OFFSET dpatch3+4 ; convice tasm to modify code... ++ mov [eax],ebx ++ mov eax,OFFSET dpatch4+4 ; convice tasm to modify code... ++ inc ebx ++ mov [eax],ebx ++ ++ ; Rate scale ptr ++ mov eax,OFFSET dpatch5+2 ; convice tasm to modify code... ++ mov [eax],edx ++ ++ ; Source ptr ++ mov eax,OFFSET dpatch6+4 ; convice tasm to modify code... ++ mov [eax],esi ++ ++ mov edi, _MV_MixDestination ; Get the position to write to ++ ++ ; Number of samples to mix ++ cmp ecx, 0 ++ je exit16S ++ ++; eax - scratch ++; ebx - scratch ++; edx - scratch ++; esi - scratch ++; ecx - count ++; edi - destination ++; ebp - frac pointer ++; dpatch1 - left volume table ++; dpatch2 - right volume table ++; dpatch3 - sample rate ++ ++ mov ebx,ebp ; begin calculating first sample ++ shr ebx,16 ; finish calculation for first sample ++ ++ movzx edx, word ptr [esi+2*ebx] ; get first sample ++ xor edx, 8000h ; Change from signed to unsigned ++ movzx esi, dh ; put high byte in esi ++ sub dh, dh ; lo byte in edx ++ ++ ALIGN 4 ++mix16Sloop: ++ ; Left channel ++dpatch1: ++ movsx eax, word ptr [2*esi+12345678h] ; volume translate high byte of sample ++dpatch2: ++ movsx ebx, byte ptr [2*edx+12345678h] ; volume translate low byte of sample ++ lea eax, [ eax + ebx + 80h ] ; mix high byte of sample ++ ++ ; Right channel ++dpatch3: ++ movsx esi, word ptr [2*esi+12345678h] ; volume translate high byte of sample ++dpatch4: ++ movsx ebx, byte ptr [2*edx+12345678h] ; volume translate low byte of sample ++ lea ebx, [ esi + ebx + 80h ] ; mix high byte of sample ++ ++dpatch7: ++ movsx edx, word ptr [edi+12345678h] ; get current sample from destination ++dpatch5: ++ add ebp,12345678h ; advance frac pointer ++ ++ add eax, edx ; mix left sample ++ ++ cmp eax, -32768 ; Harsh clip sample ++ jge short s16skip1 ++ mov eax, -32768 ++ jmp short s16skip2 ++s16skip1: ++ cmp eax, 32767 ++ jle short s16skip2 ++ mov eax, 32767 ++s16skip2: ++ movsx edx, word ptr [edi+2] ; get current sample from destination ++ mov [edi], ax ; write left sample to destination ++ add ebx, edx ; mix right sample ++ ++ cmp ebx, -32768 ; Harsh clip sample ++ jge short s16skip3 ++ mov ebx, -32768 ++ jmp short s16skip4 ++s16skip3: ++ cmp ebx, 32767 ++ jle short s16skip4 ++ mov ebx, 32767 ++s16skip4: ++ ++ mov edx, ebp ; begin calculating second sample ++dpatch8: ++ mov [edi+12345678h], bx ; write right sample to destination ++ shr edx, 16 ; finish calculation for second sample ++dpatch9: ++ add edi, 4 ; move destination to second sample ++ ++dpatch6: ++ movzx edx, word ptr [2*edx+12345678h] ; get second sample ++ xor edx, 8000h ; Change from signed to unsigned ++ movzx esi, dh ; put high byte in esi ++ sub dh, dh ; lo byte in edx ++ ++ dec ecx ; decrement count ++ jnz mix16Sloop ; loop ++ ++ mov _MV_MixDestination, edi ; Store the current write position ++ mov _MV_MixPosition, ebp ; return position ++exit16S: ++ popad ++ ret ++ENDP MV_Mix16BitStereo16_ ++ ++ ENDS ++ ++ END +diff -urN rott-1.0/rott/audiolib/mvreverb.asm trunk/rott/audiolib/mvreverb.asm +--- rott-1.0/rott/audiolib/mvreverb.asm 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/mvreverb.asm 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,181 @@ ++ IDEAL ++ ++ p386 ++ MODEL flat ++ ++ dataseg ++ CODESEG ++ ++ MASM ++ ALIGN 4 ++ ++;================ ++; ++; MV_16BitReverb ++; ++;================ ++ ++; eax - source position ++; edx - destination position ++; ebx - Volume table ++; ecx - number of samples ++ ++PROC MV_16BitReverb_ ++PUBLIC MV_16BitReverb_ ++ ++ mov esi, eax ++ lea edi, [edx - 2] ++ ++ ALIGN 4 ++rev16loop: ++ movzx eax, word ptr [esi] ; get sample ++ add edi, 2 ++ ++ movzx edx, ah ++ sub ah, ah ++ ++ movsx eax, byte ptr [2*eax+ebx+1] ; volume translate low byte of sample ++ xor edx, 80h ++ ++ movsx edx, word ptr [2*edx+ebx] ; volume translate high byte of sample ++ add esi, 2 ++ ++ lea eax, [ eax + edx + 80h ] ; mix high byte of sample ++ dec ecx ; decrement count ++ ++ mov [edi], ax ; write new sample to destination ++ jnz rev16loop ; loop ++ ++ ret ++ENDP MV_16BitReverb_ ++ ++;================ ++; ++; MV_8BitReverb ++; ++;================ ++ ++; eax - source position ++; edx - destination position ++; ebx - Volume table ++; ecx - number of samples ++ ++PROC MV_8BitReverb_ ++PUBLIC MV_8BitReverb_ ++ ++ mov esi, eax ++ lea edi, [edx - 1] ++ ++ xor eax, eax ++ ++ ALIGN 4 ++rev8loop: ++; movzx eax, byte ptr [esi] ; get sample ++ mov al, byte ptr [esi] ; get sample ++ inc edi ++ ++; movsx eax, byte ptr [2*eax+ebx] ; volume translate sample ++ mov al, byte ptr [2*eax+ebx] ; volume translate sample ++ inc esi ++ ++; add eax, 80h ++ add al, 80h ++ dec ecx ; decrement count ++ ++ mov [edi], al ; write new sample to destination ++ jnz rev8loop ; loop ++ ++ ret ++ENDP MV_8BitReverb_ ++ ++;================ ++; ++; MV_16BitReverbFast ++; ++;================ ++ ++; eax - source position ++; edx - destination position ++; ebx - number of samples ++; ecx - shift ++ ++PROC MV_16BitReverbFast_ ++PUBLIC MV_16BitReverbFast_ ++ ++ mov esi, eax ++ mov eax,OFFSET rpatch16+3 ++ ++ mov [eax],cl ++ lea edi, [edx - 2] ++ ++ ALIGN 4 ++frev16loop: ++ mov ax, word ptr [esi] ; get sample ++ add edi, 2 ++ ++rpatch16: ++ sar ax, 5 ;;;;Add 1 before shift ++ add esi, 2 ++ ++ mov [edi], ax ; write new sample to destination ++ dec ebx ; decrement count ++ ++ jnz frev16loop ; loop ++ ++ ret ++ENDP MV_16BITREVERBFAST_ ++ ++;================ ++; ++; MV_8BitReverbFast ++; ++;================ ++ ++; eax - source position ++; edx - destination position ++; ebx - number of samples ++; ecx - shift ++ ++PROC MV_8BitReverbFast_ ++PUBLIC MV_8BitReverbFast_ ++ mov esi, eax ++ mov eax,OFFSET rpatch8+2 ++ ++ mov edi, edx ++ mov edx, 80h ++ ++ mov [eax],cl ++ mov eax, 80h ++ ++ shr eax, cl ++ ++ dec edi ++ sub edx, eax ++ ++ ALIGN 4 ++frev8loop: ++ mov al, byte ptr [esi] ; get sample ++ inc esi ++ ++ mov ecx, eax ++ inc edi ++ ++rpatch8: ++ shr eax, 3 ++ xor ecx, 80h ; flip the sign bit ++ ++ shr ecx, 7 ; shift the sign down to 1 ++ add eax, edx ++ ++ add eax, ecx ; add sign bit to round to 0 ++ dec ebx ; decrement count ++ ++ mov [edi], al ; write new sample to destination ++ jnz frev8loop ; loop ++ ++ ret ++ENDP MV_8BITREVERBFAST_ ++ ++ ENDS ++ ++ END +diff -urN rott-1.0/rott/audiolib/mvreverb.c trunk/rott/audiolib/mvreverb.c +--- rott-1.0/rott/audiolib/mvreverb.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/mvreverb.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,58 @@ ++#include "multivoc.h" ++#include "_multivc.h" ++ ++void MV_16BitReverb( const char *src, char *dest, const VOLUME16 *volume, int count ) ++{ ++ int i; ++ ++ short *pdest = (short *)dest; ++ ++ for (i = 0; i < count; i++) { ++ int sl = src[i*2+0]; ++ int sh = src[i*2+1] ^ 0x80; ++ ++ sl = (*volume)[sl] >> 8; ++ sh = (*volume)[sh]; ++ ++ pdest[i] = (short)(sl + sh + 0x80); ++ } ++} ++ ++void MV_8BitReverb( const signed char *src, signed char *dest, const VOLUME16 *volume, int count ) ++{ ++ int i; ++ ++ for (i = 0; i < count; i++) { ++ unsigned char s = (unsigned char) src[i]; ++ ++ s = (*volume)[s] & 0xff; ++ ++ dest[i] = (char)(s + 0x80); ++ } ++} ++ ++void MV_16BitReverbFast( const char *src, char *dest, int count, int shift ) ++{ ++ int i; ++ ++ short *pdest = (short *)dest; ++ const short *psrc = (const short *)src; ++ ++ for (i = 0; i < count; i++) { ++ pdest[i] = psrc[i] >> shift; ++ } ++} ++ ++void MV_8BitReverbFast( const signed char *src, signed char *dest, int count, int shift ) ++{ ++ int i; ++ ++ unsigned char sh = 0x80 - (0x80 >> shift); ++ ++ for (i = 0; i < count; i++) { ++ unsigned char a = ((unsigned char) src[i]) >> shift; ++ unsigned char c = (((unsigned char) src[i]) ^ 0x80) >> 7; ++ ++ dest[i] = (signed char) (a + sh + c); ++ } ++} +diff -urN rott-1.0/rott/audiolib/myprint.c trunk/rott/audiolib/myprint.c +--- rott-1.0/rott/audiolib/myprint.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/myprint.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,310 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++#include ++#include ++#include ++#include "myprint.h" ++ ++static unsigned short disp_offset = 160 * 24; ++ ++void DrawText ++ ( ++ int x, ++ int y, ++ int ch, ++ int foreground, ++ int background ++ ) ++ ++ { ++ char *vid; ++ ++ vid = ( char * )( 0xb0000 ); ++ vid += y * 160; ++ vid += x * 2; ++ ++ if ( ch != NONE ) ++ { ++ *vid = ch; ++ } ++ vid++; ++ *vid = ( ( background & 0x0f ) << 4 ) | ( foreground & 0x0f ); ++ } ++ ++void TextBox ++ ( ++ int x1, ++ int y1, ++ int x2, ++ int y2, ++ int ch, ++ int foreground, ++ int background ++ ) ++ ++ { ++ int x; ++ int y; ++ ++ for( x = x1; x <= x2; x++ ) ++ { ++ for( y = y1; y <= y2; y++ ) ++ { ++ DrawText( x, y, ch, foreground, background ); ++ } ++ } ++ } ++ ++void TextFrame ++ ( ++ int x1, ++ int y1, ++ int x2, ++ int y2, ++ int type, ++ int foreground, ++ int background ++ ) ++ ++ { ++ int x; ++ int y; ++ ++ if ( type == 0 ) ++ { ++ for( x = x1 + 1; x < x2; x++ ) ++ { ++ DrawText( x, y1, type, foreground, background ); ++ DrawText( x, y2, type, foreground, background ); ++ } ++ for( y = y1 + 1; y < y2; y++ ) ++ { ++ DrawText( x1, y, type, foreground, background ); ++ DrawText( x2, y, type, foreground, background ); ++ } ++ } ++ if ( type == SINGLE_FRAME ) ++ { ++ DrawText( x1, y1, 'Ú', foreground, background ); ++ DrawText( x2, y1, '¿', foreground, background ); ++ DrawText( x1, y2, 'À', foreground, background ); ++ DrawText( x2, y2, 'Ù', foreground, background ); ++ for( x = x1 + 1; x < x2; x++ ) ++ { ++ DrawText( x, y1, 'Ä', foreground, background ); ++ DrawText( x, y2, 'Ä', foreground, background ); ++ } ++ for( y = y1 + 1; y < y2; y++ ) ++ { ++ DrawText( x1, y, '³', foreground, background ); ++ DrawText( x2, y, '³', foreground, background ); ++ } ++ } ++ if ( type == DOUBLE_FRAME ) ++ { ++ DrawText( x1, y1, 'É', foreground, background ); ++ DrawText( x2, y1, '»', foreground, background ); ++ DrawText( x1, y2, 'È', foreground, background ); ++ DrawText( x2, y2, '¼', foreground, background ); ++ for( x = x1 + 1; x < x2; x++ ) ++ { ++ DrawText( x, y1, 'Í', foreground, background ); ++ DrawText( x, y2, 'Í', foreground, background ); ++ } ++ for( y = y1 + 1; y < y2; y++ ) ++ { ++ DrawText( x1, y, 'º', foreground, background ); ++ DrawText( x2, y, 'º', foreground, background ); ++ } ++ } ++ } ++ ++void mysetxy ++ ( ++ int x, ++ int y ++ ) ++ ++ { ++ disp_offset = ( x * 2 ) + ( y * 160 ); ++ } ++ ++void myputch ++ ( ++ char ch ++ ) ++ ++ { ++ int j; ++ char *disp_start = (char *)( 0xb0000 ); ++ ++ if ( disp_offset >= 160 * 24 ) ++ { ++ for ( j = 160; j < 160 * 24; j += 2 ) ++ { ++ *( disp_start + j - 160 ) = *( disp_start + j ); ++ } ++ ++ disp_offset = 160 * 23; ++ ++ for ( j = disp_offset; j < ( 160 * 24 ); j += 2 ) ++ { ++ *( disp_start + j ) = ' '; ++ } ++ } ++ ++ if ( ch >= 32 ) ++ { ++ *( disp_start + disp_offset ) = ch; ++ disp_offset = disp_offset + 2; ++ } ++ ++ if ( ch == '\r' ) ++ { ++ disp_offset = disp_offset / 160; ++ disp_offset = disp_offset * 160; ++ } ++ ++ if ( ch == '\n' ) ++ { ++ disp_offset = disp_offset + 160; ++ if ( disp_offset < 160 * 24 ) ++ { ++ for ( j = disp_offset; j < ( ( ( disp_offset / 160 ) + 1 ) * ++ 160 ); j += 2 ) ++ { ++ *( disp_start + j ) = ' '; ++ } ++ } ++ } ++ } ++ ++int printstring ++ ( ++ char *string ++ ) ++ ++ { ++ int count; ++ char *ptr; ++ ++ ptr = string; ++ count = 0; ++ ++ while ( *ptr ) ++ { ++ myputch( *ptr ); ++ count++; ++ ptr++; ++ } ++ ++ return( count ); ++ } ++ ++ ++int printnum ++ ( ++ int number ++ ) ++ ++ { ++ char string[ 100 ]; ++ int count; ++ ++ itoa( number, string, 10 ); ++ count = printstring( string ); ++ ++ return( count ); ++ } ++ ++int printunsigned ++ ( ++ unsigned long number, ++ int radix ++ ) ++ ++ { ++ char string[ 100 ]; ++ int count; ++ ++ ultoa( number, string, radix ); ++ count = printstring( string ); ++ ++ return( count ); ++ } ++ ++int myprintf ++ ( ++ char *fmt, ++ ... ++ ) ++ ++ { ++ va_list argptr; ++ int count; ++ char *ptr; ++ ++ return( 0 ); ++ ++ // DEBUG ++ mysetxy( 0, 0 ); ++ ++ va_start( argptr, fmt ); ++ ptr = fmt; ++ count = 0; ++ ++ while( *ptr != 0 ) ++ { ++ if ( *ptr == '%' ) ++ { ++ ptr++; ++ switch( *ptr ) ++ { ++ case 0 : ++ return( EOF ); ++ break; ++ case 'd' : ++ count += printnum( va_arg( argptr, int ) ); ++ break; ++ case 's' : ++ count += printstring( va_arg( argptr, char * ) ); ++ break; ++ case 'u' : ++ count += printunsigned( va_arg( argptr, int ), 10 ); ++ break; ++ case 'x' : ++ case 'X' : ++ count += printunsigned( va_arg( argptr, int ), 16 ); ++ break; ++ } ++ ptr++; ++ } ++ else ++ { ++ myputch( *ptr ); ++ count++; ++ ptr++; ++ } ++ } ++ ++ va_end( argptr ); ++ ++ return( count ); ++ } +diff -urN rott-1.0/rott/audiolib/myprint.h trunk/rott/audiolib/myprint.h +--- rott-1.0/rott/audiolib/myprint.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/myprint.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,43 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++#ifndef __MYPRINT_H ++#define __MYPRINT_H ++ ++enum COLORS ++ { ++ BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY, DARKGRAY, ++ LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE ++ }; ++ ++#define NONE -1 ++#define SINGLE_FRAME -1 ++#define DOUBLE_FRAME -2 ++ ++void DrawText( int x, int y, int ch, int foreground, int background ); ++void TextBox( int x1, int y1, int x2, int y2, int ch, int foreground, int background ); ++void TextFrame( int x1, int y1, int x2, int y2, int type, int foreground, int background ); ++void mysetxy( int x, int y ); ++void myputch( char ch ); ++int printstring( char *string ); ++int printnum( int number ); ++int printunsigned( unsigned long number, int radix ); ++int myprintf( char *fmt, ... ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/newgf1.h trunk/rott/audiolib/newgf1.h +--- rott-1.0/rott/audiolib/newgf1.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/newgf1.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,431 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/*************************************************************************** ++* NAME: GF1.H ++** COPYRIGHT: ++** "Copyright (c) 1991,1992, by FORTE ++** ++** "This software is furnished under a license and may be used, ++** copied, or disclosed only in accordance with the terms of such ++** license and with the inclusion of the above copyright notice. ++** This software or any other copies thereof may not be provided or ++** otherwise made available to any other person. No title to and ++** ownership of the software is hereby transfered." ++**************************************************************************** ++* CREATION DATE: 07/01/92 ++*--------------------------------------------------------------------------* ++* VERSION DATE NAME DESCRIPTION ++*> 1.0 07/01/92 Original ++***************************************************************************/ ++ ++#ifndef _GF1_H /* allow header to be processed only once */ ++#define _GF1_H ++ ++/* error codes */ ++#define OK 0 ++#define NO_MORE_VOICES -1 ++#define BASE_NOT_FOUND 1 ++#define BAD_IRQ 2 ++#define BAD_DMA 3 ++#define OS_LOADED 4 ++#define NOT_LOADED 5 ++#define NO_MEMORY 6 ++#define DMA_BUSY 7 ++#define NO_MORE_HANDLERS 8 ++#define DMA_HUNG 9 ++#define CARD_NOT_FOUND 10 ++#define CARD_BEING_USED 11 ++#define NO_MORE_INTERRUPTS 12 ++#define BAD_TIMER 13 ++#define BAD_PATCH 14 ++#define OLD_PATCH 15 ++#define DOS_ERROR 16 ++#define FILE_NOT_FOUND 17 ++ ++/* bits */ ++#define BIT0 0x01 ++#define BIT1 0x02 ++#define BIT2 0x04 ++#define BIT3 0x08 ++#define BIT4 0x10 ++#define BIT5 0x20 ++#define BIT6 0x40 ++#define BIT7 0x80 ++ ++/* bounds for volume enveloping functions */ ++#define MIN_OFFSET 5U ++#define MAX_OFFSET 251U ++ ++/* bounds for voice allocation */ ++#define MIN_VOICES 14 ++#define MAX_VOICES 32 ++ ++/* DMA control bits */ ++#define DMA_ENABLE BIT0 ++#define DMA_READ BIT1 ++#define DMA_WIDTH_16 BIT2 /* width of DMA channel */ ++#define DMA_RATE_DIV_1 BIT3 ++#define DMA_RATE_DIV_2 BIT4 ++#define DMA_IRQ_ENABLE BIT5 ++#define DMA_IRQ_PRESENT BIT6 ++#define DMA_DATA_16 BIT6 /* width of data */ ++#define DMA_INVERT_MSB BIT7 ++ ++/* SAMPLE control bits */ ++#define DMA_STEREO 2 ++ ++/* DMA flags */ ++#define GF1_RECORD 0 /* use dma control or sample control */ ++#define GF1_DMA 1 ++ ++/* MIDI control register */ ++#define MIDI_RESET (BIT0|BIT1) ++#define MIDI_TD_INT BIT5 ++#define MIDI_RD_INT BIT7 ++ ++/* MIDI_STATUS_REGISTER */ ++#define MIDI_RD BIT0 ++#define MIDI_TD BIT1 ++#define MIDI_ERR_FRAMING BIT4 ++#define MIDI_ERR_OVERRUN BIT5 ++ ++/* digital playback flags */ ++#define TYPE_8BIT BIT0 /* 1 use 8 bit data */ ++ /* 0 use 16 bit data */ ++#define TYPE_PRELOAD BIT1 /* preload data */ ++#define TYPE_INVERT_MSB BIT2 /* invert most significant bit during dma */ ++#define TYPE_STEREO BIT3 /* 1 for stereo data */ ++ ++/* sound effects and digital music types */ ++#define SND_LOOP_MASK (BIT0|BIT1) ++#define SND_LOOP_NONE 0 ++#define SND_LOOP 1 ++#define SND_LOOP_BIDIR 2 ++#define SND_8BIT (BIT2) ++#define SND_BACKWARD (BIT3) ++ ++#define SOUND_PLAYING 2 ++#define SOUND_ACTIVE 1 ++ ++/* patch macros */ ++#define HEADER_SIZE 12 ++#define ID_SIZE 10 ++#define DESC_SIZE 60 ++#define RESERVED_SIZE 40 ++#define PATCH_HEADER_RESERVED_SIZE 36 ++#define LAYER_RESERVED_SIZE 40 ++#define PATCH_DATA_RESERVED_SIZE 36 ++#define GF1_HEADER_TEXT "GF1PATCH110" ++#define INST_NAME_SIZE 16 ++#define ENVELOPES 6 ++#define MAX_LAYERS 4 ++ ++/* patch modes */ ++#define PATCH_16 BIT0 ++#define PATCH_UNSIGNED BIT1 ++#define PATCH_LOOPEN BIT2 ++#define PATCH_BIDIR BIT3 ++#define PATCH_BACKWARD BIT4 ++#define PATCH_SUSTAIN BIT5 ++#define PATCH_NO_SRELEASE BIT6 ++#define PATCH_FAST_REL BIT7 ++ ++/* flags for patch loading */ ++#define PATCH_LOAD_8_BIT BIT0 ++ ++/* digital playback callback reasons & return values */ ++#define DIG_DONE 0 ++#define DIG_MORE_DATA 1 ++#define DIG_BUFFER_DONE 2 ++#define DIG_PAUSE 3 ++ ++/* log table used for vibrato and pitch bend. log table made public for ++** developers use */ ++#define LOG_TAB_SIZE 12 ++extern long gf1_log_table[LOG_TAB_SIZE]; ++ ++#if defined(__BORLANDC__) ++#undef RFAR ++#define RFAR far ++#elif defined(_MSC_VER) && (_MSC_VER <= 600) ++#define RFAR far ++#elif defined(_MSC_VER) && (_MSC_VER > 600) ++#define RFAR __far ++#else ++#undef RFAR ++#define RFAR ++#endif ++ ++/* structure definitions */ ++struct load_os ++{ ++ unsigned short voices; ++ unsigned short forced_base_port; ++ unsigned char forced_gf1_irq; ++ unsigned char forced_midi_irq; ++ unsigned char forced_channel_in; ++ unsigned char forced_channel_out; ++}; ++ ++struct patchheader ++{ ++ char header[ HEADER_SIZE ]; ++ char gravis_id[ ID_SIZE ]; /* Id = "ID#000002" */ ++ char description[ DESC_SIZE ]; ++ unsigned char instruments; ++ char voices; ++ char channels; ++ unsigned short wave_forms; ++ unsigned short master_volume; ++ unsigned long data_size; ++ char reserved[ PATCH_HEADER_RESERVED_SIZE ]; ++}; ++ ++struct instrumentdata ++{ ++ unsigned short instrument; ++ char instrument_name[ INST_NAME_SIZE ]; ++ long instrument_size; ++ char layers; ++ char reserved[ RESERVED_SIZE ]; ++}; ++ ++struct layerdata ++{ ++ char layer_duplicate; ++ char layer; ++ long layer_size; ++ char samples; ++ char reserved[ LAYER_RESERVED_SIZE ]; ++}; ++ ++struct patchdata ++{ ++ char wave_name[7]; ++ unsigned char fractions; ++ long wave_size; ++ long start_loop; ++ long end_loop; ++ unsigned short sample_rate; ++ long low_frequency; ++ long high_frequency; ++ long root_frequency; ++ short tune; ++ unsigned char balance; ++ unsigned char envelope_rate[ ENVELOPES ]; ++ unsigned char envelope_offset[ ENVELOPES ]; ++ unsigned char tremolo_sweep; ++ unsigned char tremolo_rate; ++ unsigned char tremolo_depth; ++ unsigned char vibrato_sweep; ++ unsigned char vibrato_rate; ++ unsigned char vibrato_depth; ++ char modes; ++ short scale_frequency; ++ unsigned short scale_factor; /* from 0 to 2048 or 0 to 2 */ ++ char reserved[ PATCH_DATA_RESERVED_SIZE ]; ++}; ++ ++struct wave_struct ++{ ++ unsigned long start_loop; ++ unsigned long end_loop; ++ long low_frequency; ++ long high_frequency; ++ long root_frequency; ++ unsigned long mem; ++ unsigned short scale_frequency; ++ unsigned short sample_rate; ++ unsigned short scale_factor; ++ unsigned short start_acc_low; ++ unsigned short start_acc_high; ++ unsigned short start_low; ++ unsigned short start_high; ++ unsigned short end_low; ++ unsigned short end_high; ++ unsigned short end_acc_low; ++ unsigned short end_acc_high; ++ unsigned short sample_ratio; ++ unsigned long wave_size; ++ unsigned char fractions; ++ unsigned char balance; ++ unsigned char envelope_rate[ ENVELOPES ]; ++ unsigned char envelope_offset[ ENVELOPES ]; ++ unsigned char tremolo_sweep; ++ unsigned char tremolo_rate; ++ unsigned char tremolo_depth; ++ unsigned char vibrato_sweep; ++ unsigned char vibrato_rate; ++ unsigned char vibrato_depth; ++ unsigned char modes; ++}; ++ ++struct patchinfo { ++ struct patchheader header; ++ struct instrumentdata idata; ++}; ++ ++struct patch { ++ short nlayers; ++ struct wave_struct RFAR *layer_waves[MAX_LAYERS]; ++ short layer_nwaves[MAX_LAYERS]; ++ unsigned short detune; ++}; ++ ++struct gf1_dma_buff { ++ unsigned char RFAR *vptr; ++ unsigned long paddr; ++}; ++ ++struct gf1_sound { ++ unsigned long mem_pos; ++ unsigned long start_loop; ++ unsigned long end_loop; ++ unsigned char type; ++}; ++ ++/* GLOBAL VARIABLES (flags) */ ++extern char gf1_linear_volumes; ++extern char gf1_dig_use_extra_voice; ++ ++/* FUNCTION PROTOTYPES */ ++/* Initializeation routines */ ++int gf1_init_ports(int); ++int gf1_load_os(struct load_os RFAR *os); ++int gf1_unload_os(void); ++void gf1_set_appname(char RFAR *); ++void reset_ultra(int); ++int gf1_asm_init(void); ++unsigned char gf1_peek(unsigned long address); ++void gf1_poke(unsigned long address, unsigned char data); ++void gf1_poke_block(unsigned char RFAR *data, unsigned long address, unsigned long len, unsigned char dma_control); ++char gf1_good_dram(unsigned long address); ++int GetUltraCfg(struct load_os RFAR *os); ++unsigned long gf1_malloc(unsigned long); ++void gf1_free(unsigned long); ++unsigned long gf1_mem_avail(void); ++unsigned long gf1_mem_largest_avail(void); ++void gf1_delay(void); ++int gf1_allocate_voice(int priority, void (RFAR *steal_notify)(int)); ++void gf1_free_voice(unsigned int i); ++void gf1_adjust_priority(int voice, int priority); ++int gf1_dram_xfer(struct gf1_dma_buff RFAR *dptr, unsigned long size, unsigned long dram_address, unsigned char dma_control, unsigned short flags); ++void gf1_stop_dma(void); ++long convert_to_16bit(long address); ++int gf1_wait_dma(void); ++int gf1_dma_ready(void); ++unsigned long gf1_amount_xferred(void); ++int gf1_detect_card(unsigned short port); ++char *gf1_error_str(int); ++int gf1_play_digital(unsigned short priority, unsigned char RFAR *buffer, ++ unsigned long size, unsigned long gf1_addr, unsigned short volume, ++ unsigned short pan, unsigned short frequency, unsigned char type, ++ struct gf1_dma_buff RFAR *dptr, ++ int (RFAR *callback)(int, int, unsigned char RFAR * RFAR *, unsigned long RFAR *)); ++void gf1_restart_digital(int voice); ++void gf1_start_digital(int voice); ++void gf1_pause_digital(int voice); ++void RFAR gf1_stop_digital(int voice); ++void gf1_dig_set_dma_rate(unsigned short rate); ++unsigned long gf1_digital_position(int voice); ++int gf1_myatoi(void); ++int gf1_update_waveform(struct wave_struct RFAR *wave_info); ++int gf1_get_patch_info(char RFAR *patch_file, struct patchinfo RFAR *patch); ++int gf1_load_patch(char RFAR *patch_file, struct patchinfo RFAR *patchinfo, ++ struct patch RFAR *patch, ++ struct gf1_dma_buff RFAR *dptr, unsigned short size, ++ unsigned char RFAR *wavemem, int flags); ++void gf1_unload_patch(struct patch RFAR *patch); ++void gf1_detune_patch(struct patch RFAR *patch, unsigned short detune); ++unsigned short gf1_calc_fc(unsigned int sample_ratio,long root,long frequency); ++void gf1_midi_stop_voice(int voice); ++void gf1_midi_wait_voice(int voice); ++unsigned short gf1_midi_status_note(int voice); ++unsigned short gf1_midi_status_voice(int voice); ++void RFAR gf1_midi_stop_note(int note_voice); ++void gf1_midi_note_on(struct patch RFAR *patch, int priority, int note, int velocity, int channel); ++void gf1_midi_note_off(int note, int channel); ++void gf1_midi_silence_patch_notes(struct patch RFAR *patch); ++void gf1_midi_patch_removed(struct patch RFAR *patch); ++int gf1_enable_timer1(int (RFAR *callback)(void), int resolution); ++int gf1_enable_timer2(int (RFAR *callback)(void), int resolution); ++void gf1_disable_timer1(void); ++void gf1_disable_timer2(void); ++void gf1_channel_pitch_bend(int channel, unsigned int bend); ++void gf1_midi_synth_volume(unsigned short synth, int master_volume); ++void gf1_midi_change_program(struct patch RFAR *patch, int channel); ++void gf1_midi_set_vibrato(int channel, int value); ++void gf1_midi_change_volume(int channel, unsigned int volume); ++void gf1_midi_set_balance(int balance, int channel); ++void gf1_midi_channel_sustain(int channel, int sustain); ++void gf1_midi_all_notes_off(int channel); ++void gf1_midi_pitch_bend(int channel, int lsb, int msb); ++void gf1_midi_parameter(int channel, int control, int value); ++int gf1_midi_get_channel_notes(int channel, int notes[]); ++int gf1_midi_get_channel_volume(int channel); ++int gf1_midi_get_master_volume(void); ++int gf1_midi_get_volume(int voice); ++unsigned short gf1_read(int handle, void RFAR *io_buffer, unsigned short size); ++unsigned short gf1_close_file(int handle); ++unsigned int gf1_seek(int handle, unsigned long offset, int method); ++int gf1_open(char RFAR *name); ++#ifdef __FLAT__ ++int gf1_atoi(char RFAR **str, int base); ++#else ++int gf1_atoi(void); ++#endif ++void gf1_leave(void); ++short gf1_enter(void); ++void gf1_enter1(void); ++int gf1_play_next_buffer(int voice, unsigned char RFAR *buff, unsigned long size); ++void gf1_dig_set_vol(unsigned short voice, unsigned short vol); ++void gf1_dig_set_pan(unsigned short voice, unsigned short pan); ++int gf1_set_external_semaphore(void RFAR *addr); ++int gf1_clear_external_semaphore(void RFAR *addr); ++void gf1_midi_reset(int c); ++int gf1_add_midi_recv_handler(int (RFAR *handler)()); ++int gf1_add_dma_handler(int (*handler)()); ++int gf1_add_voice_handler(int (*handler)(int)); ++int gf1_add_volume_handler(int (*handler)(int)); ++int gf1_add_timer_handler(int timer, int (RFAR *handler)(void)); ++void gf1_set_record_rate(unsigned long rate); ++void gf1_create_patch(struct patch RFAR *patch); ++int gf1_add_layer(struct patch RFAR *patch, int layer, char RFAR *wavemem); ++void gf1_get_waveform_info(struct patch RFAR *patch, int layer, int waven, ++ struct wave_struct RFAR *wave); ++void gf1_set_waveform_info(struct patch RFAR *patch, int layer, int waven, ++ struct wave_struct RFAR *wave); ++void gf1_enable_line_in(void); ++void gf1_disable_line_in(void); ++void gf1_enable_mic_in(void); ++void gf1_disable_mic_in(void); ++void gf1_enable_output(void); ++void gf1_disable_output(void); ++void gf1_sound_volume(unsigned short voice, int volume, ++ unsigned long period /* us*10 */); ++void gf1_sound_pan(unsigned short voice, unsigned short pan); ++void gf1_sound_frequency(unsigned short voice, unsigned long freq); ++void RFAR gf1_sound_stop(int voice); ++void gf1_sound_mode(int voice, struct gf1_sound RFAR *sound, ++ unsigned char type); ++int gf1_sound_start(unsigned short priority, struct gf1_sound RFAR *sound, ++ short volume, unsigned long period, short pan, unsigned long freq); ++int gf1_sound_playing(int voice); ++#endif +diff -urN rott-1.0/rott/audiolib/nodpmi.c trunk/rott/audiolib/nodpmi.c +--- rott-1.0/rott/audiolib/nodpmi.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/nodpmi.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,179 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: DPMI.C ++ ++ author: James R. Dose ++ date: April 8, 1994 ++ ++ Functions for performing DPMI calls. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include "dpmi.h" ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_GetRealModeVector ++ ++ Returns the vector of a real mode interrupt. ++---------------------------------------------------------------------*/ ++ ++unsigned long DPMI_GetRealModeVector ++ ( ++ int num ++ ) ++ ++ { ++ return 0; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_SetRealModeVector ++ ++ Sets the vector of a real mode interrupt. ++---------------------------------------------------------------------*/ ++ ++void DPMI_SetRealModeVector ++ ( ++ int num, ++ unsigned long vector ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_CallRealModeFunction ++ ++ Performs a call to a real mode function. ++---------------------------------------------------------------------*/ ++ ++int DPMI_CallRealModeFunction ++ ( ++ dpmi_regs *callregs ++ ) ++ ++ { ++ return( DPMI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_LockMemory ++ ++ Locks a region of memory to keep the virtual memory manager from ++ paging the region out. ++---------------------------------------------------------------------*/ ++ ++int DPMI_LockMemory ++ ( ++ void *address, ++ unsigned length ++ ) ++ ++ { ++ return ( DPMI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_LockMemoryRegion ++ ++ Locks a region of memory to keep the virtual memory manager from ++ paging the region out. ++---------------------------------------------------------------------*/ ++ ++int DPMI_LockMemoryRegion ++ ( ++ void *start, ++ void *end ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_LockMemory( start, ( char * )end - ( char * )start ); ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_UnlockMemory ++ ++ Unlocks a region of memory that was previously locked. ++---------------------------------------------------------------------*/ ++ ++int DPMI_UnlockMemory ++ ( ++ void *address, ++ unsigned length ++ ) ++ ++ { ++ return ( DPMI_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: DPMI_UnlockMemoryRegion ++ ++ Unlocks a region of memory that was previously locked. ++---------------------------------------------------------------------*/ ++ ++int DPMI_UnlockMemoryRegion ++ ( ++ void *start, ++ void *end ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_UnlockMemory( start, ( char * )end - ( char * )start ); ++ ++ return( status ); ++ } ++ ++int DPMI_GetDOSMemory( void **ptr, int *descriptor, unsigned length ) ++{ ++ /* Lovely... */ ++ ++ *ptr = (void *)malloc(length); ++ ++ *descriptor = (int) *ptr; ++ ++ return (descriptor == 0) ? DPMI_Error : DPMI_Ok; ++} ++ ++int DPMI_FreeDOSMemory( int descriptor ) ++{ ++ free((void *)descriptor); ++ ++ return (descriptor == 0) ? DPMI_Error : DPMI_Ok; ++} +diff -urN rott-1.0/rott/audiolib/nomusic.c trunk/rott/audiolib/nomusic.c +--- rott-1.0/rott/audiolib/nomusic.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/nomusic.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,115 @@ ++#include "music.h" ++ ++char *MUSIC_ErrorString(int ErrorNumber) ++{ ++ return ""; ++} ++ ++int MUSIC_Init(int SoundCard, int Address) ++{ ++ return 0; ++} ++ ++int MUSIC_Shutdown(void) ++{ ++ return 0; ++} ++ ++void MUSIC_SetMaxFMMidiChannel(int channel) ++{ ++} ++ ++void MUSIC_SetVolume(int volume) ++{ ++} ++ ++void MUSIC_SetMidiChannelVolume(int channel, int volume) ++{ ++} ++ ++void MUSIC_ResetMidiChannelVolumes(void) ++{ ++} ++ ++int MUSIC_GetVolume(void) ++{ ++ return 0; ++} ++ ++void MUSIC_SetLoopFlag(int loopflag) ++{ ++} ++ ++int MUSIC_SongPlaying(void) ++{ ++ return 0; ++} ++ ++void MUSIC_Continue(void) ++{ ++} ++ ++void MUSIC_Pause(void) ++{ ++} ++ ++int MUSIC_StopSong(void) ++{ ++ return 0; ++} ++ ++int MUSIC_PlaySong(unsigned char *song, int loopflag) ++{ ++ return 0; ++} ++ ++void MUSIC_SetContext(int context) ++{ ++} ++ ++int MUSIC_GetContext(void) ++{ ++ return 0; ++} ++ ++void MUSIC_SetSongTick(unsigned long PositionInTicks) ++{ ++} ++ ++void MUSIC_SetSongTime(unsigned long milliseconds) ++{ ++} ++ ++void MUSIC_SetSongPosition(int measure, int beat, int tick) ++{ ++} ++ ++void MUSIC_GetSongPosition(songposition *pos) ++{ ++} ++ ++void MUSIC_GetSongLength(songposition *pos) ++{ ++} ++ ++int MUSIC_FadeVolume(int tovolume, int milliseconds) ++{ ++ return 0; ++} ++ ++int MUSIC_FadeActive(void) ++{ ++ return 0; ++} ++ ++void MUSIC_StopFade(void) ++{ ++} ++ ++void MUSIC_RerouteMidiChannel(int channel, int cdecl function( int event, int c1, int c2 )) ++{ ++} ++ ++void MUSIC_RegisterTimbreBank(unsigned char *timbres) ++{ ++} +diff -urN rott-1.0/rott/audiolib/pas16.c trunk/rott/audiolib/pas16.c +--- rott-1.0/rott/audiolib/pas16.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/pas16.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,1924 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: PAS16.C ++ ++ author: James R. Dose ++ date: March 27, 1994 ++ ++ Low level routines to support Pro AudioSpectrum and compatible ++ sound cards. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include "dpmi.h" ++#include "dma.h" ++#include "interrup.h" ++#include "irq.h" ++#include "pas16.h" ++#include "_pas16.h" ++ ++#define USESTACK ++ ++static const int PAS_Interrupts[ PAS_MaxIrq + 1 ] = ++ { ++ INVALID, INVALID, 0xa, 0xb, ++ INVALID, 0xd, INVALID, 0xf, ++ INVALID, INVALID, 0x72, 0x73, ++ 0x74, INVALID, INVALID, 0x77 ++ }; ++ ++static void ( interrupt far *PAS_OldInt )( void ); ++ ++static int PAS_IntController1Mask; ++static int PAS_IntController2Mask; ++ ++static int PAS_Installed = FALSE; ++static int PAS_TranslateCode = DEFAULT_BASE; ++ ++static int PAS_OriginalPCMLeftVolume = 75; ++static int PAS_OriginalPCMRightVolume = 75; ++ ++static int PAS_OriginalFMLeftVolume = 75; ++static int PAS_OriginalFMRightVolume = 75; ++ ++unsigned int PAS_DMAChannel; ++static int PAS_Irq; ++ ++static MVState *PAS_State = NULL; ++static MVFunc *PAS_Func = NULL; ++ ++static MVState PAS_OriginalState; ++static int PAS_SampleSizeConfig; ++ ++static char *PAS_DMABuffer; ++static char *PAS_DMABufferEnd; ++static char *PAS_CurrentDMABuffer; ++static int PAS_TotalDMABufferSize; ++ ++static int PAS_TransferLength = 0; ++static int PAS_MixMode = PAS_DefaultMixMode; ++static unsigned PAS_SampleRate = PAS_DefaultSampleRate; ++static int PAS_TimeInterval = 0; ++ ++volatile int PAS_SoundPlaying; ++ ++void ( *PAS_CallBack )( void ); ++ ++// adequate stack size ++#define kStackSize 2048 ++ ++static unsigned short StackSelector = NULL; ++static unsigned long StackPointer; ++ ++static unsigned short oldStackSelector; ++static unsigned long oldStackPointer; ++ ++// This is defined because we can't create local variables in a ++// function that switches stacks. ++static int irqstatus; ++ ++// These declarations are necessary to use the inline assembly pragmas. ++ ++extern void GetStack(unsigned short *selptr,unsigned long *stackptr); ++extern void SetStack(unsigned short selector,unsigned long stackptr); ++ ++// This function will get the current stack selector and pointer and save ++// them off. ++#pragma aux GetStack = \ ++ "mov [edi],esp" \ ++ "mov ax,ss" \ ++ "mov [esi],ax" \ ++ parm [esi] [edi] \ ++ modify [eax esi edi]; ++ ++// This function will set the stack selector and pointer to the specified ++// values. ++#pragma aux SetStack = \ ++ "mov ss,ax" \ ++ "mov esp,edx" \ ++ parm [ax] [edx] \ ++ modify [eax edx]; ++ ++int PAS_ErrorCode = PAS_Ok; ++ ++#define PAS_SetErrorCode( status ) \ ++ PAS_ErrorCode = ( status ); ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *PAS_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case PAS_Warning : ++ case PAS_Error : ++ ErrorString = PAS_ErrorString( PAS_ErrorCode ); ++ break; ++ ++ case PAS_Ok : ++ ErrorString = "Pro AudioSpectrum ok."; ++ break; ++ ++ case PAS_DriverNotFound : ++ ErrorString = "MVSOUND.SYS not loaded."; ++ break; ++ ++ case PAS_DmaError : ++ ErrorString = DMA_ErrorString( DMA_Error ); ++ break; ++ ++ case PAS_InvalidIrq : ++ ErrorString = "Invalid Pro AudioSpectrum Irq."; ++ break; ++ ++ case PAS_UnableToSetIrq : ++ ErrorString = "Unable to set Pro AudioSpectrum IRQ. Try selecting an IRQ of 7 or below."; ++ break; ++ ++ case PAS_Dos4gwIrqError : ++ ErrorString = "Unsupported Pro AudioSpectrum Irq."; ++ break; ++ ++ case PAS_NoSoundPlaying : ++ ErrorString = "No sound playing on Pro AudioSpectrum."; ++ break; ++ ++ case PAS_CardNotFound : ++ ErrorString = "Could not find Pro AudioSpectrum."; ++ break; ++ ++ case PAS_DPMI_Error : ++ ErrorString = "DPMI Error in PAS16."; ++ break; ++ ++ case PAS_OutOfMemory : ++ ErrorString = "Out of conventional memory in PAS16."; ++ break; ++ ++ default : ++ ErrorString = "Unknown Pro AudioSpectrum error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define PAS_LockStart PAS_CheckForDriver ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_CheckForDriver ++ ++ Checks to see if MVSOUND.SYS is installed. ++---------------------------------------------------------------------*/ ++ ++int PAS_CheckForDriver ++ ( ++ void ++ ) ++ ++ { ++ union REGS regs; ++ unsigned result; ++ ++ regs.w.ax = MV_CheckForDriver; ++ regs.w.bx = 0x3f3f; ++ ++ #ifdef __386__ ++ int386( MV_SoundInt, ®s, ®s ); ++ #else ++ int86( MV_SoundInt, ®s, ®s ); ++ #endif ++ ++ if ( regs.w.ax != MV_CheckForDriver ) ++ { ++ PAS_SetErrorCode( PAS_DriverNotFound ); ++ return( PAS_Error ); ++ } ++ ++ result = regs.w.bx ^ regs.w.cx ^ regs.w.dx; ++ if ( result != MV_Signature ) ++ { ++ PAS_SetErrorCode( PAS_DriverNotFound ); ++ return( PAS_Error ); ++ } ++ ++ return( PAS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_GetStateTable ++ ++ Returns a pointer to the state table containing hardware state ++ information. The state table is necessary because the Pro Audio- ++ Spectrum contains only write-only registers. ++---------------------------------------------------------------------*/ ++ ++MVState *PAS_GetStateTable ++ ( ++ void ++ ) ++ ++ { ++ union REGS regs; ++ MVState *ptr; ++ ++ regs.w.ax = MV_GetPointerToStateTable; ++ ++ #ifdef __386__ ++ int386( MV_SoundInt, ®s, ®s ); ++ #else ++ int86( MV_SoundInt, ®s, ®s ); ++ #endif ++ ++ if ( regs.w.ax != MV_Signature ) ++ { ++ PAS_SetErrorCode( PAS_DriverNotFound ); ++ return( NULL ); ++ } ++ ++ #if defined(__WATCOMC__) && defined(__FLAT__) ++ ptr = ( MVState * )( ( ( ( unsigned )regs.w.dx ) << 4 ) + ++ ( ( unsigned )regs.w.bx ) ); ++ #else ++ ptr = MK_FP( regs.w.dx, regs.w.bx ); ++ #endif ++ ++ return( ptr ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_GetFunctionTable ++ ++ Returns a pointer to the function table containing addresses of ++ driver functions. ++---------------------------------------------------------------------*/ ++ ++MVFunc *PAS_GetFunctionTable ++ ( ++ void ++ ) ++ ++ { ++ union REGS regs; ++ MVFunc *ptr; ++ ++ regs.w.ax = MV_GetPointerToFunctionTable; ++ ++ #ifdef __386__ ++ int386( MV_SoundInt, ®s, ®s ); ++ #else ++ int86( MV_SoundInt, ®s, ®s ); ++ #endif ++ ++ if ( regs.w.ax != MV_Signature ) ++ { ++ PAS_SetErrorCode( PAS_DriverNotFound ); ++ return( NULL ); ++ } ++ ++ #if defined(__WATCOMC__) && defined(__FLAT__) ++ ptr = ( MVFunc * )( ( ( ( unsigned )regs.w.dx ) << 4 ) + ++ ( ( unsigned )regs.w.bx ) ); ++ #else ++ ptr = MK_FP( regs.w.dx, regs.w.bx ); ++ #endif ++ ++ return( ptr ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_GetCardSettings ++ ++ Returns the DMA and the IRQ channels of the sound card. ++---------------------------------------------------------------------*/ ++ ++int PAS_GetCardSettings ++ ( ++ void ++ ) ++ ++ { ++ union REGS regs; ++ int status; ++ ++ regs.w.ax = MV_GetDmaIrqInt; ++ ++ #ifdef __386__ ++ int386( MV_SoundInt, ®s, ®s ); ++ #else ++ int86( MV_SoundInt, ®s, ®s ); ++ #endif ++ ++ if ( regs.w.ax != MV_Signature ) ++ { ++ PAS_SetErrorCode( PAS_DriverNotFound ); ++ return( PAS_Error ); ++ } ++ ++ PAS_DMAChannel = regs.w.bx; ++ PAS_Irq = regs.w.cx; ++ ++ if ( PAS_Irq > PAS_MaxIrq ) ++ { ++ PAS_SetErrorCode( PAS_Dos4gwIrqError ); ++ return( PAS_Error ); ++ } ++ ++ if ( !VALID_IRQ( PAS_Irq ) ) ++ { ++ PAS_SetErrorCode( PAS_InvalidIrq ); ++ return( PAS_Error ); ++ } ++ ++ if ( PAS_Interrupts[ PAS_Irq ] == INVALID ) ++ { ++ PAS_SetErrorCode( PAS_InvalidIrq ); ++ return( PAS_Error ); ++ } ++ ++ status = DMA_VerifyChannel( PAS_DMAChannel ); ++ if ( status == DMA_Error ) ++ { ++ PAS_SetErrorCode( PAS_DmaError ); ++ return( PAS_Error ); ++ } ++ ++ return( PAS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_EnableInterrupt ++ ++ Enables the triggering of the sound card interrupt. ++---------------------------------------------------------------------*/ ++ ++void PAS_EnableInterrupt ++ ( ++ void ++ ) ++ ++ { ++ int mask; ++ int data; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ if ( PAS_Irq < 8 ) ++ { ++ mask = inp( 0x21 ) & ~( 1 << PAS_Irq ); ++ outp( 0x21, mask ); ++ } ++ else ++ { ++ mask = inp( 0xA1 ) & ~( 1 << ( PAS_Irq - 8 ) ); ++ outp( 0xA1, mask ); ++ ++ mask = inp( 0x21 ) & ~( 1 << 2 ); ++ outp( 0x21, mask ); ++ } ++ ++ // Flush any pending interrupts ++ PAS_Write( InterruptStatus, PAS_Read( InterruptStatus ) & 0x40 ); ++ ++ // Enable the interrupt on the PAS ++ data = PAS_State->intrctlr; ++ data |= SampleBufferInterruptFlag; ++ PAS_Write( InterruptControl, data ); ++ PAS_State->intrctlr = data; ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_DisableInterrupt ++ ++ Disables the triggering of the sound card interrupt. ++---------------------------------------------------------------------*/ ++ ++void PAS_DisableInterrupt ++ ( ++ void ++ ) ++ ++ { ++ int mask; ++ int data; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ // Disable the interrupt on the PAS ++ data = PAS_State->intrctlr; ++ data &= ~( SampleRateInterruptFlag | SampleBufferInterruptFlag ); ++ PAS_Write( InterruptControl, data ); ++ PAS_State->intrctlr = data; ++ ++ // Restore interrupt mask ++ if ( PAS_Irq < 8 ) ++ { ++ mask = inp( 0x21 ) & ~( 1 << PAS_Irq ); ++ mask |= PAS_IntController1Mask & ( 1 << PAS_Irq ); ++ outp( 0x21, mask ); ++ } ++ else ++ { ++ mask = inp( 0x21 ) & ~( 1 << 2 ); ++ mask |= PAS_IntController1Mask & ( 1 << 2 ); ++ outp( 0x21, mask ); ++ ++ mask = inp( 0xA1 ) & ~( 1 << ( PAS_Irq - 8 ) ); ++ mask |= PAS_IntController2Mask & ( 1 << ( PAS_Irq - 8 ) ); ++ outp( 0xA1, mask ); ++ } ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_ServiceInterrupt ++ ++ Handles interrupt generated by sound card at the end of a voice ++ transfer. Calls the user supplied callback function. ++---------------------------------------------------------------------*/ ++ ++void interrupt far PAS_ServiceInterrupt ++ ( ++ void ++ ) ++ ++ { ++ #ifdef USESTACK ++ // save stack ++ GetStack( &oldStackSelector, &oldStackPointer ); ++ ++ // set our stack ++ SetStack( StackSelector, StackPointer ); ++ #endif ++ ++ irqstatus = PAS_Read( InterruptStatus ); ++ if ( ( irqstatus & SampleBufferInterruptFlag ) == 0 ) ++ { ++ #ifdef USESTACK ++ // restore stack ++ SetStack( oldStackSelector, oldStackPointer ); ++ #endif ++ ++ _chain_intr( PAS_OldInt ); ++ } ++ ++ // Clear the interrupt ++ irqstatus &= ~SampleBufferInterruptFlag; ++ PAS_Write( InterruptStatus, irqstatus ); ++ ++ // send EOI to Interrupt Controller ++ if ( PAS_Irq > 7 ) ++ { ++ outp( 0xA0, 0x20 ); ++ } ++ outp( 0x20, 0x20 ); ++ ++ ++ // Keep track of current buffer ++ PAS_CurrentDMABuffer += PAS_TransferLength; ++ if ( PAS_CurrentDMABuffer >= PAS_DMABufferEnd ) ++ { ++ PAS_CurrentDMABuffer = PAS_DMABuffer; ++ } ++ ++ // Call the caller's callback function ++ if ( PAS_CallBack != NULL ) ++ { ++ PAS_CallBack(); ++ } ++ ++ #ifdef USESTACK ++ // restore stack ++ SetStack( oldStackSelector, oldStackPointer ); ++ #endif ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_Write ++ ++ Writes a byte of data to the sound card. ++---------------------------------------------------------------------*/ ++ ++void PAS_Write ++ ( ++ int Register, ++ int Data ++ ) ++ ++ { ++ int port; ++ ++ port = Register ^ PAS_TranslateCode; ++ outp( port, Data ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_Read ++ ++ Reads a byte of data from the sound card. ++---------------------------------------------------------------------*/ ++ ++int PAS_Read ++ ( ++ int Register ++ ) ++ ++ { ++ int port; ++ int data; ++ ++ port = Register ^ PAS_TranslateCode; ++ data = inp( port ); ++ return( data ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_SetSampleRateTimer ++ ++ Programs the Sample Rate Timer. ++---------------------------------------------------------------------*/ ++ ++void PAS_SetSampleRateTimer ++ ( ++ void ++ ) ++ ++ { ++ int LoByte; ++ int HiByte; ++ int data; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ // Disable the Sample Rate Timer ++ data = PAS_State->audiofilt; ++ data &= ~SampleRateTimerGateFlag; ++ PAS_Write( AudioFilterControl, data ); ++ PAS_State->audiofilt = data; ++ ++ // Select the Sample Rate Timer ++ data = SelectSampleRateTimer; ++ PAS_Write( LocalTimerControl, data ); ++ PAS_State->tmrctlr = data; ++ ++ LoByte = lobyte( PAS_TimeInterval ); ++ HiByte = hibyte( PAS_TimeInterval ); ++ ++ // Program the Sample Rate Timer ++ PAS_Write( SampleRateTimer, LoByte ); ++ PAS_Write( SampleRateTimer, HiByte ); ++ PAS_State->samplerate = PAS_TimeInterval; ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_SetSampleBufferCount ++ ++ Programs the Sample Buffer Count. ++---------------------------------------------------------------------*/ ++ ++void PAS_SetSampleBufferCount ++ ( ++ void ++ ) ++ ++ { ++ int LoByte; ++ int HiByte; ++ int count; ++ int data; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ // Disable the Sample Buffer Count ++ data = PAS_State->audiofilt; ++ data &= ~SampleBufferCountGateFlag; ++ PAS_Write( AudioFilterControl, data ); ++ PAS_State->audiofilt = data; ++ ++ // Select the Sample Buffer Count ++ data = SelectSampleBufferCount; ++ PAS_Write( LocalTimerControl, data ); ++ PAS_State->tmrctlr = data; ++ ++ count = PAS_TransferLength; ++ ++ // Check if we're using a 16-bit DMA channel ++ if ( PAS_DMAChannel > 3 ) ++ { ++ count >>= 1; ++ } ++ ++ LoByte = lobyte( count ); ++ HiByte = hibyte( count ); ++ ++ // Program the Sample Buffer Count ++ PAS_Write( SampleBufferCount, LoByte ); ++ PAS_Write( SampleBufferCount, HiByte ); ++ PAS_State->samplecnt = count; ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_SetPlaybackRate ++ ++ Sets the rate at which the digitized sound will be played in ++ hertz. ++---------------------------------------------------------------------*/ ++ ++void PAS_SetPlaybackRate ++ ( ++ unsigned rate ++ ) ++ ++ { ++ if ( rate < PAS_MinSamplingRate ) ++ { ++ rate = PAS_MinSamplingRate; ++ } ++ ++ if ( rate > PAS_MaxSamplingRate ) ++ { ++ rate = PAS_MaxSamplingRate; ++ } ++ ++ PAS_TimeInterval = ( unsigned )CalcTimeInterval( rate ); ++ if ( PAS_MixMode & STEREO ) ++ { ++ PAS_TimeInterval /= 2; ++ } ++ ++ // Keep track of what the actual rate is ++ PAS_SampleRate = CalcSamplingRate( PAS_TimeInterval ); ++ if ( PAS_MixMode & STEREO ) ++ { ++ PAS_SampleRate /= 2; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_GetPlaybackRate ++ ++ Returns the rate at which the digitized sound will be played in ++ hertz. ++---------------------------------------------------------------------*/ ++ ++unsigned PAS_GetPlaybackRate ++ ( ++ void ++ ) ++ ++ { ++ return( PAS_SampleRate ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_SetMixMode ++ ++ Sets the sound card to play samples in mono or stereo. ++---------------------------------------------------------------------*/ ++ ++int PAS_SetMixMode ++ ( ++ int mode ++ ) ++ ++ { ++ mode &= PAS_MaxMixMode; ++ ++ // Check board revision. Revision # 0 can't play 16-bit data. ++ if ( ( PAS_State->intrctlr & 0xe0 ) == 0 ) ++ { ++ // Force the mode to 8-bit data. ++ mode &= ~SIXTEEN_BIT; ++ } ++ ++ PAS_MixMode = mode; ++ ++ PAS_SetPlaybackRate( PAS_SampleRate ); ++ ++ return( mode ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_StopPlayback ++ ++ Ends the DMA transfer of digitized sound to the sound card. ++---------------------------------------------------------------------*/ ++ ++void PAS_StopPlayback ++ ( ++ void ++ ) ++ ++ { ++ int data; ++ ++ // Don't allow anymore interrupts ++ PAS_DisableInterrupt(); ++ ++ // Stop the transfer of digital data ++ data = PAS_State->crosschannel; ++ data &= PAS_PCMStopMask; ++ PAS_Write( CrossChannelControl, data ); ++ PAS_State->crosschannel = data; ++ ++ // Turn off 16-bit unsigned data ++ data = PAS_Read( SampleSizeConfiguration ); ++ data &= PAS_SampleSizeMask; ++ PAS_Write( SampleSizeConfiguration, data ); ++ ++ // Disable the DMA channel ++ DMA_EndTransfer( PAS_DMAChannel ); ++ ++ PAS_SoundPlaying = FALSE; ++ ++ PAS_DMABuffer = NULL; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_SetupDMABuffer ++ ++ Programs the DMAC for sound transfer. ++---------------------------------------------------------------------*/ ++ ++int PAS_SetupDMABuffer ++ ( ++ char *BufferPtr, ++ int BufferSize, ++ int mode ++ ) ++ ++ { ++ int DmaStatus; ++ int data; ++ ++ // Enable PAS Dma ++ data = PAS_State->crosschannel; ++ data |= PAS_DMAEnable; ++ PAS_Write( CrossChannelControl, data ); ++ PAS_State->crosschannel = data; ++ ++ DmaStatus = DMA_SetupTransfer( PAS_DMAChannel, BufferPtr, BufferSize, mode ); ++ if ( DmaStatus == DMA_Error ) ++ { ++ PAS_SetErrorCode( PAS_DmaError ); ++ return( PAS_Error ); ++ } ++ ++ PAS_DMABuffer = BufferPtr; ++ PAS_CurrentDMABuffer = BufferPtr; ++ PAS_TotalDMABufferSize = BufferSize; ++ PAS_DMABufferEnd = BufferPtr + BufferSize; ++ ++ return( PAS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_GetCurrentPos ++ ++ Returns the offset within the current sound being played. ++---------------------------------------------------------------------*/ ++ ++int PAS_GetCurrentPos ++ ( ++ void ++ ) ++ ++ { ++ char *CurrentAddr; ++ int offset; ++ ++ if ( !PAS_SoundPlaying ) ++ { ++ PAS_SetErrorCode( PAS_NoSoundPlaying ); ++ return( PAS_Error ); ++ } ++ ++ CurrentAddr = DMA_GetCurrentPos( PAS_DMAChannel ); ++ if ( CurrentAddr == NULL ) ++ { ++ PAS_SetErrorCode( PAS_DmaError ); ++ return( PAS_Error ); ++ } ++ ++ offset = ( int )( ( ( unsigned long )CurrentAddr ) - ++ ( ( unsigned long )PAS_CurrentDMABuffer ) ); ++ ++ if ( PAS_MixMode & SIXTEEN_BIT ) ++ { ++ offset >>= 1; ++ } ++ ++ if ( PAS_MixMode & STEREO ) ++ { ++ offset >>= 1; ++ } ++ ++ return( offset ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_GetFilterSetting ++ ++ Returns the bit settings for the appropriate filter level. ++---------------------------------------------------------------------*/ ++ ++int PAS_GetFilterSetting ++ ( ++ int rate ++ ) ++ ++ { ++ /* CD Quality 17897hz */ ++ if ( ( unsigned long )rate > ( unsigned long )17897L * 2 ) ++ { ++ /* 00001b 20hz to 17.8khz */ ++ return( 0x01 ); ++ } ++ ++ /* Cassette Quality 15090hz */ ++ if ( ( unsigned long )rate > ( unsigned long )15909L * 2 ) ++ { ++ /* 00010b 20hz to 15.9khz */ ++ return( 0x02 ); ++ } ++ ++ /* FM Radio Quality 11931hz */ ++ if ( ( unsigned long )rate > ( unsigned long )11931L * 2 ) ++ { ++ /* 01001b 20hz to 11.9khz */ ++ return( 0x09 ); ++ } ++ ++ /* AM Radio Quality 8948hz */ ++ if ( ( unsigned long )rate > ( unsigned long )8948L * 2 ) ++ { ++ /* 10001b 20hz to 8.9khz */ ++ return( 0x11 ); ++ } ++ ++ /* Telphone Quality 5965hz */ ++ if ( ( unsigned long )rate > ( unsigned long )5965L * 2 ) ++ { ++ /* 00100b 20hz to 5.9khz */ ++ return( 0x19 ); ++ } ++ ++ /* Male voice quality 2982hz */ ++ /* 111001b 20hz to 2.9khz */ ++ return( 0x04 ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_BeginTransfer ++ ++ Starts playback of digitized sound on the sound card. ++---------------------------------------------------------------------*/ ++ ++void PAS_BeginTransfer ++ ( ++ int mode ++ ) ++ ++ { ++ int data; ++ ++ PAS_SetSampleRateTimer(); ++ ++ PAS_SetSampleBufferCount(); ++ ++ PAS_EnableInterrupt(); ++ ++ // Get sample size configuration ++ data = PAS_Read( SampleSizeConfiguration ); ++ ++ // Check board revision. Revision # 0 can't play 16-bit data. ++ if ( PAS_State->intrctlr & 0xe0 ) ++ { ++ data &= PAS_SampleSizeMask; ++ ++ // set sample size bit ++ if ( PAS_MixMode & SIXTEEN_BIT ) ++ { ++ data |= PAS_16BitSampleFlag; ++ } ++ } ++ ++ // set oversampling rate ++ data &= PAS_OverSamplingMask; ++ data |= PAS_4xOverSampling; ++ ++ // Set sample size configuration ++ PAS_Write( SampleSizeConfiguration, data ); ++ ++ // Get Cross channel setting ++ data = PAS_State->crosschannel; ++ data &= PAS_ChannelConnectMask; ++ if ( mode == RECORD ) ++ { ++ data |= PAS_PCMStartADC; ++ } ++ else ++ { ++ data |= PAS_PCMStartDAC; ++ } ++ ++ // set stereo mode bit ++ if ( !( PAS_MixMode & STEREO ) ) ++ { ++ data |= PAS_StereoFlag; ++ } ++ ++ PAS_Write( CrossChannelControl, data ); ++ PAS_State->crosschannel = data; ++ ++ // Get the filter appropriate filter setting ++ data = PAS_GetFilterSetting( PAS_SampleRate ); ++ ++ // Enable the Sample Rate Timer and Sample Buffer Count ++ data |= SampleRateTimerGateFlag | SampleBufferCountGateFlag; ++ ++ if ( mode != RECORD ) ++ { ++ // Enable audio (not Audio Mute) ++ data |= PAS_AudioMuteFlag; ++ } ++ ++ PAS_Write( AudioFilterControl, data ); ++ PAS_State->audiofilt = data; ++ ++ PAS_SoundPlaying = TRUE; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_BeginBufferedPlayback ++ ++ Begins multibuffered playback of digitized sound on the sound card. ++---------------------------------------------------------------------*/ ++ ++int PAS_BeginBufferedPlayback ++ ( ++ char *BufferStart, ++ int BufferSize, ++ int NumDivisions, ++ unsigned SampleRate, ++ int MixMode, ++ void ( *CallBackFunc )( void ) ++ ) ++ ++ { ++ int DmaStatus; ++ ++ PAS_StopPlayback(); ++ ++ PAS_SetMixMode( MixMode ); ++ PAS_SetPlaybackRate( SampleRate ); ++ ++ PAS_TransferLength = BufferSize / NumDivisions; ++ PAS_SetCallBack( CallBackFunc ); ++ ++ DmaStatus = PAS_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitRead ); ++ if ( DmaStatus == PAS_Error ) ++ { ++ return( PAS_Error ); ++ } ++ ++ PAS_BeginTransfer( PLAYBACK ); ++ ++ return( PAS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_BeginBufferedRecord ++ ++ Begins multibuffered recording of digitized sound on the sound card. ++---------------------------------------------------------------------*/ ++ ++int PAS_BeginBufferedRecord ++ ( ++ char *BufferStart, ++ int BufferSize, ++ int NumDivisions, ++ unsigned SampleRate, ++ int MixMode, ++ void ( *CallBackFunc )( void ) ++ ) ++ ++ { ++ int DmaStatus; ++ ++ PAS_StopPlayback(); ++ ++ PAS_SetMixMode( MixMode ); ++ PAS_SetPlaybackRate( SampleRate ); ++ ++ PAS_TransferLength = BufferSize / NumDivisions; ++ PAS_SetCallBack( CallBackFunc ); ++ ++ DmaStatus = PAS_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitWrite ); ++ if ( DmaStatus == PAS_Error ) ++ { ++ return( PAS_Error ); ++ } ++ ++ PAS_BeginTransfer( RECORD ); ++ ++ return( PAS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_CallInt ++ ++ Calls interrupt 2fh. ++---------------------------------------------------------------------*/ ++ ++int PAS_CallInt( int ebx, int ecx, int edx ); ++#pragma aux PAS_CallInt = \ ++ "int 2fh", \ ++ parm [ ebx ] [ ecx ] [ edx ] modify exact [ eax ebx ecx edx esi edi ] value [ ebx ]; ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_CallMVFunction ++ ++ Performs a call to a real mode function. ++---------------------------------------------------------------------*/ ++ ++int PAS_CallMVFunction ++ ( ++ unsigned long function, ++ int ebx, ++ int ecx, ++ int edx ++ ) ++ ++ { ++ dpmi_regs callregs; ++ int status; ++ ++ callregs.EBX = ebx; ++ callregs.ECX = ecx; ++ callregs.EDX = edx; ++ ++ callregs.SS = 0; ++ callregs.SP = 0; ++ ++ callregs.DS = 0; ++ callregs.ES = 0; ++ callregs.FS = 0; ++ callregs.GS = 0; ++ ++ callregs.IP = function; ++ callregs.CS = function >> 16; ++ ++ status = DPMI_CallRealModeFunction( &callregs ); ++ if ( status != DPMI_Ok ) ++ { ++ return( PAS_Error ); ++ } ++ ++ return( callregs.EBX & 0xff ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_SetPCMVolume ++ ++ Sets the volume of digitized sound playback. ++---------------------------------------------------------------------*/ ++ ++int PAS_SetPCMVolume ++ ( ++ int volume ++ ) ++ ++ { ++ int status; ++ ++ volume = max( 0, volume ); ++ volume = min( volume, 255 ); ++ ++ volume *= 100; ++ volume /= 255; ++ ++ status = PAS_CallMVFunction( PAS_Func->SetMixer, volume, ++ OUTPUTMIXER, L_PCM ); ++ if ( status == PAS_Error ) ++ { ++ return( status ); ++ } ++ ++ status = PAS_CallMVFunction( PAS_Func->SetMixer, volume, ++ OUTPUTMIXER, R_PCM ); ++ if ( status == PAS_Error ) ++ { ++ return( status ); ++ } ++ ++ return( PAS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_GetPCMVolume ++ ++ Returns the current volume of digitized sound playback. ++---------------------------------------------------------------------*/ ++ ++int PAS_GetPCMVolume ++ ( ++ void ++ ) ++ ++ { ++ int leftvolume; ++ int rightvolume; ++ int totalvolume; ++ ++ if ( PAS_Func == NULL ) ++ { ++ return( PAS_Error ); ++ } ++ ++ leftvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, ++ OUTPUTMIXER, L_PCM ); ++ rightvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, ++ OUTPUTMIXER, R_PCM ); ++ ++ if ( ( leftvolume == PAS_Error ) || ( rightvolume == PAS_Error ) ) ++ { ++ return( PAS_Error ); ++ } ++ ++ leftvolume &= 0xff; ++ rightvolume &= 0xff; ++ ++ totalvolume = ( rightvolume + leftvolume ) / 2; ++ totalvolume *= 255; ++ totalvolume /= 100; ++ return( totalvolume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_SetFMVolume ++ ++ Sets the volume of FM sound playback. ++---------------------------------------------------------------------*/ ++ ++void PAS_SetFMVolume ++ ( ++ int volume ++ ) ++ ++ { ++ volume = max( 0, volume ); ++ volume = min( volume, 255 ); ++ ++ volume *= 100; ++ volume /= 255; ++ if ( PAS_Func ) ++ { ++ PAS_CallMVFunction( PAS_Func->SetMixer, volume, OUTPUTMIXER, L_FM ); ++ PAS_CallMVFunction( PAS_Func->SetMixer, volume, OUTPUTMIXER, R_FM ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_GetFMVolume ++ ++ Returns the current volume of FM sound playback. ++---------------------------------------------------------------------*/ ++ ++int PAS_GetFMVolume ++ ( ++ void ++ ) ++ ++ { ++ int leftvolume; ++ int rightvolume; ++ int totalvolume; ++ ++ if ( PAS_Func == NULL ) ++ { ++ return( 255 ); ++ } ++ ++ leftvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, ++ OUTPUTMIXER, L_FM ) & 0xff; ++ rightvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, ++ OUTPUTMIXER, R_FM ) & 0xff; ++ ++ totalvolume = ( rightvolume + leftvolume ) / 2; ++ totalvolume *= 255; ++ totalvolume /= 100; ++ totalvolume = min( 255, totalvolume ); ++ ++ return( totalvolume ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_GetCardInfo ++ ++ Returns the maximum number of bits that can represent a sample ++ (8 or 16) and the number of channels (1 for mono, 2 for stereo). ++---------------------------------------------------------------------*/ ++ ++int PAS_GetCardInfo ++ ( ++ int *MaxSampleBits, ++ int *MaxChannels ++ ) ++ ++ { ++ int status; ++ ++ if ( PAS_State == NULL ) ++ { ++ status = PAS_CheckForDriver(); ++ if ( status != PAS_Ok ) ++ { ++ return( status ); ++ } ++ ++ PAS_State = PAS_GetStateTable(); ++ if ( PAS_State == NULL ) ++ { ++ return( PAS_Error ); ++ } ++ } ++ ++ *MaxChannels = 2; ++ ++ // Check board revision. Revision # 0 can't play 16-bit data. ++ if ( ( PAS_State->intrctlr & 0xe0 ) == 0 ) ++ { ++ *MaxSampleBits = 8; ++ } ++ else ++ { ++ *MaxSampleBits = 16; ++ } ++ ++ return( PAS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_SetCallBack ++ ++ Specifies the user function to call at the end of a sound transfer. ++---------------------------------------------------------------------*/ ++ ++void PAS_SetCallBack ++ ( ++ void ( *func )( void ) ++ ) ++ ++ { ++ PAS_CallBack = func; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_FindCard ++ ++ Auto-detects the port the Pro AudioSpectrum is set for. ++---------------------------------------------------------------------*/ ++ ++int PAS_FindCard ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = PAS_TestAddress( DEFAULT_BASE ); ++ if ( status == 0 ) ++ { ++ PAS_TranslateCode = DEFAULT_BASE; ++ return( PAS_Ok ); ++ } ++ ++ status = PAS_TestAddress( ALT_BASE_1 ); ++ if ( status == 0 ) ++ { ++ PAS_TranslateCode = ALT_BASE_1; ++ return( PAS_Ok ); ++ } ++ ++ status = PAS_TestAddress( ALT_BASE_2 ); ++ if ( status == 0 ) ++ { ++ PAS_TranslateCode = ALT_BASE_2; ++ return( PAS_Ok ); ++ } ++ ++ status = PAS_TestAddress( ALT_BASE_3 ); ++ if ( status == 0 ) ++ { ++ PAS_TranslateCode = ALT_BASE_3; ++ return( PAS_Ok ); ++ } ++ ++ PAS_SetErrorCode( PAS_CardNotFound ); ++ return( PAS_Error ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_SaveMusicVolume ++ ++ Saves the user's FM mixer settings. ++---------------------------------------------------------------------*/ ++ ++int PAS_SaveMusicVolume ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ int data; ++ ++ if ( !PAS_Installed ) ++ { ++ status = PAS_CheckForDriver(); ++ if ( status != PAS_Ok ) ++ { ++ return( status ); ++ } ++ ++ PAS_State = PAS_GetStateTable(); ++ if ( PAS_State == NULL ) ++ { ++ return( PAS_Error ); ++ } ++ ++ PAS_Func = PAS_GetFunctionTable(); ++ if ( PAS_Func == NULL ) ++ { ++ return( PAS_Error ); ++ } ++ ++ status = PAS_GetCardSettings(); ++ if ( status != PAS_Ok ) ++ { ++ return( status ); ++ } ++ ++ status = PAS_FindCard(); ++ if ( status != PAS_Ok ) ++ { ++ return( status ); ++ } ++ ++ // Enable PAS Sound ++ data = PAS_State->audiofilt; ++ data |= PAS_AudioMuteFlag; ++ ++ PAS_Write( AudioFilterControl, data ); ++ PAS_State->audiofilt = data; ++ } ++ ++ status = PAS_CallMVFunction( PAS_Func->GetMixer, 0, OUTPUTMIXER, L_FM ); ++ if ( status != PAS_Error ) ++ { ++ PAS_OriginalFMLeftVolume = PAS_CallMVFunction( PAS_Func->GetMixer, ++ 0, OUTPUTMIXER, L_FM ) & 0xff; ++ ++ PAS_OriginalFMRightVolume = PAS_CallMVFunction( PAS_Func->GetMixer, ++ 0, OUTPUTMIXER, R_FM ) & 0xff; ++ ++ return( PAS_Ok ); ++ } ++ ++ return( PAS_Warning ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_RestoreMusicVolume ++ ++ Restores the user's FM mixer settings. ++---------------------------------------------------------------------*/ ++ ++void PAS_RestoreMusicVolume ++ ( ++ void ++ ) ++ ++ { ++ if ( PAS_Func ) ++ { ++ PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalFMLeftVolume, ++ OUTPUTMIXER, L_FM ); ++ PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalFMRightVolume, ++ OUTPUTMIXER, R_FM ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_SaveState ++ ++ Saves the original state of the PAS prior to use. ++---------------------------------------------------------------------*/ ++ ++void PAS_SaveState ++ ( ++ void ++ ) ++ ++ { ++ PAS_OriginalState.intrctlr = PAS_State->intrctlr; ++ PAS_OriginalState.audiofilt = PAS_State->audiofilt; ++ PAS_OriginalState.tmrctlr = PAS_State->tmrctlr; ++ PAS_OriginalState.samplerate = PAS_State->samplerate; ++ PAS_OriginalState.samplecnt = PAS_State->samplecnt; ++ PAS_OriginalState.crosschannel = PAS_State->crosschannel; ++ PAS_SampleSizeConfig = PAS_Read( SampleSizeConfiguration ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_RestoreState ++ ++ Restores the original state of the PAS after use. ++---------------------------------------------------------------------*/ ++ ++void PAS_RestoreState ++ ( ++ void ++ ) ++ ++ { ++ int LoByte; ++ int HiByte; ++ ++ // Select the Sample Rate Timer ++ PAS_Write( LocalTimerControl, SelectSampleRateTimer ); ++ PAS_State->tmrctlr = SelectSampleRateTimer; ++ ++ PAS_Write( SampleRateTimer, PAS_OriginalState.samplerate ); ++ PAS_State->samplerate = PAS_OriginalState.samplerate; ++ ++ // Select the Sample Buffer Count ++ PAS_Write( LocalTimerControl, SelectSampleBufferCount ); ++ PAS_State->tmrctlr = SelectSampleBufferCount; ++ ++ LoByte = lobyte( PAS_OriginalState.samplecnt ); ++ HiByte = hibyte( PAS_OriginalState.samplecnt ); ++ PAS_Write( SampleRateTimer, LoByte ); ++ PAS_Write( SampleRateTimer, HiByte ); ++ PAS_State->samplecnt = PAS_OriginalState.samplecnt; ++ ++ PAS_Write( CrossChannelControl, PAS_OriginalState.crosschannel ); ++ PAS_State->crosschannel = PAS_OriginalState.crosschannel; ++ ++ PAS_Write( SampleSizeConfiguration, PAS_SampleSizeConfig ); ++ ++ PAS_Write( InterruptControl, PAS_OriginalState.intrctlr ); ++ PAS_State->intrctlr = PAS_OriginalState.intrctlr; ++ ++ PAS_Write( AudioFilterControl, PAS_OriginalState.audiofilt ); ++ PAS_State->audiofilt = PAS_OriginalState.audiofilt; ++ ++ PAS_Write( LocalTimerControl, PAS_OriginalState.tmrctlr ); ++ PAS_State->tmrctlr = PAS_OriginalState.tmrctlr; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void PAS_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: allocateTimerStack ++ ++ Allocate a block of memory from conventional (low) memory and return ++ the selector (which can go directly into a segment register) of the ++ memory block or 0 if an error occured. ++---------------------------------------------------------------------*/ ++ ++static unsigned short allocateTimerStack ++ ( ++ unsigned short size ++ ) ++ ++ { ++ union REGS regs; ++ ++ // clear all registers ++ memset( ®s, 0, sizeof( regs ) ); ++ ++ // DPMI allocate conventional memory ++ regs.w.ax = 0x100; ++ ++ // size in paragraphs ++ regs.w.bx = ( size + 15 ) / 16; ++ ++ int386( 0x31, ®s, ®s ); ++ if (!regs.w.cflag) ++ { ++ // DPMI call returns selector in dx ++ // (ax contains real mode segment ++ // which is ignored here) ++ ++ return( regs.w.dx ); ++ } ++ ++ // Couldn't allocate memory. ++ return( NULL ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: deallocateTimerStack ++ ++ Deallocate a block of conventional (low) memory given a selector to ++ it. Assumes the block was allocated with DPMI function 0x100. ++---------------------------------------------------------------------*/ ++ ++static void deallocateTimerStack ++ ( ++ unsigned short selector ++ ) ++ ++ { ++ union REGS regs; ++ ++ if ( selector != NULL ) ++ { ++ // clear all registers ++ memset( ®s, 0, sizeof( regs ) ); ++ ++ regs.w.ax = 0x101; ++ regs.w.dx = selector; ++ int386( 0x31, ®s, ®s ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_Init ++ ++ Initializes the sound card and prepares the module to play ++ digitized sounds. ++---------------------------------------------------------------------*/ ++ ++int PAS_Init ++ ( ++ void ++ ) ++ ++ { ++ int Interrupt; ++ int status; ++ int data; ++ ++ if ( PAS_Installed ) ++ { ++ return( PAS_Ok ); ++ } ++ ++ PAS_IntController1Mask = inp( 0x21 ); ++ PAS_IntController2Mask = inp( 0xA1 ); ++ ++ status = PAS_CheckForDriver(); ++ if ( status != PAS_Ok ) ++ { ++ return( status ); ++ } ++ ++ PAS_State = PAS_GetStateTable(); ++ if ( PAS_State == NULL ) ++ { ++ return( PAS_Error ); ++ } ++ ++ PAS_Func = PAS_GetFunctionTable(); ++ if ( PAS_Func == NULL ) ++ { ++ return( PAS_Error ); ++ } ++ ++ status = PAS_GetCardSettings(); ++ if ( status != PAS_Ok ) ++ { ++ return( status ); ++ } ++ ++ status = PAS_FindCard(); ++ if ( status != PAS_Ok ) ++ { ++ return( status ); ++ } ++ ++ PAS_SaveState(); ++ ++ PAS_OriginalPCMLeftVolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, ++ OUTPUTMIXER, L_PCM ) & 0xff; ++ PAS_OriginalPCMRightVolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, ++ OUTPUTMIXER, R_PCM ) & 0xff; ++ ++ PAS_SoundPlaying = FALSE; ++ ++ PAS_SetCallBack( NULL ); ++ ++ PAS_DMABuffer = NULL; ++ ++ status = PAS_LockMemory(); ++ if ( status != PAS_Ok ) ++ { ++ PAS_UnlockMemory(); ++ return( status ); ++ } ++ ++ StackSelector = allocateTimerStack( kStackSize ); ++ if ( StackSelector == NULL ) ++ { ++ PAS_UnlockMemory(); ++ PAS_SetErrorCode( PAS_OutOfMemory ); ++ return( PAS_Error ); ++ } ++ ++ // Leave a little room at top of stack just for the hell of it... ++ StackPointer = kStackSize - sizeof( long ); ++ ++ // Install our interrupt handler ++ Interrupt = PAS_Interrupts[ PAS_Irq ]; ++ PAS_OldInt = _dos_getvect( Interrupt ); ++ if ( PAS_Irq < 8 ) ++ { ++ _dos_setvect( Interrupt, PAS_ServiceInterrupt ); ++ } ++ else ++ { ++ status = IRQ_SetVector( Interrupt, PAS_ServiceInterrupt ); ++ if ( status != IRQ_Ok ) ++ { ++ PAS_UnlockMemory(); ++ deallocateTimerStack( StackSelector ); ++ StackSelector = NULL; ++ PAS_SetErrorCode( PAS_UnableToSetIrq ); ++ return( PAS_Error ); ++ } ++ } ++ ++ // Enable PAS Sound ++ data = PAS_State->audiofilt; ++ data |= PAS_AudioMuteFlag; ++ ++ PAS_Write( AudioFilterControl, data ); ++ PAS_State->audiofilt = data; ++ ++ PAS_SetPlaybackRate( PAS_DefaultSampleRate ); ++ PAS_SetMixMode( PAS_DefaultMixMode ); ++ ++ PAS_Installed = TRUE; ++ ++ PAS_SetErrorCode( PAS_Ok ); ++ return( PAS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_Shutdown ++ ++ Ends transfer of sound data to the sound card and restores the ++ system resources used by the card. ++---------------------------------------------------------------------*/ ++ ++void PAS_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ int Interrupt; ++ ++ if ( PAS_Installed ) ++ { ++ // Halt the DMA transfer ++ PAS_StopPlayback(); ++ ++ // Restore the original interrupt ++ Interrupt = PAS_Interrupts[ PAS_Irq ]; ++ if ( PAS_Irq >= 8 ) ++ { ++ IRQ_RestoreVector( Interrupt ); ++ } ++ _dos_setvect( Interrupt, PAS_OldInt ); ++ ++ PAS_SoundPlaying = FALSE; ++ ++ PAS_DMABuffer = NULL; ++ ++ PAS_SetCallBack( NULL ); ++ ++ PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalPCMLeftVolume, ++ OUTPUTMIXER, L_PCM ); ++ PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalPCMRightVolume, ++ OUTPUTMIXER, R_PCM ); ++ ++// DEBUG ++// PAS_RestoreState(); ++ ++ PAS_UnlockMemory(); ++ ++ deallocateTimerStack( StackSelector ); ++ StackSelector = NULL; ++ ++ PAS_Installed = FALSE; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_UnlockMemory ++ ++ Unlocks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++void PAS_UnlockMemory ++ ( ++ void ++ ) ++ ++ { ++ DPMI_UnlockMemoryRegion( PAS_LockStart, PAS_LockEnd ); ++ DPMI_Unlock( PAS_Interrupts ); ++ DPMI_Unlock( PAS_OldInt ); ++ DPMI_Unlock( PAS_IntController1Mask ); ++ DPMI_Unlock( PAS_IntController2Mask ); ++ DPMI_Unlock( PAS_Installed ); ++ DPMI_Unlock( PAS_TranslateCode ); ++ DPMI_Unlock( PAS_OriginalPCMLeftVolume ); ++ DPMI_Unlock( PAS_OriginalPCMRightVolume ); ++ DPMI_Unlock( PAS_OriginalFMLeftVolume ); ++ DPMI_Unlock( PAS_OriginalFMRightVolume ); ++ DPMI_Unlock( PAS_DMAChannel ); ++ DPMI_Unlock( PAS_Irq ); ++ DPMI_Unlock( PAS_State ); ++ DPMI_Unlock( PAS_Func ); ++ DPMI_Unlock( PAS_OriginalState ); ++ DPMI_Unlock( PAS_SampleSizeConfig ); ++ DPMI_Unlock( PAS_DMABuffer ); ++ DPMI_Unlock( PAS_DMABufferEnd ); ++ DPMI_Unlock( PAS_CurrentDMABuffer ); ++ DPMI_Unlock( PAS_TotalDMABufferSize ); ++ DPMI_Unlock( PAS_TransferLength ); ++ DPMI_Unlock( PAS_MixMode ); ++ DPMI_Unlock( PAS_SampleRate ); ++ DPMI_Unlock( PAS_TimeInterval ); ++ DPMI_Unlock( PAS_SoundPlaying ); ++ DPMI_Unlock( PAS_CallBack ); ++ DPMI_Unlock( PAS_ErrorCode ); ++ DPMI_Unlock( irqstatus ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PAS_LockMemory ++ ++ Locks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++int PAS_LockMemory ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_LockMemoryRegion( PAS_LockStart, PAS_LockEnd ); ++ status |= DPMI_Lock( PAS_Interrupts ); ++ status |= DPMI_Lock( PAS_OldInt ); ++ status |= DPMI_Lock( PAS_IntController1Mask ); ++ status |= DPMI_Lock( PAS_IntController2Mask ); ++ status |= DPMI_Lock( PAS_Installed ); ++ status |= DPMI_Lock( PAS_TranslateCode ); ++ status |= DPMI_Lock( PAS_OriginalPCMLeftVolume ); ++ status |= DPMI_Lock( PAS_OriginalPCMRightVolume ); ++ status |= DPMI_Lock( PAS_OriginalFMLeftVolume ); ++ status |= DPMI_Lock( PAS_OriginalFMRightVolume ); ++ status |= DPMI_Lock( PAS_DMAChannel ); ++ status |= DPMI_Lock( PAS_Irq ); ++ status |= DPMI_Lock( PAS_State ); ++ status |= DPMI_Lock( PAS_Func ); ++ status |= DPMI_Lock( PAS_OriginalState ); ++ status |= DPMI_Lock( PAS_SampleSizeConfig ); ++ status |= DPMI_Lock( PAS_DMABuffer ); ++ status |= DPMI_Lock( PAS_DMABufferEnd ); ++ status |= DPMI_Lock( PAS_CurrentDMABuffer ); ++ status |= DPMI_Lock( PAS_TotalDMABufferSize ); ++ status |= DPMI_Lock( PAS_TransferLength ); ++ status |= DPMI_Lock( PAS_MixMode ); ++ status |= DPMI_Lock( PAS_SampleRate ); ++ status |= DPMI_Lock( PAS_TimeInterval ); ++ status |= DPMI_Lock( PAS_SoundPlaying ); ++ status |= DPMI_Lock( PAS_CallBack ); ++ status |= DPMI_Lock( PAS_ErrorCode ); ++ status |= DPMI_Lock( irqstatus ); ++ ++ if ( status != DPMI_Ok ) ++ { ++ PAS_UnlockMemory(); ++ PAS_SetErrorCode( PAS_DPMI_Error ); ++ return( PAS_Error ); ++ } ++ ++ return( PAS_Ok ); ++ } +diff -urN rott-1.0/rott/audiolib/pas16.h trunk/rott/audiolib/pas16.h +--- rott-1.0/rott/audiolib/pas16.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/pas16.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,81 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: PAS16.H ++ ++ author: James R. Dose ++ date: March 27, 1994 ++ ++ Public header for for PAS16.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __PAS16_H ++#define __PAS16_H ++ ++enum PAS_ERRORS ++ { ++ PAS_Warning = -2, ++ PAS_Error = -1, ++ PAS_Ok = 0, ++ PAS_DriverNotFound, ++ PAS_DmaError, ++ PAS_InvalidIrq, ++ PAS_UnableToSetIrq, ++ PAS_Dos4gwIrqError, ++ PAS_NoSoundPlaying, ++ PAS_CardNotFound, ++ PAS_DPMI_Error, ++ PAS_OutOfMemory ++ }; ++ ++#define PAS_MaxMixMode STEREO_16BIT ++#define PAS_DefaultSampleRate 11000 ++#define PAS_DefaultMixMode MONO_8BIT ++#define PAS_MaxIrq 15 ++ ++#define PAS_MinSamplingRate 4000 ++#define PAS_MaxSamplingRate 44000 ++ ++extern unsigned int PAS_DMAChannel; ++ ++char *PAS_ErrorString( int ErrorNumber ); ++void PAS_SetPlaybackRate( unsigned rate ); ++unsigned PAS_GetPlaybackRate( void ); ++int PAS_SetMixMode( int mode ); ++void PAS_StopPlayback( void ); ++int PAS_GetCurrentPos( void ); ++int PAS_BeginBufferedPlayback( char *BufferStart, int BufferSize, int NumDivisions, unsigned SampleRate, int MixMode, void ( *CallBackFunc )( void ) ); ++int PAS_BeginBufferedRecord( char *BufferStart, int BufferSize, int NumDivisions, unsigned SampleRate, int MixMode, void ( *CallBackFunc )( void ) ); ++int PAS_SetPCMVolume( int volume ); ++int PAS_GetPCMVolume( void ); ++void PAS_SetFMVolume( int volume ); ++int PAS_GetFMVolume( void ); ++int PAS_GetCardInfo( int *MaxSampleBits, int *MaxChannels ); ++void PAS_SetCallBack( void ( *func )( void ) ); ++int PAS_SaveMusicVolume( void ); ++void PAS_RestoreMusicVolume( void ); ++int PAS_Init( void ); ++void PAS_Shutdown( void ); ++void PAS_UnlockMemory( void ); ++int PAS_LockMemory( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/pitch.c trunk/rott/audiolib/pitch.c +--- rott-1.0/rott/audiolib/pitch.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/pitch.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,258 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: PITCH.C ++ ++ author: James R. Dose ++ date: June 14, 1993 ++ ++ Routines for pitch scaling. ++ ++ (c) Copyright 1993 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++//#include ++#include "dpmi.h" ++#include "standard.h" ++#include "pitch.h" ++ ++#define MAXDETUNE 25 ++ ++static unsigned long PitchTable[ 12 ][ MAXDETUNE ] = ++ { ++ { 0x10000, 0x10097, 0x1012f, 0x101c7, 0x10260, 0x102f9, 0x10392, 0x1042c, ++ 0x104c6, 0x10561, 0x105fb, 0x10696, 0x10732, 0x107ce, 0x1086a, 0x10907, ++ 0x109a4, 0x10a41, 0x10adf, 0x10b7d, 0x10c1b, 0x10cba, 0x10d59, 0x10df8, ++ 0x10e98 }, ++ { 0x10f38, 0x10fd9, 0x1107a, 0x1111b, 0x111bd, 0x1125f, 0x11302, 0x113a5, ++ 0x11448, 0x114eb, 0x1158f, 0x11634, 0x116d8, 0x1177e, 0x11823, 0x118c9, ++ 0x1196f, 0x11a16, 0x11abd, 0x11b64, 0x11c0c, 0x11cb4, 0x11d5d, 0x11e06, ++ 0x11eaf }, ++ { 0x11f59, 0x12003, 0x120ae, 0x12159, 0x12204, 0x122b0, 0x1235c, 0x12409, ++ 0x124b6, 0x12563, 0x12611, 0x126bf, 0x1276d, 0x1281c, 0x128cc, 0x1297b, ++ 0x12a2b, 0x12adc, 0x12b8d, 0x12c3e, 0x12cf0, 0x12da2, 0x12e55, 0x12f08, ++ 0x12fbc }, ++ { 0x1306f, 0x13124, 0x131d8, 0x1328d, 0x13343, 0x133f9, 0x134af, 0x13566, ++ 0x1361d, 0x136d5, 0x1378d, 0x13846, 0x138fe, 0x139b8, 0x13a72, 0x13b2c, ++ 0x13be6, 0x13ca1, 0x13d5d, 0x13e19, 0x13ed5, 0x13f92, 0x1404f, 0x1410d, ++ 0x141cb }, ++ { 0x1428a, 0x14349, 0x14408, 0x144c8, 0x14588, 0x14649, 0x1470a, 0x147cc, ++ 0x1488e, 0x14951, 0x14a14, 0x14ad7, 0x14b9b, 0x14c5f, 0x14d24, 0x14dea, ++ 0x14eaf, 0x14f75, 0x1503c, 0x15103, 0x151cb, 0x15293, 0x1535b, 0x15424, ++ 0x154ee }, ++ { 0x155b8, 0x15682, 0x1574d, 0x15818, 0x158e4, 0x159b0, 0x15a7d, 0x15b4a, ++ 0x15c18, 0x15ce6, 0x15db4, 0x15e83, 0x15f53, 0x16023, 0x160f4, 0x161c5, ++ 0x16296, 0x16368, 0x1643a, 0x1650d, 0x165e1, 0x166b5, 0x16789, 0x1685e, ++ 0x16934 }, ++ { 0x16a09, 0x16ae0, 0x16bb7, 0x16c8e, 0x16d66, 0x16e3e, 0x16f17, 0x16ff1, ++ 0x170ca, 0x171a5, 0x17280, 0x1735b, 0x17437, 0x17513, 0x175f0, 0x176ce, ++ 0x177ac, 0x1788a, 0x17969, 0x17a49, 0x17b29, 0x17c09, 0x17cea, 0x17dcc, ++ 0x17eae }, ++ { 0x17f91, 0x18074, 0x18157, 0x1823c, 0x18320, 0x18406, 0x184eb, 0x185d2, ++ 0x186b8, 0x187a0, 0x18888, 0x18970, 0x18a59, 0x18b43, 0x18c2d, 0x18d17, ++ 0x18e02, 0x18eee, 0x18fda, 0x190c7, 0x191b5, 0x192a2, 0x19391, 0x19480, ++ 0x1956f }, ++ { 0x1965f, 0x19750, 0x19841, 0x19933, 0x19a25, 0x19b18, 0x19c0c, 0x19d00, ++ 0x19df4, 0x19ee9, 0x19fdf, 0x1a0d5, 0x1a1cc, 0x1a2c4, 0x1a3bc, 0x1a4b4, ++ 0x1a5ad, 0x1a6a7, 0x1a7a1, 0x1a89c, 0x1a998, 0x1aa94, 0x1ab90, 0x1ac8d, ++ 0x1ad8b }, ++ { 0x1ae89, 0x1af88, 0x1b088, 0x1b188, 0x1b289, 0x1b38a, 0x1b48c, 0x1b58f, ++ 0x1b692, 0x1b795, 0x1b89a, 0x1b99f, 0x1baa4, 0x1bbaa, 0x1bcb1, 0x1bdb8, ++ 0x1bec0, 0x1bfc9, 0x1c0d2, 0x1c1dc, 0x1c2e6, 0x1c3f1, 0x1c4fd, 0x1c609, ++ 0x1c716 }, ++ { 0x1c823, 0x1c931, 0x1ca40, 0x1cb50, 0x1cc60, 0x1cd70, 0x1ce81, 0x1cf93, ++ 0x1d0a6, 0x1d1b9, 0x1d2cd, 0x1d3e1, 0x1d4f6, 0x1d60c, 0x1d722, 0x1d839, ++ 0x1d951, 0x1da69, 0x1db82, 0x1dc9c, 0x1ddb6, 0x1ded1, 0x1dfec, 0x1e109, ++ 0x1e225 }, ++ { 0x1e343, 0x1e461, 0x1e580, 0x1e6a0, 0x1e7c0, 0x1e8e0, 0x1ea02, 0x1eb24, ++ 0x1ec47, 0x1ed6b, 0x1ee8f, 0x1efb4, 0x1f0d9, 0x1f1ff, 0x1f326, 0x1f44e, ++ 0x1f576, 0x1f69f, 0x1f7c9, 0x1f8f3, 0x1fa1e, 0x1fb4a, 0x1fc76, 0x1fda3, ++ 0x1fed1 } ++ }; ++ ++ ++//static int PITCH_Installed = FALSE; ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PITCH_Init ++ ++ Initializes pitch table. ++---------------------------------------------------------------------*/ ++/* ++void PITCH_Init ++ ( ++ void ++ ) ++ ++ { ++ int note; ++ int detune; ++ ++ if ( !PITCH_Installed ) ++ { ++ for( note = 0; note < 12; note++ ) ++ { ++ for( detune = 0; detune < MAXDETUNE; detune++ ) ++ { ++ PitchTable[ note ][ detune ] = 0x10000 * ++ pow( 2, ( note * MAXDETUNE + detune ) / ( 12.0 * MAXDETUNE ) ); ++ } ++ } ++ ++ PITCH_Installed = TRUE; ++ } ++ } ++*/ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define PITCH_LockStart PITCH_GetScale ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PITCH_GetScale ++ ++ Returns a fixed-point value to scale number the specified amount. ++---------------------------------------------------------------------*/ ++ ++unsigned long PITCH_GetScale ++ ( ++ int pitchoffset ++ ) ++ ++ { ++ unsigned long scale; ++ int octaveshift; ++ int noteshift; ++ int note; ++ int detune; ++ ++// if ( !PITCH_Installed ) ++// { ++// PITCH_Init(); ++// } ++ ++ if ( pitchoffset == 0 ) ++ { ++ return( PitchTable[ 0 ][ 0 ] ); ++ } ++ ++ noteshift = pitchoffset % 1200; ++ if ( noteshift < 0 ) ++ { ++ noteshift += 1200; ++ } ++ ++ note = noteshift / 100; ++ detune = ( noteshift % 100 ) / ( 100 / MAXDETUNE ); ++ octaveshift = ( pitchoffset - noteshift ) / 1200; ++ ++ if ( detune < 0 ) ++ { ++ detune += ( 100 / MAXDETUNE ); ++ note--; ++ if ( note < 0 ) ++ { ++ note += 12; ++ octaveshift--; ++ } ++ } ++ ++ scale = PitchTable[ note ][ detune ]; ++ ++ if ( octaveshift < 0 ) ++ { ++ scale >>= -octaveshift; ++ } ++ else ++ { ++ scale <<= octaveshift; ++ } ++ ++ return( scale ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PITCH_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void PITCH_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PITCH_UnlockMemory ++ ++ Unlocks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++void PITCH_UnlockMemory ++ ( ++ void ++ ) ++ ++ { ++ DPMI_UnlockMemoryRegion( PITCH_LockStart, PITCH_LockEnd ); ++ DPMI_Unlock( PitchTable ); ++// DPMI_Unlock( PITCH_Installed ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: PITCH_LockMemory ++ ++ Unlocks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++int PITCH_LockMemory ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_LockMemoryRegion( PITCH_LockStart, PITCH_LockEnd ); ++ status |= DPMI_Lock( PitchTable ); ++// status |= DPMI_Lock( PITCH_Installed ); ++ ++ if ( status != DPMI_Ok ) ++ { ++ PITCH_UnlockMemory(); ++ return( PITCH_Error ); ++ } ++ ++ return( PITCH_Ok ); ++ } +diff -urN rott-1.0/rott/audiolib/pitch.h trunk/rott/audiolib/pitch.h +--- rott-1.0/rott/audiolib/pitch.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/pitch.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,45 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: PITCH.H ++ ++ author: James R. Dose ++ date: June 14, 1994 ++ ++ Public header for PITCH.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __PITCH_H ++#define __PITCH_H ++ ++enum PITCH_ERRORS ++ { ++ PITCH_Warning = -2, ++ PITCH_Error = -1, ++ PITCH_Ok = 0, ++ }; ++ ++//void PITCH_Init( void ); ++unsigned long PITCH_GetScale( int pitchoffset ); ++void PITCH_UnlockMemory( void ); ++int PITCH_LockMemory( void ); ++#endif +diff -urN rott-1.0/rott/audiolib/platform.h trunk/rott/audiolib/platform.h +--- rott-1.0/rott/audiolib/platform.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/platform.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,77 @@ ++#ifndef _INCLUDE_PLATFORM_H_ ++#define _INCLUDE_PLATFORM_H_ ++ ++/* this file originally from buildengine */ ++#ifdef BUILDENGINE ++ ++#if (defined PLATFORM_WIN32) ++#include "win32_compat.h" ++#elif (defined PLATFORM_UNIX) ++#include "unix_compat.h" ++#elif (defined PLATFORM_DOS) ++#include "doscmpat.h" ++#else ++#error Define your platform! ++#endif ++ ++#if (!defined __EXPORT__) ++#define __EXPORT__ ++#endif ++ ++#if ((defined PLATFORM_SUPPORTS_SDL) && (!defined PLATFORM_TIMER_HZ)) ++#define PLATFORM_TIMER_HZ 100 ++#endif ++ ++#if (!defined PLATFORM_TIMER_HZ) ++#error You need to define PLATFORM_TIMER_HZ for your platform. ++#endif ++ ++#if (defined __WATCOMC__) ++#define snprintf _snprintf ++#endif ++ ++#endif ++ ++static __inline unsigned short _swap16(unsigned short D) ++{ ++#if PLATFORM_MACOSX ++ register unsigned short returnValue; ++ __asm__ volatile("lhbrx %0,0,%1" ++ : "=r" (returnValue) ++ : "r" (&D) ++ ); ++ return returnValue; ++#else ++ return((D<<8)|(D>>8)); ++#endif ++} ++ ++static __inline unsigned int _swap32(unsigned int D) ++{ ++#if PLATFORM_MACOSX ++ register unsigned int returnValue; ++ __asm__ volatile("lwbrx %0,0,%1" ++ : "=r" (returnValue) ++ : "r" (&D) ++ ); ++ return returnValue; ++#else ++ return((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24)); ++#endif ++} ++ ++#if PLATFORM_MACOSX ++#define PLATFORM_BIGENDIAN 1 ++#define BUILDSWAP_INTEL16(x) _swap16(x) ++#define BUILDSWAP_INTEL32(x) _swap32(x) ++#else ++#define PLATFORM_LITTLEENDIAN 1 ++#define BUILDSWAP_INTEL16(x) (x) ++#define BUILDSWAP_INTEL32(x) (x) ++#endif ++ ++#endif /* !defined _INCLUDE_PLATFORM_H_ */ ++ ++/* end of platform.h ... */ ++ ++ +diff -urN rott-1.0/rott/audiolib/sndcards.h trunk/rott/audiolib/sndcards.h +--- rott-1.0/rott/audiolib/sndcards.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/sndcards.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,55 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: SNDCARDS.H ++ ++ author: James R. Dose ++ date: March 31, 1994 ++ ++ Contains enumerated type definitions for sound cards. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __SNDCARDS_H ++#define __SNDCARDS_H ++ ++#define ASS_VERSION_STRING "1.12" ++ ++typedef enum ++ { ++// ASS_NoSound, ++ SoundBlaster, ++ ProAudioSpectrum, ++ SoundMan16, ++ Adlib, ++ GenMidi, ++ SoundCanvas, ++ Awe32, ++ WaveBlaster, ++ SoundScape, ++ UltraSound, ++ SoundSource, ++ TandySoundSource, ++ PC, ++ NumSoundCards ++ } soundcardnames; ++ ++#endif +diff -urN rott-1.0/rott/audiolib/sndscape.c trunk/rott/audiolib/sndscape.c +--- rott-1.0/rott/audiolib/sndscape.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/sndscape.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,1661 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: SNDSCAPE.C ++ ++ author: James R. Dose ++ date: October 25, 1994 ++ ++ Low level routines to support the Ensoniq Soundscape. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "interrup.h" ++#include "dpmi.h" ++#include "dma.h" ++#include "irq.h" ++#include "sndscape.h" ++#include "_sndscap.h" ++ ++const int SOUNDSCAPE_Interrupts[ SOUNDSCAPE_MaxIrq + 1 ] = ++ { ++ INVALID, INVALID, 0xa, INVALID, ++ INVALID, 0xd, INVALID, 0xf, ++ INVALID, INVALID, 0x72, INVALID, ++ INVALID, INVALID, INVALID, INVALID ++ }; ++ ++const int SOUNDSCAPE_SampleSize[ SOUNDSCAPE_MaxMixMode + 1 ] = ++ { ++ MONO_8BIT_SAMPLE_SIZE, STEREO_8BIT_SAMPLE_SIZE, ++ MONO_16BIT_SAMPLE_SIZE, STEREO_16BIT_SAMPLE_SIZE ++ }; ++ ++static void ( __interrupt __far *SOUNDSCAPE_OldInt )( void ); ++ ++static int SOUNDSCAPE_Installed = FALSE; ++static int SOUNDSCAPE_FoundCard = FALSE; ++ ++static char *SOUNDSCAPE_DMABuffer; ++static char *SOUNDSCAPE_DMABufferEnd; ++static char *SOUNDSCAPE_CurrentDMABuffer; ++static int SOUNDSCAPE_TotalDMABufferSize; ++ ++static int SOUNDSCAPE_TransferLength = 0; ++static int SOUNDSCAPE_MixMode = SOUNDSCAPE_DefaultMixMode; ++static int SOUNDSCAPE_SamplePacketSize = MONO_16BIT_SAMPLE_SIZE; ++static unsigned SOUNDSCAPE_SampleRate = SOUNDSCAPE_DefaultSampleRate; ++ ++volatile int SOUNDSCAPE_SoundPlaying; ++ ++void ( *SOUNDSCAPE_CallBack )( void ); ++ ++static int SOUNDSCAPE_IntController1Mask; ++static int SOUNDSCAPE_IntController2Mask; ++ ++// some globals for chip type, ports, DMA, IRQs ... and stuff ++static struct ++ { ++ int BasePort; // base address of the Ensoniq gate-array chip ++ int WavePort; // the AD-1848 base address ++ int DMAChan; // the DMA channel used for PCM ++ int WaveIRQ; // the PCM IRQ ++ int MIDIIRQ; // the MPU-401 IRQ ++ int ChipID; // the Ensoniq chip type ++ int SBEmul; // SoundBlaster emulation flag ++ int CDROM; // CD-ROM flag ++ int IRQIndx; // the Wave IRQ index - for hardware regs ++ int OldIRQs; // Old IRQs flag to support older HW ++ } SOUNDSCAPE_Config; ++ ++// adequate stack size ++#define kStackSize 2048 ++ ++static unsigned short StackSelector = NULL; ++static unsigned long StackPointer; ++ ++static unsigned short oldStackSelector; ++static unsigned long oldStackPointer; ++ ++// These declarations are necessary to use the inline assembly pragmas. ++ ++extern void GetStack(unsigned short *selptr,unsigned long *stackptr); ++extern void SetStack(unsigned short selector,unsigned long stackptr); ++ ++// This function will get the current stack selector and pointer and save ++// them off. ++#pragma aux GetStack = \ ++ "mov [edi],esp" \ ++ "mov ax,ss" \ ++ "mov [esi],ax" \ ++ parm [esi] [edi] \ ++ modify [eax esi edi]; ++ ++// This function will set the stack selector and pointer to the specified ++// values. ++#pragma aux SetStack = \ ++ "mov ss,ax" \ ++ "mov esp,edx" \ ++ parm [ax] [edx] \ ++ modify [eax edx]; ++ ++int SOUNDSCAPE_DMAChannel = -1; ++ ++int SOUNDSCAPE_ErrorCode = SOUNDSCAPE_Ok; ++ ++#define SOUNDSCAPE_SetErrorCode( status ) \ ++ SOUNDSCAPE_ErrorCode = ( status ); ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *SOUNDSCAPE_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case SOUNDSCAPE_Warning : ++ case SOUNDSCAPE_Error : ++ ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_ErrorCode ); ++ break; ++ ++ case SOUNDSCAPE_Ok : ++ ErrorString = "SoundScape ok."; ++ break; ++ ++ case SOUNDSCAPE_EnvNotFound : ++ ErrorString = "SNDSCAPE environment variable not set. This is used to locate \n" ++ "SNDSCAPE.INI which is used to describe your sound card setup."; ++ break; ++ ++ case SOUNDSCAPE_InitFileNotFound : ++ ErrorString = "Missing SNDSCAPE.INI file for SoundScape. This file should be \n" ++ "located in the directory indicated by the SNDSCAPE environment \n" ++ "variable or in 'C:\SNDSCAPE' if SNDSCAPE is not set."; ++ break; ++ ++ case SOUNDSCAPE_MissingProductInfo : ++ ErrorString = "Missing 'Product' field in SNDSCAPE.INI file for SoundScape."; ++ break; ++ ++ case SOUNDSCAPE_MissingPortInfo : ++ ErrorString = "Missing 'Port' field in SNDSCAPE.INI file for SoundScape."; ++ break; ++ ++ case SOUNDSCAPE_MissingDMAInfo : ++ ErrorString = "Missing 'DMA' field in SNDSCAPE.INI file for SoundScape."; ++ break; ++ ++ case SOUNDSCAPE_MissingIRQInfo : ++ ErrorString = "Missing 'IRQ' field in SNDSCAPE.INI file for SoundScape."; ++ break; ++ ++ case SOUNDSCAPE_MissingSBIRQInfo : ++ ErrorString = "Missing 'SBIRQ' field in SNDSCAPE.INI file for SoundScape."; ++ break; ++ ++ case SOUNDSCAPE_MissingSBENABLEInfo : ++ ErrorString = "Missing 'SBEnable' field in SNDSCAPE.INI file for SoundScape."; ++ break; ++ ++ case SOUNDSCAPE_MissingWavePortInfo : ++ ErrorString = "Missing 'WavePort' field in SNDSCAPE.INI file for SoundScape."; ++ break; ++ ++ case SOUNDSCAPE_HardwareError : ++ ErrorString = "Could not detect SoundScape. Make sure your SNDSCAPE.INI file \n" ++ "contains correct information about your hardware setup."; ++ break; ++ ++ case SOUNDSCAPE_NoSoundPlaying : ++ ErrorString = "No sound playing on SoundScape."; ++ break; ++ ++ case SOUNDSCAPE_InvalidSBIrq : ++ ErrorString = "Invalid SoundScape Irq in SBIRQ field of SNDSCAPE.INI."; ++ break; ++ ++ case SOUNDSCAPE_UnableToSetIrq : ++ ErrorString = "Unable to set SoundScape IRQ. Try selecting an IRQ of 7 or below."; ++ break; ++ ++ case SOUNDSCAPE_DmaError : ++ ErrorString = DMA_ErrorString( DMA_Error ); ++ break; ++ ++ case SOUNDSCAPE_DPMI_Error : ++ ErrorString = "DPMI Error in SoundScape."; ++ break; ++ ++ case SOUNDSCAPE_OutOfMemory : ++ ErrorString = "Out of conventional memory in SoundScape."; ++ break; ++ ++ default : ++ ErrorString = "Unknown SoundScape error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define SOUNDSCAPE_LockStart SOUNDSCAPE_EnableInterrupt ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_EnableInterrupt ++ ++ Enables the triggering of the sound card interrupt. ++---------------------------------------------------------------------*/ ++ ++static void SOUNDSCAPE_EnableInterrupt ++ ( ++ void ++ ) ++ ++ { ++ int mask; ++ ++ // Unmask system interrupt ++ if ( SOUNDSCAPE_Config.WaveIRQ < 8 ) ++ { ++ mask = inp( 0x21 ) & ~( 1 << SOUNDSCAPE_Config.WaveIRQ ); ++ outp( 0x21, mask ); ++ } ++ else ++ { ++ mask = inp( 0xA1 ) & ~( 1 << ( SOUNDSCAPE_Config.WaveIRQ - 8 ) ); ++ outp( 0xA1, mask ); ++ ++ mask = inp( 0x21 ) & ~( 1 << 2 ); ++ outp( 0x21, mask ); ++ } ++ ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_DisableInterrupt ++ ++ Disables the triggering of the sound card interrupt. ++---------------------------------------------------------------------*/ ++ ++static void SOUNDSCAPE_DisableInterrupt ++ ( ++ void ++ ) ++ ++ { ++ int mask; ++ ++ // Restore interrupt mask ++ if ( SOUNDSCAPE_Config.WaveIRQ < 8 ) ++ { ++ mask = inp( 0x21 ) & ~( 1 << SOUNDSCAPE_Config.WaveIRQ ); ++ mask |= SOUNDSCAPE_IntController1Mask & ( 1 << SOUNDSCAPE_Config.WaveIRQ ); ++ outp( 0x21, mask ); ++ } ++ else ++ { ++ mask = inp( 0x21 ) & ~( 1 << 2 ); ++ mask |= SOUNDSCAPE_IntController1Mask & ( 1 << 2 ); ++ outp( 0x21, mask ); ++ ++ mask = inp( 0xA1 ) & ~( 1 << ( SOUNDSCAPE_Config.WaveIRQ - 8 ) ); ++ mask |= SOUNDSCAPE_IntController2Mask & ( 1 << ( SOUNDSCAPE_Config.WaveIRQ - 8 ) ); ++ outp( 0xA1, mask ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_ServiceInterrupt ++ ++ Handles interrupt generated by sound card at the end of a voice ++ transfer. Calls the user supplied callback function. ++---------------------------------------------------------------------*/ ++ ++static void __interrupt __far SOUNDSCAPE_ServiceInterrupt ++ ( ++ void ++ ) ++ ++ { ++ // save stack ++ GetStack( &oldStackSelector, &oldStackPointer ); ++ ++ // set our stack ++ SetStack( StackSelector, StackPointer ); ++ ++ if ( !( inp( SOUNDSCAPE_Config.WavePort + AD_STATUS ) & 0x01 ) ) ++ { ++ // restore stack ++ SetStack( oldStackSelector, oldStackPointer ); ++ ++ // Wasn't our interrupt. Call the old one. ++ _chain_intr( SOUNDSCAPE_OldInt ); ++ } ++ ++ // clear the AD-1848 interrupt ++ outp( SOUNDSCAPE_Config.WavePort + AD_STATUS, 0x00 ); ++ ++ // Keep track of current buffer ++ SOUNDSCAPE_CurrentDMABuffer += SOUNDSCAPE_TransferLength; ++ if ( SOUNDSCAPE_CurrentDMABuffer >= SOUNDSCAPE_DMABufferEnd ) ++ { ++ SOUNDSCAPE_CurrentDMABuffer = SOUNDSCAPE_DMABuffer; ++ } ++ ++ // Call the caller's callback function ++ if ( SOUNDSCAPE_CallBack != NULL ) ++ { ++ SOUNDSCAPE_CallBack(); ++ } ++ ++ // restore stack ++ SetStack( oldStackSelector, oldStackPointer ); ++ ++ // send EOI to Interrupt Controller ++ if ( SOUNDSCAPE_Config.WaveIRQ > 7 ) ++ { ++ outp( 0xA0, 0x20 ); ++ } ++ outp( 0x20, 0x20 ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ga_read ++ ++ Reads Ensoniq indirect registers. ++---------------------------------------------------------------------*/ ++ ++static int ga_read ++ ( ++ int rnum ++ ) ++ ++ { ++ int data; ++ ++ outp( SOUNDSCAPE_Config.BasePort + GA_REGADDR, rnum ); ++ data = inp( SOUNDSCAPE_Config.BasePort + GA_REGDATA ); ++ return( data ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ga_write ++ ++ Writes to Ensoniq indirect registers. ++---------------------------------------------------------------------*/ ++ ++static void ga_write ++ ( ++ int rnum, ++ int value ++ ) ++ ++ { ++ outp( SOUNDSCAPE_Config.BasePort + GA_REGADDR, rnum ); ++ outp( SOUNDSCAPE_Config.BasePort + GA_REGDATA, value ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ad_read ++ ++ Reads the AD-1848 indirect registers. This function should not be ++ used while the AD-1848 mode change is enabled ++---------------------------------------------------------------------*/ ++ ++static int ad_read ++ ( ++ int rnum ++ ) ++ ++ { ++ int data; ++ ++ outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, rnum ); ++ data = inp( SOUNDSCAPE_Config.WavePort + AD_REGDATA ); ++ return( data ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: ad_write ++ ++ Writes to the AD-1848 indirect registers. This function should ++ not be used while the AD-1848 mode change is enabled. ++---------------------------------------------------------------------*/ ++ ++static void ad_write ++ ( ++ int rnum, ++ int value ++ ) ++ ++ { ++ outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, rnum ); ++ outp( SOUNDSCAPE_Config.WavePort + AD_REGDATA, value ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: tdelay ++ ++ Delay function - 250ms - for AD-1848 re-synch and autocalibration. ++---------------------------------------------------------------------*/ ++ ++static void tdelay ++ ( ++ void ++ ) ++ ++ { ++ long time; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ _enable(); ++ time = clock() + CLOCKS_PER_SEC/4; ++ while(clock() < time) ++ ; ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: pcm_format ++ ++ Sets the PCM data format. ++---------------------------------------------------------------------*/ ++ ++static void pcm_format ++ ( ++ void ++ ) ++ ++ { ++ int format; ++ ++ // build the register value based on format ++ format = 0; ++ ++ switch( SOUNDSCAPE_SampleRate ) ++ { ++ case 11025: ++ format = 0x03; ++ break; ++ ++ case 22050: ++ format = 0x07; ++ break; ++ ++ case 44100: ++ format = 0x0b; ++ break; ++ ++ default: ++ // Set it to 11025 hz ++ format = 0x03; ++ break; ++ } ++ ++ // set other format bits and format globals ++ if ( SOUNDSCAPE_MixMode & SIXTEEN_BIT ) ++ { ++ format |= 0x40; ++ } ++ ++ if ( SOUNDSCAPE_MixMode & STEREO ) ++ { ++ format |= 0x10; ++ } ++ ++ // enable mode change, point to format reg ++ outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x40 | AD_FORMAT ); ++ ++ // write the format ++ outp( SOUNDSCAPE_Config.WavePort + AD_REGDATA, format ); ++ ++ // delay for internal re-synch ++ tdelay(); ++ ++ // exit mode change state ++ outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x00 ); ++ ++ // delay for autocalibration ++ tdelay(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_SetPlaybackRate ++ ++ Sets the rate at which the digitized sound will be played in ++ hertz. ++---------------------------------------------------------------------*/ ++ ++void SOUNDSCAPE_SetPlaybackRate ++ ( ++ unsigned rate ++ ) ++ ++ { ++ if ( rate < 20000 ) ++ { ++ rate = 11025; ++ } ++ else if ( rate < 30000 ) ++ { ++ rate = 22050; ++ } ++ else ++ { ++ rate = 44100; ++ } ++ ++ SOUNDSCAPE_SampleRate = rate; ++ ++ // Set the rate ++ pcm_format(); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_GetPlaybackRate ++ ++ Returns the rate at which the digitized sound will be played in ++ hertz. ++---------------------------------------------------------------------*/ ++ ++unsigned SOUNDSCAPE_GetPlaybackRate ++ ( ++ void ++ ) ++ ++ { ++ return( SOUNDSCAPE_SampleRate ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_SetMixMode ++ ++ Sets the sound card to play samples in mono or stereo. ++---------------------------------------------------------------------*/ ++ ++int SOUNDSCAPE_SetMixMode ++ ( ++ int mode ++ ) ++ ++ { ++ SOUNDSCAPE_MixMode = mode & SOUNDSCAPE_MaxMixMode; ++ SOUNDSCAPE_SamplePacketSize = SOUNDSCAPE_SampleSize[ SOUNDSCAPE_MixMode ]; ++ ++ // Set the mixmode ++ pcm_format(); ++ ++ return( mode ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_StopPlayback ++ ++ Ends the DMA transfer of digitized sound to the sound card. ++---------------------------------------------------------------------*/ ++ ++void SOUNDSCAPE_StopPlayback ++ ( ++ void ++ ) ++ ++ { ++ // Don't allow anymore interrupts ++ SOUNDSCAPE_DisableInterrupt(); ++ ++ /* stop the AD-1848 */ ++ ad_write( AD_CONFIG, 0x00 ); ++ ++ /* let it finish it's cycles */ ++ tdelay(); ++ ++ // Disable the DMA channel ++ DMA_EndTransfer( SOUNDSCAPE_Config.DMAChan ); ++ ++ SOUNDSCAPE_SoundPlaying = FALSE; ++ ++ SOUNDSCAPE_DMABuffer = NULL; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_SetupDMABuffer ++ ++ Programs the DMAC for sound transfer. ++---------------------------------------------------------------------*/ ++ ++static int SOUNDSCAPE_SetupDMABuffer ++ ( ++ char *BufferPtr, ++ int BufferSize, ++ int mode ++ ) ++ ++ { ++ int DmaStatus; ++ ++ DmaStatus = DMA_SetupTransfer( SOUNDSCAPE_Config.DMAChan, BufferPtr, BufferSize, mode ); ++ if ( DmaStatus == DMA_Error ) ++ { ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_DmaError ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ SOUNDSCAPE_DMAChannel = SOUNDSCAPE_Config.DMAChan; ++ SOUNDSCAPE_DMABuffer = BufferPtr; ++ SOUNDSCAPE_CurrentDMABuffer = BufferPtr; ++ SOUNDSCAPE_TotalDMABufferSize = BufferSize; ++ SOUNDSCAPE_DMABufferEnd = BufferPtr + BufferSize; ++ ++ return( SOUNDSCAPE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_GetCurrentPos ++ ++ Returns the offset within the current sound being played. ++---------------------------------------------------------------------*/ ++ ++int SOUNDSCAPE_GetCurrentPos ++ ( ++ void ++ ) ++ ++ { ++ char *CurrentAddr; ++ int offset; ++ ++ if ( !SOUNDSCAPE_SoundPlaying ) ++ { ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_NoSoundPlaying ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ CurrentAddr = DMA_GetCurrentPos( SOUNDSCAPE_Config.DMAChan ); ++ ++ offset = ( int )( ( ( unsigned long )CurrentAddr ) - ++ ( ( unsigned long )SOUNDSCAPE_CurrentDMABuffer ) ); ++ ++ if ( SOUNDSCAPE_MixMode & SIXTEEN_BIT ) ++ { ++ offset >>= 1; ++ } ++ ++ if ( SOUNDSCAPE_MixMode & STEREO ) ++ { ++ offset >>= 1; ++ } ++ ++ return( offset ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_BeginPlayback ++ ++ Starts playback of digitized sound. ++---------------------------------------------------------------------*/ ++ ++static int SOUNDSCAPE_BeginPlayback ++ ( ++ int length ++ ) ++ ++ { ++ int SampleLength; ++ int LoByte; ++ int HiByte; ++ ++ if ( SOUNDSCAPE_MixMode & SIXTEEN_BIT ) ++ { ++ SampleLength = length / 2; ++ } ++ else ++ { ++ SampleLength = length; ++ } ++ ++ if ( SOUNDSCAPE_MixMode & STEREO ) ++ { ++ SampleLength >>= 1; ++ } ++ ++ SampleLength--; ++ ++ // setup the AD-1848 interrupt count ++ // set the interrupt count value based on the format. ++ // count will decrement every sample period and generate ++ // an interrupt when in rolls over. we want this always ++ // to be at every 1/2 buffer, regardless of the data format, ++ // so the count must be adjusted accordingly. ++ HiByte = hibyte( SampleLength ); ++ LoByte = lobyte( SampleLength ); ++ ad_write( AD_LCOUNT, LoByte ); ++ ad_write( AD_UCOUNT, HiByte ); ++ ++ /* unmask the host DMA controller */ ++ SOUNDSCAPE_EnableInterrupt(); ++ ++ /* start the AD-1848 */ ++ ad_write(AD_CONFIG, 0x01); ++ ++ SOUNDSCAPE_SoundPlaying = TRUE; ++ ++ return( SOUNDSCAPE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_BeginBufferedPlayback ++ ++ Begins multibuffered playback of digitized sound on the sound card. ++---------------------------------------------------------------------*/ ++ ++int SOUNDSCAPE_BeginBufferedPlayback ++ ( ++ char *BufferStart, ++ int BufferSize, ++ int NumDivisions, ++ unsigned SampleRate, ++ int MixMode, ++ void ( *CallBackFunc )( void ) ++ ) ++ ++ { ++ int DmaStatus; ++ int TransferLength; ++ ++ if ( SOUNDSCAPE_SoundPlaying ) ++ { ++ SOUNDSCAPE_StopPlayback(); ++ } ++ ++ SOUNDSCAPE_SetMixMode( MixMode ); ++ ++ DmaStatus = SOUNDSCAPE_SetupDMABuffer( BufferStart, BufferSize, ++ DMA_AutoInitRead ); ++ if ( DmaStatus == SOUNDSCAPE_Error ) ++ { ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ SOUNDSCAPE_SetPlaybackRate( SampleRate ); ++ ++ SOUNDSCAPE_SetCallBack( CallBackFunc ); ++ ++ SOUNDSCAPE_EnableInterrupt(); ++ ++ TransferLength = BufferSize / NumDivisions; ++ SOUNDSCAPE_TransferLength = TransferLength; ++ ++ SOUNDSCAPE_BeginPlayback( TransferLength ); ++ ++ return( SOUNDSCAPE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_GetCardInfo ++ ++ Returns the maximum number of bits that can represent a sample ++ (8 or 16) and the number of channels (1 for mono, 2 for stereo). ++---------------------------------------------------------------------*/ ++ ++int SOUNDSCAPE_GetCardInfo ++ ( ++ int *MaxSampleBits, ++ int *MaxChannels ++ ) ++ ++ { ++ int status; ++ ++ status = SOUNDSCAPE_FindCard(); ++ if ( status == SOUNDSCAPE_Ok ) ++ { ++ *MaxChannels = 2; ++ *MaxSampleBits = 16; ++ return( SOUNDSCAPE_Ok ); ++ } ++ ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_SetCallBack ++ ++ Specifies the user function to call at the end of a sound transfer. ++---------------------------------------------------------------------*/ ++ ++void SOUNDSCAPE_SetCallBack ++ ( ++ void ( *func )( void ) ++ ) ++ ++ { ++ SOUNDSCAPE_CallBack = func; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void SOUNDSCAPE_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_UnlockMemory ++ ++ Unlocks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++static void SOUNDSCAPE_UnlockMemory ++ ( ++ void ++ ) ++ ++ { ++ DPMI_UnlockMemoryRegion( SOUNDSCAPE_LockStart, SOUNDSCAPE_LockEnd ); ++ DPMI_Unlock( SOUNDSCAPE_Config ); ++ DPMI_Unlock( SOUNDSCAPE_OldInt ); ++ DPMI_Unlock( SOUNDSCAPE_Installed ); ++ DPMI_Unlock( SOUNDSCAPE_DMABuffer ); ++ DPMI_Unlock( SOUNDSCAPE_DMABufferEnd ); ++ DPMI_Unlock( SOUNDSCAPE_CurrentDMABuffer ); ++ DPMI_Unlock( SOUNDSCAPE_TotalDMABufferSize ); ++ DPMI_Unlock( SOUNDSCAPE_TransferLength ); ++ DPMI_Unlock( SOUNDSCAPE_MixMode ); ++ DPMI_Unlock( SOUNDSCAPE_SamplePacketSize ); ++ DPMI_Unlock( SOUNDSCAPE_SampleRate ); ++ DPMI_Unlock( SOUNDSCAPE_SoundPlaying ); ++ DPMI_Unlock( SOUNDSCAPE_CallBack ); ++ DPMI_Unlock( SOUNDSCAPE_IntController1Mask ); ++ DPMI_Unlock( SOUNDSCAPE_IntController2Mask ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_LockMemory ++ ++ Locks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++static int SOUNDSCAPE_LockMemory ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_LockMemoryRegion( SOUNDSCAPE_LockStart, SOUNDSCAPE_LockEnd ); ++ status |= DPMI_Lock( SOUNDSCAPE_Config ); ++ status |= DPMI_Lock( SOUNDSCAPE_OldInt ); ++ status |= DPMI_Lock( SOUNDSCAPE_Installed ); ++ status |= DPMI_Lock( SOUNDSCAPE_DMABuffer ); ++ status |= DPMI_Lock( SOUNDSCAPE_DMABufferEnd ); ++ status |= DPMI_Lock( SOUNDSCAPE_CurrentDMABuffer ); ++ status |= DPMI_Lock( SOUNDSCAPE_TotalDMABufferSize ); ++ status |= DPMI_Lock( SOUNDSCAPE_TransferLength ); ++ status |= DPMI_Lock( SOUNDSCAPE_MixMode ); ++ status |= DPMI_Lock( SOUNDSCAPE_SamplePacketSize ); ++ status |= DPMI_Lock( SOUNDSCAPE_SampleRate ); ++ status |= DPMI_Lock( SOUNDSCAPE_SoundPlaying ); ++ status |= DPMI_Lock( SOUNDSCAPE_CallBack ); ++ status |= DPMI_Lock( SOUNDSCAPE_IntController1Mask ); ++ status |= DPMI_Lock( SOUNDSCAPE_IntController2Mask ); ++ ++ if ( status != DPMI_Ok ) ++ { ++ SOUNDSCAPE_UnlockMemory(); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_DPMI_Error ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ return( SOUNDSCAPE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: allocateTimerStack ++ ++ Allocate a block of memory from conventional (low) memory and return ++ the selector (which can go directly into a segment register) of the ++ memory block or 0 if an error occured. ++---------------------------------------------------------------------*/ ++ ++static unsigned short allocateTimerStack ++ ( ++ unsigned short size ++ ) ++ ++ { ++ union REGS regs; ++ ++ // clear all registers ++ memset( ®s, 0, sizeof( regs ) ); ++ ++ // DPMI allocate conventional memory ++ regs.w.ax = 0x100; ++ ++ // size in paragraphs ++ regs.w.bx = ( size + 15 ) / 16; ++ ++ int386( 0x31, ®s, ®s ); ++ if (!regs.w.cflag) ++ { ++ // DPMI call returns selector in dx ++ // (ax contains real mode segment ++ // which is ignored here) ++ ++ return( regs.w.dx ); ++ } ++ ++ // Couldn't allocate memory. ++ return( NULL ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: deallocateTimerStack ++ ++ Deallocate a block of conventional (low) memory given a selector to ++ it. Assumes the block was allocated with DPMI function 0x100. ++---------------------------------------------------------------------*/ ++ ++static void deallocateTimerStack ++ ( ++ unsigned short selector ++ ) ++ ++ { ++ union REGS regs; ++ ++ if ( selector != NULL ) ++ { ++ // clear all registers ++ memset( ®s, 0, sizeof( regs ) ); ++ ++ regs.w.ax = 0x101; ++ regs.w.dx = selector; ++ int386( 0x31, ®s, ®s ); ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: parse ++ ++ Parses for the right hand string of an .INI file equate. ++---------------------------------------------------------------------*/ ++ ++static int parse ++ ( ++ char *val, ++ char *str, ++ FILE *p1 ++ ) ++ ++ { ++ int i; ++ int j; ++ char tmpstr[ 81 ]; ++ ++ rewind( p1 ); ++ ++ while( !feof( p1 ) ) ++ { ++ // get a new string ++ fgets( tmpstr, 81, p1 ); ++ if( ( tmpstr[ 0 ] == '[' ) || ( tmpstr[ 0 ] == ';' ) || ++ ( tmpstr[ 0 ] == '\n' ) ) ++ { ++ continue; ++ } ++ ++ // parse up to the '=' ++ i = 0; ++ while( ( tmpstr[ i ] != '=' ) && ( tmpstr[ i ] != '\n' ) ) ++ { ++ i++; ++ } ++ ++ if( tmpstr[ i ] != '=' ) ++ { ++ continue; ++ } ++ ++ tmpstr[ i ] = '\0'; ++ ++ // see if it's the one we want ++ if ( strcmp( tmpstr, str ) ) ++ { ++ continue; ++ } ++ ++ // copy the right hand value to the destination string ++ i++; ++ for( j = 0; j < 32; j++ ) ++ { ++ if ( ( tmpstr[ i ] == ' ' ) || ( tmpstr[ i ] == '\t' ) || ++ ( tmpstr[ i ] == ',' ) || ( tmpstr[ i ] == '\n' ) ) ++ { ++ break; ++ } ++ ++ val[ j ] = tmpstr[ i ]; ++ i++; ++ } ++ val[j] = '\0'; ++ ++ return( TRUE ); ++ } ++ ++ return( FALSE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_FindCard ++ ++ Determines if a SoundScape is present and where it is located. ++---------------------------------------------------------------------*/ ++ ++static int SOUNDSCAPE_FindCard ++ ( ++ void ++ ) ++ ++ { ++ int found; ++ int status; ++ int tmp; ++ char *cp; ++ char str[ 33 ]; ++ FILE *fp; ++ ++ if ( SOUNDSCAPE_FoundCard ) ++ { ++ return( SOUNDSCAPE_Ok ); ++ } ++ ++ cp = getenv( "SNDSCAPE" ); ++ if ( cp == NULL ) ++ { ++ strcpy( str, "C:\\SNDSCAPE" ); ++ } ++ else ++ { ++ strcpy( str, cp ); ++ } ++ ++ strcat(str, "\\SNDSCAPE.INI"); ++ ++ fp = fopen( str, "r" ); ++ if ( fp == NULL ) ++ { ++ if ( cp == NULL ) ++ { ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_EnvNotFound ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_InitFileNotFound ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ found = parse( str, "Product", fp ); ++ if ( !found ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingProductInfo ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ if( strstr( str, "SoundFX" ) == NULL ) ++ { ++ SOUNDSCAPE_Config.OldIRQs = FALSE; ++ } ++ else ++ { ++ SOUNDSCAPE_Config.OldIRQs = TRUE; ++ } ++ ++ found = parse( str, "Port", fp ); ++ if ( !found ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingPortInfo ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ SOUNDSCAPE_Config.BasePort = strtol( str, ( char ** )0, 16); ++ ++ found = parse( str, "DMA", fp ); ++ if ( !found ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingDMAInfo ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ SOUNDSCAPE_Config.DMAChan = ( int )strtol( str, ( char ** )0, 10 ); ++ status = DMA_VerifyChannel( SOUNDSCAPE_Config.DMAChan ); ++ if ( status == DMA_Error ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_DmaError ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ found = parse( str, "IRQ", fp ); ++ if ( !found ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingIRQInfo ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ SOUNDSCAPE_Config.MIDIIRQ = ( int )strtol( str, ( char ** )0, 10 ); ++ if ( SOUNDSCAPE_Config.MIDIIRQ == 2 ) ++ { ++ SOUNDSCAPE_Config.MIDIIRQ = 9; ++ } ++ ++ found = parse( str, "SBIRQ", fp ); ++ if ( !found ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingSBIRQInfo ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ SOUNDSCAPE_Config.WaveIRQ = ( int )strtol( str, ( char ** )0, 10 ); ++ if ( SOUNDSCAPE_Config.WaveIRQ == 2 ) ++ { ++ SOUNDSCAPE_Config.WaveIRQ = 9; ++ } ++ ++ if ( !VALID_IRQ( SOUNDSCAPE_Config.WaveIRQ ) ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_InvalidSBIrq ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ if ( SOUNDSCAPE_Interrupts[ SOUNDSCAPE_Config.WaveIRQ ] == INVALID ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_InvalidSBIrq ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ found = parse( str, "SBEnable", fp ); ++ if ( !found ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingSBENABLEInfo ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ if( !strcmp( str, "false" ) ) ++ { ++ SOUNDSCAPE_Config.SBEmul = FALSE; ++ } ++ else ++ { ++ SOUNDSCAPE_Config.SBEmul = TRUE; ++ } ++ ++ // do a hardware test ++ outp( SOUNDSCAPE_Config.BasePort + GA_REGADDR, 0x00f5 ); ++ tmp = inp( SOUNDSCAPE_Config.BasePort + GA_REGADDR ); ++ if ( ( tmp & 0x000f ) != 0x0005 ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_HardwareError ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ if( ( tmp & 0x00f0 ) == 0x00f0 ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_HardwareError ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ // formulate the chip ID ++ tmp >>= 4; ++ if( tmp == 0 ) ++ { ++ SOUNDSCAPE_Config.ChipID = ODIE; ++ } ++ else if ( !( tmp & 0x0008 ) ) ++ { ++ SOUNDSCAPE_Config.ChipID = OPUS; ++ } ++ else ++ { ++ SOUNDSCAPE_Config.ChipID = MMIC; ++ } ++ ++ // parse for the AD-1848 address if necessary ++ if( SOUNDSCAPE_Config.ChipID == ODIE ) ++ { ++ found = parse( str, "WavePort", fp ); ++ if ( !found ) ++ { ++ fclose( fp ); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingWavePortInfo ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ SOUNDSCAPE_Config.WavePort = strtol( str, ( char ** )0, 16 ); ++ } ++ else ++ { ++ // otherwise, the base address is fixed ++ SOUNDSCAPE_Config.WavePort = SOUNDSCAPE_Config.BasePort + AD_OFFSET; ++ } ++ ++ // we're done with the file ++ fclose( fp ); ++ ++ // if it's an ODIE board, note CD-ROM decode enable ++ if ( SOUNDSCAPE_Config.ChipID == ODIE ) ++ { ++ SOUNDSCAPE_Config.CDROM = ga_read( GA_CDCFG ) & 0x80; ++ } ++ ++ // build the Wave IRQ index value ++ if( !SOUNDSCAPE_Config.OldIRQs ) ++ { ++ switch( SOUNDSCAPE_Config.WaveIRQ ) ++ { ++ case 9 : ++ SOUNDSCAPE_Config.IRQIndx = 0; ++ break; ++ ++ case 5 : ++ SOUNDSCAPE_Config.IRQIndx = 1; ++ break; ++ ++ case 7 : ++ SOUNDSCAPE_Config.IRQIndx = 2; ++ break; ++ ++ default : ++ SOUNDSCAPE_Config.IRQIndx = 3; ++ break; ++ } ++ } ++ else ++ { ++ switch( SOUNDSCAPE_Config.WaveIRQ ) ++ { ++ case 9 : ++ SOUNDSCAPE_Config.IRQIndx = 0; ++ break; ++ ++ case 5 : ++ SOUNDSCAPE_Config.IRQIndx = 2; ++ break; ++ ++ case 7 : ++ SOUNDSCAPE_Config.IRQIndx = 1; ++ break; ++ ++ default : ++ SOUNDSCAPE_Config.IRQIndx = 3; ++ break; ++ } ++ } ++ ++ SOUNDSCAPE_FoundCard = TRUE; ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_Ok ); ++ return( SOUNDSCAPE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_Setup ++ ++ Setup the Soundscape card for native mode PCM. ++---------------------------------------------------------------------*/ ++ ++static int SOUNDSCAPE_Setup ++ ( ++ void ++ ) ++ ++ { ++ int tmp; ++ int Interrupt; ++ int status; ++ ++ // if necessary, clear any pending SB ints ++ if ( SOUNDSCAPE_Config.SBEmul ) ++ { ++ inp( SB_IACK ); ++ } ++ ++ SOUNDSCAPE_DisableInterrupt(); ++ ++ // make sure the AD-1848 is not running ++ if ( ad_read( AD_CONFIG ) & 0x01 ) ++ { ++ SOUNDSCAPE_StopPlayback(); ++ } ++ ++ // if necessary, do some signal re-routing ++ if( SOUNDSCAPE_Config.ChipID != MMIC ) ++ { ++ // get the gate-array off of the DMA channel ++ ga_write( GA_DMACHB, 0x20 ); ++ ++ if ( !SOUNDSCAPE_Config.OldIRQs ) ++ { ++ switch( SOUNDSCAPE_Config.MIDIIRQ ) ++ { ++ case 5 : ++ tmp = 1; ++ break; ++ ++ case 7 : ++ tmp = 2; ++ break; ++ ++ case 9 : ++ tmp = 0; ++ break; ++ ++ default : ++ tmp = 3; ++ break; ++ } ++ } ++ else ++ { ++ switch( SOUNDSCAPE_Config.MIDIIRQ ) ++ { ++ case 5 : ++ tmp = 2; ++ break; ++ ++ case 7 : ++ tmp = 1; ++ break; ++ ++ case 9 : ++ tmp = 0; ++ break; ++ ++ default : ++ tmp = 3; ++ break; ++ } ++ } ++ ++ // set HostIRQ to MIDIIRQ for now ++ ga_write( GA_INTCFG, 0xf0 | ( tmp << 2 ) | tmp ); ++ ++ // now, route the AD-1848 stuff ... ++ if ( SOUNDSCAPE_Config.ChipID == OPUS ) ++ { ++ // set the AD-1848 chip decode ++ ga_write( GA_HMCTL, ( ga_read( GA_HMCTL ) & 0xcf ) | 0x10 ); ++ } ++ // setup the DMA polarity ++ ga_write( GA_DMACFG, 0x50 ); ++ ++ // init the CD-ROM (AD-1848) config register ++ ga_write( GA_CDCFG, 0x89 | ( SOUNDSCAPE_Config.DMAChan << 4 ) | ( SOUNDSCAPE_Config.IRQIndx << 1 ) ); ++ ++ // enable mode change, point to config reg ++ outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x40 | AD_CONFIG ); ++ ++ // set interf cnfg reg for DMA mode, single chan, autocal on ++ outp( SOUNDSCAPE_Config.WavePort + AD_REGDATA, 0x0c ); ++ ++ // exit mode change state ++ outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x00 ); ++ ++ // delay for autocalibration ++ tdelay(); ++ } ++ ++ // Install our interrupt handler ++ Interrupt = SOUNDSCAPE_Interrupts[ SOUNDSCAPE_Config.WaveIRQ ]; ++ SOUNDSCAPE_OldInt = _dos_getvect( Interrupt ); ++ if ( SOUNDSCAPE_Config.WaveIRQ < 8 ) ++ { ++ _dos_setvect( Interrupt, SOUNDSCAPE_ServiceInterrupt ); ++ } ++ else ++ { ++ status = IRQ_SetVector( Interrupt, SOUNDSCAPE_ServiceInterrupt ); ++ if ( status != IRQ_Ok ) ++ { ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_UnableToSetIrq ); ++ return( SOUNDSCAPE_Error ); ++ } ++ } ++ ++ // max left and right volumes ++ ad_write( AD_LEFTOUT, 0 ); ++ ad_write( AD_RIGHTOUT, 0 ); ++ ++ // clear any pending interrupt condition ++ outp( SOUNDSCAPE_Config.WavePort + AD_STATUS, 0x00 ); ++ ++ // enable the interrupt pin ++ ad_write( AD_PINCTRL, ad_read( AD_PINCTRL ) | 0x02 ); ++ ++ SOUNDSCAPE_EnableInterrupt(); ++ ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_Ok ); ++ return( SOUNDSCAPE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_GetMIDIPort ++ ++ Gets the address of the SoundScape MIDI port. ++---------------------------------------------------------------------*/ ++ ++int SOUNDSCAPE_GetMIDIPort ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = SOUNDSCAPE_FindCard(); ++ if ( status != SOUNDSCAPE_Ok ) ++ { ++ return( status ); ++ } ++ ++ return( SOUNDSCAPE_Config.BasePort ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_Init ++ ++ Initializes the sound card and prepares the module to play ++ digitized sounds. ++---------------------------------------------------------------------*/ ++ ++int SOUNDSCAPE_Init ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ if ( SOUNDSCAPE_Installed ) ++ { ++ SOUNDSCAPE_Shutdown(); ++ } ++ ++ // Save the interrupt masks ++ SOUNDSCAPE_IntController1Mask = inp( 0x21 ); ++ SOUNDSCAPE_IntController2Mask = inp( 0xA1 ); ++ ++ SOUNDSCAPE_SoundPlaying = FALSE; ++ SOUNDSCAPE_SetCallBack( NULL ); ++ SOUNDSCAPE_DMABuffer = NULL; ++ ++ status = SOUNDSCAPE_FindCard(); ++ if ( status != SOUNDSCAPE_Ok ) ++ { ++ return( status ); ++ } ++ ++ status = SOUNDSCAPE_LockMemory(); ++ if ( status != SOUNDSCAPE_Ok ) ++ { ++ SOUNDSCAPE_UnlockMemory(); ++ return( status ); ++ } ++ ++ StackSelector = allocateTimerStack( kStackSize ); ++ if ( StackSelector == NULL ) ++ { ++ SOUNDSCAPE_UnlockMemory(); ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_OutOfMemory ); ++ return( SOUNDSCAPE_Error ); ++ } ++ ++ // Leave a little room at top of stack just for the hell of it... ++ StackPointer = kStackSize - sizeof( long ); ++ ++ SOUNDSCAPE_Installed = TRUE; ++ ++ status = SOUNDSCAPE_Setup(); ++ if ( status != SOUNDSCAPE_Ok ) ++ { ++ SOUNDSCAPE_Shutdown(); ++ return( status ); ++ } ++ ++// printf("Testing DMA and IRQ ...\n"); ++// if( test_dma_irq() ) ++// { ++// printf("\t\007Hardware Not Responding\n\n"); ++// close_soundscape(); ++// return( SOUNDSCAPE_Error ); ++// } ++ ++ SOUNDSCAPE_SetPlaybackRate( SOUNDSCAPE_DefaultSampleRate ); ++ SOUNDSCAPE_SetMixMode( SOUNDSCAPE_DefaultMixMode ); ++ ++ SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_Ok ); ++ return( SOUNDSCAPE_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SOUNDSCAPE_Shutdown ++ ++ Ends transfer of sound data to the sound card and restores the ++ system resources used by the card. ++---------------------------------------------------------------------*/ ++ ++void SOUNDSCAPE_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ int Interrupt; ++ ++ // Halt the DMA transfer ++ SOUNDSCAPE_StopPlayback(); ++ ++ // disable the AD-1848 interrupt pin ++ ad_write( AD_PINCTRL, ad_read( AD_PINCTRL ) & 0xfd ); ++ ++ // if necessary, do some signal re-routing ++ if ( SOUNDSCAPE_Config.ChipID != MMIC ) ++ { ++ // re-init the CD-ROM (AD-1848) config register as needed. ++ // this will disable the AD-1848 interface. ++ if ( SOUNDSCAPE_Config.ChipID == ODIE ) ++ { ++ ga_write( GA_CDCFG, SOUNDSCAPE_Config.CDROM ); ++ } ++ else ++ { ++ ga_write( GA_CDCFG, ga_read( GA_CDCFG ) & 0x7f); ++ } ++ ++ // if necessary, reset the SoundBlaster IRQ ++ if ( SOUNDSCAPE_Config.SBEmul ) ++ { ++ ga_write( GA_INTCFG, ( ga_read( GA_INTCFG ) & 0xf3 ) | ++ ( SOUNDSCAPE_Config.IRQIndx << 2 ) ); ++ } ++ ++ // re-assign the gate-array DMA channel ++ ga_write( GA_DMACHB, 0x80 | ( SOUNDSCAPE_Config.DMAChan << 4 ) ); ++ } ++ ++ // Restore the original interrupt ++ Interrupt = SOUNDSCAPE_Interrupts[ SOUNDSCAPE_Config.WaveIRQ ]; ++ if ( SOUNDSCAPE_Config.WaveIRQ >= 8 ) ++ { ++ IRQ_RestoreVector( Interrupt ); ++ } ++ _dos_setvect( Interrupt, SOUNDSCAPE_OldInt ); ++ ++ SOUNDSCAPE_SoundPlaying = FALSE; ++ ++ SOUNDSCAPE_DMABuffer = NULL; ++ ++ SOUNDSCAPE_SetCallBack( NULL ); ++ ++ SOUNDSCAPE_UnlockMemory(); ++ ++ if ( StackSelector != NULL ) ++ { ++ deallocateTimerStack( StackSelector ); ++ StackSelector = NULL; ++ } ++ ++ SOUNDSCAPE_Installed = FALSE; ++ } +diff -urN rott-1.0/rott/audiolib/sndscape.h trunk/rott/audiolib/sndscape.h +--- rott-1.0/rott/audiolib/sndscape.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/sndscape.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,73 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: SNDSCAPE.H ++ ++ author: James R. Dose ++ date: October 26, 1994 ++ ++ Public header for SNDSCAPE.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __SNDSCAPE_H ++#define __SNDSCAPE_H ++ ++extern int SOUNDSCAPE_DMAChannel; ++extern int SOUNDSCAPE_ErrorCode; ++ ++enum SOUNDSCAPE_ERRORS ++ { ++ SOUNDSCAPE_Warning = -2, ++ SOUNDSCAPE_Error = -1, ++ SOUNDSCAPE_Ok = 0, ++ SOUNDSCAPE_EnvNotFound, ++ SOUNDSCAPE_InitFileNotFound, ++ SOUNDSCAPE_MissingProductInfo, ++ SOUNDSCAPE_MissingPortInfo, ++ SOUNDSCAPE_MissingDMAInfo, ++ SOUNDSCAPE_MissingIRQInfo, ++ SOUNDSCAPE_MissingSBIRQInfo, ++ SOUNDSCAPE_MissingSBENABLEInfo, ++ SOUNDSCAPE_MissingWavePortInfo, ++ SOUNDSCAPE_HardwareError, ++ SOUNDSCAPE_NoSoundPlaying, ++ SOUNDSCAPE_InvalidSBIrq, ++ SOUNDSCAPE_UnableToSetIrq, ++ SOUNDSCAPE_DmaError, ++ SOUNDSCAPE_DPMI_Error, ++ SOUNDSCAPE_OutOfMemory ++ }; ++ ++char *SOUNDSCAPE_ErrorString( int ErrorNumber ); ++void SOUNDSCAPE_SetPlaybackRate( unsigned rate ); ++unsigned SOUNDSCAPE_GetPlaybackRate( void ); ++int SOUNDSCAPE_SetMixMode( int mode ); ++void SOUNDSCAPE_StopPlayback( void ); ++int SOUNDSCAPE_GetCurrentPos( void ); ++int SOUNDSCAPE_BeginBufferedPlayback( char *BufferStart, int BufferSize, int NumDivisions, unsigned SampleRate, int MixMode, void ( *CallBackFunc )( void ) ); ++int SOUNDSCAPE_GetCardInfo( int *MaxSampleBits, int *MaxChannels ); ++void SOUNDSCAPE_SetCallBack( void ( *func )( void ) ); ++int SOUNDSCAPE_GetMIDIPort( void ); ++int SOUNDSCAPE_Init( void ); ++void SOUNDSCAPE_Shutdown( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/sndsrc.c trunk/rott/audiolib/sndsrc.c +--- rott-1.0/rott/audiolib/sndsrc.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/sndsrc.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,658 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: SNDSRC.C ++ ++ author: James R. Dose ++ date: March 26, 1994 ++ ++ Low level routines to support the Disney Sound Source. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#define STEREO 1 ++#define SIXTEEN_BIT 2 ++ ++#define MONO_8BIT 0 ++#define STEREO_8BIT ( STEREO ) ++#define MONO_16BIT ( SIXTEEN_BIT ) ++#define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) ++ ++#include ++#include ++#include ++#include "dpmi.h" ++#include "task_man.h" ++#include "sndcards.h" ++#include "user.h" ++#include "sndsrc.h" ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++static int SS_Installed = FALSE; ++ ++static int SS_Port = SS_DefaultPort; ++static int SS_OffCommand = 0xc; ++ ++static char *SS_BufferStart; ++static char *SS_BufferEnd; ++static char *SS_CurrentBuffer; ++static int SS_BufferNum = 0; ++static int SS_NumBuffers = 0; ++static int SS_TotalBufferSize = 0; ++static int SS_TransferLength = 0; ++static int SS_CurrentLength = 0; ++ ++static char *SS_SoundPtr; ++volatile int SS_SoundPlaying; ++ ++static task *SS_Timer; ++ ++void ( *SS_CallBack )( void ); ++ ++int SS_ErrorCode = SS_Ok; ++ ++#define SS_SetErrorCode( status ) \ ++ SS_ErrorCode = ( status ); ++ ++/*--------------------------------------------------------------------- ++ Function: SS_ErrorString ++ ++ Returns a pointer to the error message associated with an error ++ number. A -1 returns a pointer the current error. ++---------------------------------------------------------------------*/ ++ ++char *SS_ErrorString ++ ( ++ int ErrorNumber ++ ) ++ ++ { ++ char *ErrorString; ++ ++ switch( ErrorNumber ) ++ { ++ case SS_Error : ++ ErrorString = SS_ErrorString( SS_ErrorCode ); ++ break; ++ ++ case SS_Ok : ++ ErrorString = "Sound Source ok."; ++ break; ++ ++ case SS_NotFound : ++ ErrorString = "Could not detect Sound Source."; ++ break; ++ ++ case SS_NoSoundPlaying : ++ ErrorString = "No sound playing in SndSrc."; ++ break; ++ ++ case SS_DPMI_Error : ++ ErrorString = "DPMI Error in SndSrc."; ++ break; ++ ++ default : ++ ErrorString = "Unknown Sound Source error code."; ++ break; ++ } ++ ++ return( ErrorString ); ++ } ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define SS_LockStart SS_ServiceInterrupt ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_ServiceInterrupt ++ ++ Handles interrupt generated by sound card at the end of a voice ++ transfer. Calls the user supplied callback function. ++---------------------------------------------------------------------*/ ++ ++static void SS_ServiceInterrupt ++ ( ++ task *Task ++ ) ++ ++ { ++ int port = SS_Port; ++ int count; ++ ++ count = 0; ++ while( ( inp( port + 1 ) & 0x40 ) == 0 ) ++ { ++ outp( port, *SS_SoundPtr++ ); ++ outp( port + 2, SS_OffCommand ); ++ outp( port + 2, 4 ); ++ ++ SS_CurrentLength--; ++ if ( SS_CurrentLength == 0 ) ++ { ++ // Keep track of current buffer ++ SS_CurrentBuffer += SS_TransferLength; ++ SS_BufferNum++; ++ if ( SS_BufferNum >= SS_NumBuffers ) ++ { ++ SS_BufferNum = 0; ++ SS_CurrentBuffer = SS_BufferStart; ++ } ++ ++ SS_CurrentLength = SS_TransferLength; ++ SS_SoundPtr = SS_CurrentBuffer; ++ ++ // Call the caller's callback function ++ if ( SS_CallBack != NULL ) ++ { ++ SS_CallBack(); ++ } ++ } ++ ++ count++; ++ // Only do at most 14 samples per tick ++ if ( count > 13 ) ++ { ++ break; ++ } ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_StopPlayback ++ ++ Ends the transfer of digitized sound to the Sound Source. ++---------------------------------------------------------------------*/ ++ ++void SS_StopPlayback ++ ( ++ void ++ ) ++ ++ { ++ if ( SS_SoundPlaying ) ++ { ++ TS_Terminate( SS_Timer ); ++ ++ outp( SS_Port, 0x80 ); ++ outp( SS_Port + 2, SS_OffCommand ); ++ outp( SS_Port + 2, 4 ); ++ ++ SS_SoundPlaying = FALSE; ++ ++ SS_BufferStart = NULL; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_GetCurrentPos ++ ++ Returns the offset within the current sound being played. ++---------------------------------------------------------------------*/ ++ ++int SS_GetCurrentPos ++ ( ++ void ++ ) ++ ++ { ++ int offset; ++ ++ if ( !SS_SoundPlaying ) ++ { ++ SS_SetErrorCode( SS_NoSoundPlaying ); ++ return( SS_Warning ); ++ } ++ ++ offset = ( int )( ( ( unsigned long )SS_SoundPtr ) - ++ ( ( unsigned long )SS_CurrentBuffer ) ); ++ ++ return( offset ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void SS_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_BeginBufferedPlayback ++ ++ Begins multibuffered playback of digitized sound on the Sound Source. ++---------------------------------------------------------------------*/ ++ ++int SS_BeginBufferedPlayback ++ ( ++ char *BufferStart, ++ int BufferSize, ++ int NumDivisions, ++ void ( *CallBackFunc )( void ) ++ ) ++ ++ { ++ if ( SS_SoundPlaying ) ++ { ++ SS_StopPlayback(); ++ } ++ ++ SS_SetCallBack( CallBackFunc ); ++ ++ SS_BufferStart = BufferStart; ++ SS_CurrentBuffer = BufferStart; ++ SS_SoundPtr = BufferStart; ++ SS_TotalBufferSize = BufferSize; ++ SS_BufferEnd = BufferStart + BufferSize; ++ SS_TransferLength = BufferSize / NumDivisions; ++ SS_CurrentLength = SS_TransferLength; ++ SS_BufferNum = 0; ++ SS_NumBuffers = NumDivisions; ++ ++ SS_SoundPlaying = TRUE; ++ ++// SS_Timer = TS_ScheduleTask( SS_ServiceInterrupt, 438, 1, NULL ); ++ SS_Timer = TS_ScheduleTask( SS_ServiceInterrupt, 510, 1, NULL ); ++ TS_Dispatch(); ++ ++ return( SS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_GetPlaybackRate ++ ++ Returns the rate at which the digitized sound will be played in ++ hertz. ++---------------------------------------------------------------------*/ ++ ++int SS_GetPlaybackRate ++ ( ++ void ++ ) ++ ++ { ++ return( SS_SampleRate ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_SetMixMode ++ ++ Sets the sound card to play samples in mono or stereo. ++---------------------------------------------------------------------*/ ++ ++int SS_SetMixMode ++ ( ++ int mode ++ ) ++ ++ { ++ mode = MONO_8BIT; ++ return( mode ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_SetPort ++ ++ Selects which port to use to write to the Sound Source. ++---------------------------------------------------------------------*/ ++ ++int SS_SetPort ++ ( ++ int port ++ ) ++ ++ { ++ if ( SS_Installed ) ++ { ++ SS_Shutdown(); ++ } ++ ++ SS_Port = port; ++ ++ return( SS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_SetCallBack ++ ++ Specifies the user function to call at the end of a sound transfer. ++---------------------------------------------------------------------*/ ++ ++void SS_SetCallBack ++ ( ++ void ( *func )( void ) ++ ) ++ ++ { ++ SS_CallBack = func; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_TestTimer ++ ++ Used as a delay in SS_TestSoundSource. ++---------------------------------------------------------------------*/ ++ ++void SS_TestTimer ++ ( ++ task *Task ++ ) ++ ++ { ++ ( *( int * )( Task->data ) )++; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_TestSoundSource ++ ++ Detect if the Sound Source is located at the specified port. ++---------------------------------------------------------------------*/ ++ ++int SS_TestSoundSource ++ ( ++ int port ++ ) ++ ++ { ++ int present; ++ task *timer; ++ volatile int ticks; ++ int i; ++ ++ present = FALSE; ++ ++ timer = TS_ScheduleTask( SS_TestTimer, 140, 1, &ticks ); ++ TS_Dispatch(); ++ ++ outp( port + 2, 4 ); ++ ++ ticks = 0; ++ ++ while( ticks < 4 ) ++ { ++ // Do nothing for a while ++ } ++ ++ TS_Terminate( timer ); ++ ++ if ( ( inp( port + 1 ) & 0x40 ) == 0 ) ++ { ++ for( i = 32; i > 0; i-- ) ++ { ++ outp( port, 0x80 ); ++ outp( port + 2, SS_OffCommand ); ++ outp( port + 2, 4 ); ++ } ++ ++ if ( inp( port + 1 ) & 0x40 ) ++ { ++ present = TRUE; ++ } ++ } ++ ++ outp( port + 2, SS_OffCommand ); ++ ++ return( present ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_DetectSoundSource ++ ++ Detects which port the Sound Source is located. ++---------------------------------------------------------------------*/ ++ ++int SS_DetectSoundSource ++ ( ++ void ++ ) ++ ++ { ++ if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT1 ) ) ++ { ++ SS_Port = SS_Port1; ++ return( TRUE ); ++ } ++ ++ if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT2 ) ) ++ { ++ SS_Port = SS_Port2; ++ return( TRUE ); ++ } ++ ++ if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT3 ) ) ++ { ++ SS_Port = SS_Port3; ++ return( TRUE ); ++ } ++ ++ if ( SS_TestSoundSource( SS_Port1 ) ) ++ { ++ SS_Port = SS_Port1; ++ return( TRUE ); ++ } ++ ++ if ( SS_TestSoundSource( SS_Port2 ) ) ++ { ++ SS_Port = SS_Port2; ++ return( TRUE ); ++ } ++ ++ if ( SS_TestSoundSource( SS_Port3 ) ) ++ { ++ SS_Port = SS_Port3; ++ return( TRUE ); ++ } ++ ++ return( FALSE ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_Init ++ ++ Initializes the Sound Source prepares the module to play digitized ++ sounds. ++---------------------------------------------------------------------*/ ++ ++int SS_Init ++ ( ++ int soundcard ++ ) ++ ++ { ++ int status; ++ ++ if ( SS_Installed ) ++ { ++ SS_Shutdown(); ++ } ++ ++ if ( ( soundcard == TandySoundSource ) || ++ ( USER_CheckParameter( SELECT_TANDY_SOUNDSOURCE ) ) ) ++ { ++ // Tandy ++ SS_OffCommand = 0x0e; ++ } ++ else ++ { ++ // Disney ++ SS_OffCommand = 0x0c; ++ } ++ ++ status = SS_DetectSoundSource(); ++ if ( !status ) ++ { ++ SS_SetErrorCode( SS_NotFound ); ++ return( SS_Warning ); ++ } ++ ++ status = SS_LockMemory(); ++ if ( status != SS_Ok ) ++ { ++ SS_UnlockMemory(); ++ return( status ); ++ } ++ ++ status = SS_Ok; ++ ++ outp( SS_Port + 2, 4 ); ++ ++ SS_SoundPlaying = FALSE; ++ ++ SS_SetCallBack( NULL ); ++ ++ SS_BufferStart = NULL; ++ ++ SS_Installed = TRUE; ++ ++ SS_SetErrorCode( status ); ++ return( status ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_Shutdown ++ ++ Ends transfer of sound data to the Sound Source. ++---------------------------------------------------------------------*/ ++ ++void SS_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ // Halt the transfer ++ SS_StopPlayback(); ++ ++ outp( SS_Port + 2, SS_OffCommand ); ++ ++ SS_SoundPlaying = FALSE; ++ ++ SS_BufferStart = NULL; ++ ++ SS_SetCallBack( NULL ); ++ ++ SS_UnlockMemory(); ++ ++ SS_Installed = FALSE; ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_UnlockMemory ++ ++ Unlocks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++void SS_UnlockMemory ++ ( ++ void ++ ) ++ ++ { ++ DPMI_UnlockMemoryRegion( SS_LockStart, SS_LockEnd ); ++ DPMI_Unlock( SS_Installed ); ++ DPMI_Unlock( SS_Port ); ++ DPMI_Unlock( SS_OffCommand ); ++ DPMI_Unlock( SS_BufferStart ); ++ DPMI_Unlock( SS_BufferEnd ); ++ DPMI_Unlock( SS_CurrentBuffer ); ++ DPMI_Unlock( SS_BufferNum ); ++ DPMI_Unlock( SS_NumBuffers ); ++ DPMI_Unlock( SS_TotalBufferSize ); ++ DPMI_Unlock( SS_TransferLength ); ++ DPMI_Unlock( SS_CurrentLength ); ++ DPMI_Unlock( SS_SoundPtr ); ++ DPMI_Unlock( SS_SoundPlaying ); ++ DPMI_Unlock( SS_Timer ); ++ DPMI_Unlock( SS_CallBack ); ++ DPMI_Unlock( SS_ErrorCode ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: SS_LockMemory ++ ++ Locks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++int SS_LockMemory ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_LockMemoryRegion( SS_LockStart, SS_LockEnd ); ++ status |= DPMI_Lock( SS_Installed ); ++ status |= DPMI_Lock( SS_Port ); ++ status |= DPMI_Lock( SS_OffCommand ); ++ status |= DPMI_Lock( SS_BufferStart ); ++ status |= DPMI_Lock( SS_BufferEnd ); ++ status |= DPMI_Lock( SS_CurrentBuffer ); ++ status |= DPMI_Lock( SS_BufferNum ); ++ status |= DPMI_Lock( SS_NumBuffers ); ++ status |= DPMI_Lock( SS_TotalBufferSize ); ++ status |= DPMI_Lock( SS_TransferLength ); ++ status |= DPMI_Lock( SS_CurrentLength ); ++ status |= DPMI_Lock( SS_SoundPtr ); ++ status |= DPMI_Lock( SS_SoundPlaying ); ++ status |= DPMI_Lock( SS_Timer ); ++ status |= DPMI_Lock( SS_CallBack ); ++ status |= DPMI_Lock( SS_ErrorCode ); ++ ++ if ( status != DPMI_Ok ) ++ { ++ SS_UnlockMemory(); ++ SS_SetErrorCode( SS_DPMI_Error ); ++ return( SS_Error ); ++ } ++ ++ return( SS_Ok ); ++ } +diff -urN rott-1.0/rott/audiolib/sndsrc.h trunk/rott/audiolib/sndsrc.h +--- rott-1.0/rott/audiolib/sndsrc.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/sndsrc.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,70 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: SNDSRC.H ++ ++ author: James R. Dose ++ date: March 26, 1994 ++ ++ Public header for for SNDSRC.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __SNDSRC_H ++#define __SNDSRC_H ++ ++enum SS_ERRORS ++ { ++ SS_Warning = -2, ++ SS_Error = -1, ++ SS_Ok = 0, ++ SS_NotFound, ++ SS_NoSoundPlaying, ++ SS_DPMI_Error ++ }; ++ ++#define SELECT_SOUNDSOURCE_PORT1 "ss1" ++#define SELECT_SOUNDSOURCE_PORT2 "ss2" ++#define SELECT_SOUNDSOURCE_PORT3 "ss3" ++#define SELECT_TANDY_SOUNDSOURCE "sst" ++ ++#define SS_Port1 0x3bc ++#define SS_Port2 0x378 ++#define SS_Port3 0x278 ++ ++#define SS_DefaultPort 0x378 ++#define SS_SampleRate 7000 ++#define SS_DMAChannel -1 ++ ++char *SS_ErrorString( int ErrorNumber ); ++void SS_StopPlayback( void ); ++int SS_GetCurrentPos( void ); ++int SS_BeginBufferedPlayback( char *BufferStart, int BufferSize, int NumDivisions, void ( *CallBackFunc )( void ) ); ++int SS_GetPlaybackRate( void ); ++int SS_SetMixMode( int mode ); ++int SS_SetPort( int port ); ++void SS_SetCallBack( void ( *func )( void ) ); ++int SS_Init( int soundcard ); ++void SS_Shutdown( void ); ++void SS_UnlockMemory( void ); ++int SS_LockMemory( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/standard.h trunk/rott/audiolib/standard.h +--- rott-1.0/rott/audiolib/standard.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/standard.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,72 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: STANDARD.H ++ ++ author: James R. Dose ++ date: May 25, 1994 ++ ++ Header containing standard definitions. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __STANDARD_H ++#define __STANDARD_H ++ ++typedef int boolean; ++typedef int errorcode; ++ ++#ifndef TRUE ++ #define TRUE ( 1 == 1 ) ++ #define FALSE ( !TRUE ) ++#endif ++ ++enum STANDARD_ERRORS ++ { ++ Warning = -2, ++ FatalError = -1, ++ Success = 0 ++ }; ++ ++#define BITSET( data, bit ) \ ++ ( ( ( data ) & ( bit ) ) == ( bit ) ) ++ ++#define ARRAY_LENGTH( array ) \ ++ ( sizeof( array ) / sizeof( ( array )[ 0 ] ) ) ++ ++#define WITHIN_BOUNDS( array, index ) \ ++ ( ( 0 <= ( index ) ) && ( ( index ) < ARRAY_LENGTH( array ) ) ) ++ ++#define FOREVER for( ; ; ) ++ ++#ifdef NDEBUG ++ #define DEBUGGING 0 ++#else ++ #define DEBUGGING 1 ++#endif ++ ++#define DEBUG_CODE \ ++ if ( DEBUGGING == 0 ) \ ++ { \ ++ } \ ++ else ++ ++#endif +diff -urN rott-1.0/rott/audiolib/task_man.c trunk/rott/audiolib/task_man.c +--- rott-1.0/rott/audiolib/task_man.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/task_man.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,976 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: TASK_MAN.C ++ ++ author: James R. Dose ++ date: July 25, 1994 ++ ++ Low level timer task scheduler. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++//#define USESTACK ++#define LOCKMEMORY ++#define NOINTS ++#define USE_USRHOOKS ++ ++#include ++#include ++#include ++#include ++#include "interrup.h" ++#include "linklist.h" ++#include "task_man.h" ++ ++#ifdef USESTACK ++#include "dpmi.h" ++#endif ++#ifdef LOCKMEMORY ++#include "dpmi.h" ++#endif ++ ++#ifdef USE_USRHOOKS ++#include "usrhooks.h" ++#define FreeMem( ptr ) USRHOOKS_FreeMem( ( ptr ) ) ++#else ++#define FreeMem( ptr ) free( ( ptr ) ) ++#endif ++ ++typedef struct ++ { ++ task *start; ++ task *end; ++ } tasklist; ++ ++ ++/*--------------------------------------------------------------------- ++ Global variables ++---------------------------------------------------------------------*/ ++ ++#ifdef USESTACK ++ ++// adequate stack size ++#define kStackSize 2048 ++ ++static unsigned short StackSelector = NULL; ++static unsigned long StackPointer; ++ ++static unsigned short oldStackSelector; ++static unsigned long oldStackPointer; ++ ++#endif ++ ++static task HeadTask; ++static task *TaskList = &HeadTask; ++ ++static void ( __interrupt __far *OldInt8 )( void ); ++ ++static volatile long TaskServiceRate = 0x10000L; ++static volatile long TaskServiceCount = 0; ++ ++#ifndef NOINTS ++static volatile int TS_TimesInInterrupt; ++#endif ++ ++static char TS_Installed = FALSE; ++ ++volatile int TS_InInterrupt = FALSE; ++ ++/*--------------------------------------------------------------------- ++ Function prototypes ++---------------------------------------------------------------------*/ ++ ++static void TS_FreeTaskList( void ); ++static void TS_SetClockSpeed( long speed ); ++static long TS_SetTimer( long TickBase ); ++static void TS_SetTimerToMaxTaskRate( void ); ++static void __interrupt __far TS_ServiceSchedule( void ); ++static void __interrupt __far TS_ServiceScheduleIntEnabled( void ); ++static void TS_AddTask( task *ptr ); ++static int TS_Startup( void ); ++static void RestoreRealTimeClock( void ); ++ ++// These declarations are necessary to use the inline assembly pragmas. ++ ++extern void GetStack(unsigned short *selptr,unsigned long *stackptr); ++extern void SetStack(unsigned short selector,unsigned long stackptr); ++ ++// This function will get the current stack selector and pointer and save ++// them off. ++#pragma aux GetStack = \ ++ "mov [edi],esp" \ ++ "mov ax,ss" \ ++ "mov [esi],ax" \ ++ parm [esi] [edi] \ ++ modify [eax esi edi]; ++ ++// This function will set the stack selector and pointer to the specified ++// values. ++#pragma aux SetStack = \ ++ "mov ss,ax" \ ++ "mov esp,edx" \ ++ parm [ax] [edx] \ ++ modify [eax edx]; ++ ++ ++/********************************************************************** ++ ++ Memory locked functions: ++ ++**********************************************************************/ ++ ++ ++#define TS_LockStart TS_FreeTaskList ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_FreeTaskList ++ ++ Terminates all tasks and releases any memory used for control ++ structures. ++---------------------------------------------------------------------*/ ++ ++static void TS_FreeTaskList ++ ( ++ void ++ ) ++ ++ { ++ task *node; ++ task *next; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ node = TaskList->next; ++ while( node != TaskList ) ++ { ++ next = node->next; ++ FreeMem( node ); ++ node = next; ++ } ++ ++ TaskList->next = TaskList; ++ TaskList->prev = TaskList; ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_SetClockSpeed ++ ++ Sets the rate of the 8253 timer. ++---------------------------------------------------------------------*/ ++ ++static void TS_SetClockSpeed ++ ( ++ long speed ++ ) ++ ++ { ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ if ( ( speed > 0 ) && ( speed < 0x10000L ) ) ++ { ++ TaskServiceRate = speed; ++ } ++ else ++ { ++ TaskServiceRate = 0x10000L; ++ } ++ ++ outp( 0x43, 0x36 ); ++ outp( 0x40, TaskServiceRate ); ++ outp( 0x40, TaskServiceRate >> 8 ); ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_SetTimer ++ ++ Calculates the rate at which a task will occur and sets the clock ++ speed if necessary. ++---------------------------------------------------------------------*/ ++ ++static long TS_SetTimer ++ ( ++ long TickBase ++ ) ++ ++ { ++ long speed; ++ ++ speed = 1192030L / TickBase; ++ if ( speed < TaskServiceRate ) ++ { ++ TS_SetClockSpeed( speed ); ++ } ++ ++ return( speed ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_SetTimerToMaxTaskRate ++ ++ Finds the fastest running task and sets the clock to operate at ++ that speed. ++---------------------------------------------------------------------*/ ++ ++static void TS_SetTimerToMaxTaskRate ++ ( ++ void ++ ) ++ ++ { ++ task *ptr; ++ long MaxServiceRate; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ MaxServiceRate = 0x10000L; ++ ++ ptr = TaskList->next; ++ while( ptr != TaskList ) ++ { ++ if ( ptr->rate < MaxServiceRate ) ++ { ++ MaxServiceRate = ptr->rate; ++ } ++ ++ ptr = ptr->next; ++ } ++ ++ if ( TaskServiceRate != MaxServiceRate ) ++ { ++ TS_SetClockSpeed( MaxServiceRate ); ++ } ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++#ifdef NOINTS ++/*--------------------------------------------------------------------- ++ Function: TS_ServiceSchedule ++ ++ Interrupt service routine ++---------------------------------------------------------------------*/ ++ ++static void __interrupt __far TS_ServiceSchedule ++ ( ++ void ++ ) ++ ++ { ++ task *ptr; ++ task *next; ++ ++ ++ TS_InInterrupt = TRUE; ++ ++ #ifdef USESTACK ++ // save stack ++ GetStack( &oldStackSelector, &oldStackPointer ); ++ ++ // set our stack ++ SetStack( StackSelector, StackPointer ); ++ #endif ++ ++ ptr = TaskList->next; ++ while( ptr != TaskList ) ++ { ++ next = ptr->next; ++ ++ if ( ptr->active ) ++ { ++ ptr->count += TaskServiceRate; ++//JIM ++// if ( ptr->count >= ptr->rate ) ++ while( ptr->count >= ptr->rate ) ++ { ++ ptr->count -= ptr->rate; ++ ptr->TaskService( ptr ); ++ } ++ } ++ ptr = next; ++ } ++ ++ #ifdef USESTACK ++ // restore stack ++ SetStack( oldStackSelector, oldStackPointer ); ++ #endif ++ ++ TaskServiceCount += TaskServiceRate; ++ if ( TaskServiceCount > 0xffffL ) ++ { ++ TaskServiceCount &= 0xffff; ++ _chain_intr( OldInt8 ); ++ } ++ ++ outp( 0x20,0x20 ); ++ ++ TS_InInterrupt = FALSE; ++ } ++ ++#else ++ ++/*--------------------------------------------------------------------- ++ Function: TS_ServiceScheduleIntEnabled ++ ++ Interrupt service routine with interrupts enabled. ++---------------------------------------------------------------------*/ ++ ++static void __interrupt __far TS_ServiceScheduleIntEnabled ++ ( ++ void ++ ) ++ ++ { ++ task *ptr; ++ task *next; ++ ++ TS_TimesInInterrupt++; ++ TaskServiceCount += TaskServiceRate; ++ if ( TaskServiceCount > 0xffffL ) ++ { ++ TaskServiceCount &= 0xffff; ++ _chain_intr( OldInt8 ); ++ } ++ ++ outp( 0x20,0x20 ); ++ ++ if ( TS_InInterrupt ) ++ { ++ return; ++ } ++ ++ TS_InInterrupt = TRUE; ++ _enable(); ++ ++ #ifdef USESTACK ++ // save stack ++ GetStack( &oldStackSelector, &oldStackPointer ); ++ ++ // set our stack ++ SetStack( StackSelector, StackPointer ); ++ #endif ++ ++ while( TS_TimesInInterrupt ) ++ { ++ ptr = TaskList->next ; ++ while( ptr != TaskList ) ++ { ++ next = ptr->next; ++ ++ if ( ptr->active ) ++ { ++ ptr->count += TaskServiceRate; ++ if ( ptr->count >= ptr->rate ) ++ { ++ ptr->count -= ptr->rate; ++ ptr->TaskService( ptr ); ++ } ++ } ++ ptr = next; ++ } ++ TS_TimesInInterrupt--; ++ } ++ ++ _disable(); ++ ++ #ifdef USESTACK ++ // restore stack ++ SetStack( oldStackSelector, oldStackPointer ); ++ #endif ++ ++ TS_InInterrupt = FALSE; ++ } ++#endif ++ ++ ++#ifdef USESTACK ++ ++/*--------------------------------------------------------------------- ++ Function: allocateTimerStack ++ ++ Allocate a block of memory from conventional (low) memory and return ++ the selector (which can go directly into a segment register) of the ++ memory block or 0 if an error occured. ++---------------------------------------------------------------------*/ ++ ++static unsigned short allocateTimerStack ++ ( ++ unsigned short size ++ ) ++ ++ { ++ union REGS regs; ++ ++ // clear all registers ++ memset( ®s, 0, sizeof( regs ) ); ++ ++ // DPMI allocate conventional memory ++ regs.w.ax = 0x100; ++ ++ // size in paragraphs ++ regs.w.bx = ( size + 15 ) / 16; ++ ++ int386( 0x31, ®s, ®s ); ++ if (!regs.w.cflag) ++ { ++ // DPMI call returns selector in dx ++ // (ax contains real mode segment ++ // which is ignored here) ++ ++ return( regs.w.dx ); ++ } ++ ++ // Couldn't allocate memory. ++ return( NULL ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: deallocateTimerStack ++ ++ Deallocate a block of conventional (low) memory given a selector to ++ it. Assumes the block was allocated with DPMI function 0x100. ++---------------------------------------------------------------------*/ ++ ++static void deallocateTimerStack ++ ( ++ unsigned short selector ++ ) ++ ++ { ++ union REGS regs; ++ ++ if ( selector != NULL ) ++ { ++ // clear all registers ++ memset( ®s, 0, sizeof( regs ) ); ++ ++ regs.w.ax = 0x101; ++ regs.w.dx = selector; ++ int386( 0x31, ®s, ®s ); ++ } ++ } ++ ++#endif ++ ++/*--------------------------------------------------------------------- ++ Function: TS_Startup ++ ++ Sets up the task service routine. ++---------------------------------------------------------------------*/ ++ ++static int TS_Startup ++ ( ++ void ++ ) ++ ++ { ++ if ( !TS_Installed ) ++ { ++#ifdef LOCKMEMORY ++ ++ int status; ++ ++ status = TS_LockMemory(); ++ if ( status != TASK_Ok ) ++ { ++ TS_UnlockMemory(); ++ return( status ); ++ } ++ ++#endif ++ ++#ifdef USESTACK ++ ++ StackSelector = allocateTimerStack( kStackSize ); ++ if ( StackSelector == NULL ) ++ { ++ ++#ifdef LOCKMEMORY ++ ++ TS_UnlockMemory(); ++ ++#endif ++ return( TASK_Error ); ++ } ++ ++ // Leave a little room at top of stack just for the hell of it... ++ StackPointer = kStackSize - sizeof( long ); ++ ++#endif ++ ++//static const task *TaskList = &HeadTask; ++ TaskList->next = TaskList; ++ TaskList->prev = TaskList; ++ ++ TaskServiceRate = 0x10000L; ++ TaskServiceCount = 0; ++ ++#ifndef NOINTS ++ TS_TimesInInterrupt = 0; ++#endif ++ ++ OldInt8 = _dos_getvect( 0x08 ); ++ #ifdef NOINTS ++ _dos_setvect( 0x08, TS_ServiceSchedule ); ++ #else ++ _dos_setvect( 0x08, TS_ServiceScheduleIntEnabled ); ++ #endif ++ ++ TS_Installed = TRUE; ++ } ++ ++ return( TASK_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_Shutdown ++ ++ Ends processing of all tasks. ++---------------------------------------------------------------------*/ ++ ++void TS_Shutdown ++ ( ++ void ++ ) ++ ++ { ++ if ( TS_Installed ) ++ { ++ TS_FreeTaskList(); ++ ++ TS_SetClockSpeed( 0 ); ++ ++ _dos_setvect( 0x08, OldInt8 ); ++ ++#ifdef USESTACK ++ ++ deallocateTimerStack( StackSelector ); ++ StackSelector = NULL; ++ ++#endif ++ ++ // Set Date and Time from CMOS ++// RestoreRealTimeClock(); ++ ++#ifdef LOCKMEMORY ++ ++ TS_UnlockMemory(); ++ ++#endif ++ TS_Installed = FALSE; ++ } ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_ScheduleTask ++ ++ Schedules a new task for processing. ++---------------------------------------------------------------------*/ ++ ++task *TS_ScheduleTask ++ ( ++ void ( *Function )( task * ), ++ int rate, ++ int priority, ++ void *data ++ ) ++ ++ { ++ task *ptr; ++ ++#ifdef USE_USRHOOKS ++ int status; ++ ++ ptr = NULL; ++ ++ status = USRHOOKS_GetMem( &ptr, sizeof( task ) ); ++ if ( status == USRHOOKS_Ok ) ++#else ++ ptr = malloc( sizeof( task ) ); ++ if ( ptr != NULL ) ++#endif ++ { ++ if ( !TS_Installed ) ++ { ++ status = TS_Startup(); ++ if ( status != TASK_Ok ) ++ { ++ FreeMem( ptr ); ++ return( NULL ); ++ } ++ } ++ ++ ptr->TaskService = Function; ++ ptr->data = data; ++ ptr->rate = TS_SetTimer( rate ); ++ ptr->count = 0; ++ ptr->priority = priority; ++ ptr->active = FALSE; ++ ++ TS_AddTask( ptr ); ++ } ++ ++ return( ptr ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_AddTask ++ ++ Adds a new task to our list of tasks. ++---------------------------------------------------------------------*/ ++ ++static void TS_AddTask ++ ( ++ task *node ++ ) ++ ++ { ++ LL_SortedInsertion( TaskList, node, next, prev, task, priority ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_Terminate ++ ++ Ends processing of a specific task. ++---------------------------------------------------------------------*/ ++ ++int TS_Terminate ++ ( ++ task *NodeToRemove ++ ) ++ ++ { ++ task *ptr; ++ task *next; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ ptr = TaskList->next; ++ while( ptr != TaskList ) ++ { ++ next = ptr->next; ++ ++ if ( ptr == NodeToRemove ) ++ { ++ LL_RemoveNode( NodeToRemove, next, prev ); ++ NodeToRemove->next = NULL; ++ NodeToRemove->prev = NULL; ++ FreeMem( NodeToRemove ); ++ ++ TS_SetTimerToMaxTaskRate(); ++ ++ RestoreInterrupts( flags ); ++ ++ return( TASK_Ok ); ++ } ++ ++ ptr = next; ++ } ++ ++ RestoreInterrupts( flags ); ++ ++ return( TASK_Warning ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_Dispatch ++ ++ Begins processing of all inactive tasks. ++---------------------------------------------------------------------*/ ++ ++void TS_Dispatch ++ ( ++ void ++ ) ++ ++ { ++ task *ptr; ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ ptr = TaskList->next; ++ while( ptr != TaskList ) ++ { ++ ptr->active = TRUE; ++ ptr = ptr->next; ++ } ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_SetTaskRate ++ ++ Sets the rate at which the specified task is serviced. ++---------------------------------------------------------------------*/ ++ ++void TS_SetTaskRate ++ ( ++ task *Task, ++ int rate ++ ) ++ ++ { ++ unsigned flags; ++ ++ flags = DisableInterrupts(); ++ ++ Task->rate = TS_SetTimer( rate ); ++ TS_SetTimerToMaxTaskRate(); ++ ++ RestoreInterrupts( flags ); ++ } ++ ++ ++#ifdef LOCKMEMORY ++ ++/*--------------------------------------------------------------------- ++ Function: TS_LockEnd ++ ++ Used for determining the length of the functions to lock in memory. ++---------------------------------------------------------------------*/ ++ ++static void TS_LockEnd ++ ( ++ void ++ ) ++ ++ { ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_UnlockMemory ++ ++ Unlocks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++void TS_UnlockMemory ++ ( ++ void ++ ) ++ ++ { ++ DPMI_UnlockMemoryRegion( TS_LockStart, TS_LockEnd ); ++ DPMI_Unlock( TaskList ); ++ DPMI_Unlock( OldInt8 ); ++ DPMI_Unlock( TaskServiceRate ); ++ DPMI_Unlock( TaskServiceCount ); ++ DPMI_Unlock( TS_Installed ); ++ ++#ifndef NOINTS ++ DPMI_Unlock( TS_TimesInInterrupt ); ++#endif ++ ++#ifdef USESTACK ++ DPMI_Unlock( StackSelector ); ++ DPMI_Unlock( StackPointer ); ++ DPMI_Unlock( oldStackSelector ); ++ DPMI_Unlock( oldStackPointer ); ++#endif ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: TS_LockMemory ++ ++ Locks all neccessary data. ++---------------------------------------------------------------------*/ ++ ++int TS_LockMemory ++ ( ++ void ++ ) ++ ++ { ++ int status; ++ ++ status = DPMI_LockMemoryRegion( TS_LockStart, TS_LockEnd ); ++ status |= DPMI_Lock( TaskList ); ++ status |= DPMI_Lock( OldInt8 ); ++ status |= DPMI_Lock( TaskServiceRate ); ++ status |= DPMI_Lock( TaskServiceCount ); ++ status |= DPMI_Lock( TS_Installed ); ++ ++#ifndef NOINTS ++ status |= DPMI_Lock( TS_TimesInInterrupt ); ++#endif ++ ++#ifdef USESTACK ++ status |= DPMI_Lock( StackSelector ); ++ status |= DPMI_Lock( StackPointer ); ++ status |= DPMI_Lock( oldStackSelector ); ++ status |= DPMI_Lock( oldStackPointer ); ++#endif ++ ++ if ( status != DPMI_Ok ) ++ { ++ TS_UnlockMemory(); ++ return( TASK_Error ); ++ } ++ ++ return( TASK_Ok ); ++ } ++ ++#endif ++ ++/* ++// Converts a hex byte to an integer ++ ++static int btoi ++ ( ++ unsigned char bcd ++ ) ++ ++ { ++ unsigned b; ++ unsigned c; ++ unsigned d; ++ ++ b = bcd / 16; ++ c = bcd - b * 16; ++ d = b * 10 + c; ++ return( d ); ++ } ++ ++ ++static void RestoreRealTimeClock ++ ( ++ void ++ ) ++ ++ { ++ int read; ++ int i; ++ int hr; ++ int min; ++ int sec; ++ int cent; ++ int yr; ++ int mo; ++ int day; ++ int year; ++ union REGS inregs; ++ ++ // Read Real Time Clock Time. ++ read = FALSE; ++ inregs.h.ah = 0x02; ++ for( i = 1; i <= 3; i++ ) ++ { ++ int386( 0x1A, &inregs, &inregs ); ++ if ( inregs.x.cflag == 0 ) ++ { ++ read = TRUE; ++ } ++ } ++ ++ if ( read ) ++ { ++ //and convert BCD to integer format ++ hr = btoi( inregs.h.ch ); ++ min = btoi( inregs.h.cl ); ++ sec = btoi( inregs.h.dh ); ++ ++ // Read Real Time Clock Date. ++ inregs.h.ah = 0x04; ++ int386( 0x1A, &inregs, &inregs ); ++ if ( inregs.x.cflag == 0 ) ++ { ++ //and convert BCD to integer format ++ cent = btoi( inregs.h.ch ); ++ yr = btoi( inregs.h.cl ); ++ mo = btoi( inregs.h.dh ); ++ day = btoi( inregs.h.dl ); ++ year = cent * 100 + yr; ++ ++ // Set System Time. ++ inregs.h.ch = hr; ++ inregs.h.cl = min; ++ inregs.h.dh = sec; ++ inregs.h.dl = 0; ++ inregs.h.ah = 0x2D; ++ int386( 0x21, &inregs, &inregs ); ++ ++ // Set System Date. ++ inregs.w.cx = year; ++ inregs.h.dh = mo; ++ inregs.h.dl = day; ++ inregs.h.ah = 0x2B; ++ int386( 0x21, &inregs, &inregs ); ++ } ++ } ++ } ++*/ ++/* ++ struct dostime_t time; ++ struct dosdate_t date; ++ ++ outp(0x70,0); ++ time.second=inp(0x71); ++ outp(0x70,2); ++ time.minute=inp(0x71); ++ outp(0x70,4); ++ time.hour=inp(0x71); ++ ++ outp(0x70,7); ++ date.day=inp(0x71); ++ outp(0x70,8); ++ date.month=inp(0x71); ++ outp(0x70,9); ++ date.year=inp(0x71); ++ ++ time.second=(time.second&0x0f)+((time.second>>4)*10); ++ time.minute=(time.minute&0x0f)+((time.minute>>4)*10); ++ time.hour=(time.hour&0x0f)+((time.hour>>4)*10); ++ ++ date.day=(date.day&0x0f)+((date.day>>4)*10); ++ date.month=(date.month&0x0f)+((date.month>>4)*10); ++ date.year=(date.year&0x0f)+((date.year>>4)*10); ++ ++ _dos_settime(&time); ++ _dos_setdate(&date); ++ ++*/ +diff -urN rott-1.0/rott/audiolib/task_man.h trunk/rott/audiolib/task_man.h +--- rott-1.0/rott/audiolib/task_man.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/task_man.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,68 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: TASK_MAN.C ++ ++ author: James R. Dose ++ date: July 25, 1994 ++ ++ Public header for TASK_MAN.C, a low level timer task scheduler. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __TASK_MAN_H ++#define __TASK_MAN_H ++ ++enum TASK_ERRORS ++ { ++ TASK_Warning = -2, ++ TASK_Error = -1, ++ TASK_Ok = 0 ++ }; ++ ++typedef struct task ++{ ++ struct task *next; ++ struct task *prev; ++ void ( *TaskService )( struct task * ); ++ void *data; ++ long rate; ++ volatile long count; ++ int priority; ++ int active; ++} task; ++ ++// TS_InInterrupt is TRUE during a taskman interrupt. ++// Use this if you have code that may be used both outside ++// and within interrupts. ++ ++extern volatile int TS_InInterrupt; ++ ++void TS_Shutdown( void ); ++task *TS_ScheduleTask( void ( *Function )( task * ), int rate, ++ int priority, void *data ); ++int TS_Terminate( task *ptr ); ++void TS_Dispatch( void ); ++void TS_SetTaskRate( task *Task, int rate ); ++void TS_UnlockMemory( void ); ++int TS_LockMemory( void ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/user.c trunk/rott/audiolib/user.c +--- rott-1.0/rott/audiolib/user.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/user.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,133 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: USER.C ++ ++ author: James R. Dose ++ date: April 26, 1994 ++ ++ Routines to parse command line options. ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifdef PLAT_DOS ++#include ++#endif ++ ++#include ++#include "user.h" ++ ++#define TRUE ( 1 == 1 ) ++#define FALSE ( !TRUE ) ++ ++#ifdef PLAT_DOS ++extern int _argc; ++extern char **_argv; ++#endif ++ ++/*--------------------------------------------------------------------- ++ Function: USER_CheckParameter ++ ++ Checks if the specified string is present in the command line. ++---------------------------------------------------------------------*/ ++ ++int USER_CheckParameter ++ ( ++ const char *parameter ++ ) ++ ++ { ++#ifdef PLAT_DOS ++ int i; ++ int found; ++ char *ptr; ++ ++ found = FALSE; ++ i = 1; ++ while( i < _argc ) ++ { ++ ptr = _argv[ i ]; ++ ++ // Only check parameters preceded by - or / ++ if ( ( *ptr == '-' ) || ( *ptr == '/' ) ) ++ { ++ ptr++; ++ if ( stricmp( parameter, ptr ) == 0 ) ++ { ++ found = TRUE; ++ break; ++ } ++ } ++ ++ i++; ++ } ++ ++ return( found ); ++#else ++ return FALSE; ++#endif ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: USER_GetText ++ ++ Checks if the specified string is present in the command line ++ and returns a pointer to the text following it. ++---------------------------------------------------------------------*/ ++ ++char *USER_GetText ++ ( ++ const char *parameter ++ ) ++ ++ { ++#ifdef PLAT_DOS ++ int i; ++ char *text; ++ char *ptr; ++ ++ text = NULL; ++ i = 1; ++ while( i < _argc ) ++ { ++ ptr = _argv[ i ]; ++ ++ // Only check parameters preceded by - or / ++ if ( ( *ptr == '-' ) || ( *ptr == '/' ) ) ++ { ++ ptr++; ++ if ( stricmp( parameter, ptr ) == 0 ) ++ { ++ i++; ++ text = _argv[ i ]; ++ break; ++ } ++ } ++ ++ i++; ++ } ++ ++ return( text ); ++#else ++ return NULL; ++#endif ++ } +diff -urN rott-1.0/rott/audiolib/user.h trunk/rott/audiolib/user.h +--- rott-1.0/rott/audiolib/user.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/user.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,38 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: USER.H ++ ++ author: James R. Dose ++ phone: (214)-271-1365 Ext #221 ++ date: April 26, 1994 ++ ++ Public header for USER.C ++ ++ (c) Copyright 1994 James R. Dose. All Rights Reserved. ++**********************************************************************/ ++ ++#ifndef __USER_H ++#define __USER_H ++ ++int USER_CheckParameter( const char *parameter ); ++char *USER_GetText( const char *parameter ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/usrhooks.c trunk/rott/audiolib/usrhooks.c +--- rott-1.0/rott/audiolib/usrhooks.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/usrhooks.c 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,84 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: USRHOOKS.C ++ ++ author: James R. Dose ++ date: July 26, 1994 ++ ++ This module contains cover functions for operations the library ++ needs that may be restricted by the calling program. This code ++ is left public for you to modify. ++**********************************************************************/ ++ ++#include ++#include "usrhooks.h" ++ ++ ++/*--------------------------------------------------------------------- ++ Function: USRHOOKS_GetMem ++ ++ Allocates the requested amount of memory and returns a pointer to ++ its location, or NULL if an error occurs. NOTE: pointer is assumed ++ to be dword aligned. ++---------------------------------------------------------------------*/ ++ ++int USRHOOKS_GetMem ++ ( ++ void **ptr, ++ unsigned long size ++ ) ++ ++ { ++ void *memory; ++ ++ memory = malloc( size ); ++ if ( memory == NULL ) ++ { ++ return( USRHOOKS_Error ); ++ } ++ ++ *ptr = memory; ++ ++ return( USRHOOKS_Ok ); ++ } ++ ++ ++/*--------------------------------------------------------------------- ++ Function: USRHOOKS_FreeMem ++ ++ Deallocates the memory associated with the specified pointer. ++---------------------------------------------------------------------*/ ++ ++int USRHOOKS_FreeMem ++ ( ++ void *ptr ++ ) ++ ++ { ++ if ( ptr == NULL ) ++ { ++ return( USRHOOKS_Error ); ++ } ++ ++ free( ptr ); ++ ++ return( USRHOOKS_Ok ); ++ } +diff -urN rott-1.0/rott/audiolib/usrhooks.h trunk/rott/audiolib/usrhooks.h +--- rott-1.0/rott/audiolib/usrhooks.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/usrhooks.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,55 @@ ++/* ++Copyright (C) 1994-1995 Apogee Software, Ltd. ++ ++This program is free software; you can redistribute it and/or ++modify it under the terms of the GNU General Public License ++as published by the Free Software Foundation; either version 2 ++of the License, or (at your option) any later version. ++ ++This program is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ ++See the GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; if not, write to the Free Software ++Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++*/ ++/********************************************************************** ++ module: USRHOOKS.H ++ ++ author: James R. Dose ++ date: July 26, 1994 ++ ++ Public header file for USRHOOKS.C. ++ ++ This module contains cover functions for operations the library ++ needs that may be restricted by the calling program. The function ++ prototypes in this header should not be modified. ++**********************************************************************/ ++ ++#ifndef __USRHOOKS_H ++#define __USRHOOKS_H ++ ++/*--------------------------------------------------------------------- ++ Error definitions ++---------------------------------------------------------------------*/ ++ ++enum USRHOOKS_Errors ++ { ++ USRHOOKS_Warning = -2, ++ USRHOOKS_Error = -1, ++ USRHOOKS_Ok = 0 ++ }; ++ ++ ++/*--------------------------------------------------------------------- ++ Function Prototypes ++---------------------------------------------------------------------*/ ++ ++int USRHOOKS_GetMem( void **ptr, unsigned long size ); ++int USRHOOKS_FreeMem( void *ptr ); ++ ++#endif +diff -urN rott-1.0/rott/audiolib/util.h trunk/rott/audiolib/util.h +--- rott-1.0/rott/audiolib/util.h 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/audiolib/util.h 2007-05-05 20:44:28.000000000 +0200 +@@ -0,0 +1,13 @@ ++#ifndef AUDIOLIB__UTIL_H ++#define AUDIOLIB__UTIL_H ++ ++#ifndef min ++#define min(a, b) ((a) < (b) ? (a) : (b)) ++#endif ++ ++#ifndef max ++#define max(a, b) ((a) > (b) ? (a) : (b)) ++#endif ++ ++#endif ++ +diff -urN rott-1.0/rott/byteordr.h trunk/rott/byteordr.h +--- rott-1.0/rott/byteordr.h 2002-12-24 05:44:45.000000000 +0100 ++++ trunk/rott/byteordr.h 2007-05-05 20:44:31.000000000 +0200 +@@ -23,6 +23,9 @@ + // + //*************************************************************************** + ++#ifndef BYTEORDER_H ++#define BYTEORDER_H ++ + typedef void (*converter_t)(void *, int); + + #define DECLARE_CONVERTER(type) void Cvt_##type(void *lmp, int num); +@@ -36,3 +39,5 @@ + DECLARE_CONVERTER(cfont_t); + void CvtNull(void *lmp, int num); + void CvtFixme(void *lmp, int num); ++ ++#endif +diff -urN rott-1.0/rott/cin_glob.h trunk/rott/cin_glob.h +--- rott-1.0/rott/cin_glob.h 2002-12-20 21:15:27.000000000 +0100 ++++ trunk/rott/cin_glob.h 2007-05-05 20:44:31.000000000 +0200 +@@ -22,6 +22,9 @@ + #include "isr.h" + #include + ++#ifndef CIN_GLOB_H ++#define CIN_GLOB_H ++ + #define DUMP 0 + + #define CLOCKSPEED (VBLCOUNTER) +@@ -31,3 +34,4 @@ + boolean CinematicAbort( void ); + void ClearCinematicAbort( void ); + ++#endif +diff -urN rott-1.0/rott/dukemusc.c trunk/rott/dukemusc.c +--- rott-1.0/rott/dukemusc.c 1970-01-01 01:00:00.000000000 +0100 ++++ trunk/rott/dukemusc.c 2007-05-05 20:44:31.000000000 +0200 +@@ -0,0 +1,507 @@ ++/* ++ * A reimplementation of Jim Dose's FX_MAN routines, using SDL_mixer 1.2. ++ * Whee. FX_MAN is also known as the "Apogee Sound System", or "ASS" for ++ * short. How strangely appropriate that seems. ++ * ++ * Written by Ryan C. Gordon. (icculus@clutteredmind.org) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define ROTT ++ ++#ifdef DUKE3D ++#include "duke3d.h" ++#include "buildengine/cache1d.h" ++#endif ++ ++#if PLATFORM_DOS ++// Use the original Apogee Sound System libs instead. --ryan. ++#error you probably should not compile this. ++#endif ++ ++#if (defined __WATCOMC__) ++// This is probably out of date. --ryan. ++#include "dukesnd_watcom.h" ++#endif ++ ++#if (!defined __WATCOMC__) ++#define cdecl ++#endif ++ ++#include "SDL.h" ++#include "SDL_mixer.h" ++#ifdef ROTT ++#include "rt_def.h" // ROTT music hack ++#include "rt_cfg.h" // ROTT music hack ++#include "rt_util.h" // ROTT music hack ++#endif ++#include "music.h" ++ ++#define __FX_TRUE (1 == 1) ++#define __FX_FALSE (!__FX_TRUE) ++ ++#define DUKESND_DEBUG "DUKESND_DEBUG" ++ ++#ifndef min ++#define min(a, b) (((a) < (b)) ? (a) : (b)) ++#endif ++ ++#ifndef max ++#define max(a, b) (((a) > (b)) ? (a) : (b)) ++#endif ++ ++int MUSIC_ErrorCode = MUSIC_Ok; ++ ++static char warningMessage[80]; ++static char errorMessage[80]; ++static int fx_initialized = 0; ++static int numChannels = MIX_CHANNELS; ++static void (*callback)(unsigned long); ++static int reverseStereo = 0; ++static int reverbDelay = 256; ++static int reverbLevel = 0; ++static int fastReverb = 0; ++static FILE *debug_file = NULL; ++static int initialized_debugging = 0; ++static int mixerIsStereo = 1; ++ ++// This gets called all over the place for information and debugging messages. ++// If the user set the DUKESND_DEBUG environment variable, the messages ++// go to the file that is specified in that variable. Otherwise, they ++// are ignored for the expense of the function call. If DUKESND_DEBUG is ++// set to "-" (without the quotes), then the output goes to stdout. ++static void musdebug(const char *fmt, ...) ++{ ++ va_list ap; ++ ++ if (debug_file) ++ { ++ fprintf(debug_file, "DUKEMUS: "); ++ va_start(ap, fmt); ++ vfprintf(debug_file, fmt, ap); ++ va_end(ap); ++ fprintf(debug_file, "\n"); ++ fflush(debug_file); ++ } // if ++} // musdebug ++ ++static void init_debugging(void) ++{ ++ const char *envr; ++ ++ if (initialized_debugging) ++ return; ++ ++ envr = getenv(DUKESND_DEBUG); ++ if (envr != NULL) ++ { ++ if (strcmp(envr, "-") == 0) ++ debug_file = stdout; ++ else ++ debug_file = fopen(envr, "w"); ++ ++ if (debug_file == NULL) ++ fprintf(stderr, "DUKESND: -WARNING- Could not open debug file!\n"); ++ else ++ setbuf(debug_file, NULL); ++ } // if ++ ++ initialized_debugging = 1; ++} // init_debugging ++ ++static void setWarningMessage(const char *msg) ++{ ++ strncpy(warningMessage, msg, sizeof (warningMessage)); ++ // strncpy() doesn't add the null char if there isn't room... ++ warningMessage[sizeof (warningMessage) - 1] = '\0'; ++ musdebug("Warning message set to [%s].", warningMessage); ++} // setErrorMessage ++ ++ ++static void setErrorMessage(const char *msg) ++{ ++ strncpy(errorMessage, msg, sizeof (errorMessage)); ++ // strncpy() doesn't add the null char if there isn't room... ++ errorMessage[sizeof (errorMessage) - 1] = '\0'; ++ musdebug("Error message set to [%s].", errorMessage); ++} // setErrorMessage ++ ++// The music functions... ++ ++char *MUSIC_ErrorString(int ErrorNumber) ++{ ++ switch (ErrorNumber) ++ { ++ case MUSIC_Warning: ++ return(warningMessage); ++ ++ case MUSIC_Error: ++ return(errorMessage); ++ ++ case MUSIC_Ok: ++ return("OK; no error."); ++ ++ case MUSIC_ASSVersion: ++ return("Incorrect sound library version."); ++ ++ case MUSIC_SoundCardError: ++ return("General sound card error."); ++ ++ case MUSIC_InvalidCard: ++ return("Invalid sound card."); ++ ++ case MUSIC_MidiError: ++ return("MIDI error."); ++ ++ case MUSIC_MPU401Error: ++ return("MPU401 error."); ++ ++ case MUSIC_TaskManError: ++ return("Task Manager error."); ++ ++ case MUSIC_FMNotDetected: ++ return("FM not detected error."); ++ ++ case MUSIC_DPMI_Error: ++ return("DPMI error."); ++ ++ default: ++ return("Unknown error."); ++ } // switch ++ ++ assert(0); // shouldn't hit this point. ++ return(NULL); ++} // MUSIC_ErrorString ++ ++ ++static int music_initialized = 0; ++static int music_context = 0; ++static int music_loopflag = MUSIC_PlayOnce; ++static char *music_songdata = NULL; ++static Mix_Music *music_musicchunk = NULL; ++ ++int MUSIC_Init(int SoundCard, int Address) ++{ ++ init_debugging(); ++ ++ musdebug("INIT! card=>%d, address=>%d...", SoundCard, Address); ++ ++ if (music_initialized) ++ { ++ setErrorMessage("Music system is already initialized."); ++ return(MUSIC_Error); ++ } // if ++ ++ if (SoundCard != SoundScape) // We pretend there's a SoundScape installed. ++ { ++ setErrorMessage("Card not found."); ++ musdebug("We pretend to be an Ensoniq SoundScape only."); ++ return(MUSIC_Error); ++ } // if ++ ++ music_initialized = 1; ++ return(MUSIC_Ok); ++} // MUSIC_Init ++ ++ ++int MUSIC_Shutdown(void) ++{ ++ musdebug("shutting down sound subsystem."); ++ ++ if (!music_initialized) ++ { ++ setErrorMessage("Music system is not currently initialized."); ++ return(MUSIC_Error); ++ } // if ++ ++ MUSIC_StopSong(); ++ music_context = 0; ++ music_initialized = 0; ++ music_loopflag = MUSIC_PlayOnce; ++ ++ return(MUSIC_Ok); ++} // MUSIC_Shutdown ++ ++ ++void MUSIC_SetMaxFMMidiChannel(int channel) ++{ ++ musdebug("STUB ... MUSIC_SetMaxFMMidiChannel(%d).\n", channel); ++} // MUSIC_SetMaxFMMidiChannel ++ ++ ++void MUSIC_SetVolume(int volume) ++{ ++ Mix_VolumeMusic(volume >> 1); // convert 0-255 to 0-128. ++} // MUSIC_SetVolume ++ ++ ++void MUSIC_SetMidiChannelVolume(int channel, int volume) ++{ ++ musdebug("STUB ... MUSIC_SetMidiChannelVolume(%d, %d).\n", channel, volume); ++} // MUSIC_SetMidiChannelVolume ++ ++ ++void MUSIC_ResetMidiChannelVolumes(void) ++{ ++ musdebug("STUB ... MUSIC_ResetMidiChannelVolumes().\n"); ++} // MUSIC_ResetMidiChannelVolumes ++ ++ ++int MUSIC_GetVolume(void) ++{ ++ return(Mix_VolumeMusic(-1) << 1); // convert 0-128 to 0-255. ++} // MUSIC_GetVolume ++ ++ ++void MUSIC_SetLoopFlag(int loopflag) ++{ ++ music_loopflag = loopflag; ++} // MUSIC_SetLoopFlag ++ ++ ++int MUSIC_SongPlaying(void) ++{ ++ return((Mix_PlayingMusic()) ? __FX_TRUE : __FX_FALSE); ++} // MUSIC_SongPlaying ++ ++ ++void MUSIC_Continue(void) ++{ ++ if (Mix_PausedMusic()) ++ Mix_ResumeMusic(); ++ else if (music_songdata) ++ MUSIC_PlaySong(music_songdata, MUSIC_PlayOnce); ++} // MUSIC_Continue ++ ++ ++void MUSIC_Pause(void) ++{ ++ Mix_PauseMusic(); ++} // MUSIC_Pause ++ ++ ++int MUSIC_StopSong(void) ++{ ++ //if (!fx_initialized) ++ if (!Mix_QuerySpec(NULL, NULL, NULL)) ++ { ++ setErrorMessage("Need FX system initialized, too. Sorry."); ++ return(MUSIC_Error); ++ } // if ++ ++ if ( (Mix_PlayingMusic()) || (Mix_PausedMusic()) ) ++ Mix_HaltMusic(); ++ ++ if (music_musicchunk) ++ Mix_FreeMusic(music_musicchunk); ++ ++ music_songdata = NULL; ++ music_musicchunk = NULL; ++ return(MUSIC_Ok); ++} // MUSIC_StopSong ++ ++ ++int MUSIC_PlaySong(unsigned char *song, int loopflag) ++{ ++ //SDL_RWops *rw; ++ ++ MUSIC_StopSong(); ++ ++ music_songdata = song; ++ ++ // !!! FIXME: This could be a problem...SDL/SDL_mixer wants a RWops, which ++ // !!! FIXME: is an i/o abstraction. Since we already have the MIDI data ++ // !!! FIXME: in memory, we fake it with a memory-based RWops. None of ++ // !!! FIXME: this is a problem, except the RWops wants to know how big ++ // !!! FIXME: its memory block is (so it can do things like seek on an ++ // !!! FIXME: offset from the end of the block), and since we don't have ++ // !!! FIXME: this information, we have to give it SOMETHING. ++ ++ /* !!! ARGH! There's no LoadMUS_RW ?! ++ rw = SDL_RWFromMem((void *) song, (10 * 1024) * 1024); // yikes. ++ music_musicchunk = Mix_LoadMUS_RW(rw); ++ Mix_PlayMusic(music_musicchunk, (loopflag == MUSIC_PlayOnce) ? 0 : -1); ++ */ ++ ++musdebug("Need to use PlaySongROTT. :("); ++ ++ return(MUSIC_Ok); ++} // MUSIC_PlaySong ++ ++ ++extern char ApogeePath[256]; ++ ++#ifdef DUKE3D ++// Duke3D-specific. --ryan. ++void PlayMusic(char *_filename) ++{ ++ //char filename[MAX_PATH]; ++ //strcpy(filename, _filename); ++ //FixFilePath(filename); ++ ++ char filename[MAX_PATH]; ++ long handle; ++ long size; ++ void *song; ++ long rc; ++ ++ MUSIC_StopSong(); ++ ++ // Read from a groupfile, write it to disk so SDL_mixer can read it. ++ // Lame. --ryan. ++ handle = kopen4load(_filename, 0); ++ if (handle == -1) ++ return; ++ ++ size = kfilelength(handle); ++ if (size == -1) ++ { ++ kclose(handle); ++ return; ++ } // if ++ ++ song = malloc(size); ++ if (song == NULL) ++ { ++ kclose(handle); ++ return; ++ } // if ++ ++ rc = kread(handle, song, size); ++ kclose(handle); ++ if (rc != size) ++ { ++ free(song); ++ return; ++ } // if ++ ++ // save the file somewhere, so SDL_mixer can load it ++ GetPathFromEnvironment(filename, MAX_PATH, "tmpsong.mid"); ++ handle = SafeOpenWrite(filename, filetype_binary); ++ ++ SafeWrite(handle, song, size); ++ close(handle); ++ free(song); ++ ++ //music_songdata = song; ++ ++ music_musicchunk = Mix_LoadMUS(filename); ++ if (music_musicchunk != NULL) ++ { ++ // !!! FIXME: I set the music to loop. Hope that's okay. --ryan. ++ Mix_PlayMusic(music_musicchunk, -1); ++ } // if ++} ++#endif ++ ++#ifdef ROTT ++// ROTT Special - SBF ++int MUSIC_PlaySongROTT(unsigned char *song, int size, int loopflag) ++{ ++ char filename[MAX_PATH]; ++ int handle; ++ ++ MUSIC_StopSong(); ++ ++ // save the file somewhere, so SDL_mixer can load it ++ GetPathFromEnvironment(filename, ApogeePath, "tmpsong.mid"); ++ handle = SafeOpenWrite(filename); ++ ++ SafeWrite(handle, song, size); ++ close(handle); ++ ++ music_songdata = song; ++ ++ // finally, we can load it with SDL_mixer ++ music_musicchunk = Mix_LoadMUS(filename); ++ if (music_musicchunk == NULL) { ++ return MUSIC_Error; ++ } ++ ++ Mix_PlayMusic(music_musicchunk, (loopflag == MUSIC_PlayOnce) ? 0 : -1); ++ ++ return(MUSIC_Ok); ++} // MUSIC_PlaySongROTT ++#endif ++ ++ ++void MUSIC_SetContext(int context) ++{ ++ musdebug("STUB ... MUSIC_SetContext().\n"); ++ music_context = context; ++} // MUSIC_SetContext ++ ++ ++int MUSIC_GetContext(void) ++{ ++ return(music_context); ++} // MUSIC_GetContext ++ ++ ++void MUSIC_SetSongTick(unsigned long PositionInTicks) ++{ ++ musdebug("STUB ... MUSIC_SetSongTick().\n"); ++} // MUSIC_SetSongTick ++ ++ ++void MUSIC_SetSongTime(unsigned long milliseconds) ++{ ++ musdebug("STUB ... MUSIC_SetSongTime().\n"); ++}// MUSIC_SetSongTime ++ ++ ++void MUSIC_SetSongPosition(int measure, int beat, int tick) ++{ ++ musdebug("STUB ... MUSIC_SetSongPosition().\n"); ++} // MUSIC_SetSongPosition ++ ++ ++void MUSIC_GetSongPosition(songposition *pos) ++{ ++ musdebug("STUB ... MUSIC_GetSongPosition().\n"); ++} // MUSIC_GetSongPosition ++ ++ ++void MUSIC_GetSongLength(songposition *pos) ++{ ++ musdebug("STUB ... MUSIC_GetSongLength().\n"); ++} // MUSIC_GetSongLength ++ ++ ++int MUSIC_FadeVolume(int tovolume, int milliseconds) ++{ ++ Mix_FadeOutMusic(milliseconds); ++ return(MUSIC_Ok); ++} // MUSIC_FadeVolume ++ ++ ++int MUSIC_FadeActive(void) ++{ ++ return((Mix_FadingMusic() == MIX_FADING_OUT) ? __FX_TRUE : __FX_FALSE); ++} // MUSIC_FadeActive ++ ++ ++void MUSIC_StopFade(void) ++{ ++ musdebug("STUB ... MUSIC_StopFade().\n"); ++} // MUSIC_StopFade ++ ++ ++void MUSIC_RerouteMidiChannel(int channel, int cdecl (*function)( int event, int c1, int c2 )) ++{ ++ musdebug("STUB ... MUSIC_RerouteMidiChannel().\n"); ++} // MUSIC_RerouteMidiChannel ++ ++ ++void MUSIC_RegisterTimbreBank(unsigned char *timbres) ++{ ++ musdebug("STUB ... MUSIC_RegisterTimbreBank().\n"); ++} // MUSIC_RegisterTimbreBank ++ ++ ++// end of fx_man.c ... +diff -urN rott-1.0/rott/fx_man.c trunk/rott/fx_man.c +--- rott-1.0/rott/fx_man.c 2003-01-07 07:54:13.000000000 +0100 ++++ trunk/rott/fx_man.c 2007-05-05 20:44:31.000000000 +0200 +@@ -426,7 +426,7 @@ + return(FX_Error); + } // if + +- audio_format = (samplebits == 8) ? AUDIO_U8 : AUDIO_S16; ++ audio_format = (samplebits == 8) ? AUDIO_U8 : AUDIO_S16SYS; + if (Mix_OpenAudio(mixrate, audio_format, numchannels, 256) < 0) + { + setErrorMessage(SDL_GetError()); +diff -urN rott-1.0/rott/isr.c trunk/rott/isr.c +--- rott-1.0/rott/isr.c 2002-12-31 08:50:25.000000000 +0100 ++++ trunk/rott/isr.c 2007-05-05 20:44:31.000000000 +0200 +@@ -801,10 +801,9 @@ + delay=(VBLCOUNTER*delay)/10; + IN_ClearKeysDown(); + time=GetTicCount(); +- while (GetTicCount()randgibspeed = true; +-// SpawnParticles(ob,GUTS,75); +-//MED ++ ++#ifdef MEDGIBS + SpawnParticles(ob,GUTS,150); ++#else ++ SpawnParticles(ob,GUTS,75); ++#endif ++ + MISCVARS->randgibspeed = false; + } + SpawnParticles(ob,GUTS,40); +@@ -3846,10 +3850,12 @@ + (randadj<<4); + dz = 100 + (randadj<<3); + +-//MED +-// nspeed = 0x2800 + (randadj<<7); ++#ifdef MEDGIBS + nspeed = 0x2800; +- ++#else ++ nspeed = 0x2800 + (randadj<<7); ++#endif ++ + randphi = atan2_appx(FindDistance(dx,dy),dz<<10); + } + +@@ -3871,8 +3877,11 @@ + new->temp3 = (MISCVARS->gibgravity == -1)?(GRAVITY):(MISCVARS->gibgravity); + + new->speed = nspeed>>1; +- //if (MISCVARS->randgibspeed == true) +- // new->speed += (randadj << 11); ++ ++#ifndef MEDGIBS ++ if (MISCVARS->randgibspeed == true) ++ new->speed += (randadj << 11); ++#endif + + // if (ob->state == &s_snakefireworks) + new->z = ob->z; +diff -urN rott-1.0/rott/rt_cfg.c trunk/rott/rt_cfg.c +--- rott-1.0/rott/rt_cfg.c 2002-12-31 08:50:26.000000000 +0100 ++++ trunk/rott/rt_cfg.c 2007-05-05 20:44:31.000000000 +0200 +@@ -377,6 +377,7 @@ + void ConvertStringToPasswordString ( char * string ) + { + int i; ++ unsigned int j; + char temp[3]; + + memset(temp,0,sizeof(temp)); +@@ -384,7 +385,11 @@ + for (i=0;i<13;i++) + { + memcpy(&temp[0],&string[i<<1],2); +- sscanf(&temp[0],"%x",(unsigned int *)&passwordstring[i]); ++ sscanf(&temp[0],"%x",&j); ++ passwordstring[i+0] = j & 0xff; j >>= 8; ++ passwordstring[i+1] = j & 0xff; j >>= 8; ++ passwordstring[i+2] = j & 0xff; j >>= 8; ++ passwordstring[i+3] = j & 0xff; + } + } + +diff -urN rott-1.0/rott/rt_def.h trunk/rott/rt_def.h +--- rott-1.0/rott/rt_def.h 2003-01-01 10:24:18.000000000 +0100 ++++ trunk/rott/rt_def.h 2007-05-05 20:44:31.000000000 +0200 +@@ -247,9 +247,6 @@ + #define MaxKbds 2 + #define MaxJoys 2 + #define NumCodes 128 +-#define MReset 0 +-#define MButtons 3 +-#define MDelta 11 + + // Key definitions + +diff -urN rott-1.0/rott/rt_door.c trunk/rott/rt_door.c +--- rott-1.0/rott/rt_door.c 2002-12-24 06:16:27.000000000 +0100 ++++ trunk/rott/rt_door.c 2007-05-05 20:44:31.000000000 +0200 +@@ -4200,13 +4200,13 @@ + + for (i=0;iflags); + memcpy(&flags,bufptr,size); + bufptr+=size; +- if (flags!=mw->flags) ++ if ((flags&0xff)!=mw->flags) // Preserves original behavior + UpdateMaskedWall(i); + if (mw->flags&MW_SWITCHON) + mw->toptexture--; +diff -urN rott-1.0/rott/rt_game.c trunk/rott/rt_game.c +--- rott-1.0/rott/rt_game.c 2003-01-01 10:24:34.000000000 +0100 ++++ trunk/rott/rt_game.c 2007-05-05 20:44:31.000000000 +0200 +@@ -104,12 +104,12 @@ + + static int KeyX[4] = {KEY1_X, KEY2_X, KEY3_X, KEY4_X}; + +-static char *Names[ 5 ] = ++static const char *Names[ 5 ] = + { + "Taradino", "Thi", "Doug", "Lorelei", "Ian Paul" + }; + +-static char *LastNames[ 5 ] = ++static const char *LastNames[ 5 ] = + { + "Cassatt", "Barrett", "Wendt", "Ni", "Freeley" + }; +@@ -487,7 +487,7 @@ + VW_MeasurePropString( LastNames[ character ], &width, &height ); + + DrawGameString ( MEN_X + 44 - width, MEN_Y + 8, +- Names[ character + 5 ], bufferofsonly ); ++ LastNames[ character ], bufferofsonly ); + + UpdateLives( locplayerstate->lives ); + UpdateScore( gamestate.score ); +@@ -996,7 +996,7 @@ + // + //****************************************************************************** + +-void DrawGameString (int x, int y, char * str, boolean bufferofsonly) ++void DrawGameString (int x, int y, const char * str, boolean bufferofsonly) + { + unsigned tempbuf; + +@@ -1777,7 +1777,7 @@ + GiveLives(1); + if (ob==player) + { +- AddMessage("100 Life Item Points! Extra Life!\n",MSG_BONUS); ++ AddMessage("100 Life Item Points! Extra Life!",MSG_BONUS); + SD_PlaySoundRTP (SD_GET1UPSND, player->x, player->y); + } + pstate->triads -= 100; +@@ -4183,7 +4183,7 @@ + killangle=startangle+(TOTALDEATHROT>>1); + if (dopefish==true) + { +- AddMessage("Dopefish Death Cam\n",MSG_SYSTEM); ++ AddMessage("Dopefish Death Cam",MSG_SYSTEM); + } + for (iangle=startangle;;) + { +diff -urN rott-1.0/rott/rt_game.h trunk/rott/rt_game.h +--- rott-1.0/rott/rt_game.h 2002-12-21 01:36:20.000000000 +0100 ++++ trunk/rott/rt_game.h 2007-05-05 20:44:31.000000000 +0200 +@@ -93,7 +93,7 @@ + + void DrawKills (boolean bufferofsonly); + void DrawPlayers ( void ); +-void DrawGameString (int x, int y, char * str, boolean bufferofsonly); ++void DrawGameString (int x, int y, const char * str, boolean bufferofsonly); + void DrawNumber (int x, int y, int width, int which, boolean bufferofsonly); + void TakeDamage (int points, objtype *attacker); + void HealPlayer (int points, objtype * ob); +diff -urN rott-1.0/rott/rt_main.c trunk/rott/rt_main.c +--- rott-1.0/rott/rt_main.c 2003-01-07 07:34:09.000000000 +0100 ++++ trunk/rott/rt_main.c 2007-05-05 20:44:31.000000000 +0200 +@@ -1291,8 +1291,7 @@ + + WaitKeyUp(); + LastScan = 0; +- while (!LastScan) +- ; ++ while (!LastScan) IN_UpdateKeyboard(); // Thanks again DrLex + LastScan=0; + } + #endif +diff -urN rott-1.0/rott/rt_menu.c trunk/rott/rt_menu.c +--- rott-1.0/rott/rt_menu.c 2002-12-29 05:54:44.000000000 +0100 ++++ trunk/rott/rt_menu.c 2007-05-05 20:44:31.000000000 +0200 +@@ -2948,10 +2948,10 @@ + LastScan=0; + while (LastScan == 0) + { ++ IN_UpdateKeyboard(); + RefreshMenuBuf( 0 ); + } + LastScan = 0; +- IN_UpdateKeyboard(); + } + IN_ClearKeysDown(); + return( retval ); +diff -urN rott-1.0/rott/rt_sound.c trunk/rott/rt_sound.c +--- rott-1.0/rott/rt_sound.c 2002-12-31 11:33:00.000000000 +0100 ++++ trunk/rott/rt_sound.c 2007-05-05 20:44:31.000000000 +0200 +@@ -375,7 +375,6 @@ + + snd=W_CacheLumpNum(SoundNumber(sndnum),PU_STATIC, CvtNull, 1); + +-#ifdef DOS + if ( *snd == 'C' ) + { + voice = FX_PlayVOC3D( snd, pitch, angle, distance, +@@ -386,24 +385,6 @@ + voice = FX_PlayWAV3D( snd, pitch, angle, distance, + sounds[sndnum].priority, (unsigned long) sndnum ); + } +-#else +-/* +- Oh boy. The library used to implement these functions may need a +- file size. So, let's just hack these in! +- */ +- if ( *snd == 'C' ) +- { +- voice = FX_PlayVOC3D_ROTT( snd, W_LumpLength(SoundNumber(sndnum)), +- pitch, angle, distance, +- sounds[sndnum].priority, (unsigned long) sndnum ); +- } +- else +- { +- voice = FX_PlayWAV3D_ROTT( snd, W_LumpLength(SoundNumber(sndnum)), +- pitch, angle, distance, +- sounds[sndnum].priority, (unsigned long) sndnum ); +- } +-#endif + + if ( voice < FX_Ok ) + { +diff -urN rott-1.0/rott/rt_str.c trunk/rott/rt_str.c +--- rott-1.0/rott/rt_str.c 2002-12-25 05:40:40.000000000 +0100 ++++ trunk/rott/rt_str.c 2007-05-05 20:44:31.000000000 +0200 +@@ -1109,6 +1109,8 @@ + // if (GameEscaped == true) + // PauseLoop (); + ++ IN_PumpEvents(); ++ + if (cursorvis) + USL_XORICursor (x, y, xx, cursor, color); + +diff -urN rott-1.0/rott/rt_ted.c trunk/rott/rt_ted.c +--- rott-1.0/rott/rt_ted.c 2003-01-07 07:35:24.000000000 +0100 ++++ trunk/rott/rt_ted.c 2007-05-05 20:44:31.000000000 +0200 +@@ -1141,7 +1141,7 @@ + int ticdelay; + unsigned tempbuf; + +-#if defined(PLATFORM_MACOSX) ++#if defined(PLATFORM_MACOSX) || defined(__sparc__) + #warning "Precaching is disabled. Fix." + // Precaching confuses the byteswapping code, since we have + // no simple way of knowing the type of each resource. +diff -urN rott-1.0/rott/rt_util.c trunk/rott/rt_util.c +--- rott-1.0/rott/rt_util.c 2003-01-07 07:31:51.000000000 +0100 ++++ trunk/rott/rt_util.c 2007-05-05 20:44:31.000000000 +0200 +@@ -927,7 +927,7 @@ + { + *ptr = '\0'; + f->dir = opendir(f->pattern); +- memmove(f->pattern, ptr + 1, strlen(ptr) + 1); ++ memmove(f->pattern, ptr + 1, strlen(ptr + 1) + 1); + } + + return(_dos_findnext(f)); +@@ -1850,9 +1850,15 @@ + + return (true); + #else +- STUB_FUNCTION; ++ if (!*path) { ++ return true; ++ } + +- return false; ++ if (chdir (path) == -1) { ++ return (false); ++ } ++ ++ return true; + #endif + } + +Binary files rott-1.0/rott/spball.lib and trunk/rott/spball.lib differ +diff -urN rott-1.0/rott/version.h trunk/rott/version.h +--- rott-1.0/rott/version.h 2002-12-20 21:15:28.000000000 +0100 ++++ trunk/rott/version.h 2007-05-05 20:44:31.000000000 +0200 +@@ -17,6 +17,12 @@ + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ ++ ++#ifndef VERSION_H ++#define VERSION_H ++ + #define ROTTMAJORVERSION 1 + #define ROTTMINORVERSION 4 + #define ROTTVERSION ((ROTTMAJORVERSION*10)+(ROTTMINORVERSION)) ++ ++#endif +diff -urN rott-1.0/rott/watcom.c trunk/rott/watcom.c +--- rott-1.0/rott/watcom.c 2002-12-25 09:00:13.000000000 +0100 ++++ trunk/rott/watcom.c 2007-05-05 20:44:31.000000000 +0200 +@@ -9,11 +9,8 @@ + + fixed FixedMul(fixed a, fixed b) + { +- __int64 x = a; +- __int64 y = b; +- __int64 z = x * y + 0x8000; +- +- return (z >> 16) & 0xffffffff; ++ __int64 scratch1 = (__int64) a * (__int64) b + (__int64) 0x8000; ++ return (scratch1 >> 16) & 0xffffffff; + } + + fixed FixedMulShift(fixed a, fixed b, fixed shift) +diff -urN rott-1.0/rott/z_zone.c trunk/rott/z_zone.c +--- rott-1.0/rott/z_zone.c 2002-12-24 05:34:44.000000000 +0100 ++++ trunk/rott/z_zone.c 2007-05-05 20:44:31.000000000 +0200 +@@ -289,6 +289,12 @@ + // + size += sizeof(memblock_t); // account for size of block header + ++#if defined(__sparc__) ++ /* ensure word alignment */ ++ if (size % 4) { ++ size = size + (4 - size % 4); ++ } ++#endif + + // + // if there is a free block behind the rover, back up over them diff --git a/rott-1.0-fixes.patch b/rott-1.0-fixes.patch new file mode 100644 index 0000000..6ec3d38 --- /dev/null +++ b/rott-1.0-fixes.patch @@ -0,0 +1,11 @@ +diff -urN rott-1.0.orig/rott/rt_ted.c rott-1.0/rott/rt_ted.c +--- rott-1.0.orig/rott/rt_ted.c 2007-05-06 23:57:48.000000000 +0200 ++++ rott-1.0/rott/rt_ted.c 2007-05-06 23:45:11.000000000 +0200 +@@ -5959,6 +6020,7 @@ + ambush = (GameRandomNumber("rand actor",0) < 128); + i = randloc[locindex].x; + j = randloc[locindex].y; ++ tile = mapplanes[1][j*mapwidth + i]; + SpawnStand(randomtype,i,j,tile-122,ambush); + used[locindex] = 1; + PreCacheActor(randomtype,0); diff --git a/rott-1.0-more-fixes.patch b/rott-1.0-more-fixes.patch new file mode 100644 index 0000000..ea2e601 --- /dev/null +++ b/rott-1.0-more-fixes.patch @@ -0,0 +1,20 @@ +--- rott-1.0/rott/scriplib.c~ 2007-05-16 16:57:34.000000000 +0200 ++++ rott-1.0/rott/scriplib.c 2007-05-16 16:57:34.000000000 +0200 +@@ -43,7 +43,7 @@ + + char token[MAXTOKEN]; + char name[MAXTOKEN*2]; +-char scriptfilename[30]; ++char scriptfilename[512]; + char *scriptbuffer,*script_p,*scriptend_p; + int scriptline; + boolean endofscript; +@@ -63,7 +63,7 @@ + + size = LoadFile (filename, (void **)&scriptbuffer); + +- strcpy(&scriptfilename[0],filename); ++ snprintf(scriptfilename, sizeof(scriptfilename), "%s", filename); + script_p = scriptbuffer; + scriptend_p = script_p + size; + scriptline = 1; diff --git a/rott-1.0-registered.patch b/rott-1.0-registered.patch new file mode 100644 index 0000000..e14062c --- /dev/null +++ b/rott-1.0-registered.patch @@ -0,0 +1,13 @@ +--- rott-1.0/rott/develop.h~ 2007-05-11 10:24:32.000000000 +0200 ++++ rott-1.0/rott/develop.h 2007-05-11 10:24:32.000000000 +0200 +@@ -41,8 +41,8 @@ + + #define BNACRASHPREVENT 1 //bna added + // Make sure only one of the following are on at one time +-#define SHAREWARE 1 +-#define SUPERROTT 0 ++#define SHAREWARE 0 ++#define SUPERROTT 1 + #define SITELICENSE 0 + + // cute little dopefish thing, only works with special patch? diff --git a/rott-1.0-winrott-fixes.patch b/rott-1.0-winrott-fixes.patch new file mode 100644 index 0000000..0fd0781 --- /dev/null +++ b/rott-1.0-winrott-fixes.patch @@ -0,0 +1,1576 @@ +diff -ur rott-1.0.orig/README rott-1.0/README +--- rott-1.0.orig/README 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/README 2007-05-10 13:55:24.000000000 +0200 +@@ -55,8 +55,6 @@ + ------------ + + - Demos go out of sync. +-- DOS border coloring not implemented. +-- Screen shake from DOS version not implemented. + - No netplay support. + + +diff -ur rott-1.0.orig/rott/WinRott.h rott-1.0/rott/WinRott.h +--- rott-1.0.orig/rott/WinRott.h 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/WinRott.h 2007-05-10 13:55:24.000000000 +0200 +@@ -17,6 +17,10 @@ + + extern int iGLOBAL_FOCALWIDTH; + extern double dGLOBAL_FPFOCALWIDTH; ++ ++void EnableScreenStretch(void); ++void DisableScreenStretch(void); ++ + /* + double dYZANGLELIMIT; + +diff -ur rott-1.0.orig/rott/cin_efct.c rott-1.0/rott/cin_efct.c +--- rott-1.0.orig/rott/cin_efct.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/cin_efct.c 2007-05-10 13:55:24.000000000 +0200 +@@ -308,7 +308,9 @@ + + DrawBlankScreen ( ); + ++#ifdef DOS + VL_SetVGAPlaneMode (); ++#endif + + CinematicSetPalette (curpal); + +@@ -885,6 +887,7 @@ + int i; + int plane; + byte src[200]; ++ int width = StretchScreen? 320:iGLOBAL_SCREENWIDTH; + + DrawClearBuffer (); + +@@ -898,9 +901,9 @@ + VGAWRITEMAP(plane); + + #ifdef DOS +- for (i=plane;iheight<<2),buf++) ++ for (i=plane;iheight<<2),buf++) + #else +- for (i=0;iheight,buf++) ++ for (i=0;iheight,buf++) + #endif + { + DrawFilmPost(buf,src,height); +diff -ur rott-1.0.orig/rott/isr.c rott-1.0/rott/isr.c +--- rott-1.0.orig/rott/isr.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/isr.c 2007-05-10 13:55:24.000000000 +0200 +@@ -801,7 +801,7 @@ + delay=(VBLCOUNTER*delay)/10; + IN_ClearKeysDown(); + time=GetTicCount(); +- while (!LastScan && GetTicCount() 320)){//bna++ +- StrechMemPicture (); ++ if (StretchScreen){//bna++ ++ StretchMemPicture (); + }else{ + DrawCenterAim (); + } +@@ -719,8 +721,8 @@ + if (bufferofs > page3start) + bufferofs = page1start; + #else +- if ((StrechScreen==true)&&(iGLOBAL_SCREENWIDTH > 320)){//bna++ +- StrechMemPicture (); ++ if (StretchScreen){//bna++ ++ StretchMemPicture (); + }else{ + DrawCenterAim (); + } +@@ -732,154 +734,59 @@ + #endif + + +- +- +- +- +-// bna section ------------------------------------------- +-void StrechMemPicture () ++void EnableScreenStretch(void) + { +- +- //strech mem // SetTextMode ( ); +- byte *source,*target,*tmp,*tmp2; +- int x,y,x1,y1; +- int cnt,NbOfLines; +- float Yratio,Xratio,old; +- +- //strech pixels in X direction +- source = ( byte * )( sdl_surface->pixels);//store screen in tmp pic mem +- sdl_surfacePTR = source; +- memcpy( tmpPICbuf, source, (200*iGLOBAL_SCREENWIDTH) ); +- +- source = tmpPICbuf; +- target = ( byte * )( sdl_surface->pixels);//screen buffer +- +- Xratio = iGLOBAL_SCREENWIDTH * 10/ 320; +- Xratio = (Xratio/10); +- cnt = (int)Xratio; +- Xratio = (Xratio - cnt)/2; +- old = 0; +- +- for (y=0;y<200;y++){ +- tmp = source; +- tmp2 = target; +- //write pixel x and x-1 in line 1 +- for (x=0;x<320;x++){ +- for (x1=0;x1 1) { +- //copy extra pixel +- *(target++) = *(source) ; +- old -= 1; +- } +- } +- source++; +- } +- source = tmp + iGLOBAL_SCREENWIDTH; +- target = tmp2 + iGLOBAL_SCREENWIDTH; +- } +- +- //strech lines in Y direction +- source = ( byte * )( sdl_surface->pixels);//store screen in tmp pic mem +- memcpy( tmpPICbuf, source, (200*iGLOBAL_SCREENWIDTH) ); +- +- source = tmpPICbuf; +- target = ( byte * )( sdl_surface->pixels);//screen buffer +- +- Yratio = iGLOBAL_SCREENHEIGHT * 10/ 200;//we shall strech 200 lines to 480/600 +- Yratio = (Yratio/10); +- cnt = (int)Yratio; //2 +- Yratio = (Yratio - cnt)/2; //.2 +- NbOfLines=0;//make sure we dont exeed iGLOBAL_SCREENHEIGHT or we get a crash +- old = 0; +- +- for (y=0;y<200;y++){ +- for (y1=0;y1= iGLOBAL_SCREENHEIGHT-1){goto stopx;} +- target += (iGLOBAL_SCREENWIDTH); +- old += Yratio; +- //----------------------------------- +- if (old > 1) { +- //copy extra line +- memcpy(target, source,iGLOBAL_SCREENWIDTH); +- if (NbOfLines++ >= iGLOBAL_SCREENHEIGHT-1){goto stopx;} +- target += (iGLOBAL_SCREENWIDTH); +- old -= 1; +- } +- } +- source += iGLOBAL_SCREENWIDTH; +- } +-stopx:; +- +- +- +- ++ int i,offset; ++ ++ if (iGLOBAL_SCREENWIDTH <= 320 || StretchScreen) return; ++ ++ if (unstretch_sdl_surface == NULL) ++ { ++ /* should really be just 320x200, but there is code all over the ++ places which crashes then */ ++ unstretch_sdl_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, ++ iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT, 8, 0, 0, 0, 0); ++ } ++ ++ displayofs = unstretch_sdl_surface->pixels + ++ (displayofs - (byte *)sdl_surface->pixels); ++ bufferofs = unstretch_sdl_surface->pixels; ++ page1start = unstretch_sdl_surface->pixels; ++ page2start = unstretch_sdl_surface->pixels; ++ page3start = unstretch_sdl_surface->pixels; ++ StretchScreen = 1; + } + ++void DisableScreenStretch(void) ++{ ++ if (iGLOBAL_SCREENWIDTH <= 320 || !StretchScreen) return; ++ ++ displayofs = sdl_surface->pixels + ++ (displayofs - (byte *)unstretch_sdl_surface->pixels); ++ bufferofs = sdl_surface->pixels; ++ page1start = sdl_surface->pixels; ++ page2start = sdl_surface->pixels; ++ page3start = sdl_surface->pixels; ++ StretchScreen = 0; ++} + +-void SchrinkMemPicture( byte * source) +-{ +- //schrink mem picure and plce it in tmpPICbuf +- byte *target,*tmp,*tmp2; +- int x,y; +- int cnt,NbOfLines; +- float Yratio,Xratio,old; +- +- target = tmpPICbuf; +- +- Xratio = iGLOBAL_SCREENWIDTH * 10/ 320; +- Xratio = (Xratio/10); +- cnt = (int)Xratio; //2 +- Xratio = (Xratio - cnt)/2; //.2 +- old = 0; + +- // delte redunted pixels +- for (y=0;y= 1) { +- source++; +- old -= 1; +- } +- } +- source = tmp + iGLOBAL_SCREENWIDTH; +- target = tmp2 + iGLOBAL_SCREENWIDTH; +- } +- //delete every redunted lines +- source = tmpPICbuf;//+(1* iGLOBAL_SCREENWIDTH); +- target = tmpPICbuf; +- +- Yratio = iGLOBAL_SCREENHEIGHT * 10 / 200;//we shall schrink 480/600 lines to 200 +- Yratio = (Yratio/10); +- cnt = (int)Yratio; //2 +- Yratio = (Yratio - cnt); //.2 +- NbOfLines=0;//make sure we dont exeed iGLOBAL_SCREENHEIGHT or we get a crash +- old = 0; +-//SetTextMode ( ); +- for (y=0;y<200;y++){ +- //if (source > (tmpPICbuf+(iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT))){goto stopy;} +- memcpy(target, source, iGLOBAL_SCREENWIDTH); +- source += (cnt * iGLOBAL_SCREENWIDTH); +- old += Yratio; +- if (old > 1) { +- //delte extra line +- source += iGLOBAL_SCREENWIDTH; +- old -= 1; +- } +- target += iGLOBAL_SCREENWIDTH; +- } +- +-//stopy:; ++// bna section ------------------------------------------- ++static void StretchMemPicture () ++{ ++ SDL_Rect src; ++ SDL_Rect dest; ++ ++ src.x = 0; ++ src.y = 0; ++ src.w = 320; ++ src.h = 200; ++ ++ dest.x = 0; ++ dest.y = 0; ++ dest.w = iGLOBAL_SCREENWIDTH; ++ dest.h = iGLOBAL_SCREENHEIGHT; ++ SDL_SoftStretch(unstretch_sdl_surface, &src, sdl_surface, &dest); + } + + // bna function added start +@@ -889,7 +796,7 @@ + void DrawCenterAim () + { + int x; +- if (iG_aimCross > 0){ ++ if (iG_aimCross && !GamePaused){ + if (( ingame == true )&&(iGLOBAL_SCREENWIDTH>320)){ + if ((iG_playerTilt <0 )||(iG_playerTilt >iGLOBAL_SCREENHEIGHT/2)){ + iG_playerTilt = -(2048 - iG_playerTilt); +@@ -913,7 +820,7 @@ + } + } + for (x=4;x<=10;x++){ +- if (((iG_buf_center-(x*iGLOBAL_SCREENWIDTH)+iG_X_center) < bufofsTopLimit)&&((iG_buf_center-(x*iGLOBAL_SCREENWIDTH)+iG_X_center) > bufofsBottomLimit)){ ++ if (((iG_buf_center+(x*iGLOBAL_SCREENWIDTH)+iG_X_center) < bufofsTopLimit)&&((iG_buf_center+(x*iGLOBAL_SCREENWIDTH)+iG_X_center) > bufofsBottomLimit)){ + *(iG_buf_center+(x*iGLOBAL_SCREENWIDTH)+iG_X_center) = 75; + } + } +diff -ur rott-1.0.orig/rott/modexlib.h rott-1.0/rott/modexlib.h +--- rott-1.0.orig/rott/modexlib.h 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/modexlib.h 2007-05-10 13:55:24.000000000 +0200 +@@ -108,7 +108,7 @@ + #define PEL_DATA 0x3c9 + #endif + +-extern boolean StrechScreen;//bná++ ++extern boolean StretchScreen;//bná++ + + //extern int ylookup[MAXSCREENHEIGHT]; // Table of row offsets + extern int ylookup[600]; // just set to max res +diff -ur rott-1.0.orig/rott/rt_cfg.c rott-1.0/rott/rt_cfg.c +--- rott-1.0.orig/rott/rt_cfg.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_cfg.c 2007-05-10 13:55:24.000000000 +0200 +@@ -91,6 +91,7 @@ + //****************************************************************************** + + extern int G_weaponscale; ++extern boolean iG_aimCross; + + boolean WriteSoundFile = true; + +@@ -109,6 +110,7 @@ + boolean usemouselook = 0; + int inverse_mouse = 1; //set to -1 to invert mouse + boolean usejump = 0; ++boolean sdl_fullscreen = 1; + + boolean joystickenabled = 0; + boolean joypadenabled = 0; +@@ -507,6 +509,9 @@ + // Read in UseJump + ReadBoolean("UseJump",&usejump); + ++ // Read in CrossHair ++ ReadBoolean("CrossHair",&iG_aimCross); ++ + // Read in JoystickEnabled + ReadBoolean("JoystickEnabled",&joystickenabled); + +@@ -516,6 +521,13 @@ + // Read in JoystickPort + + ReadInt("JoystickPort",&joystickport); ++ ++ // Read in fullscreen ++ ReadBoolean("FullScreen", &sdl_fullscreen); ++ ++ // Read in resolution ++ ReadInt("ScreenWidth", &iGLOBAL_SCREENWIDTH); ++ ReadInt("ScreenHeight", &iGLOBAL_SCREENHEIGHT); + + // Read in ViewSize + +@@ -1725,6 +1737,12 @@ + SafeWriteString(file,"; 0 - usejump Disabled\n"); + WriteParameter(file,"UseJump ",usejump); + ++ // Write out CrossHair ++ SafeWriteString(file,"\n;\n"); ++ SafeWriteString(file,"; 1 - CrossHair Enabled\n"); ++ SafeWriteString(file,"; 0 - CrossHair Disabled\n"); ++ WriteParameter(file,"CrossHair ", iG_aimCross); ++ + // Write out JoystickEnabled + + SafeWriteString(file,"\n;\n"); +@@ -1746,6 +1764,19 @@ + SafeWriteString(file,"; 1 - Use Joystick Port 2\n"); + WriteParameter(file,"JoystickPort ",joystickport); + ++ // Write out fullscreen ++ SafeWriteString(file,"\n;\n"); ++ SafeWriteString(file,"; 0 - Start in windowed mode\n"); ++ SafeWriteString(file,"; 1 - Start in fullscreen mode\n"); ++ WriteParameter(file,"FullScreen ",sdl_fullscreen); ++ ++ // Write out resolution ++ SafeWriteString(file,"\n;\n"); ++ SafeWriteString(file,"; Screen Resolution, supported resolutions: \n"); ++ SafeWriteString(file,"; 320x200, 640x480 and 800x600\n"); ++ WriteParameter(file,"ScreenWidth ",iGLOBAL_SCREENWIDTH); ++ WriteParameter(file,"ScreenHeight ",iGLOBAL_SCREENHEIGHT); ++ + // Write out ViewSize + + SafeWriteString(file,"\n;\n"); +diff -ur rott-1.0.orig/rott/rt_debug.c rott-1.0/rott/rt_debug.c +--- rott-1.0.orig/rott/rt_debug.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_debug.c 2007-05-10 13:55:24.000000000 +0200 +@@ -47,7 +47,7 @@ + #include "w_wad.h" + + extern int iDemoNames; +-extern int iG_aimCross; ++extern boolean iG_aimCross; + + + extern void DisplayMessage (int num,int position); +@@ -424,7 +424,7 @@ + int level; + + +- StrechScreen=true;//bna++ shut on streech mode ++ EnableScreenStretch();//bna++ shut on streech mode + + + MU_StoreSongPosition(); +@@ -445,13 +445,13 @@ + pic_t *shape; + shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); + DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape ); +- StrechScreen=false;//dont strech when we go BACK TO GAME ++ DisableScreenStretch();//dont strech when we go BACK TO GAME + DrawPlayScreen(true);//repaint ammo and life stat + VW_UpdateScreen ();//update screen + } + //bna section end + +- StrechScreen=true;//bna++ shut on streech mode ++ EnableScreenStretch();//bna++ shut on streech mode + while( Keyboard[ sc_Escape ] ) + { + IN_UpdateKeyboard(); +@@ -475,7 +475,7 @@ + } + else + { +- StrechScreen=false;//dont strech when we go BACK TO GAME ++ DisableScreenStretch();//dont strech when we go BACK TO GAME + SetupScreen(true); + } + +@@ -494,7 +494,7 @@ + + { + if (iGLOBAL_SCREENWIDTH > 320) { +- StrechScreen=true;//bna++ shut on streech mode ++ EnableScreenStretch();//bna++ shut on streech mode + } + StopWind(); + ShutdownClientControls(); +@@ -512,7 +512,7 @@ + pic_t *shape; + shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); + DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape ); +- StrechScreen=false;//dont strech when we go BACK TO GAME ++ DisableScreenStretch();//dont strech when we go BACK TO GAME + DrawPlayScreen(true);//repaint ammo and life stat + VW_UpdateScreen ();//update screen + } +@@ -707,7 +707,7 @@ + + void RestartNormal (void) + { +- StrechScreen=true;//bna ++ EnableScreenStretch();//bna + DoNormalThing (); + + AddMessage ("Restart to level 1", MSG_CHEAT); +@@ -1037,7 +1037,7 @@ + IN_ClearKeyboardQueue (); + + StartupClientControls(); +- StrechScreen = false; ++ DisableScreenStretch(); + } + + +@@ -1082,7 +1082,7 @@ + if ((level > 0) && (level < 9)) + #endif + { +- StrechScreen=true;//bna ++ EnableScreenStretch();//bna + gamestate.mapon = level-1; + playstate = ex_demorecord; + } +@@ -1140,7 +1140,7 @@ + + StartupClientControls(); + +- StrechScreen = true; ++ EnableScreenStretch(); + } + + /* +diff -ur rott-1.0.orig/rott/rt_draw.c rott-1.0/rott/rt_draw.c +--- rott-1.0.orig/rott/rt_draw.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_draw.c 2007-05-10 13:55:24.000000000 +0200 +@@ -80,8 +80,6 @@ + ============================================================================= + */ + +-extern char *tmpPICbuf; +-extern char *sdl_surfacePTR; + int iG_masked; + + int whereami=-1; +@@ -3073,7 +3071,7 @@ + shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); + DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );//bna++ + DrawPlayScreen(false); +- StrechScreen = false; ++ DisableScreenStretch(); + SHAKETICS = 0xFFFF; + //bna section end + } +@@ -3136,7 +3134,7 @@ + //memset(RotatedImage,0xff,131072*8); + + if ((masked == false)&&(iGLOBAL_SCREENWIDTH == 800)) { +- StrechScreen = false; ++ DisableScreenStretch(); + // SetTextMode ( ); + + k=(28*512);//14336; +@@ -3152,7 +3150,7 @@ + //k+=512*2; + } + }else if ((masked == false)&&(iGLOBAL_SCREENWIDTH == 640)) { +- StrechScreen = false; ++ DisableScreenStretch(); + k=(28*512);//14336; + for (a=0;atime!=-1) + { + ScreenSaver->time-=tics; +@@ -4367,7 +4365,7 @@ + int i; + + byte pal[768]; +- StrechScreen = true; ++ EnableScreenStretch(); + + viewwidth = 320;//MAXSCREENWIDTH; + viewheight = 200;//MAXSCREENHEIGHT; +@@ -5532,7 +5530,7 @@ + + void DoEndCinematic ( void ) + { +- StrechScreen = true; ++ EnableScreenStretch(); + + viewwidth = 320;//MAXSCREENWIDTH; + viewheight = 200;//MAXSCREENHEIGHT; +@@ -5768,7 +5766,7 @@ + byte * bkgnd; + font_t * oldfont; + int i; +- StrechScreen = true; ++ EnableScreenStretch(); + viewwidth = 320;//MAXSCREENWIDTH; + viewheight = 200;//MAXSCREENHEIGHT; + +diff -ur rott-1.0.orig/rott/rt_game.c rott-1.0/rott/rt_game.c +--- rott-1.0.orig/rott/rt_game.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_game.c 2007-05-10 13:55:24.000000000 +0200 +@@ -95,7 +95,6 @@ + {"Jim",20000,2,1}, + {"Steve",10000,1,1}, + }; +-extern char *tmpPICbuf; + + //****************************************************************************** + // +@@ -1109,6 +1108,7 @@ + tempbuf=bufferofs; + bufferofs=page1start; + VW_DrawPropString (str); ++#ifdef DOS + px=x; + py=y; + bufferofs=page2start; +@@ -1117,6 +1117,7 @@ + py=y; + bufferofs=page3start; + VW_DrawPropString (str); ++#endif + bufferofs=tempbuf; + } + } +@@ -3421,11 +3422,11 @@ + EndBonusSkip = false; + EndBonusStartY = 90; + +- StrechScreen=true; ++ EnableScreenStretch(); + tmpPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 ); + VWB_DrawPic( 0, 0, tmpPic ); + VW_UpdateScreen(); +- StrechScreen=false; ++ DisableScreenStretch(); + + IN_StartAck(); + EndBonusVoice = 0; +@@ -3531,9 +3532,9 @@ + picbuf = (byte *)SafeMalloc (64000); + memcpy(picbuf ,bufferofs ,64000); + +- StrechScreen=true; ++ EnableScreenStretch(); + VW_UpdateScreen();//tmpPICbuf is destroyed here +- StrechScreen=false; ++ DisableScreenStretch(); + //copy it back + + memcpy(bufferofs ,picbuf , 64000); +@@ -3758,9 +3759,9 @@ + + + //bna section +- StrechScreen=true;//bna++ ++ EnableScreenStretch();//bna++ + VW_UpdateScreen();//bna++ +-// StrechScreen=false;//bna++ ++// DisableScreenStretch();//bna++ + //bna section end + + +@@ -4211,7 +4212,7 @@ + int Player; + char text[80]; + +- StrechScreen=true; ++ EnableScreenStretch(); + + IN_ClearKeysDown (); + +diff -ur rott-1.0.orig/rott/rt_in.c rott-1.0/rott/rt_in.c +--- rott-1.0.orig/rott/rt_in.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_in.c 2007-05-10 14:00:55.000000000 +0200 +@@ -104,6 +104,7 @@ + static word sdl_sticks_joybits = 0; + static int sdl_mouse_grabbed = 0; + static unsigned int scancodes[SDLK_LAST]; ++extern boolean sdl_fullscreen; + #endif + + +@@ -213,7 +214,7 @@ + } /* if */ + else + { +- if (sdl_mouse_grabbed) ++ if (sdl_mouse_grabbed || sdl_fullscreen) + { + mouse_relative_x = event->motion.xrel; + mouse_relative_y = event->motion.yrel; +@@ -459,11 +460,14 @@ + (event->key.state == SDL_PRESSED) && + (event->key.keysym.mod & KMOD_CTRL) ) + { ++ if (!sdl_fullscreen) ++ { + sdl_mouse_grabbed = ((sdl_mouse_grabbed) ? 0 : 1); + if (sdl_mouse_grabbed) + grab_mode = SDL_GRAB_ON; + SDL_WM_GrabInput(grab_mode); +- return(0); ++ } ++ return(0); + } /* if */ + + else if ( ( (event->key.keysym.sym == SDLK_RETURN) || +@@ -471,15 +475,19 @@ + (event->key.state == SDL_PRESSED) && + (event->key.keysym.mod & KMOD_ALT) ) + { +- SDL_Surface *surface = SDL_GetVideoSurface(); +- if (surface != NULL) +- { +- Uint32 sdl_flags = surface->flags; +- attempt_fullscreen_toggle(&surface, &sdl_flags); +- } /* if */ ++ if (SDL_WM_ToggleFullScreen(SDL_GetVideoSurface())) ++ sdl_fullscreen ^= 1; + return(0); + } /* if */ + ++ /* HDG: put this above the scancode lookup otherwise it is never reached */ ++ if ( (event->key.keysym.sym == SDLK_PAUSE) && ++ (event->key.state == SDL_PRESSED)) ++ { ++ PausePressed = true; ++ return(0); ++ } ++ + k = handle_keypad_enter_hack(event); + if (!k) + { +@@ -487,14 +495,14 @@ + if (!k) /* No DOS equivalent defined. */ + return(0); + } /* if */ +- +- if (event->key.state == SDL_RELEASED) ++ ++ /* Fix elweirdo SDL capslock/numlock handling, always treat as press */ ++ if ( (event->key.keysym.sym != SDLK_CAPSLOCK) && ++ (event->key.keysym.sym != SDLK_NUMLOCK) && ++ (event->key.state == SDL_RELEASED) ) + k += 128; /* +128 signifies that the key is released in DOS. */ + +- if (event->key.keysym.sym == SDLK_PAUSE) +- PausePressed = true; +- +- else if (event->key.keysym.sym == SDLK_SCROLLOCK) ++ if (event->key.keysym.sym == SDLK_SCROLLOCK) + PanicPressed = true; + + else +@@ -1120,7 +1128,9 @@ + scancodes[SDLK_HOME] = sc_Home; + scancodes[SDLK_UP] = sc_UpArrow; + scancodes[SDLK_PAGEUP] = sc_PgUp; +- scancodes[SDLK_KP_MINUS] = 0xE04A; ++ // Make this a normal minus, for viewport changing ++ //scancodes[SDLK_KP_MINUS] = 0xE04A; ++ scancodes[SDLK_KP_MINUS] = sc_Minus; + scancodes[SDLK_KP4] = sc_LeftArrow; + scancodes[SDLK_KP5] = 0x4C; + scancodes[SDLK_KP6] = sc_RightArrow; +diff -ur rott-1.0.orig/rott/rt_main.c rott-1.0/rott/rt_main.c +--- rott-1.0.orig/rott/rt_main.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_main.c 2007-05-10 14:33:10.000000000 +0200 +@@ -164,7 +164,8 @@ + //extern char G_argv[30][80]; + int G_weaponscale; + extern int iDropDemo; +-extern int iG_aimCross; ++extern boolean iG_aimCross; ++extern boolean sdl_fullscreen; + + extern void ComSetTime ( void ); + extern void VH_UpdateScreen (void); +@@ -220,8 +221,6 @@ + gamestate.Product = ROTT_REGISTERED; + #endif + +- SetRottScreenRes (640, 480); +- + DrawRottTitle (); + gamestate.randomseed=-1; + +@@ -248,6 +247,8 @@ + GetMenuInfo (); + } + ++ SetRottScreenRes (iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT); ++ + // if (modemgame==true) + // { + // SCREENSHOTS=true; +@@ -571,6 +572,20 @@ + SetTextMode (); + printf ("Rise of the Triad (c) 1995 Apogee Software\n\n"); + printf ("COMMAND LINE PARAMETERS\n"); ++ printf (" AIM - Give Aim Crosshair.\n"); ++ printf (" FULLSCREEN - Start in fullscreen mode\n"); ++ printf (" WINDOW - Start in windowed mode\n"); ++ printf (" RESOLUTION - Specify the screen resolution to use\n"); ++ printf (" - next param is , valid resolutions are:\n"); ++ printf (" - 320x200, 640x480 and 800x600\n"); ++#if (SHAREWARE==0) ++ printf (" FILERTL - used to load Userlevels (RTL files)\n"); ++ printf (" - next parameter is RTL filename\n"); ++ printf (" FILERTC - used to load Battlelevels (RTC files)\n"); ++ printf (" - next parameter is RTC filename\n"); ++ printf (" FILE - used to load Extern WAD files\n"); ++ printf (" - next parameter is WAD filename\n"); ++#endif + printf (" SPACEBALL - Enable check for Spaceball.\n"); + printf (" NOJOYS - Disable check for joystick.\n"); + printf (" NOMOUSE - Disable check for mouse.\n"); +@@ -593,6 +608,57 @@ + printf (" MAXTIMELIMIT - Maximimum time to count down from\n"); + printf (" next paramater is time in seconds\n"); + printf (" DOPEFISH - ?\n"); ++ printf (" \n"); ++ printf ("CONTROLS\n"); ++ printf (" Arrows - Move\n"); ++ printf (" Ctrl - Fire\n"); ++ printf (" Comma/Alt+left - Sidestep Left\n"); ++ printf (" Period/Alt+right - Sidestep Right\n"); ++ printf (" Shift - Run/Turn faster\n"); ++ printf (" Space - Use/Open\n"); ++ printf (" 1-4 - Choose Weapon\n"); ++ printf (" 5-6 - Scale Weapon Up/Down\n"); ++ printf (" Enter - Swap Weapon\n"); ++ printf (" Backspace - Turn 180\n"); ++ printf (" Delete - Drop Weapon\n"); ++ printf (" +/- - Change Viewsize\n"); ++ printf (" PgUp/PgDn - Look Up/Down\n"); ++ printf (" Home/End - Aim Up/Down\n"); ++ printf (" [ ] - Sound Volumen\n"); ++ printf (" ( ) - Music Volumen\n"); ++ printf (" Tab - Enter Automapper\n"); ++ printf (" \n"); ++ printf ("AUTO-MAPPER\n"); ++ printf (" Arrows - Scroll around\n"); ++ printf (" PgUp - Zoom Out\n"); ++ printf (" PgDn - Zoom In\n"); ++ printf (" Tab - Exit Auto-Mapper\n"); ++ printf (" \n"); ++ printf ("HOTKEYS\n"); ++ printf (" F1 - Help\n"); ++ printf (" F2 - Save Game\n"); ++ printf (" F3 - Restore Game\n"); ++ printf (" F4 - Controls/Sound/Music\n"); ++ printf (" F5 - Change Detail Level\n"); ++ printf (" F6 - Quick Save\n"); ++ printf (" F7 - Messages On/Off\n"); ++ printf (" F8 - End Game\n"); ++ printf (" F9 - Quick Load\n"); ++ printf (" F10 - Quit\n"); ++ printf (" F11 - Gamma Correction\n"); ++ printf (" \n"); ++ printf ("COMM-BAT\n"); ++ printf (" F1 - F10 - RemoteRidicule(tm) sounds\n"); ++ printf (" F12 - Live RemoteRidicule\n"); ++ printf (" T - Type message to all\n"); ++ printf (" Z - Type directed message\n"); ++ printf (" Tab - Toggle KillCount display\n"); ++ printf (" \n"); ++ printf ("SCREENSHOOT\n"); ++#ifdef DOS /* makes no sense under Linux as there are no lbm viewers there */ ++ printf (" Alt+V - Screenshoot in LBM format\n"); ++#endif ++ printf (" Alt+C - Screenshoot in PCX format\n"); + exit (0); + } + +@@ -738,25 +804,49 @@ + void SetupWads( void ) + { + char *newargs[99]; +- int argnum = 0; +-#if (SHAREWARE==0) +- int arg; +-#endif ++ int i, arg, argnum = 0; + char tempstr[129]; ++ char *PStrings[] = {"AIM", "FULLSCREEN", "WINDOW", "RESOLUTION", NULL }; + +-#if (SHAREWARE==0) +- +- +- // Check for aimcross +- arg = CheckParm ("aim"); +- if (arg!=0) ++ // These must be checked here so that they can override the cfg file ++ for (i = 1;i < _argc;i++) + { +- iG_aimCross = 1; +- }else{ +- iG_aimCross = 0; ++ arg = US_CheckParm(_argv[i],PStrings); ++ switch(arg) ++ { ++ case 0: ++ iG_aimCross = 1; ++ break; ++ case 1: ++ sdl_fullscreen = 1; ++ break; ++ case 2: ++ sdl_fullscreen = 0; ++ break; ++ case 3: ++ i++; ++ if (i < _argc) ++ { ++ int width, height; ++ if ( (sscanf(_argv[i], "%dx%d", &width, &height) == 2) && ++ ( ( (width == 320) && (height == 200) ) || ++ ( (width == 640) && (height == 480) ) || ++ ( (width == 800) && (height == 600) ) ) ) ++ { ++ iGLOBAL_SCREENWIDTH = width; ++ iGLOBAL_SCREENHEIGHT = height; ++ } ++ else ++ printf("Invalid resolution parameter: %s\n", _argv[i]); ++ } ++ else ++ printf("Missing resolution parameter\n"); ++ break; ++ } + } + + ++#if (SHAREWARE==0) + // Check for rtl files + arg = CheckParm ("filertl"); + if (arg!=0) +@@ -1049,7 +1139,7 @@ + + BATTLE_Shutdown(); + MU_StartSong(song_title); +- StrechScreen=true; ++ EnableScreenStretch(); + if ((NoWait==false)&&(!modemgame)) + { + byte dimpal[768]; +@@ -1095,9 +1185,7 @@ + break; + } + +- if (iGLOBAL_SCREENWIDTH > 320) { //need fixing, crashes by 320 ,bna + DoCreditScreen (); +- } + if ((!LastScan) && (!IN_GetMouseButtons())) + CheckHighScore (0, 0, false); + #if (SHAREWARE==0) +@@ -1147,7 +1235,7 @@ + case ex_resetgame: + + // SetTextMode ( ); //12345678 +- StrechScreen=true;//bna++ shut on streech mode ++ EnableScreenStretch();//bna++ shut on streech mode + InitCharacter(); + + InitializeMessages(); +@@ -1232,7 +1320,7 @@ + MenuFixup (); + playstate=ex_stillplaying; + +- StrechScreen=false;//bna++ shut off streech mode ++ DisableScreenStretch();//bna++ shut off streech mode + + break; + +@@ -1257,7 +1345,7 @@ + // SetTextMode ( ); //12345678 + Died (); + StopWind(); +- StrechScreen=false;//bna++ shut off streech mode ++ DisableScreenStretch();//bna++ shut off streech mode + while (damagecount>0) + DoBorderShifts(); + +@@ -1438,6 +1526,11 @@ + demoplayback = false; + + Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND); // Free current level ++ if (predemo_violence != -1) ++ { ++ gamestate.violence = predemo_violence; ++ predemo_violence = -1; ++ } + playstate=ex_titles; + break; + +@@ -1486,7 +1579,7 @@ + + { + +- StrechScreen=true;//bna++ ++ EnableScreenStretch();//bna++ + + if ( pickquick ) + { +@@ -1831,7 +1924,7 @@ + pic_t *shape; + shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); + DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape ); +- StrechScreen=false;//dont strech when we go BACK TO GAME ++ DisableScreenStretch();//dont strech when we go BACK TO GAME + DrawPlayScreen(true);//repaint ammo and life stat + VW_UpdateScreen ();//update screen + } +@@ -2319,6 +2412,7 @@ + // Shrink screen + if ( Keyboard[ sc_Minus ] ) + { ++ Keyboard[ sc_Minus ] = false; // HDG debounce + if ( viewsize > 0 ) + { + viewsize--; +@@ -2329,6 +2423,7 @@ + // Expand screen + if ( Keyboard[ sc_Plus ] ) + { ++ Keyboard[ sc_Plus ] = false; // HDG debounce + if ( viewsize < MAXVIEWSIZES - 1 ) + { + viewsize++; +@@ -2542,12 +2637,29 @@ + { + SaveScreen( false ); + } ++#ifdef DOS /* makes no sense under Linux as there are no lbm viewers there */ + else if ( Keyboard[ sc_Alt] && Keyboard[ sc_V ] ) + { + SaveScreen( true ); + } ++#endif + #endif + } ++#ifdef USE_SDL ++ /* SDL doesn't send proper release events for these */ ++ if (Keystate[sc_CapsLock]) ++ { ++ Keystate[sc_CapsLock]++; ++ if (Keystate[sc_CapsLock] == 3) ++ Keystate[sc_CapsLock] = 0; ++ } ++ if (Keystate[0x45]) /* numlock */ ++ { ++ Keystate[0x45]++; ++ if (Keystate[0x45] == 3) ++ Keystate[0x45] = 0; ++ } ++#endif + waminot(); + } + +@@ -3082,14 +3194,22 @@ + + if (saveLBM) + { +- WriteLBMfile (filename, buffer, 320, 200); ++ WriteLBMfile (filename, buffer, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT); ++#if (DEVELOPMENT == 1) + while (Keyboard[sc_CapsLock] && Keyboard[sc_C]) ++#else ++ while (Keyboard[sc_Alt] && Keyboard[sc_V]) ++#endif + IN_UpdateKeyboard (); + } + else + { + WritePCX (filename, buffer); ++#if (DEVELOPMENT == 1) + while (Keyboard[sc_CapsLock] && Keyboard[sc_X]) ++#else ++ while (Keyboard[sc_Alt] && Keyboard[sc_C]) ++#endif + IN_UpdateKeyboard (); + } + +diff -ur rott-1.0.orig/rott/rt_map.c rott-1.0/rott/rt_map.c +--- rott-1.0.orig/rott/rt_map.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_map.c 2007-05-10 13:55:24.000000000 +0200 +@@ -898,7 +898,7 @@ + int quitkey; + ControlInfo control; + +-StrechScreen = true;//bna++ ++EnableScreenStretch();//bna++ + + ShutdownClientControls(); + +@@ -1041,7 +1041,7 @@ + pic_t *shape; + shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); + DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );//bna++ +- StrechScreen=false;//dont strech when we go BACK TO GAME ++ DisableScreenStretch();//dont strech when we go BACK TO GAME + VW_UpdateScreen (); + DrawPlayScreen(true);//repaint ammo and life stat + +diff -ur rott-1.0.orig/rott/rt_menu.c rott-1.0/rott/rt_menu.c +--- rott-1.0.orig/rott/rt_menu.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_menu.c 2007-05-10 13:55:24.000000000 +0200 +@@ -38,6 +38,7 @@ + #include + #elif PLATFORM_UNIX + #include ++#include + #endif + + #include +@@ -132,8 +133,6 @@ + + int quicksaveslot=-1; + +-extern char *tmpPICbuf; +- + //****************************************************************************** + // + // LOCALS +@@ -753,17 +752,18 @@ + "MOUSELOOK", + "INVERSE MOUSE", + "CROSS HAIR", +- "JUMPING" +- ++ "JUMPING", ++ "FULLSCREEN" + }; +-CP_iteminfo ExtOptionsItems = { 20, MENU_Y, 4, 0, 43, ExtOptionsNames, mn_largefont }; ++CP_iteminfo ExtOptionsItems = { 20, MENU_Y, 5, 0, 43, ExtOptionsNames, mn_largefont }; + + CP_itemtype ExtOptionsMenu[] = + { + {1, "", 'M', NULL}, + {1, "", 'I', NULL}, + {1, "", 'C', NULL}, +- {1, "", 'J', NULL} ++ {1, "", 'J', NULL}, ++ {1, "", 'F', NULL} + }; + + //bna added end +@@ -1757,7 +1757,7 @@ + StartGame = false; + + SetUpControlPanel(); +- StrechScreen=true; ++ EnableScreenStretch(); + // + // F-KEYS FROM WITHIN GAME + // +@@ -1842,7 +1842,7 @@ + // Main menu loop. "Exit options" or "New game" exits + // + StartGame = false; +- StrechScreen=true; ++ EnableScreenStretch(); + + while( !StartGame ) + { +@@ -1861,7 +1861,7 @@ + } + + StartGame = true; +- StrechScreen=false;//bna++ shut off streech mode ++ DisableScreenStretch();//bna++ shut off streech mode + break; + + case -1: +@@ -1894,7 +1894,7 @@ + { + + MenuNum = 1; +- StrechScreen=true;//bna++ shut off streech mode ++ EnableScreenStretch();//bna++ shut off streech mode + // + // CHANGE "GAME" AND "DEMO" + // +@@ -2632,9 +2632,9 @@ + + do + { +- StrechScreen=true;//bna++ ++ EnableScreenStretch();//bna++ + DrawOrderInfo( page ); +- StrechScreen=false;//bna++ turn off or screen will be strected every time it passes VW_UpdateScreen ++ DisableScreenStretch();//bna++ turn off or screen will be strected every time it passes VW_UpdateScreen + if ( newpage ) + { + while( Keyboard[ key ] ) +@@ -2699,7 +2699,7 @@ + + Keyboard[ key ] = 0; + LastScan = 0; +- StrechScreen=true;//bna++ ++ EnableScreenStretch();//bna++ + MN_PlayMenuSnd( SD_ESCPRESSEDSND ); + } + +@@ -3173,7 +3173,7 @@ + + gamestate.battlemode = battle_StandAloneGame; + StartGame = true; +- StrechScreen=false; ++ DisableScreenStretch(); + playstate = ex_resetgame; + + +@@ -3201,7 +3201,7 @@ + action = CP_DisplayMsg( ENDGAMESTR, 12 ); + + StartGame = false; +- StrechScreen=true; ++ EnableScreenStretch(); + if ( action ) + { + EndGameStuff (); +@@ -3307,7 +3307,7 @@ + if (LoadTheGame (which, &game) == true) + { + MenuFixup (); +- StrechScreen=false; ++ DisableScreenStretch(); + StartGame = true; + exit = 1; + } +@@ -5036,7 +5036,7 @@ + + void DoMainMenu (void) + { +- StrechScreen=true;//bna++ shut on streech mode ++ EnableScreenStretch();//bna++ shut on streech mode + SetAlternateMenuBuf(); + ClearMenuBuf(); + DrawMainMenu(); +@@ -5351,6 +5351,7 @@ + extern boolean usemouselook; + extern int iG_aimCross; + extern boolean usejump; ++extern boolean sdl_fullscreen; + + void CP_ExtOptionsMenu (void) + { +@@ -5374,6 +5375,13 @@ + break; + case 2: iG_aimCross ^= 1; DrawExtOptionsButtons (); break; + case 3: usejump ^= 1; DrawExtOptionsButtons (); break; ++ case 4: ++ if (SDL_WM_ToggleFullScreen(SDL_GetVideoSurface())) ++ { ++ sdl_fullscreen ^= 1; ++ DrawExtOptionsButtons (); ++ } ++ break; + } + + } while (which >= 0); +@@ -5405,6 +5413,7 @@ + case 1: if (inverse_mouse == -1)on = 1; break; + case 2: if (iG_aimCross == 1) on = 1; break; + case 3: if (usejump == 1) on = 1; break; ++ case 4: if (sdl_fullscreen== 1) on = 1; break; + } + + if (on) +@@ -5697,7 +5706,7 @@ + if ( status ) + { + StartGame = true; +- StrechScreen=false; ++ DisableScreenStretch(); + handlewhich = -2; + playstate = ex_resetgame; + BATTLEMODE = true; +@@ -7156,7 +7165,7 @@ + + { + int i; +- StrechScreen=true; ++ EnableScreenStretch(); + // SetTextMode ( ); + + SetAlternateMenuBuf(); +@@ -7209,7 +7218,7 @@ + FlipMenuBuf(); + RefreshMenuBuf (0); + +- StrechScreen=false; ++ DisableScreenStretch(); + } + + +diff -ur rott-1.0.orig/rott/rt_net.c rott-1.0/rott/rt_net.c +--- rott-1.0.orig/rott/rt_net.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_net.c 2007-05-10 13:55:24.000000000 +0200 +@@ -95,6 +95,7 @@ + *lastdemoptr, + *demobuffer=NULL; + boolean demodone = false; ++int predemo_violence = -1; + int oldmomx; + int oldmomy; + int oldspdang; +@@ -3080,6 +3081,7 @@ + + filename[4] = (char)('0' + (byte)demonumber); + filename[6] = (char)('0' + (byte)gamestate.violence); ++ FixFilePath(filename); + } + //**************************************************************************** + // +@@ -3095,8 +3097,19 @@ + if (access (demo, F_OK) == 0) + return true; + else +- return false; +- ++ { ++ /* Saves the users violence level, only do this once, otherwise ++ we might override the saved level with one already modified by us */ ++ if (predemo_violence == -1) ++ predemo_violence = gamestate.violence; ++ /* The demos distributed with rott are all for a violence level of 3 */ ++ gamestate.violence = 3; ++ GetDemoFilename (demonumber, &demo[0]); ++ if (access (demo, F_OK) == 0) ++ return true; ++ else ++ return false; ++ } + } + + //**************************************************************************** +diff -ur rott-1.0.orig/rott/rt_net.h rott-1.0/rott/rt_net.h +--- rott-1.0.orig/rott/rt_net.h 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_net.h 2007-05-10 13:55:24.000000000 +0200 +@@ -263,6 +263,7 @@ + *lastdemoptr, + *demobuffer; + extern boolean demodone; ++extern int predemo_violence; + + void ControlPlayer (void); + void ControlRemote (objtype * ob); +diff -ur rott-1.0.orig/rott/rt_str.c rott-1.0/rott/rt_str.c +--- rott-1.0.orig/rott/rt_str.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_str.c 2007-05-10 14:11:23.000000000 +0200 +@@ -1455,7 +1455,8 @@ + + void US_CenterWindow (int w, int h) + { +- US_DrawWindow (((MaxX / 8) - w) / 2,((MaxY / 8) - h) / 2, w, h); ++ //HDG US_DrawWindow (((MaxX / 8) - w) / 2, ((MaxY / 8) - h) / 2, w, h); ++ US_DrawWindow (((iGLOBAL_SCREENWIDTH / 8) - w) / 2,((iGLOBAL_SCREENHEIGHT / 8) - h) / 2, w, h); + } + + +@@ -1521,7 +1522,7 @@ + + mask = 1 << ( px & 3 ); + +- if ((iGLOBAL_SCREENWIDTH <= 320)||(StrechScreen == true)){ ++ if ((iGLOBAL_SCREENWIDTH <= 320)||(StretchScreen == true)){ + while( width-- ) + { + VGAMAPMASK( mask ); +diff -ur rott-1.0.orig/rott/rt_ted.c rott-1.0/rott/rt_ted.c +--- rott-1.0.orig/rott/rt_ted.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_ted.c 2007-05-10 13:55:24.000000000 +0200 +@@ -74,8 +74,6 @@ + // GLOBAL VARIABLES + //======================================== + +-extern char *tmpPICbuf; +-extern int iXmas; + extern boolean UseBaseMarker; + + teamtype TEAM[MAXPLAYERS]; +@@ -1235,7 +1233,7 @@ + DrawNormalSprite (91+3+(Gs*(lastcache<<2)),573,W_GetNumForName ("led2"));//led2 progressbar + DrawNormalSprite (91+3+(Gs*(lastcache<<2)),573+3,W_GetNumForName ("led2"));//led2 progressbar + } +- StrechScreen=false;//bna++ ++ DisableScreenStretch();//bna++ + VW_UpdateScreen ();//bna++ + lastcache++; + ticdelay--; +@@ -1251,7 +1249,7 @@ + } + } + } +- StrechScreen=false;//bna++ ++ DisableScreenStretch();//bna++ + VW_UpdateScreen ();//bna++ + //I_Delay(200); + bufferofs=tempbuf; +@@ -1265,7 +1263,7 @@ + WHratio = WHratio/100; + /// iGLOBAL_SCREENWIDTH = 640; + // iGLOBAL_SCREENHEIGHT = 480; +-StrechScreen=false; ++DisableScreenStretch(); + + // Cache in fonts + // shape = W_CacheLumpNum (W_GetNumForName ("newfnt1"), PU_STATIC, Cvt_font_t, 1); +@@ -1285,7 +1283,7 @@ + while (!IN_CheckAck ()) + ; + } +- // StrechScreen=true; ++ // EnableScreenStretch(); + #if (DEVELOPMENT == 1) + tempbuf=bufferofs; + bufferofs=displayofs; +@@ -5749,6 +5747,10 @@ + SNAKELEVEL = 0; + whichpath = 0; + ++ // som of the code / calls below need bufferofs & friends to point ++ // to to the real screen, not the stretch buffer ++ DisableScreenStretch();//bna++ shut off streech mode ++ + InitializePlayerstates(); + + ResetCheatCodes(); +@@ -5898,6 +5900,8 @@ + insetupgame=false; + + tedlevel = false; // turn it off once we have done any ted stuff ++ ++ EnableScreenStretch(); + } + + +diff -ur rott-1.0.orig/rott/rt_vid.c rott-1.0/rott/rt_vid.c +--- rott-1.0.orig/rott/rt_vid.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/rt_vid.c 2007-05-10 14:13:33.000000000 +0200 +@@ -321,7 +321,8 @@ + + void VWB_DrawPic (int x, int y, pic_t *pic) + { +- if (VW_MarkUpdateBlock (x, y, x+(pic->width<<2)-1, y+(pic->height)-1)) ++ if (((iGLOBAL_SCREENWIDTH > 320) && !StretchScreen) || ++ VW_MarkUpdateBlock (x, y, x+(pic->width<<2)-1, y+(pic->height)-1)) + VL_MemToScreen ((byte *)&pic->data, pic->width, pic->height, x, y); + } + +@@ -397,7 +398,8 @@ + + void VWB_Bar (int x, int y, int width, int height, int color) + { +- if (VW_MarkUpdateBlock (x,y,x+width,y+height-1) ) ++ if (((iGLOBAL_SCREENWIDTH > 320) && !StretchScreen) || ++ VW_MarkUpdateBlock (x,y,x+width,y+height-1) ) + VL_Bar (x, y, width, height, color); + } + +@@ -1190,7 +1192,7 @@ + } + + SafeFree(origbuf); +- StrechScreen=true;//bna++ shut on streech mode ++ EnableScreenStretch();//bna++ shut on streech mode + if (flip==true) + VW_UpdateScreen (); + +diff -ur rott-1.0.orig/rott/winrott.c rott-1.0/rott/winrott.c +--- rott-1.0.orig/rott/winrott.c 2007-05-10 14:38:57.000000000 +0200 ++++ rott-1.0/rott/winrott.c 2007-05-10 13:55:24.000000000 +0200 +@@ -6,8 +6,8 @@ + + //typedef unsigned char byte; + +-int iGLOBAL_SCREENWIDTH;//bna val 800 +-int iGLOBAL_SCREENHEIGHT;//bna val 600 ++int iGLOBAL_SCREENWIDTH = 640;//bna val 800 ++int iGLOBAL_SCREENHEIGHT = 480;//bna val 600 + int iGLOBAL_SCREENBWIDE ; + int iG_SCREENWIDTH;// default screen width in bytes + +@@ -24,9 +24,7 @@ + int iG_X_center; + int iG_Y_center; + +-char *tmpPICbuf;//used to strech and schrink mem pictures +- +-int iG_aimCross = 0; ++boolean iG_aimCross = 0; + + extern int viewheight; + extern int viewwidth; +@@ -74,8 +72,6 @@ + dTopYZANGLELIMIT = (90*FINEANGLES/360);; + } + +- tmpPICbuf = malloc(iGLOBAL_SCREENHEIGHT*iGLOBAL_SCREENWIDTH); +- + //dYZANGLELIMIT = (12*FINEANGLES/360); + //#define YZANGLELIMIT (12*FINEANGLES/360)//bna--(30*FINEANGLES/360) + diff --git a/rott-1.0-winrott.patch b/rott-1.0-winrott.patch new file mode 100644 index 0000000..1082f21 --- /dev/null +++ b/rott-1.0-winrott.patch @@ -0,0 +1,5511 @@ +diff -urN rott-1.0.orig/rott/Makefile rott-1.0/rott/Makefile +--- rott-1.0.orig/rott/Makefile 2007-05-06 22:30:12.000000000 +0200 ++++ rott-1.0/rott/Makefile 2007-05-06 22:56:40.000000000 +0200 +@@ -105,7 +105,8 @@ + z_zone.o \ + byteordr.o \ + dukemusc.o \ +- audiolib/audiolib.a ++ audiolib/audiolib.a \ ++ winrott.o + $(CC) $^ $(LDLIBS) -o $@ + + clean: +diff -urN rott-1.0.orig/rott/WinRott.h rott-1.0/rott/WinRott.h +--- rott-1.0.orig/rott/WinRott.h 1970-01-01 01:00:00.000000000 +0100 ++++ rott-1.0/rott/WinRott.h 2007-05-06 22:43:18.000000000 +0200 +@@ -0,0 +1,51 @@ ++ ++ ++// winrott.h ++ ++ ++//husk at rette i winrott.c ++ ++extern int iGLOBAL_SCREENWIDTH;//bna val 800 ++extern int iGLOBAL_SCREENHEIGHT;//bna val 600 ++extern int iGLOBAL_SCREENBWIDE ; ++extern int iG_SCREENWIDTH;// default screen width in bytes ++ ++extern int iGLOBAL_HEALTH_X; ++extern int iGLOBAL_HEALTH_Y; ++extern int iGLOBAL_AMMO_X; ++extern int iGLOBAL_AMMO_Y; ++ ++extern int iGLOBAL_FOCALWIDTH; ++extern double dGLOBAL_FPFOCALWIDTH; ++/* ++double dYZANGLELIMIT; ++ ++#define FOCALWIDTH 160//160 ++#define FPFOCALWIDTH 160.0//160.0 ++ ++ ++ ++#define MAXSCREENHEIGHT 480//600// 200*2 ++#define MAXSCREENWIDTH 640//800// 320*2 ++#define SCREENBWIDE 640*(96/320)//800*(96/320)// 96*2 ++#define MAXVIEWWIDTH 640// 320*2 ++#define SCREENWIDTH 640*(96/320)//800*(96/320)// 96*2 // default screen width in bytes ++ ++ ++#define MAXSCREENHEIGHT 600 ++#define MAXSCREENWIDTH 800 ++#define SCREENBWIDE 800*(96/320) ++#define MAXVIEWWIDTH 800 ++#define SCREENWIDTH 800*(96/320)// default screen width in bytes ++ ++*/ ++//#define VIEWWIDTH MAXSCREENWIDTH//320*2 // size of view window ++//#define VIEWHEIGHT MAXSCREENHEIGHT//200*2 ++//#define MAXSCANLINES MAXSCREENHEIGHT//200*2 // size of ylookup table ++ ++ ++ ++ ++ ++ ++ +diff -urN rott-1.0.orig/rott/_rt_floo.h rott-1.0/rott/_rt_floo.h +--- rott-1.0.orig/rott/_rt_floo.h 2002-12-20 21:15:28.000000000 +0100 ++++ rott-1.0/rott/_rt_floo.h 2007-05-06 22:34:18.000000000 +0200 +@@ -20,9 +20,9 @@ + #ifndef _rt_floor_private + #define _rt_floor_private + +-#define MAXVIEWHEIGHT MAXSCREENHEIGHT ++//#define MAXVIEWHEIGHT MAXSCREENHEIGHT + #define MAXSKYSEGS 2048 + #define MAXSKYDATA 8 +-#define MINSKYHEIGHT 148 ++#define MINSKYHEIGHT 0//148 //bna++ sky change here + + #endif +diff -urN rott-1.0.orig/rott/_rt_game.h rott-1.0/rott/_rt_game.h +--- rott-1.0.orig/rott/_rt_game.h 2003-01-01 10:23:03.000000000 +0100 ++++ rott-1.0/rott/_rt_game.h 2007-05-06 22:34:18.000000000 +0200 +@@ -65,16 +65,25 @@ + #define LEADER_NAME_Y ( LEADER_Y + 2 ) + #define LEADER_WIDTH 88 + #define LEADER_HEIGHT 16 +- ++/* bna++ + #define HEALTH_X 20 + #define HEALTH_Y 185 + + #define AMMO_X 300 + #define AMMO_Y 184 ++*/ ++//-------------------- ++#define HEALTH_X 20*2 ++#define HEALTH_Y (185*2)+16 ++ ++#define AMMO_X 300*2 ++#define AMMO_Y (184*2)+16 ++//-------------------- + + #define SCORE_X 4 + #define SCORE_Y 0 + ++/* + #define KEY1_X 152 + #define KEY2_X 160 + #define KEY3_X 168 +@@ -89,7 +98,23 @@ + + #define MEN_X 216 + #define MEN_Y 0 ++*/ ++//-------------------- ++#define KEY1_X 152 ++#define KEY2_X 160 ++#define KEY3_X 168 ++#define KEY4_X 176 ++#define KEY_Y 0 + ++#define POWER_X (184) ++#define POWER_Y 0 ++ ++#define ARMOR_X 200 ++#define ARMOR_Y 0 ++ ++#define MEN_X 216 ++#define MEN_Y 0 ++//-------------------- + #define HOUR_X 7 + #define MIN_X 26 + #define SEC_X 45 +diff -urN rott-1.0.orig/rott/_rt_play.h rott-1.0/rott/_rt_play.h +--- rott-1.0.orig/rott/_rt_play.h 2002-12-20 21:15:28.000000000 +0100 ++++ rott-1.0/rott/_rt_play.h 2007-05-06 22:34:18.000000000 +0200 +@@ -21,11 +21,20 @@ + #define _rt_playr_private + + #include "watcom.h" ++//double dTopYZANGLELIMIT; in winrott.c ++#define TopYZANGLELIMIT (44*FINEANGLES/360)//bna added ++#define YZANGLELIMIT (80*FINEANGLES/360)//bna--(30*FINEANGLES/360) ++/* ++//bna++ had to limit this or the sky would fuck up ++#define TopYZANGLELIMIT (6*FINEANGLES/360)//bna added ++#define YZANGLELIMIT (40*FINEANGLES/360)//bna--(30*FINEANGLES/360) ++//partly fixed you can now se up but not down very much see rt_playr.c TopYZANGLELIMIT ++*/ + +-#define YZANGLELIMIT (30*FINEANGLES/360) +-#define YZTILTSPEED 20 +-#define SNAPBACKSPEED 10 +-#define YZHORIZONSPEED 4 ++ ++#define YZTILTSPEED 20*4//*2 = bna added ++#define SNAPBACKSPEED 10*15//*2 = bna added ++#define YZHORIZONSPEED 4*5//*2 = bna added + #define HORIZONYZOFFSET (FINEANGLES/4) + #define SetPlayerHorizon(ps,hlevel) \ + { \ +diff -urN rott-1.0.orig/rott/cin_efct.c rott-1.0/rott/cin_efct.c +--- rott-1.0.orig/rott/cin_efct.c 2002-12-24 06:16:25.000000000 +0100 ++++ rott-1.0/rott/cin_efct.c 2007-05-06 22:34:18.000000000 +0200 +@@ -253,8 +253,8 @@ + bottomscreen = topscreen + (cin_invscale*length); + cin_yl = (topscreen+FRACTIONUNIT-1)>>FRACTIONBITS; + cin_yh = (bottomscreen-FRACTIONUNIT)>>FRACTIONBITS; +- if (cin_yh >= MAXSCREENHEIGHT) +- cin_yh = MAXSCREENHEIGHT-1; ++ if (cin_yh >= iGLOBAL_SCREENHEIGHT) ++ cin_yh = iGLOBAL_SCREENHEIGHT-1; + if (cin_yl < 0) + cin_yl = 0; + if (cin_yl <= cin_yh) +@@ -354,10 +354,10 @@ + pic=(lpic_t *)W_CacheLumpName(back->name,PU_CACHE, Cvt_lpic_t, 1); + + height = pic->height; +- if (height+back->yoffset>MAXSCREENHEIGHT) +- height=MAXSCREENHEIGHT-back->yoffset; ++ if (height+back->yoffset>iGLOBAL_SCREENHEIGHT) ++ height=iGLOBAL_SCREENHEIGHT-back->yoffset; + +- if (height!=MAXSCREENHEIGHT) ++ if (height!=iGLOBAL_SCREENHEIGHT) + DrawClearBuffer (); + + plane = 0; +@@ -372,9 +372,9 @@ + VGAWRITEMAP(plane); + + #ifdef DOS +- for (i=plane;i=back->backdropwidth) +@@ -406,10 +406,10 @@ + int height; + + height = back->height; +- if (height+back->yoffset>MAXSCREENHEIGHT) +- height=MAXSCREENHEIGHT-back->yoffset; ++ if (height+back->yoffset>iGLOBAL_SCREENHEIGHT) ++ height=iGLOBAL_SCREENHEIGHT-back->yoffset; + +- if (height!=MAXSCREENHEIGHT) ++ if (height!=iGLOBAL_SCREENHEIGHT) + DrawClearBuffer (); + + plane = 0; +@@ -424,9 +424,9 @@ + VGAWRITEMAP(plane); + + #ifdef DOS +- for (i=plane;i=back->backdropwidth) +@@ -467,7 +467,7 @@ + toppost=-p->topoffset+back->yoffset; + + plane = 0; +- ++ + #ifdef DOS + for (plane=0;plane<4;plane++) + #endif +@@ -478,9 +478,9 @@ + VGAWRITEMAP(plane); + + #ifdef DOS +- for (i=plane;i=back->backdropwidth) +@@ -552,7 +552,7 @@ + // calculate edges of the shape + // + x1 = (xcent+(tx*cin_invscale))>>FRACTIONBITS; +- if (x1 >= MAXSCREENWIDTH) ++ if (x1 >= iGLOBAL_SCREENWIDTH) + return; // off the right side + tx+=p->width; + x2 = ((xcent+(tx*cin_invscale)) >>FRACTIONBITS) - 1 ; +@@ -568,7 +568,7 @@ + } + else + frac=0; +- x2 = x2 >= MAXSCREENWIDTH ? (MAXSCREENWIDTH-1) : x2; ++ x2 = x2 >= iGLOBAL_SCREENWIDTH ? (iGLOBAL_SCREENWIDTH-1) : x2; + + cin_texturemid = (((p->origsize>>1)+p->topoffset)<>1); + cin_sprtopoffset = (cin_ycenter<<16) - FixedMul(cin_texturemid,cin_invscale); +@@ -687,9 +687,9 @@ + { + #ifdef DOS + VGAMAPMASK(15); +- memset((byte *)bufferofs,0,SCREENBWIDE*MAXSCREENHEIGHT); ++ memset((byte *)bufferofs,0,iGLOBAL_SCREENBWIDE*iGLOBAL_SCREENHEIGHT); + #else +- memset((byte *)bufferofs,0,MAXSCREENWIDTH*MAXSCREENHEIGHT); ++ memset((byte *)bufferofs,0,iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT); + #endif + } + +@@ -898,9 +898,9 @@ + VGAWRITEMAP(plane); + + #ifdef DOS +- for (i=plane;iheight<<2),buf++) ++ for (i=plane;iheight<<2),buf++) + #else +- for (i=0;iheight,buf++) ++ for (i=0;iheight,buf++) + #endif + { + DrawFilmPost(buf,src,height); +diff -urN rott-1.0.orig/rott/cin_main.c rott-1.0/rott/cin_main.c +--- rott-1.0.orig/rott/cin_main.c 2002-12-24 06:16:25.000000000 +0100 ++++ rott-1.0/rott/cin_main.c 2007-05-06 22:34:18.000000000 +0200 +@@ -267,7 +267,7 @@ + + while (count--) { + *dest = cin_source[(frac>>SFRACBITS)]; +- dest += MAXSCREENWIDTH; ++ dest += iGLOBAL_SCREENWIDTH; + frac += fracstep; + } + } +diff -urN rott-1.0.orig/rott/engine.c rott-1.0/rott/engine.c +--- rott-1.0.orig/rott/engine.c 2003-01-01 10:23:03.000000000 +0100 ++++ rott-1.0/rott/engine.c 2007-05-06 22:34:18.000000000 +0200 +@@ -38,8 +38,9 @@ + + ============================================================================= + */ +- +-wallcast_t posts[321]; ++//wallcast_t posts[642];//bna++ ++wallcast_t posts[800+2];//bna++ ++//wallcast_t posts[321]; + int lasttilex; + int lasttiley; + /* +diff -urN rott-1.0.orig/rott/engine.h rott-1.0/rott/engine.h +--- rott-1.0.orig/rott/engine.h 2003-01-01 10:23:03.000000000 +0100 ++++ rott-1.0/rott/engine.h 2007-05-06 22:34:18.000000000 +0200 +@@ -19,6 +19,8 @@ + */ + #ifndef _engine_public + #define _engine_public ++ ++#include "modexlib.h" + //*************************************************************************** + // + // ENGINE.C +@@ -36,8 +38,9 @@ + int posttype; + int alttile; + } wallcast_t; +- +-extern wallcast_t posts[321]; ++extern wallcast_t posts[800+2];//bna++ JUST MAKE IT MAX RES ++//extern wallcast_t posts[642];//bna++ ++//extern wallcast_t posts[321]; + + extern int lasttilex; + extern int lasttiley; +diff -urN rott-1.0.orig/rott/lookups.c rott-1.0/rott/lookups.c +--- rott-1.0.orig/rott/lookups.c 2002-12-22 19:59:34.000000000 +0100 ++++ rott-1.0/rott/lookups.c 2007-05-06 22:34:18.000000000 +0200 +@@ -118,7 +118,8 @@ + for (i=0;ipixels; + page2start=sdl_surface->pixels; + page3start=sdl_surface->pixels; + displayofs = page1start; + bufferofs = page2start; ++ ++ iG_X_center = iGLOBAL_SCREENWIDTH / 2; ++ iG_Y_center = (iGLOBAL_SCREENHEIGHT / 2)+10 ;//+10 = move aim down a bit ++ ++ iG_buf_center = bufferofs + (screensize/2);//(iG_Y_center*iGLOBAL_SCREENWIDTH);//+iG_X_center; ++ ++ bufofsTopLimit = bufferofs + screensize - iGLOBAL_SCREENWIDTH; ++ bufofsBottomLimit = bufferofs + iGLOBAL_SCREENWIDTH; ++ + XFlipPage (); + } + +@@ -637,7 +664,7 @@ + VGAMAPMASK(15); + memset((byte *)(0xa000<<4),color,0x10000); + #else +- memset (sdl_surface->pixels, color, MAXSCREENWIDTH*MAXSCREENHEIGHT); ++ memset (sdl_surface->pixels, color, iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT); + #endif + } + +@@ -657,10 +684,17 @@ + /* C version of rt_vh_a.asm */ + + void VH_UpdateScreen (void) +-{ ++{ ++ ++ if ((StrechScreen==true)&&(iGLOBAL_SCREENWIDTH > 320)){//bna++ ++ StrechMemPicture (); ++ }else{ ++ DrawCenterAim (); ++ } + SDL_UpdateRect (SDL_GetVideoSurface (), 0, 0, 0, 0); + } + ++ + /* + ================= + = +@@ -685,8 +719,213 @@ + if (bufferofs > page3start) + bufferofs = page1start; + #else ++ if ((StrechScreen==true)&&(iGLOBAL_SCREENWIDTH > 320)){//bna++ ++ StrechMemPicture (); ++ }else{ ++ DrawCenterAim (); ++ } + SDL_UpdateRect (sdl_surface, 0, 0, 0, 0); ++ + #endif + } + + #endif ++ ++ ++ ++ ++ ++ ++// bna section ------------------------------------------- ++void StrechMemPicture () ++{ ++ ++ //strech mem // SetTextMode ( ); ++ byte *source,*target,*tmp,*tmp2; ++ int x,y,x1,y1; ++ int cnt,NbOfLines; ++ float Yratio,Xratio,old; ++ ++ //strech pixels in X direction ++ source = ( byte * )( sdl_surface->pixels);//store screen in tmp pic mem ++ sdl_surfacePTR = source; ++ memcpy( tmpPICbuf, source, (200*iGLOBAL_SCREENWIDTH) ); ++ ++ source = tmpPICbuf; ++ target = ( byte * )( sdl_surface->pixels);//screen buffer ++ ++ Xratio = iGLOBAL_SCREENWIDTH * 10/ 320; ++ Xratio = (Xratio/10); ++ cnt = (int)Xratio; ++ Xratio = (Xratio - cnt)/2; ++ old = 0; ++ ++ for (y=0;y<200;y++){ ++ tmp = source; ++ tmp2 = target; ++ //write pixel x and x-1 in line 1 ++ for (x=0;x<320;x++){ ++ for (x1=0;x1 1) { ++ //copy extra pixel ++ *(target++) = *(source) ; ++ old -= 1; ++ } ++ } ++ source++; ++ } ++ source = tmp + iGLOBAL_SCREENWIDTH; ++ target = tmp2 + iGLOBAL_SCREENWIDTH; ++ } ++ ++ //strech lines in Y direction ++ source = ( byte * )( sdl_surface->pixels);//store screen in tmp pic mem ++ memcpy( tmpPICbuf, source, (200*iGLOBAL_SCREENWIDTH) ); ++ ++ source = tmpPICbuf; ++ target = ( byte * )( sdl_surface->pixels);//screen buffer ++ ++ Yratio = iGLOBAL_SCREENHEIGHT * 10/ 200;//we shall strech 200 lines to 480/600 ++ Yratio = (Yratio/10); ++ cnt = (int)Yratio; //2 ++ Yratio = (Yratio - cnt)/2; //.2 ++ NbOfLines=0;//make sure we dont exeed iGLOBAL_SCREENHEIGHT or we get a crash ++ old = 0; ++ ++ for (y=0;y<200;y++){ ++ for (y1=0;y1= iGLOBAL_SCREENHEIGHT-1){goto stopx;} ++ target += (iGLOBAL_SCREENWIDTH); ++ old += Yratio; ++ //----------------------------------- ++ if (old > 1) { ++ //copy extra line ++ memcpy(target, source,iGLOBAL_SCREENWIDTH); ++ if (NbOfLines++ >= iGLOBAL_SCREENHEIGHT-1){goto stopx;} ++ target += (iGLOBAL_SCREENWIDTH); ++ old -= 1; ++ } ++ } ++ source += iGLOBAL_SCREENWIDTH; ++ } ++stopx:; ++ ++ ++ ++ ++} ++ ++ ++void SchrinkMemPicture( byte * source) ++{ ++ //schrink mem picure and plce it in tmpPICbuf ++ byte *target,*tmp,*tmp2; ++ int x,y; ++ int cnt,NbOfLines; ++ float Yratio,Xratio,old; ++ ++ target = tmpPICbuf; ++ ++ Xratio = iGLOBAL_SCREENWIDTH * 10/ 320; ++ Xratio = (Xratio/10); ++ cnt = (int)Xratio; //2 ++ Xratio = (Xratio - cnt)/2; //.2 ++ old = 0; ++ ++ // delte redunted pixels ++ for (y=0;y= 1) { ++ source++; ++ old -= 1; ++ } ++ } ++ source = tmp + iGLOBAL_SCREENWIDTH; ++ target = tmp2 + iGLOBAL_SCREENWIDTH; ++ } ++ //delete every redunted lines ++ source = tmpPICbuf;//+(1* iGLOBAL_SCREENWIDTH); ++ target = tmpPICbuf; ++ ++ Yratio = iGLOBAL_SCREENHEIGHT * 10 / 200;//we shall schrink 480/600 lines to 200 ++ Yratio = (Yratio/10); ++ cnt = (int)Yratio; //2 ++ Yratio = (Yratio - cnt); //.2 ++ NbOfLines=0;//make sure we dont exeed iGLOBAL_SCREENHEIGHT or we get a crash ++ old = 0; ++//SetTextMode ( ); ++ for (y=0;y<200;y++){ ++ //if (source > (tmpPICbuf+(iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT))){goto stopy;} ++ memcpy(target, source, iGLOBAL_SCREENWIDTH); ++ source += (cnt * iGLOBAL_SCREENWIDTH); ++ old += Yratio; ++ if (old > 1) { ++ //delte extra line ++ source += iGLOBAL_SCREENWIDTH; ++ old -= 1; ++ } ++ target += iGLOBAL_SCREENWIDTH; ++ } ++ ++//stopy:; ++} ++ ++// bna function added start ++extern boolean ingame; ++int iG_playerTilt; ++ ++void DrawCenterAim () ++{ ++ int x; ++ if (iG_aimCross > 0){ ++ if (( ingame == true )&&(iGLOBAL_SCREENWIDTH>320)){ ++ if ((iG_playerTilt <0 )||(iG_playerTilt >iGLOBAL_SCREENHEIGHT/2)){ ++ iG_playerTilt = -(2048 - iG_playerTilt); ++ } ++ if (iGLOBAL_SCREENWIDTH == 640){ x = iG_playerTilt;iG_playerTilt=x/2; } ++ iG_buf_center = bufferofs + ((iG_Y_center-iG_playerTilt)*iGLOBAL_SCREENWIDTH);//+iG_X_center; ++ ++ for (x=iG_X_center-10;x<=iG_X_center-4;x++){ ++ if ((iG_buf_center+x < bufofsTopLimit)&&(iG_buf_center+x > bufofsBottomLimit)){ ++ *(iG_buf_center+x) = 75; ++ } ++ } ++ for (x=iG_X_center+4;x<=iG_X_center+10;x++){ ++ if ((iG_buf_center+x < bufofsTopLimit)&&(iG_buf_center+x > bufofsBottomLimit)){ ++ *(iG_buf_center+x) = 75; ++ } ++ } ++ for (x=10;x>=4;x--){ ++ if (((iG_buf_center-(x*iGLOBAL_SCREENWIDTH)+iG_X_center) < bufofsTopLimit)&&((iG_buf_center-(x*iGLOBAL_SCREENWIDTH)+iG_X_center) > bufofsBottomLimit)){ ++ *(iG_buf_center-(x*iGLOBAL_SCREENWIDTH)+iG_X_center) = 75; ++ } ++ } ++ for (x=4;x<=10;x++){ ++ if (((iG_buf_center-(x*iGLOBAL_SCREENWIDTH)+iG_X_center) < bufofsTopLimit)&&((iG_buf_center-(x*iGLOBAL_SCREENWIDTH)+iG_X_center) > bufofsBottomLimit)){ ++ *(iG_buf_center+(x*iGLOBAL_SCREENWIDTH)+iG_X_center) = 75; ++ } ++ } ++ } ++ } ++} ++// bna function added end ++ ++ ++ ++ ++// bna section ------------------------------------------- ++ ++ ++ +diff -urN rott-1.0.orig/rott/modexlib.h rott-1.0/rott/modexlib.h +--- rott-1.0.orig/rott/modexlib.h 2007-05-06 23:57:48.000000000 +0200 ++++ rott-1.0/rott/modexlib.h 2007-05-06 22:34:18.000000000 +0200 +@@ -26,14 +26,19 @@ + #ifndef _modexlib_public + #define _modexlib_public + ++#include "WinRott.h" + #include "rt_def.h" ++/* ++int iGLOBAL_SCREENWIDTH;//bna val 800 ++int iGLOBAL_SCREENHEIGHT;//bna val 600 + +-#define MAXSCREENHEIGHT 200 +-#define MAXSCREENWIDTH 320 +-#define SCREENBWIDE 96 +-#define MAXVIEWWIDTH 320 +-#define SCREENWIDTH 96 // default screen width in bytes + ++#define MAXSCREENHEIGHT 600// 200*2 ++#define MAXSCREENWIDTH 800// 320*2 ++#define SCREENBWIDE 800*(96/320)// 96*2 ++#define MAXVIEWWIDTH 800// 320*2 ++#define SCREENWIDTH 800*(96/320)// 96*2 // default screen width in bytes ++*/ + //*************************************************************************** + // + // Video (ModeX) Constants +@@ -103,7 +108,10 @@ + #define PEL_DATA 0x3c9 + #endif + +-extern int ylookup[MAXSCREENHEIGHT]; // Table of row offsets ++extern boolean StrechScreen;//bná++ ++ ++//extern int ylookup[MAXSCREENHEIGHT]; // Table of row offsets ++extern int ylookup[600]; // just set to max res + extern int linewidth; + extern byte *page1start; + extern byte *page2start; +diff -urN rott-1.0.orig/rott/rt_cfg.c rott-1.0/rott/rt_cfg.c +--- rott-1.0.orig/rott/rt_cfg.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/rt_cfg.c 2007-05-06 22:43:28.000000000 +0200 +@@ -90,6 +90,8 @@ + // + //****************************************************************************** + ++extern int G_weaponscale; ++ + boolean WriteSoundFile = true; + + int FXMode = 0; +@@ -104,6 +106,10 @@ + }; + + boolean mouseenabled = 1; ++boolean usemouselook = 0; ++int inverse_mouse = 1; //set to -1 to invert mouse ++boolean usejump = 0; ++ + boolean joystickenabled = 0; + boolean joypadenabled = 0; + int joystickport = 0; +@@ -491,15 +497,20 @@ + if (version == ROTTVERSION) + { + // Read in MouseEnabled +- + ReadBoolean("MouseEnabled",&mouseenabled); + +- // Read in JoystickEnabled ++ // Read in UseMouseLook ++ ReadBoolean("UseMouseLook",&usemouselook); ++ ++ ReadInt("InverseMouse",&inverse_mouse); ++ ++ // Read in UseJump ++ ReadBoolean("UseJump",&usejump); + ++ // Read in JoystickEnabled + ReadBoolean("JoystickEnabled",&joystickenabled); + + // Read in JoypadEnabled +- + ReadBoolean("JoypadEnabled",&joypadenabled); + + // Read in JoystickPort +@@ -510,6 +521,19 @@ + + ReadInt("ViewSize",&viewsize); + ++ // Read in Weaponscale ++ ++ ReadInt("Weaponscale",&G_weaponscale);//bna added ++ if ((G_weaponscale <150)||(G_weaponscale>600)){ ++ if (iGLOBAL_SCREENWIDTH == 320){ ++ G_weaponscale=168; ++ }else if (iGLOBAL_SCREENWIDTH == 640){ ++ G_weaponscale=299; ++ }else if (iGLOBAL_SCREENWIDTH == 800) { ++ G_weaponscale=376; ++ } ++ } ++ + // Read in MouseAdjustment + + ReadInt("MouseAdjustment",&mouseadjustment); +@@ -1683,6 +1707,24 @@ + SafeWriteString(file,"; 0 - Mouse Disabled\n"); + WriteParameter(file,"MouseEnabled ",mouseenabled); + ++ // Write out UseMouseLook ++ SafeWriteString(file,"\n;\n"); ++ SafeWriteString(file,"; 1 - UseMouseLook Enabled\n"); ++ SafeWriteString(file,"; 0 - UseMouseLook Disabled\n"); ++ WriteParameter(file,"UseMouseLook ",usemouselook); ++ ++ // Write out InverseMouse ++ SafeWriteString(file,"\n;\n"); ++ SafeWriteString(file,"; 1 - Normal Mouse Enabled\n"); ++ SafeWriteString(file,"; -1 - Inverse Mouse Enabled\n"); ++ WriteParameter(file,"InverseMouse ",inverse_mouse); ++ ++ // Write out UseJump ++ SafeWriteString(file,"\n;\n"); ++ SafeWriteString(file,"; 1 - usejump Enabled\n"); ++ SafeWriteString(file,"; 0 - usejump Disabled\n"); ++ WriteParameter(file,"UseJump ",usejump); ++ + // Write out JoystickEnabled + + SafeWriteString(file,"\n;\n"); +@@ -1711,6 +1753,25 @@ + SafeWriteString(file,"; (smallest) 0 - 10 (largest)\n"); + WriteParameter(file,"ViewSize ",viewsize); + ++ // Write out WEAPONSCALE bna added ++ ++ SafeWriteString(file,"\n;\n"); ++ SafeWriteString(file,"; Size of Weaponscale.\n"); ++ SafeWriteString(file,"; (smallest) 150 - 600 (largest)\n"); ++ G_weaponscale = (weaponscale * 168 )/65536; ++ ++ if ((G_weaponscale <150)||(G_weaponscale>600)){ ++ if (iGLOBAL_SCREENWIDTH == 320){ ++ G_weaponscale=168; ++ }else if (iGLOBAL_SCREENWIDTH == 640){ ++ G_weaponscale=299; ++ }else if (iGLOBAL_SCREENWIDTH == 800) { ++ G_weaponscale=376; ++ } ++ } ++ WriteParameter(file,"Weaponscale ",G_weaponscale); ++ ++ + // Write out MouseAdjustment + + SafeWriteString(file,"\n;\n"); +diff -urN rott-1.0.orig/rott/rt_debug.c rott-1.0/rott/rt_debug.c +--- rott-1.0.orig/rott/rt_debug.c 2002-12-21 01:42:57.000000000 +0100 ++++ rott-1.0/rott/rt_debug.c 2007-05-06 22:34:18.000000000 +0200 +@@ -44,6 +44,13 @@ + #include + //MED + #include "memcheck.h" ++#include "w_wad.h" ++ ++extern int iDemoNames; ++extern int iG_aimCross; ++ ++ ++extern void DisplayMessage (int num,int position); + + + typedef struct { +@@ -127,6 +134,8 @@ + WEAPONFIREWALLALT, // give firewall + WEAPONGOD, // give godhand + WEAPONGODALT, // give godhand ++ AIMCROSS, // bna++ ++ AIMCROSSALT, // give bna++ + + #if (SHAREWARE == 0) + +@@ -156,7 +165,7 @@ + MAXCODES + }; + +-CodeStruct Codes[MAXCODES + 4] = ++CodeStruct Codes[MAXCODES + 6] = + { + {"KCITSPID", 8}, // enable cheats + {"CCE\\", 4}, // enable cheats +@@ -214,11 +223,11 @@ + {"PFO\\", 4}, // all keys, armor, 100% health, MP40, heatseek + {"EM68", 4}, // kill player + {"EID\\", 4}, // kill player +- {"NEER", 4}, // re-enter level ++ {"REEN", 4}, // re-enter level + {"LER\\", 4}, // re-enter level + {"OOWNHOJ", 7}, // give double pistol + {"2WG\\", 4}, // give double pistol +- {"MEGULP", 6}, // give mp40 ++ {"EMGULP", 6}, // give mp40 + {"3WG\\", 4}, // give mp40 + {"ALLINAV", 7}, // give bazooka + {"4WG\\", 4}, // give bazooka +@@ -232,6 +241,10 @@ + {"8WG\\", 4}, // give firewall + {"AYEES", 5}, // give god hand + {"9WG\\", 4}, // give god hand ++ {"MIA", 3}, // give aim bna++ ++ {"MIA\\", 4}, // give aim bna++ ++ ++ + + #if (SHAREWARE == 0) + +@@ -370,7 +383,7 @@ + = + ================ + */ +- ++#include "byteordr.h"//bna++ + void DoWarp (void) + { + /* +@@ -410,6 +423,10 @@ + + int level; + ++ ++ StrechScreen=true;//bna++ shut on streech mode ++ ++ + MU_StoreSongPosition(); + MU_StartSong( song_secretmenu); + StopWind(); +@@ -423,6 +440,18 @@ + CleanUpControlPanel(); + ShutdownMenuBuf(); + ++ //bna++ section ++ if (( playstate == ex_stillplaying )&&(iGLOBAL_SCREENWIDTH > 320)){ ++ pic_t *shape; ++ shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); ++ DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape ); ++ StrechScreen=false;//dont strech when we go BACK TO GAME ++ DrawPlayScreen(true);//repaint ammo and life stat ++ VW_UpdateScreen ();//update screen ++ } ++ //bna section end ++ ++ StrechScreen=true;//bna++ shut on streech mode + while( Keyboard[ sc_Escape ] ) + { + IN_UpdateKeyboard(); +@@ -446,6 +475,7 @@ + } + else + { ++ StrechScreen=false;//dont strech when we go BACK TO GAME + SetupScreen(true); + } + +@@ -460,12 +490,12 @@ + ================ + */ + +-void DoJukeBox +- ( +- void +- ) ++void DoJukeBox (void) + + { ++ if (iGLOBAL_SCREENWIDTH > 320) { ++ StrechScreen=true;//bna++ shut on streech mode ++ } + StopWind(); + ShutdownClientControls(); + +@@ -477,6 +507,17 @@ + CleanUpControlPanel(); + ShutdownMenuBuf(); + ++ //bna++ section ++ if (( playstate == ex_stillplaying )&&(iGLOBAL_SCREENWIDTH > 320)){ ++ pic_t *shape; ++ shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); ++ DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape ); ++ StrechScreen=false;//dont strech when we go BACK TO GAME ++ DrawPlayScreen(true);//repaint ammo and life stat ++ VW_UpdateScreen ();//update screen ++ } ++ //bna section end ++ + SetupScreen(true); + + while( Keyboard[ sc_Escape ] ) +@@ -666,6 +707,7 @@ + + void RestartNormal (void) + { ++ StrechScreen=true;//bna + DoNormalThing (); + + AddMessage ("Restart to level 1", MSG_CHEAT); +@@ -995,6 +1037,7 @@ + IN_ClearKeyboardQueue (); + + StartupClientControls(); ++ StrechScreen = false; + } + + +@@ -1039,8 +1082,9 @@ + if ((level > 0) && (level < 9)) + #endif + { +- gamestate.mapon = level-1; +- playstate = ex_demorecord; ++ StrechScreen=true;//bna ++ gamestate.mapon = level-1; ++ playstate = ex_demorecord; + } + } + +@@ -1095,6 +1139,8 @@ + IN_ClearKeyboardQueue (); + + StartupClientControls(); ++ ++ StrechScreen = true; + } + + /* +@@ -1443,6 +1489,19 @@ + FloorandCeiling (true); + break; + ++ ++ case AIMCROSS: ++ case AIMCROSSALT: ++ if (iG_aimCross == 0) { ++ iG_aimCross = 1; ++ AddMessage("Crosshair on",MSG_GAME); ++ }else{ ++ iG_aimCross = 0; ++ AddMessage("Crosshair off",MSG_GAME); ++ } ++ break; ++ ++ + case BULLETARMOR: + case BULLETARMORALT: + GiveBulletProofArmor (); +diff -urN rott-1.0.orig/rott/rt_def.h rott-1.0/rott/rt_def.h +--- rott-1.0.orig/rott/rt_def.h 2007-05-06 23:57:48.000000000 +0200 ++++ rott-1.0/rott/rt_def.h 2007-05-06 22:34:18.000000000 +0200 +@@ -154,13 +154,17 @@ + // + //*************************************************************************** + #define VIEWGLOBAL 0x10000 // globals visable flush to wall +-#define VIEWWIDTH 320 // size of view window +-#define VIEWHEIGHT 200 +-#define MAXSCANLINES 200 // size of ylookup table ++/* ++#define VIEWWIDTH MAXSCREENWIDTH//320*2 // size of view window ++#define VIEWHEIGHT MAXSCREENHEIGHT//200*2 ++#define MAXSCANLINES MAXSCREENHEIGHT//200*2 // size of ylookup table ++*/ + #define CHARWIDTH 2 + #define TILEWIDTH 4 + #define STATUSLINES 16 + ++ ++ + //*************************************************************************** + // + // Engine Constants +diff -urN rott-1.0.orig/rott/rt_draw.c rott-1.0/rott/rt_draw.c +--- rott-1.0.orig/rott/rt_draw.c 2007-05-06 23:57:48.000000000 +0200 ++++ rott-1.0/rott/rt_draw.c 2007-05-06 23:26:15.000000000 +0200 +@@ -66,6 +66,12 @@ + //MED + #include "memcheck.h" + ++ ++extern void VH_UpdateScreen (void); ++ ++ ++ ++//int testval; + /* + ============================================================================= + +@@ -74,6 +80,10 @@ + ============================================================================= + */ + ++extern char *tmpPICbuf; ++extern char *sdl_surfacePTR; ++int iG_masked; ++ + int whereami=-1; + + byte * shadingtable; +@@ -154,6 +164,8 @@ + static int netlump; + static int gmasklump; + ++int G_gmasklump; ++ + static const int weaponshape[NUMWEAPGRAPHICS] = + { + #if (SHAREWARE == 0) +@@ -274,6 +286,7 @@ + netlump=W_GetNumForName("net1"); + #endif + gmasklump=W_GetNumForName("p_gmask"); ++ G_gmasklump = gmasklump; + + preindex=0; + pretics[0]=0x10000; +@@ -2928,29 +2941,30 @@ + OUTP (CRTC_INDEX, CRTC_STARTLOW); + OUTP (CRTC_DATA, (displayofs&0x000000FF)); + // _enable(); ++ SHAKETICS = 0xFFFF; + } + + //****************************************************************************** + // + // DrawScaledScreen +-// ++// draw sreen after reentering fro restore game + //****************************************************************************** + + void DrawScaledScreen(int x, int y, int step, byte * src) + { + int xfrac; + int yfrac; +- int plane; ++// int plane; + int i,j; + byte * p; + byte * buf; + int xsize; + int ysize; + +- xsize=(320<<16)/step; +- if (xsize>320) xsize=320; +- ysize=(200<<16)/step; +- if (ysize>200) ysize=200; ++ xsize=(iGLOBAL_SCREENWIDTH<<16)/step; ++ if (xsize>iGLOBAL_SCREENWIDTH) xsize=iGLOBAL_SCREENWIDTH; ++ ysize=(iGLOBAL_SCREENHEIGHT<<16)/step; ++ if (ysize>iGLOBAL_SCREENHEIGHT) ysize=iGLOBAL_SCREENHEIGHT; + + #ifdef DOS + for (plane=x;plane>16)); ++ p=src+(iGLOBAL_SCREENWIDTH*(yfrac>>16)); + #ifdef DOS + buf=(byte *)bufferofs+ylookup[j]+(plane>>2); + #else +@@ -3010,7 +3024,12 @@ + int time; + int i; + byte * destscreen; ++ pic_t *shape;//bna++ ++ ++ + ++ ++ + fizzlein=false; + x=(18+SaveGamePicX)<<16; + y=(30+SaveGamePicY)<<16; +@@ -3020,10 +3039,11 @@ + dy=(-y)/time; + ds=-((s-0x1000000)/time); + +- destscreen=SafeMalloc(64000); ++ destscreen=SafeMalloc(64000*8);//bna fixme + + SetupScreen(false); + ThreeDRefresh(); ++ + FlipPage(); + FlipPage(); + +@@ -3042,12 +3062,20 @@ + if (y<0) y=0; + s+=(ds*tics); + } ++ + DrawScaledScreen(0,0,0x10000,destscreen); + FlipPage(); + VL_CopyDisplayToHidden (); + SafeFree(destscreen); + CalcTics(); + CalcTics(); ++ //bna++ section ++ shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); ++ DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );//bna++ ++ DrawPlayScreen(false); ++ StrechScreen = false; ++ SHAKETICS = 0xFFFF; ++ //bna section end + } + + //****************************************************************************** +@@ -3059,33 +3087,93 @@ + boolean RotateBufferStarted = false; + void StartupRotateBuffer ( int masked) + { +- int i,a,b; ++ int k;////zxcv ++ int a,b; ++ ++// int Xres = 320;//org ++// int Yres = 200;//org ++ int Xres = iGLOBAL_SCREENWIDTH;//bna val 800 ++ int Yres = iGLOBAL_SCREENHEIGHT;//bna val 600 ++ ++ ++ iG_masked = masked; + + if (RotateBufferStarted == true) + return; + + RotateBufferStarted = true; + +- RotatedImage=SafeMalloc(131072); +- if (masked==0) +- memset(RotatedImage,0,131072); +- else +- memset(RotatedImage,0xff,131072); +-#ifdef DOS +- for (i=0;i<4;i++) +-#endif +- { +- VGAREADMAP(i); +- for (a=0;a<200;a++) +-#ifdef DOS +- for (b=0;b<80;b++) +- *(RotatedImage+99+i+((a+28)<<9)+(b<<2))=*((byte *)bufferofs+(a*linewidth)+b); +-#else +- for (b=0;b<320;b++) +- *(RotatedImage+99+((a+28)<<9)+b)=*((byte *)bufferofs+(a*linewidth)+b); +-#endif +- } ++ // RotatedImage=SafeMalloc(131072);org ++ //RotatedImage=SafeMalloc(131072*8); ++ if (iGLOBAL_SCREENWIDTH == 320) { ++ RotatedImage=SafeMalloc(131072); ++ }else if (iGLOBAL_SCREENWIDTH == 640) { ++ RotatedImage=SafeMalloc(131072*4); ++ }else if (iGLOBAL_SCREENWIDTH == 800) { ++ RotatedImage=SafeMalloc(131072*8); ++ } ++//SetupScreen(false);//used these 2 to test screen size ++//VW_UpdateScreen (); ++ if (masked==0) { ++ if (iGLOBAL_SCREENWIDTH == 320) { ++ memset(RotatedImage,0,131072); ++ }else if (iGLOBAL_SCREENWIDTH == 640) { ++ memset(RotatedImage,0,131072*4); ++ }else if (iGLOBAL_SCREENWIDTH == 800) { ++ //memset(RotatedImage,0,131072);//org ++ memset(RotatedImage,0,131072*8); ++ } ++ } else { ++ if (iGLOBAL_SCREENWIDTH == 320) { ++ memset(RotatedImage,0xff,131072); ++ }else if (iGLOBAL_SCREENWIDTH == 640) { ++ memset(RotatedImage,0xff,131072*4); ++ }else if (iGLOBAL_SCREENWIDTH == 800) { ++ memset(RotatedImage,0xff,131072*8); ++ } ++ } ++ //memset(RotatedImage,0xff,131072);//org ++ //memset(RotatedImage,0xff,131072*8); ++ ++ if ((masked == false)&&(iGLOBAL_SCREENWIDTH == 800)) { ++ StrechScreen = false; ++ // SetTextMode ( ); ++ ++ k=(28*512);//14336; ++ //k=((0+28)<<10);//28672 ++ for (a=0;a 512 i difference ++*(RotatedImage+(512)+0) = bufferofs+(0*800)+0); ++*(RotatedImage+(512)+100) = bufferofs+(100*800)+0); ++*/ + + //****************************************************************************** + // +@@ -3116,30 +3204,59 @@ + int scale; + int i; + ++ ++//bna section ++// int Xh = 160;//org ++// int Yh = 100;//org ++ ++ int Xh = iGLOBAL_SCREENWIDTH/2; ++ int Yh = iGLOBAL_SCREENHEIGHT/2; ++ // Xh = 259; ++ // Yh = 109; ++ ++ time = time; ++////zxcv ++ StrechScreen=false;//bna++ ++ ++ + anglestep=((endangle-startangle)<<16)/time; + scalestep=((endscale-startscale)<<6)/time; + + angle=(startangle<<16); ++ + scale=(startscale<<6); + + CalcTics(); + CalcTics(); + for (i=0;i>16)&(FINEANGLES-1),scale>>6,0); ++ {//zxcv ++ DrawRotatedScreen(Xh,Yh, (byte *)bufferofs,(angle>>16)&(FINEANGLES-1),scale>>6,0); + FlipPage(); + scale+=(scalestep*tics); + angle+=(anglestep*tics); + CalcTics(); + } +- DrawRotatedScreen(160,100, (byte *)bufferofs,endangle&(FINEANGLES-1),endscale,0); ++ ++ DrawRotatedScreen(Xh,Yh, (byte *)bufferofs,endangle&(FINEANGLES-1),endscale,0); + FlipPage(); +- DrawRotatedScreen(160,100, (byte *)bufferofs,endangle&(FINEANGLES-1),endscale,0); ++ DrawRotatedScreen(Xh,Yh, (byte *)bufferofs,endangle&(FINEANGLES-1),endscale,0); + FlipPage(); +- DrawRotatedScreen(160,100, (byte *)bufferofs,endangle&(FINEANGLES-1),endscale,0); ++ DrawRotatedScreen(Xh,Yh, (byte *)bufferofs,endangle&(FINEANGLES-1),endscale,0); + CalcTics(); + CalcTics(); ++ //I_Delay (240);//bna++ ++ //bna++ section ++ if ( playstate == ex_stillplaying ) {//bna++ ++ pic_t *shape; ++ shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); ++ DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );//bna++ ++ StrechScreen=false;//dont strech when we go BACK TO GAME ++ DrawPlayScreen(true);//repaint ammo and life stat ++ } + } ++ //bna section end ++ ++ + + //****************************************************************************** + // +@@ -3173,60 +3290,70 @@ + //****************************************************************************** + + void DrawRotatedScreen(int cx, int cy, byte *destscreen, int angle, int scale, int masked) +-{ ++{//ZXCV + int c, s; + int xst, xct; + int y; +- int plane; ++ + byte * screen; ++ //int Xres = 320;//old value ++ //int Yres = 200;//old val ++ ++ int Xr = iGLOBAL_SCREENWIDTH;//640; ++ int Yr = (iGLOBAL_SCREENHEIGHT);//400; //bna aaaa fix + ++// SetTextMode ( ); + c = FixedMulShift(scale,costable[angle],11); + s = FixedMulShift(scale,sintable[angle],11); +- xst = (((-cx)*s)+(128<<16))-(cy*c); +- xct = (((-cx)*c)+(256<<16)+(1<<18)-(1<<16))+(cy*s); +-#ifdef DOS +- mr_xstep=s<<2; +- mr_ystep=c<<2; +-#else ++ ++// c = c/2; //these values are to rotate degres or? ++// s = s/2; ++// xst & xct= start center values ; ++ if ((iGLOBAL_SCREENWIDTH == 320 )||(masked == true)) { ++ xst = (((-cx)*s)+(128<<16))-(cy*c); ++ xct = (((-cx)*c)+(256<<16)+(1<<18)-(1<<16))+(cy*s); ++ } ++ else if ((iGLOBAL_SCREENWIDTH == 640 )&&(masked == false)) { ++ xst = (((-cx)*s)+((268)<<16))-(cy*c); ++ xct = (((-cx)*c)+((317)<<16)+(1<<18)-(1<<16))+(cy*s); ++ }//y=268;x=317 ++ else if ((iGLOBAL_SCREENWIDTH == 800 )&&(masked == false)) { ++ xst = (((-cx)*s)+((328)<<16))-(cy*c); ++ xct = (((-cx)*c)+((397)<<16)+(1<<18)-(1<<16))+(cy*s); ++ }//328 397 ++ + mr_xstep=s; + mr_ystep=c; +-#endif +- screen=destscreen; ++ ++ ++ if ((iGLOBAL_SCREENWIDTH == 800)&&(masked==0)) { ++ screen=destscreen+iGLOBAL_SCREENWIDTH;//bna aaaa fix ++ }else{ ++ screen=destscreen; ++ } + + if (masked==0) + { +-#ifdef DOS +- for (plane=0;plane<4;plane++,xst+=s,xct+=c) +-#endif +- { ++ // paint hole 800x600 screen ++ { + mr_yfrac=xct; + mr_xfrac=xst; + VGAWRITEMAP(plane); +- for (y=0; y<200; y++,mr_xfrac+=c,mr_yfrac-=s) +-#ifdef DOS +- DrawRotRow(((320-plane)>>2)+1,screen+ylookup[y]+(plane>>2),RotatedImage); +-#else +- DrawRotRow(320,screen+ylookup[y],RotatedImage); +-#endif ++ for (y=0; y>2)+1,screen+ylookup[y]+(plane>>2),RotatedImage); +-#else +- DrawMaskedRotRow(320,screen+ylookup[y],RotatedImage); +-#endif ++ for (y=0; yphase=0; + ScreenSaver->pausetime=PAUSETIME; ++ if (iGLOBAL_SCREENWIDTH == 320){ ++ ScreenSaver->pausex=120; ++ ScreenSaver->pausey=84; ++ }else if (iGLOBAL_SCREENWIDTH == 640){ ++ ScreenSaver->pausex=240; ++ ScreenSaver->pausey=201; ++ }else if (iGLOBAL_SCREENWIDTH == 800){ ++ ScreenSaver->pausex=300; ++ ScreenSaver->pausey=252; ++ } + ScreenSaver->pausex=120; + ScreenSaver->pausey=84; + SetupScreenSaverPhase(); +@@ -3517,6 +3660,9 @@ + + ShutdownRotateBuffer (); + SafeFree(ScreenSaver); ++ //bna section ++ StartupClientControls(); ++ + } + + //****************************************************************************** +@@ -3529,6 +3675,7 @@ + #define MAXSPEED 8 + void UpdateScreenSaver ( void ) + { ++ //StrechScreen = true; + if (ScreenSaver->time!=-1) + { + ScreenSaver->time-=tics; +@@ -3548,9 +3695,9 @@ + ScreenSaver->dx=abs(ScreenSaver->dx); + ScreenSaver->dy+=(RandomNumber("Rotate",0)>>6)-2; + } +- else if (ScreenSaver->x>320-SPINSIZE) ++ else if (ScreenSaver->x>iGLOBAL_SCREENWIDTH-SPINSIZE) + { +- ScreenSaver->x=320-SPINSIZE; ++ ScreenSaver->x=iGLOBAL_SCREENWIDTH-SPINSIZE; + ScreenSaver->dx=-(abs(ScreenSaver->dx)); + ScreenSaver->dy+=(RandomNumber("Rotate",0)>>6)-2; + } +@@ -3560,9 +3707,9 @@ + ScreenSaver->dy=abs(ScreenSaver->dy); + ScreenSaver->dx+=(RandomNumber("Rotate",0)>>6)-2; + } +- else if (ScreenSaver->y>200-SPINSIZE) ++ else if (ScreenSaver->y>iGLOBAL_SCREENHEIGHT-SPINSIZE) + { +- ScreenSaver->y=200-SPINSIZE; ++ ScreenSaver->y=iGLOBAL_SCREENHEIGHT-SPINSIZE; + ScreenSaver->dy=-(abs(ScreenSaver->dy)); + ScreenSaver->dx+=(RandomNumber("Rotate",0)>>6)-2; + } +@@ -3577,11 +3724,19 @@ + + ScreenSaver->pausetime-=tics; + if (ScreenSaver->pausetime<=0) +- { ++ { + ScreenSaver->pausetime=PAUSETIME; +- ScreenSaver->pausex=RandomNumber ("pausex",0)%240; +- ScreenSaver->pausey=RandomNumber ("pausey",0)%168; +- } ++ if (iGLOBAL_SCREENWIDTH == 320){ ++ ScreenSaver->pausex=RandomNumber ("pausex",0)%240; ++ ScreenSaver->pausey=RandomNumber ("pausey",0)%168; ++ }else if (iGLOBAL_SCREENWIDTH == 640){ ++ ScreenSaver->pausex=RandomNumber ("pausex",0)%480; ++ ScreenSaver->pausey=RandomNumber ("pausey",0)%403; ++ }else if (iGLOBAL_SCREENWIDTH == 800){ ++ ScreenSaver->pausex=RandomNumber ("pausex",0)%600; ++ ScreenSaver->pausey=RandomNumber ("pausey",0)%504; ++ } ++ } + DrawPauseXY (ScreenSaver->pausex, ScreenSaver->pausey); + + FlipPage(); +@@ -3958,10 +4113,10 @@ + + void DrawBackground ( byte * bkgnd ) + { +- int plane; ++// int plane; + int size; + +- size=linewidth*200; ++ size=linewidth*400; + + #ifdef DOS + for (plane=0;plane<4;plane++) +@@ -3982,10 +4137,10 @@ + + void PrepareBackground ( byte * bkgnd ) + { +- int plane; ++// int plane; + int size; + +- size=linewidth*200; ++ size=linewidth*400; + + #ifdef DOS + for (plane=0;plane<4;plane++) +@@ -4212,10 +4367,10 @@ + int i; + + byte pal[768]; ++ StrechScreen = true; + +- +- viewwidth = MAXSCREENWIDTH; +- viewheight = MAXSCREENHEIGHT; ++ viewwidth = 320;//MAXSCREENWIDTH; ++ viewheight = 200;//MAXSCREENHEIGHT; + + MU_StartSong(song_youwin); + +@@ -5377,8 +5532,10 @@ + + void DoEndCinematic ( void ) + { +- viewwidth = MAXSCREENWIDTH; +- viewheight = MAXSCREENHEIGHT; ++ StrechScreen = true; ++ ++ viewwidth = 320;//MAXSCREENWIDTH; ++ viewheight = 200;//MAXSCREENHEIGHT; + MU_FadeOut ( 1000 ); + MU_StopSong (); + +@@ -5611,13 +5768,16 @@ + byte * bkgnd; + font_t * oldfont; + int i; +- +- viewwidth = MAXSCREENWIDTH; +- viewheight = MAXSCREENHEIGHT; ++ StrechScreen = true; ++ viewwidth = 320;//MAXSCREENWIDTH; ++ viewheight = 200;//MAXSCREENHEIGHT; + + bkgnd=SafeMalloc(800*linewidth); ++ + trilogo=W_GetNumForName("trilogo"); + VL_DrawPostPic (trilogo); ++// SetTextMode ( ); ++ + PrepareBackground ( bkgnd ); + + oldfont=CurrentFont; +@@ -5711,7 +5871,7 @@ + + FlipPage(); + MenuFadeIn(); +- I_Delay (280); ++ I_Delay (100);//240 + + VL_FadeOut (0, 255, 0, 0, 0, 20); + } +@@ -5743,23 +5903,86 @@ + void DrawRotRow(int count, byte * dest, byte * src) + { + unsigned eax, ecx, edx; ++// unsigned a, b, c,d; ++ byte * srctmp; ++ byte * desttmp; + + ecx = mr_yfrac; + edx = mr_xfrac; + +- while (count--) { +- eax = edx >> 16; +- if (eax < 256 && (ecx >> 16) < 512) { +- eax = (eax << 9) | ((ecx << 7) >> (32-9)); ++ if ((iGLOBAL_SCREENWIDTH == 320)||(iG_masked==true)) ++ { ++ while (count--) { ++ eax = edx >> 16; ++ if (eax < 256 && (ecx >> 16) < 512) { ++ eax = (eax << 9) | ((ecx << 7) >> (32-9)); ++ } else { ++ eax = 0; ++ } ++ ++ *dest++ = src[eax]; ++ ++ edx += mr_xstep; ++ ecx += mr_ystep; ++ } ++ }else if (iGLOBAL_SCREENWIDTH == 640) { ++ while (count--) { ++ eax = edx >> 16; ++ if (eax < (256*2.0) && (ecx >> 16) < (512*1.8)) { ++ eax = (eax << 10) | ((ecx << 6) >> (32-10)); ++ } else { ++ eax = 0; ++ } ++ ++ *dest++ = src[eax]; ++ ++ edx += mr_xstep; ++ ecx += mr_ystep; ++ } ++ }else if (iGLOBAL_SCREENWIDTH == 800) { ++ ++ ++ ++ srctmp = src; ++ desttmp = dest; ++ ++ desttmp -= (iGLOBAL_SCREENWIDTH*1); ++ ++ ecx = mr_yfrac; ++ edx = mr_xfrac; ++ //count = 800 ++//zxcv ++ while (count--) { ++ eax = edx >> 16;//edx=4146069504 eax=63264 edx/eax = 65536->0x10000 ++ ++ //a=(eax << 9); //=eax*512 ++ //a=(eax << 7); //=eax*128 ++ //a=512|128; = 640; ++ //SetTextMode ( ); ++ //a=(ecx >> 16);//ecx=4102225920 a=62595 ecx/65536 = 62595 ++ ++ // Y-dir x-dir ++ if (eax < (256*2.5) && (ecx >> 16) < (512*2)) { ++ //eax = (eax << 9) | ((ecx << 7) >> (32-9)); ++ eax = (eax << 10) | ((ecx << 6) >> (32-10)); ++ /* eax = (eax * 512*2) ; ++ //(23) ++ eax += ((ecx ) >> (32-9));//ecx=196608 ++ */ + } else { + eax = 0; ++ ++ + } +- +- *dest++ = src[eax]; ++ //desttmp -= centeroffset; ++ *desttmp++ = srctmp[eax]; ++ //*desttmp++ = srctmp[eax]; + + edx += mr_xstep; + ecx += mr_ystep; + } ++ ++ } + } + + void DrawMaskedRotRow(int count, byte * dest, byte * src) +@@ -5788,15 +6011,58 @@ + + void DrawSkyPost (byte * buf, byte * src, int height) + { +- while (height--) { +- *buf = shadingtable[*src]; ++// bna fix for missing sky by high res eg 800x600 ++// when sky is >400 (max skyheight) then reverse mouintain to missing spot ++// there should be 200 line of mouintain (400+200) = 600 height lines ++// not the best solution but what it works ++ ++ if (iGLOBAL_SCREENWIDTH > 320){ ++ // bna section start ++ //int n = 0; ++ int orgh = 0;//height; ++ if (height > 400){orgh=height;} ++ ++ while (height--) { ++ if ((orgh > 0)&&( height<(orgh-400))){ ++ src-=2; ++ *buf = shadingtable[*src]; ++ }else{ ++ ++ *buf = shadingtable[*src]; ++ } ++ buf += linewidth; ++ src++; ++ } ++ // bna section end ++ } ++ else { ++ // org code ++ while (height--) { ++ *buf = shadingtable[*src]; ++ ++ buf += linewidth; ++ src++; ++ } ++ // ++ } ++ ++ /* ++ int lw = linewidth * 2; ++ int h = height; ++ ++ while (h--) { ++ *(buf) = shadingtable[*src]; ++ buf += lw; ++ *(buf) = shadingtable[*src]; ++ buf += lw; + +- buf += linewidth; ++ //buf += lw; + src++; +- } ++ ++ }*/ + } + +-#define CEILINGCOLOR 24 ++#define CEILINGCOLOR 24 //default color when no sky or floor + #define FLOORCOLOR 32 + + void RefreshClear (void) +@@ -5812,7 +6078,7 @@ + start = min(centery, viewheight); + + if (start > 0) { +- VL_Bar(0, 0, MAXSCREENWIDTH, start, CEILINGCOLOR); ++ VL_Bar(0, 0, iGLOBAL_SCREENHEIGHT, start, CEILINGCOLOR); + } else { + start = 0; + } +@@ -5821,7 +6087,7 @@ + + start = min(viewheight-start, viewheight); + if (start > 0) { +- VL_Bar(0, base, MAXSCREENWIDTH, start, FLOORCOLOR); ++ VL_Bar(0, base, iGLOBAL_SCREENHEIGHT, start, FLOORCOLOR); + } + } + +diff -urN rott-1.0.orig/rott/rt_floor.c rott-1.0/rott/rt_floor.c +--- rott-1.0.orig/rott/rt_floor.c 2002-12-24 06:16:28.000000000 +0100 ++++ rott-1.0/rott/rt_floor.c 2007-05-06 22:34:18.000000000 +0200 +@@ -75,21 +75,25 @@ + + static byte *floor; + static byte *ceiling; +-static int xstarts[MAXVIEWHEIGHT]; ++//static int xstarts[MAXVIEWHEIGHT]; ++static int xstarts[600];//set to max hight res + static byte * skysegs[MAXSKYSEGS]; + static byte * skydata[MAXSKYDATA]; + static int horizonheight; + static int centerskypost; + static int oldsky=-1; + ++ ++//bna fixit skyerror by 800x600 clouds not big enough ++ + void DrawSky( void ) + { + + byte * src; + int dest; +- int plane; ++// int plane; + int height; +- int height2; ++// int height2; + int ang; + int angle; + int ofs; +@@ -106,11 +110,11 @@ + { + ofs=centerskypost; + } +- else if (((centerskypost-ofs)+viewheight)>399) ++ else if (((centerskypost-ofs)+viewheight)>1799) + { +- ofs=-(399-(centerskypost+viewheight)); ++ ofs=-(1799-(centerskypost+viewheight)); + } +- ++//ofs=centerskypost; + #ifdef DOS + if (doublestep>0) + { +@@ -200,9 +204,9 @@ + { + ofs=centerskypost; + } +- else if (((centerskypost-ofs)+viewheight)>399) ++ else if (((centerskypost-ofs)+viewheight)>599) + { +- ofs=-(399-(centerskypost+viewheight)); ++ ofs=-(599-(centerskypost+viewheight)); + } + + bufferofs+=screenofs; +@@ -269,16 +273,23 @@ + byte * ptr; + int c; + +- temp=SafeMalloc(256*400); ++ temp=SafeMalloc(256*800); + + ptr=temp; + + for (c=0;c<256;c++) + { ++ + memcpy(ptr,skydata[1]+(c*200),200); + ptr+=200; ++ + memcpy(ptr,skydata[0]+(c*200),200); + ptr+=200; ++ ++ //memcpy(ptr,skydata[1]+(c*200),200); ++ //ptr+=200; ++ //memcpy(ptr,skydata[0]+(c*200),200); ++ //ptr+=200; + } + skydata[0]=temp; + } +@@ -425,7 +436,7 @@ + else + ceilingnum = MAPSPOT(1,0,0)-197; + +- floornum = MAPSPOT(0,0,0)-179; ++ floornum = MAPSPOT(0,0,0)-(179); + + floornum = GetFloorCeilingLump ( floornum ); + //ceilingnum = GetFloorCeilingLump ( ceilingnum ); +diff -urN rott-1.0.orig/rott/rt_game.c rott-1.0/rott/rt_game.c +--- rott-1.0.orig/rott/rt_game.c 2007-05-06 23:57:48.000000000 +0200 ++++ rott-1.0/rott/rt_game.c 2007-05-06 22:43:28.000000000 +0200 +@@ -82,7 +82,8 @@ + SD_PLAYERLNSND, SD_PLAYERIPFSND}; + + +-int SHAKETICS = 0xFFFF; ++unsigned short SHAKETICS = 0xFFFF;//bna++ ++//int SHAKETICS = 0xFFFF; + int damagecount = 0; + HighScore Scores[MaxScores] = + { +@@ -94,7 +95,7 @@ + {"Jim",20000,2,1}, + {"Steve",10000,1,1}, + }; +- ++extern char *tmpPICbuf; + + //****************************************************************************** + // +@@ -161,8 +162,13 @@ + #define NUMBONUSES 11 + #define BONUSBONUS 100000 + +-void DrawPPic (int xpos, int ypos, int width, int height, byte *src, int num, boolean up, boolean bufferofsonly); + ++extern void VL_MemToScreenClipped (byte *source, int width, int height, int x, int y); ++void DrawPPic (int xpos, int ypos, int width, int height, byte *src, int num, boolean up, boolean bufferofsonly); ++extern void MoveScreenUpLeft(); ++extern void MoveScreenUpRight(); ++extern void MoveScreenDownLeft(); ++extern void MoveScreenDownRight(); + //****************************************************************************** + // + // V_ReDrawBkgnd () +@@ -415,19 +421,50 @@ + // DrawPlayScreen () + // + //****************************************************************************** +-void DrawPlayScreen +- ( +- boolean bufferofsonly +- ) ++void DrawPlayScreen (boolean bufferofsonly) + + { + pic_t *shape; + int shapenum; ++ int ShowKillsYoffset = 0;//bna++ ++ ++//return; + + if ( SHOW_TOP_STATUS_BAR() ) + { +- shape = W_CacheLumpName( "stat_bar", PU_CACHE, Cvt_pic_t, 1 ); +- GameMemToScreen( shape, 0, 0, bufferofsonly ); ++ if (iGLOBAL_SCREENWIDTH == 640) { ++ //use this as dummy pic to fill out missing bar ++ shape = ( pic_t * ) W_CacheLumpName( "bottbar", PU_CACHE, Cvt_pic_t, 1 ); ++ //GameMemToScreen( shape, 0, 0, bufferofsonly ); ++ GameMemToScreen( shape, 320, 0, bufferofsonly ); ++ // delete hart in middle of topbar ++ DrawPPic( 323,1, 8 >> 2, 16, ++ ( byte * )&erase->data, 2, true, bufferofsonly ); ++ // delete bullet in end of topbar ++ DrawPPic( 620,1, 8 >> 2, 16, ++ ( byte * )&erase->data, 2, true, bufferofsonly ); ++ shape = ( pic_t * )W_CacheLumpName( "stat_bar", PU_CACHE, Cvt_pic_t, 1 ); ++ GameMemToScreen( shape, 0, 0, bufferofsonly ); ++ }else if (iGLOBAL_SCREENWIDTH == 800) { ++ //use this as dummy pic to fill out missing bar ++ shape = ( pic_t * ) W_CacheLumpName( "bottbar", PU_CACHE, Cvt_pic_t, 1 ); ++ GameMemToScreen( shape, 0, 0, bufferofsonly ); ++ GameMemToScreen( shape, 260, 0, bufferofsonly ); ++ GameMemToScreen( shape, 800-320, 0, bufferofsonly ); ++ // delete hart in middle of topbar ++ DrawPPic( 480+3,1, 8 >> 2, 16, ++ ( byte * )&erase->data, 2, true, bufferofsonly ); ++ // delete bullet in end of topbar ++ DrawPPic( 780,1, 8 >> 2, 16, ++ ( byte * )&erase->data, 2, true, bufferofsonly ); ++ shape = ( pic_t * )W_CacheLumpName( "stat_bar", PU_CACHE, Cvt_pic_t, 1 ); ++ GameMemToScreen( shape, 0, 0, bufferofsonly ); ++ }else if (iGLOBAL_SCREENWIDTH == 320) { ++ ++ //SetTextMode ( ); ++ shape = ( pic_t * )W_CacheLumpName( "stat_bar", PU_CACHE, Cvt_pic_t, 1 ); ++ GameMemToScreen( shape, 0, 0, bufferofsonly ); ++ } + } + + if ( BATTLEMODE ) +@@ -441,43 +478,93 @@ + + if ( SHOW_KILLS() ) + { +- GameMemToScreen( shape, 0, 160, bufferofsonly ); +- } +- else +- { +- GameMemToScreen( shape, 0, 184, bufferofsonly ); ++ ShowKillsYoffset = KILLS_HEIGHT; ++ //shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); ++ //DrawTiledRegion( 0, 584, iGLOBAL_SCREENWIDTH, 32-16, 0, 16, shape );//bna++ ++ ++ ++ // health_y = iGLOBAL_HEALTH_Y; ++ // if ( SHOW_KILLS() ) ++ // { ++ // health_y -= KILLS_HEIGHT; ++ //GameMemToScreen( shape, 0, (iGLOBAL_SCREENHEIGHT-40)+16, bufferofsonly ); ++ ++ //GameMemToScreen( shape, 0, 160, bufferofsonly );bna++ ++ } ++ //else ++ { ++ ++ if (iGLOBAL_SCREENWIDTH == 640) { ++ //bna fix - not to good? but no one has 286 any more ++ //statusbar dosent cover hole screen, because its a lump picture width max 320 ++ //first write dummy shape and next over it ++ GameMemToScreen( shape, 320, (224*2)+16-ShowKillsYoffset, bufferofsonly ); ++ //copy next shape to mem ++ GameMemToScreen( shape, 0, (224*2)+16-ShowKillsYoffset, bufferofsonly ); ++ // delete bullet in middle of shape picture ++ DrawPPic( 310, (224*2)+17-ShowKillsYoffset, 8 >> 2, 16, ++ ( byte * )&erase->data, 2, true, bufferofsonly ); ++ // delete hart in middle of shape picture ++ DrawPPic( 324, (224*2)+17-ShowKillsYoffset, 8 >> 2, 16, ++ ( byte * )&erase->data, 2, true, bufferofsonly ); ++ ++ }else if (iGLOBAL_SCREENWIDTH == 800) { ++ GameMemToScreen( shape, 800-320, 584-ShowKillsYoffset, bufferofsonly ); ++ //copy next shape to mem ++ GameMemToScreen( shape, 300, 584-ShowKillsYoffset, bufferofsonly ); ++ //copy next shape to mem ++ GameMemToScreen( shape, 0, 584-ShowKillsYoffset, bufferofsonly ); ++ // delete 2 bullets in middle of shape picture ++ DrawPPic( 305, 584+1-ShowKillsYoffset, 8 >> 2, 16, ++ ( byte * )&erase->data, 2, true, bufferofsonly ); ++ // delete hart in middle of shape picture ++ DrawPPic( 610, 584+1-ShowKillsYoffset, 8 >> 2, 16, ++ ( byte * )&erase->data, 2, true, bufferofsonly ); ++ ++ }else{ ++ GameMemToScreen( shape, 0, 184, bufferofsonly ); ++ } + } + + DrawBarAmmo( bufferofsonly ); + DrawBarHealth( bufferofsonly ); + + if ( demoplayback ) +- { +- shape = ( pic_t * )W_CacheLumpName( "demo", PU_CACHE, Cvt_pic_t, 1 ); +- DrawPPic( 148, 185, shape->width, shape->height, +- ( byte * )&shape->data, 1, true, bufferofsonly ); +- } +- } ++ { ++ shape = ( pic_t * )W_CacheLumpName( "demo", PU_CACHE, Cvt_pic_t, 1 ); ++ if (iGLOBAL_SCREENWIDTH == 640) { ++ //DrawPPic( 148, 185, shape->width, shape->height, ++ // ( byte * )&shape->data, 1, true, bufferofsonly );bna ++ DrawPPic( 148*2, 465, shape->width, shape->height, ++ ( byte * )&shape->data, 1, true, bufferofsonly ); ++ }else if (iGLOBAL_SCREENWIDTH == 800) { ++ DrawPPic( 380, 585, shape->width, shape->height, ++ ( byte * )&shape->data, 1, true, bufferofsonly ); ++ }else{ ++ DrawPPic( 148, 185, shape->width, shape->height, ++ ( byte * )&shape->data, 1, true, bufferofsonly ); ++ } ++ } ++ } + + if ( !SHOW_TOP_STATUS_BAR() ) + { + return; + } + +- ++//draws small player picture and name in topbar + oldsec = -1; + + DrawTime( bufferofsonly ); + + if ( !BATTLEMODE ) +- { ++ { + int character; + int width; + int height; + + character = locplayerstate->player; +- GameMemToScreen( men[ character ], MEN_X, MEN_Y, +- bufferofsonly ); ++ GameMemToScreen( men[ character ], MEN_X, MEN_Y,bufferofsonly ); + + CurrentFont = tinyfont; + +@@ -605,6 +692,7 @@ + int playernum; + int playerimage; + int temp; ++ int iKILLS_Y; + pic_t *pic; + + CurrentFont = tinyfont; +@@ -757,12 +845,23 @@ + } + + // Only draw the rest of the rifraff when the kill count is selected ++ + if ( !SHOW_KILLS() ) + { + return; + } +- ++// SetTextMode ( ); + // Draw all the other losers ++ //#define KILLS_Y 176 ++ iKILLS_Y = iGLOBAL_SCREENHEIGHT - 24; ++ //draw blank status pic->width = 8;pic->height = 24 ++ pic = blankfragpic; ++ for (temp = iGLOBAL_SCREENWIDTH-pic->width-24;temp > pic->width; temp -= pic->width){ ++ DrawPPic( temp, iKILLS_Y, pic->width, pic->height, ++ (byte *)&pic->data, 1, true, bufferofsonly ); ++ ++ } ++ + xpos = KILLS_X; + for( rank = 0; rank < BATTLE_NumberOfTeams; rank++ ) + { +@@ -790,7 +889,7 @@ + pic = frag100pic[ PLAYERSTATE[ playerimage ].player ]; + } + } +- DrawPPic( xpos, KILLS_Y, pic->width, pic->height, ++ DrawPPic( xpos, iKILLS_Y, pic->width, pic->height, + (byte *)&pic->data, 1, true, bufferofsonly ); + + // Draw number of points +@@ -808,13 +907,13 @@ + { + width = 3; + } +- DrawNumber( xpos + KILLS_OFFSET + 16 - ( 8 * width ), KILLS_Y, width, 4, bufferofsonly); ++ DrawNumber( xpos + KILLS_OFFSET + 16 - ( 8 * width ), iKILLS_Y, width, 4, bufferofsonly); + } + else + { +- pic = W_CacheLumpName( "minus", PU_CACHE, Cvt_pic_t, 1 ); +- StatusDrawColoredPic( ( xpos + KILLS_OFFSET ), KILLS_Y, pic, bufferofsonly, playeruniformcolor ); +- StatusDrawColoredPic( ( xpos + KILLS_OFFSET + 8 ), KILLS_Y, pic, bufferofsonly, playeruniformcolor ); ++ pic = ( pic_t * )W_CacheLumpName( "minus", PU_CACHE, Cvt_pic_t, 1 ); ++ StatusDrawColoredPic( ( xpos + KILLS_OFFSET ), iKILLS_Y, pic, bufferofsonly, playeruniformcolor ); ++ StatusDrawColoredPic( ( xpos + KILLS_OFFSET + 8 ), iKILLS_Y, pic, bufferofsonly, playeruniformcolor ); + } + + // Get codename +@@ -835,7 +934,7 @@ + // Advance to next position + xpos += KILLS_WIDTH; + +- if ( xpos >= 320 ) ++ if ( xpos >= iGLOBAL_SCREENWIDTH ) + { + break; + } +@@ -843,13 +942,13 @@ + + for( rank = BATTLE_NumberOfTeams; rank <= MAXKILLBOXES; rank++ ) + { +- if ( xpos >= 320 ) ++ if ( xpos >= iGLOBAL_SCREENWIDTH ) + { + break; + } + + pic = blankfragpic; +- DrawPPic( xpos, KILLS_Y, pic->width, pic->height, ++ DrawPPic( xpos, iKILLS_Y, pic->width, pic->height, + (byte *)&pic->data, 1, true, bufferofsonly ); + + // Advance to next position +@@ -888,11 +987,11 @@ + friend = ( pic_t * )W_CacheLumpName( "t_friend", PU_CACHE, Cvt_pic_t, 1 ); + enemy = ( pic_t * )W_CacheLumpName( "t_enemy", PU_CACHE, Cvt_pic_t, 1 ); + +- // Draw all the losers ++ // Draw all the losers + CurrentFont = tinyfont; + +- xpos = ( 320 - min( numplayers, MAXKILLBOXES ) * KILLS_WIDTH ) / 2; +- ++ xpos = (iGLOBAL_SCREENWIDTH - min( numplayers, MAXKILLBOXES ) * KILLS_WIDTH ) / 2; ++//SetTextMode ( );//PLAYERSTATE + for( team = 0; team < BATTLE_NumberOfTeams; team++ ) + { + for( player = 0; player < numplayers; player++ ) +@@ -952,12 +1051,12 @@ + xpos += KILLS_WIDTH; + } + } +- if ( xpos >= 320 ) ++ if ( xpos >= iGLOBAL_SCREENWIDTH ) + { + break; + } + } +- if ( xpos >= 320 ) ++ if ( xpos >= iGLOBAL_SCREENWIDTH ) + { + break; + } +@@ -1922,7 +2021,7 @@ + return; + } + +- health_y = HEALTH_Y; ++ health_y = iGLOBAL_HEALTH_Y; + if ( SHOW_KILLS() ) + { + health_y -= KILLS_HEIGHT; +@@ -1935,7 +2034,7 @@ + + if ( playstate == ex_died ) + { +- DrawPPic( HEALTH_X, health_y, 8 >> 2, 16, ( byte * )&erase->data, ++ DrawPPic( iGLOBAL_HEALTH_X, health_y, 8 >> 2, 16, ( byte * )&erase->data, + 10, true, bufferofsonly ); + + return; +@@ -1953,26 +2052,26 @@ + + if ( oldpercenthealth < 4 ) + { +- DrawPPic( HEALTH_X, health_y, 8 >> 2, 16, ++ DrawPPic( iGLOBAL_HEALTH_X, health_y, 8 >> 2, 16, + ( byte * )&health[ 0 ]->data, oldpercenthealth, + true, bufferofsonly ); + } + else if ( oldpercenthealth < 5 ) + { +- DrawPPic( HEALTH_X, health_y, 8 >> 2, 16, ++ DrawPPic( iGLOBAL_HEALTH_X, health_y, 8 >> 2, 16, + (byte *)&health[ 1 ]->data, oldpercenthealth, + true, bufferofsonly ); + } + else + { +- DrawPPic( HEALTH_X, health_y, 8 >> 2, 16, ++ DrawPPic( iGLOBAL_HEALTH_X, health_y, 8 >> 2, 16, + ( byte * )&health[ 2 ]->data, oldpercenthealth, + true, bufferofsonly ); + } + + if ( oldpercenthealth < 10 ) + { +- DrawPPic( HEALTH_X + ( 8 * oldpercenthealth ), health_y, ++ DrawPPic( iGLOBAL_HEALTH_X + ( 8 * oldpercenthealth ), health_y, + 8 >> 2, 16, ( byte * )&erase->data, 10 - oldpercenthealth, + true, bufferofsonly ); + } +@@ -1998,13 +2097,13 @@ + return; + } + +- ammo_y = AMMO_Y; ++ ammo_y = iGLOBAL_AMMO_Y; + if ( SHOW_KILLS() ) + { + ammo_y -= KILLS_HEIGHT; + } + +- DrawPPic ( AMMO_X, ammo_y + 1, 8 >> 2, 16, ( byte * )&erase->data, ++ DrawPPic ( iGLOBAL_AMMO_X, ammo_y + 1, 8 >> 2, 16, ( byte * )&erase->data, + 10, false, bufferofsonly ); + + if ( !ARMED( player->dirchoosetime ) ) +@@ -2016,25 +2115,25 @@ + ( gamestate.BattleOptions.Ammo == bo_infinite_shots ) + ) + { +- DrawPPic( AMMO_X - 16, ammo_y, 24 >> 2, 16, ++ DrawPPic( iGLOBAL_AMMO_X - 16, ammo_y, 24 >> 2, 16, + ( byte * )&ammo[ 0 ]->data, 1, true, bufferofsonly); + +- DrawPPic( AMMO_X - 32, ammo_y + 1, 8 >> 2, 16, ++ DrawPPic( iGLOBAL_AMMO_X - 32, ammo_y + 1, 8 >> 2, 16, + ( byte * )&erase->data, 2, true, bufferofsonly ); + } + #if (SHAREWARE == 0) + else if ( locplayerstate->new_weapon == wp_dog ) + { +- DrawPPic( AMMO_X - 16, ammo_y, 24 >> 2, 16, ++ DrawPPic( iGLOBAL_AMMO_X - 16, ammo_y, 24 >> 2, 16, + ( byte * )&ammo[12]->data, 1, true, bufferofsonly ); + +- DrawPPic( AMMO_X - 32, ammo_y + 1, 8 >> 2, 16, ++ DrawPPic( iGLOBAL_AMMO_X - 32, ammo_y + 1, 8 >> 2, 16, + ( byte * )&erase->data, 2, true, bufferofsonly ); + } + #endif + else + { +- DrawPPic( AMMO_X, ammo_y + 1, 8 >> 2, 16, ++ DrawPPic( iGLOBAL_AMMO_X, ammo_y + 1, 8 >> 2, 16, + ( byte * )&ammo[ locplayerstate->new_weapon]->data, + locplayerstate->ammo, false, bufferofsonly ); + } +@@ -2154,8 +2253,8 @@ + // DrawTiledRegion( 0, 160, 320, 24, shape ); + // } + +- health_y = HEALTH_Y; +- ammo_y = AMMO_Y; ++ health_y = iGLOBAL_HEALTH_Y; ++ ammo_y = iGLOBAL_AMMO_Y; + + if ( SHOW_KILLS() ) + { +@@ -2180,17 +2279,17 @@ + + if ( oldpercenthealth < 4 ) + { +- SingleDrawPPic( HEALTH_X - 16, health_y, 8 >> 2, 16, ++ SingleDrawPPic( iGLOBAL_HEALTH_X - 16, health_y, 8 >> 2, 16, + ( byte * )&health[ 3 ]->data, oldpercenthealth, true); + } + else if ( oldpercenthealth < 5 ) + { +- SingleDrawPPic( HEALTH_X - 16, health_y, 8 >> 2, 16, ++ SingleDrawPPic( iGLOBAL_HEALTH_X - 16, health_y, 8 >> 2, 16, + ( byte * )&health[ 4 ]->data, oldpercenthealth, true ); + } + else + { +- SingleDrawPPic( HEALTH_X - 16, health_y, 8 >> 2, 16, ++ SingleDrawPPic( iGLOBAL_HEALTH_X - 16, health_y, 8 >> 2, 16, + ( byte * )&health[ 5 ]->data, oldpercenthealth, true ); + } + +@@ -2202,19 +2301,19 @@ + ) + + { +- SingleDrawPPic( AMMO_X - 16, ammo_y, 24 >> 2, 16, ++ SingleDrawPPic( iGLOBAL_AMMO_X - 16, ammo_y, 24 >> 2, 16, + ( byte * )&ammo[13]->data, 1, true ); + } + #if (SHAREWARE == 0) + else if ( locplayerstate->new_weapon == wp_dog ) + { +- SingleDrawPPic( AMMO_X - 16, ammo_y + 1, 24 >> 2, 16, ++ SingleDrawPPic( iGLOBAL_AMMO_X - 16, ammo_y + 1, 24 >> 2, 16, + ( byte * )&ammo[25]->data, 1, true ); + } + #endif + else + { +- SingleDrawPPic( AMMO_X, ammo_y + 1, 8 >> 2, 16, ++ SingleDrawPPic( iGLOBAL_AMMO_X, ammo_y + 1, 8 >> 2, 16, + ( byte * )&ammo[13 + locplayerstate->new_weapon]->data, + locplayerstate->ammo, false ); + } +@@ -2231,18 +2330,27 @@ + void DrawPauseXY (int x, int y) + { + pic_t *p; ++ byte *buftmp; ++ ++ buftmp = bufferofs; + + if (GamePaused == true) + { + p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("paused"), PU_CACHE, Cvt_pic_t, 1); +- VWB_DrawPic (x, y, p); ++ VL_MemToScreen ((byte *)&p->data, p->width, p->height,x, y); ++ //VWB_DrawPic (x, y, p); ++ bufferofs = buftmp; + DrawEpisodeLevel (x,y); ++ //VL_MemToScreen ((byte *)&p->data, p->width, p->height,x, y); ++ + } + else + { + p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("wait"), PU_CACHE, Cvt_pic_t, 1); +- VWB_DrawPic (x, y, p); ++ VL_MemToScreen ((byte *)&p->data, p->width, p->height,x, y); ++ //VWB_DrawPic (x, y, p); + } ++ bufferofs = buftmp; + } + + //**************************************************************************** +@@ -2260,14 +2368,93 @@ + + if (GamePaused == true) + { ++ bufferofs = bufftemp; + p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("paused"), PU_CACHE, Cvt_pic_t, 1); +- DrawPauseXY( (320-(p->width<<2) ) >>1, (200-p->height)>>1); ++ DrawPauseXY( (iGLOBAL_SCREENWIDTH-(p->width<<2) ) >>1, (iGLOBAL_SCREENHEIGHT-p->height)>>1);//bna++ ++ //DrawPauseXY( (320-(p->width<<2) ) >>1, (200-p->height)>>1); ++/* ++ //buf = (byte *) SafeMalloc (64000); ++ w = p->width; ++ h = p->height; ++ x = (iGLOBAL_SCREENWIDTH-((p->width)<<2) ) >>1; ++ y = (iGLOBAL_SCREENHEIGHT-(p->height))>>1; ++ ++ x1 = (iGLOBAL_SCREENWIDTH-((p->width*2)<<2) ) >>1; ++ y1 = (iGLOBAL_SCREENHEIGHT-(p->height*2))>>1; ++ ++ source = bufferofs + (iGLOBAL_SCREENWIDTH*y)+x; ++ target = bufferofs + (iGLOBAL_SCREENWIDTH*y1)+x1; ++ ++ // memcpy(tmpPICbuf,bufftemp,iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT); ++ ++ bufferofs = bufftemp;//(byte *)tmpPICbuf;//buf;//write picture in tmpbuf ++ VL_MemToScreen ((byte *)&p->data, p->width, p->height,x, y); ++ bufferofs = bufftemp; ++ DrawEpisodeLevel (x,y); ++ ++ ++ //VL_MemStrechedToScreen ((byte *)&p->data, p->width, p->height,(iGLOBAL_SCREENWIDTH-((p->width*2)<<2) ) >>1, (iGLOBAL_SCREENHEIGHT-(p->height*2))>>1); ++ //DrawEpisodeLevel (x,y); ++ ++ //VL_MemToScreen ((byte *)&p->data, p->width, p->height,0, 0); ++ //bufferofs = bufftemp;//move ptr back ++ //write it back to bufferofs while streching ++ ++ //buf = bufftemp; ++ //b = tmpPICbuf ; ++ ++ source = bufferofs + (iGLOBAL_SCREENWIDTH*y)+x+(w*4); ++ target = bufferofs + (iGLOBAL_SCREENWIDTH*y1)+x+(2*w*4); ++ ++ //first strech lines in x direction ++ for (y=0;ywidth<<2) ) >>1, (200-p->height)>>1); ++ DrawPauseXY( (iGLOBAL_SCREENWIDTH-(p->width<<2) ) >>1, (iGLOBAL_SCREENHEIGHT-p->height)>>1);//bna++ ++ //DrawPauseXY( (320-(p->width<<2) ) >>1, (200-p->height)>>1); + } ++// VH_UpdateScreen () ; + + bufferofs = bufftemp; + } +@@ -2546,14 +2733,16 @@ + { + ltoa (gamestate.episode, str, 10); + +- Drawpic (x+29, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data); ++ //bna-- Drawpic (x+29, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data); ++ VL_MemToScreenClipped ((byte *)&timenums[str[0]-'0']->data, 8>>2, 16, x+29, y+16); + + if ((gamestate.mapon == 6) || (gamestate.mapon == 14) || + (gamestate.mapon == 22) || (gamestate.mapon == 32) || + (gamestate.mapon == 33)) + { + p = (pic_t *) W_CacheLumpName ("tnumb", PU_CACHE, Cvt_pic_t, 1); +- Drawpic (x+40, y+16, 8>>2, 16, (byte *)&p->data); ++ //Drawpic (x+40, y+16, 8>>2, 16, (byte *)&p->data); ++ VL_MemToScreenClipped ((byte *)&p->data, 8>>2, 16, x+40, y+16); + + if (gamestate.mapon == 6) + level = 1; +@@ -2575,28 +2764,34 @@ + level = abs(level); + ltoa (level, str, 10); + +- if (level < 10) +- Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data); +- else +- { +- Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data); +- Drawpic (x+57, y+16, 8>>2, 16, (byte *)&timenums[str[1]-'0']->data); ++ if (level < 10){ ++ //Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data); ++ VL_MemToScreenClipped ((byte *)&timenums[str[0]-'0']->data, 8>>2, 16, x+49, y+16); ++ }else{ ++ //Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data); ++ VL_MemToScreenClipped ((byte *)&timenums[str[0]-'0']->data, 8>>2, 16, x+49, y+16); ++ //Drawpic (x+57, y+16, 8>>2, 16, (byte *)&timenums[str[1]-'0']->data); ++ VL_MemToScreenClipped ((byte *)&timenums[str[1]-'0']->data, 8>>2, 16, x+57, y+16); ++ + } + } + else + { + p = (pic_t *) W_CacheLumpName ("battp", PU_CACHE, Cvt_pic_t, 1); +- Drawpic (x+16, y+15, 32>>2, 16, (byte *)&p->data); ++ //Drawpic (x+16, y+15, 32>>2, 16, (byte *)&p->data); ++ VL_MemToScreenClipped ((byte *)&p->data, 32>>2, 16, x+16, y+15); + + level = abs(gamestate.mapon + 1); + ltoa (level, str, 10); + +- if (level < 10) +- Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data); +- else +- { +- Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data); +- Drawpic (x+57, y+16, 8>>2, 16, (byte *)&timenums[str[1]-'0']->data); ++ if (level < 10){ ++ //Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data); ++ VL_MemToScreenClipped ((byte *)&timenums[str[0]-'0']->data, 8>>2, 16, x+49, y+16); ++ }else { ++ //Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data); ++ VL_MemToScreenClipped ((byte *)&timenums[str[0]-'0']->data, 8>>2, 16, x+49, y+16); ++ //Drawpic (x+57, y+16, 8>>2, 16, (byte *)&timenums[str[1]-'0']->data); ++ VL_MemToScreenClipped ((byte *)&timenums[str[1]-'0']->data, 8>>2, 16, x+57, y+16); + } + } + } +@@ -2679,10 +2874,11 @@ + void ScreenShake (void) + { + static int which = 0; +- ++// SetTextMode ( ); + if (SHAKETICS != 0xFFFF) + { + SHAKETICS -= tics; ++ if (SHAKETICS >= 0xFF00){SHAKETICS = 0xFFFF;}//bna safety val check + + which = (RandomNumber ("ScreenShake",0) & 3); + +@@ -2690,20 +2886,29 @@ + { + case 0: + displayofs += 1; ++ MoveScreenUpLeft();//SetTextMode ( ); ++ DrawPlayScreen(true);//repaint ammo and life stat + break; + + case 1: + displayofs -= 1; ++ MoveScreenUpRight(); ++ DrawPlayScreen(true);//repaint ammo and life stat + break; + + case 2: +- displayofs += 3*SCREENBWIDE; ++ displayofs += 3*iGLOBAL_SCREENBWIDE; ++ MoveScreenDownLeft(); ++ DrawPlayScreen(true);//repaint ammo and life stat + break; + + case 3: +- displayofs -= 3*SCREENBWIDE; ++ displayofs -= 3*iGLOBAL_SCREENBWIDE; ++ MoveScreenDownRight(); ++ DrawPlayScreen(true);//repaint ammo and life stat + break; + } ++ + } + } + +@@ -3156,7 +3361,7 @@ + + case 2 : + VL_FillPalette(255,255,255); +- VW_UpdateScreen(); ++ //bna--VW_UpdateScreen(); + VL_FadeIn(0,255,origpal,10); + EndBonusVoice = SD_Play( SD_LIGHTNINGSND ); + break; +@@ -3164,7 +3369,7 @@ + + EndBonusStartY += 10; + +- VW_UpdateScreen(); ++ //bna--VW_UpdateScreen(); + while( SD_SoundActive( EndBonusVoice ) && !EndBonusSkip ) + { + if ( IN_CheckAck() ) +@@ -3208,13 +3413,24 @@ + int plantratio; + int cnt; + ++ pic_t *tmpPic; ++// byte *picbuf; ++ + EndBonusNumBonuses = 0; + EndBonusFirst = true; + EndBonusSkip = false; + EndBonusStartY = 90; + ++ StrechScreen=true; ++ tmpPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 ); ++ VWB_DrawPic( 0, 0, tmpPic ); ++ VW_UpdateScreen(); ++ StrechScreen=false; ++ + IN_StartAck(); + EndBonusVoice = 0; ++ ++ + if ( playstate != ex_bossdied ) + { + EndBonusVoice = SD_Play( SD_LEVELDONESND ); +@@ -3309,16 +3525,36 @@ + } + + DrawEOLHeader( playstate ); ++/* ++ //bna section store picture because its written on again ++ // store screen first ++ picbuf = (byte *)SafeMalloc (64000); ++ memcpy(picbuf ,bufferofs ,64000); ++ ++ StrechScreen=true; ++ VW_UpdateScreen();//tmpPICbuf is destroyed here ++ StrechScreen=false; ++ //copy it back ++ ++ memcpy(bufferofs ,picbuf , 64000); ++ //bna section end ++*/ ++ ++EndBonusSkip = true; + + while( SD_SoundActive( EndBonusVoice ) && !EndBonusSkip ) + { +- VW_UpdateScreen(); ++ ++ //bna--VW_UpdateScreen(); ++ + if ( IN_CheckAck() ) + { + EndBonusSkip = true; + } + } +- ++ // tmpPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 ); ++ // VWB_DrawPic( 0, 0, tmpPic ); ++ + if ( GetNextMap(player->tilex,player->tiley) == -1) + { + if ( gamestate.dipballs == 3 ) +@@ -3506,15 +3742,27 @@ + EndBonusFirst = true; + EndBonusStartY = 110; + DrawEndBonus( "You have done well.", NULL, 3 ); ++ + #if (SHAREWARE==1) + EndBonusVoice = SD_Play( SD_RICOCHET3SND ); + #else + EndBonusVoice = SD_Play( SD_PERCENT100SND ); + #endif ++ + EndBonusSkip = false; + DrawEndBonus( "This level is toast.", NULL, 3 ); ++ + } + } ++ ++ ++ ++ //bna section ++ StrechScreen=true;//bna++ ++ VW_UpdateScreen();//bna++ ++// StrechScreen=false;//bna++ ++ //bna section end ++ + + IN_StartAck(); + while( !IN_CheckAck() ) +@@ -3586,8 +3834,21 @@ + VWB_DrawPic ( 8, 24, Name ); + VWB_DrawPic ( 136, 24, TimesPersonKilledYou ); + break; +- } +- ++//bna added ++ case 4 : ++ VWB_DrawPic ( 198+48, 8, Blank ); ++ VWB_DrawPic ( 8, 8, TopBar ); ++ DrawIntensityString( 12, 11, "FINAL SCORE", 20 ); ++ VWB_DrawPic ( 8, 24, TopBar );//used to blank ++ VWB_DrawPic ( 8, 24, Name ); ++ VWB_DrawPic ( 136, 24, KillCount); ++ VWB_DrawPic ( 198, 24, TimesPersonKilledYou); ++ VWB_DrawPic ( 198+48, 24, Blank ); ++ VWB_DrawPic ( 272, 24, Score ); ++ break; ++//bna added end ++ } ++ + DrawTimeXY( TALLYTIME_X, TALLYTIME_Y, gamestate.TimeCount / VBLCOUNTER, + true ); + } +@@ -3950,6 +4211,8 @@ + int Player; + char text[80]; + ++ StrechScreen=true; ++ + IN_ClearKeysDown (); + + Player = localplayer; +@@ -4141,7 +4404,7 @@ + int slowrate; + playertype *pstate; + objtype * killerobj=(objtype *)player->target; +- ++player->yzangle=0; + + if (killerobj == NULL) + killerobj = player; +@@ -4462,12 +4725,14 @@ + py = 152; + if (whichstr) + { +- VW_DrawPropString ("ƒ"); ++// VW_DrawPropString ("ƒ"); ++ VW_DrawPropString ("."); + whichstr = 0; + } + else + { +- VW_DrawPropString ("„"); ++// VW_DrawPropString ("„"); ++ VW_DrawPropString ("."); + whichstr = 1; + } + bufferofs = temp; +diff -urN rott-1.0.orig/rott/rt_game.h rott-1.0/rott/rt_game.h +--- rott-1.0.orig/rott/rt_game.h 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/rt_game.h 2007-05-06 22:34:18.000000000 +0200 +@@ -74,7 +74,8 @@ + + extern int PlayerSnds[5]; + +-extern int SHAKETICS; ++//extern int SHAKETICS; ++extern unsigned short SHAKETICS;//bna++ + extern int damagecount; + + extern HighScore Scores[MaxScores]; +diff -urN rott-1.0.orig/rott/rt_main.c rott-1.0/rott/rt_main.c +--- rott-1.0.orig/rott/rt_main.c 2007-05-06 23:57:48.000000000 +0200 ++++ rott-1.0/rott/rt_main.c 2007-05-06 22:43:28.000000000 +0200 +@@ -153,12 +153,26 @@ + void PlayTurboGame( void ); + void Init_Tables (void); + void CheckRemoteRidicule ( int scancode ); ++void SetRottScreenRes (int Width, int Height); + + #ifndef DOS + extern void crash_print (int); + extern int setup_homedir (void); + #endif + ++//extern int G_argc; ++//extern char G_argv[30][80]; ++int G_weaponscale; ++extern int iDropDemo; ++extern int iG_aimCross; ++ ++extern void ComSetTime ( void ); ++extern void VH_UpdateScreen (void); ++extern void RottConsole ( void ); ++extern void ReadDelay(long delay); ++extern void RecordDemoQuery ( void ); ++ ++ + int main (int argc, char *argv[]) + { + char *macwd; +@@ -206,6 +220,8 @@ + gamestate.Product = ROTT_REGISTERED; + #endif + ++ SetRottScreenRes (640, 480); ++ + DrawRottTitle (); + gamestate.randomseed=-1; + +@@ -730,8 +746,91 @@ + + #if (SHAREWARE==0) + +- // Check for User wads + ++ // Check for aimcross ++ arg = CheckParm ("aim"); ++ if (arg!=0) ++ { ++ iG_aimCross = 1; ++ }else{ ++ iG_aimCross = 0; ++ } ++ ++ ++ // Check for rtl files ++ arg = CheckParm ("filertl"); ++ if (arg!=0) ++ { ++ FILE *f;char buf[32]; ++ if (_argv[arg+1] != 0) { //are there a filename included ++ strcpy (tempstr,_argv[arg+1]);//copy it to tempstr ++ if (strlen (tempstr) < MAX_PATH) { ++ if (access (tempstr, 0) != 0) { //try open ++ strcat (tempstr,".rtc");//non exists, try add .rtc ++ if (access (tempstr, 0) != 0) { //try open again ++ //stil no useful filename ++ strcat (tempstr," not found, skipping RTL file "); ++ printf(tempstr); ++ goto NoRTL; ++ } ++ } ++ if((f = fopen( tempstr, "r" )) == NULL ){ //try opnong file ++ strcat (tempstr," not could not be opened, skipping RTL file "); ++ printf(tempstr); ++ goto NoRTL; ++ }else{ ++ fread(buf,3,3,f);//is the 3 first letters RTL (RTC) ++ if (((strstr(buf,"RTL") != 0)||strstr(buf,"RTC") != 0)) { ++ strcpy (GameLevels.file,tempstr); ++ GameLevels.avail++; ++ strcpy (buf,"Adding "); ++ strcat (buf,tempstr); ++ printf(buf); ++ } ++ fclose(f); ++ } ++ } ++ }else{printf("Missing RTL filename");} ++ } ++NoRTL:; ++ // Check for rtc files ++ arg = CheckParm ("filertc"); ++ if (arg!=0) ++ { ++ FILE *f;char buf[32]; ++ if (_argv[arg+1] != 0) { //are there a filename included ++ strcpy (tempstr,_argv[arg+1]);//copy it to tempstr ++ if (strlen (tempstr) < MAX_PATH) { ++ if (access (tempstr, 0) != 0) { //try open ++ strcat (tempstr,".rtc");//non exists, try add .rtc ++ if (access (tempstr, 0) != 0) { //try open again ++ //stil no useful filename ++ strcat (tempstr," not found, skipping RTC file "); ++ printf(tempstr); ++ goto NoRTL; ++ } ++ } ++ if((f = fopen( tempstr, "r" )) == NULL ){ //try opening file ++ strcat (tempstr," not could not be opened, skipping RTC file "); ++ printf(tempstr); ++ goto NoRTL; ++ }else{ ++ fread(buf,3,3,f);//is the 3 first letters RTL (RTC) ++ if (((strstr(buf,"RTL") != 0)||strstr(buf,"RTC") != 0)) { ++ strcpy (BattleLevels.file,tempstr); ++ BattleLevels.avail++; ++ strcpy (buf,"Adding "); ++ strcat (buf,tempstr); ++ printf(buf); ++ } ++ fclose(f); ++ } ++ } ++ }else{printf("Missing RTC filename");} ++ } ++NoRTC:; ++ ++ // Check for User wads + arg = CheckParm ("file"); + if (arg!=0) + { +@@ -836,7 +935,7 @@ + blockstart = &blockstarts[0]; + for (y=0;y>2; +@@ -940,14 +1039,17 @@ + CalcTics(); + CalcTics(); + ++ + playstate = ex_titles; + } + + switch (playstate) + { + case ex_titles: ++ + BATTLE_Shutdown(); + MU_StartSong(song_title); ++ StrechScreen=true; + if ((NoWait==false)&&(!modemgame)) + { + byte dimpal[768]; +@@ -993,7 +1095,9 @@ + break; + } + +- DoCreditScreen (); ++ if (iGLOBAL_SCREENWIDTH > 320) { //need fixing, crashes by 320 ,bna ++ DoCreditScreen (); ++ } + if ((!LastScan) && (!IN_GetMouseButtons())) + CheckHighScore (0, 0, false); + #if (SHAREWARE==0) +@@ -1036,10 +1140,14 @@ + NoWait = false; + SwitchPalette(origpal,35); + CP_MainMenu(); ++ + } + break; + + case ex_resetgame: ++ ++ // SetTextMode ( ); //12345678 ++ StrechScreen=true;//bna++ shut on streech mode + InitCharacter(); + + InitializeMessages(); +@@ -1123,6 +1231,9 @@ + + MenuFixup (); + playstate=ex_stillplaying; ++ ++ StrechScreen=false;//bna++ shut off streech mode ++ + break; + + case ex_stillplaying: +@@ -1143,10 +1254,10 @@ + + case ex_died: + loadit = done = false; +- ++// SetTextMode ( ); //12345678 + Died (); + StopWind(); +- ++ StrechScreen=false;//bna++ shut off streech mode + while (damagecount>0) + DoBorderShifts(); + +@@ -1371,12 +1482,12 @@ + waminot(); + } + +-boolean CheckForQuickLoad +- ( +- void +- ) ++boolean CheckForQuickLoad (void ) + + { ++ ++ StrechScreen=true;//bna++ ++ + if ( pickquick ) + { + SetupMenuBuf(); +@@ -1715,6 +1826,17 @@ + oldpolltime++; + if (GamePaused==false) + { ++ //bna++ section ++ if (( playstate == ex_stillplaying )&&(iGLOBAL_SCREENWIDTH > 320)){ ++ pic_t *shape; ++ shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); ++ DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape ); ++ StrechScreen=false;//dont strech when we go BACK TO GAME ++ DrawPlayScreen(true);//repaint ammo and life stat ++ VW_UpdateScreen ();//update screen ++ } ++ StartupClientControls(); ++ //bna section end + break; + } + } +@@ -2707,7 +2829,7 @@ + int handle; + int i; + +- lbm = lbmptr = (byte *) SafeMalloc (65000); ++ lbm = lbmptr = (byte *) SafeMalloc ((iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT)+4000); + + // + // start FORM +@@ -2916,7 +3038,8 @@ + ThreeDRefresh (); + doublestep = 2 - DetailLevel; + +- buffer = (byte *) SafeMalloc (65000); ++ //buffer = (byte *) SafeMalloc (65000); ++ buffer = (byte *) SafeMalloc ((iGLOBAL_SCREENHEIGHT*iGLOBAL_SCREENWIDTH)+4000); + + #if (BETA == 1) + if (SCREENSHOTS == false) +@@ -2949,10 +3072,13 @@ + } + #endif + +- VL_CopyPlanarPageToMemory(screen,buffer); ++ + + GetFileName (saveLBM); + GetPathFromEnvironment( filename, ApogeePath, savename ); ++ // ++ memcpy(buffer,screen , iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT);//bna ++ //bna--VL_CopyPlanarPageToMemory(screen,buffer); + + if (saveLBM) + { +@@ -3003,15 +3129,15 @@ + + pcxHDR.bitsperpixel = 8; //bpp; + pcxHDR.xmin = pcxHDR.ymin = 0; +- pcxHDR.xmax = 319; //bitmap->box.w - 1; +- pcxHDR.ymax = 199; //bitmap->box.h - 1; +- pcxHDR.hres = 320; //N_COLUMNS; +- pcxHDR.vres = 200; //N_LINES; ++ pcxHDR.xmax = iGLOBAL_SCREENWIDTH - 1; ++ pcxHDR.ymax = iGLOBAL_SCREENHEIGHT - 1; ++ pcxHDR.hres = iGLOBAL_SCREENWIDTH; //N_COLUMNS; ++ pcxHDR.vres = iGLOBAL_SCREENHEIGHT; //N_LINES; + + // bytesperline doesn't take into account multiple planes. + // Output in same format as bitmap (planar vs packed). + // +- pcxHDR.bytesperline = 320; //bitmap->width; ++ pcxHDR.bytesperline = iGLOBAL_SCREENWIDTH; //bitmap->width; + + pcxHDR.nplanes = 1; //bitmap->planes; + pcxHDR.reserved = 0; +@@ -3032,15 +3158,15 @@ + + SafeWrite (pcxhandle, &buffer1, GAP_SIZE); + +- tempbuffer = (byte *) SafeMalloc (65000); ++ tempbuffer = (byte *) SafeMalloc ((iGLOBAL_SCREENHEIGHT*iGLOBAL_SCREENWIDTH)+4000); + bptr = tempbuffer; + totalbytes = 0; + + // + // Write to a bit-packed file. + // +- for (y = 0; y < 200; ++y) // for each line in band +- if (PutBytes (((unsigned char *) (source+(y*320))), ++ for (y = 0; y < iGLOBAL_SCREENHEIGHT; ++y) // for each line in band ++ if (PutBytes (((unsigned char *) (source+(y*iGLOBAL_SCREENWIDTH))), + pcxHDR.bytesperline)) + Error ("Error writing PCX bit-packed line!\n"); + +diff -urN rott-1.0.orig/rott/rt_map.c rott-1.0/rott/rt_map.c +--- rott-1.0.orig/rott/rt_map.c 2002-12-29 05:54:29.000000000 +0100 ++++ rott-1.0/rott/rt_map.c 2007-05-06 22:34:18.000000000 +0200 +@@ -644,9 +644,9 @@ + #endif + + #ifdef DOS +- for (mapy=0;mapytilex ) && (mapy==player->tiley)) +@@ -898,6 +898,7 @@ + int quitkey; + ControlInfo control; + ++StrechScreen = true;//bna++ + + ShutdownClientControls(); + +@@ -1035,6 +1036,16 @@ + else if (y<-(yscale<<15)) + y=-(yscale<<15); + } ++ ++ if ( playstate == ex_stillplaying ) {//bna++ ++ pic_t *shape; ++ shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); ++ DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );//bna++ ++ StrechScreen=false;//dont strech when we go BACK TO GAME ++ VW_UpdateScreen (); ++ DrawPlayScreen(true);//repaint ammo and life stat ++ ++ } + while (Keyboard[quitkey]) + IN_UpdateKeyboard (); + +diff -urN rott-1.0.orig/rott/rt_menu.c rott-1.0/rott/rt_menu.c +--- rott-1.0.orig/rott/rt_menu.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/rt_menu.c 2007-05-06 22:34:18.000000000 +0200 +@@ -132,6 +132,8 @@ + + int quicksaveslot=-1; + ++extern char *tmpPICbuf; ++ + //****************************************************************************** + // + // LOCALS +@@ -715,18 +722,22 @@ + { + "CONTROLS", + "USER OPTIONS", ++ "EXT USER OPTIONS",//bna added + "MUSIC VOLUME", + "SOUND FX VOLUME" +- }; + +-CP_iteminfo ControlMItems = {32, 48, 4, 0, 32, ControlMMenuNames, mn_largefont }; ++ }; ++CP_iteminfo ControlMItems = {32, 48-8, 5, 0, 32, ControlMMenuNames, mn_largefont };//bna added ++//CP_iteminfo ControlMItems = {32, 48, 4, 0, 32, ControlMMenuNames, mn_largefont }; + + CP_itemtype ControlMMenu[] = + { + {2, "cntl\0", 'C', (menuptr)CP_Control}, + {1, "uopt\0", 'U', (menuptr)CP_OptionsMenu}, ++ {1, "euopt\0", 'E', (menuptr)CP_ExtOptionsMenu},//bna added + {1, "muvolumn\0", 'M', (menuptr)MusicVolume}, + {1, "fxvolumn\0", 'S', (menuptr)FXVolume} ++ + }; + + CP_MenuNames OptionsNames[] = +@@ -741,6 +752,26 @@ + "VIOLENCE LEVEL", + "SCREEN SIZE" + }; ++//bna added ++CP_MenuNames ExtOptionsNames[] = ++ { ++ "MOUSELOOK", ++ "INVERSE MOUSE", ++ "CROSS HAIR", ++ "JUMPING" ++ ++ }; ++CP_iteminfo ExtOptionsItems = { 20, MENU_Y, 4, 0, 43, ExtOptionsNames, mn_largefont }; ++ ++CP_itemtype ExtOptionsMenu[] = ++{ ++ {1, "", 'M', NULL}, ++ {1, "", 'I', NULL}, ++ {1, "", 'C', NULL}, ++ {1, "", 'J', NULL} ++}; ++ ++//bna added end + + CP_iteminfo OptionsItems = { 20, MENU_Y, 9, 0, 43, OptionsNames, mn_largefont }; + +@@ -1479,11 +1481,26 @@ + byte * b; + byte * s; + ++// int Xres = 320;//org ++// int Yres = 200;//org ++ int Xres = 640; ++ int Yres = 400; ++ ++ //dont work in 800x600 until we get a better screen schrinker ++ // int Xres = iGLOBAL_SCREENWIDTH;//640; ++ // int Yres = iGLOBAL_SCREENHEIGHT;//400; ++ ++ Xres = 640; ++ Yres = 400; ++ ++ ++ + // Save the current game screen + +- savedscreen = SafeMalloc (16000); ++ //bna--savedscreen = SafeMalloc (16000); ++ savedscreen = SafeMalloc (16000*8); + +- // Copy the current screen to this buffer ++ // Copy the current save game screen (½ size) to this buffer + + if (RefreshPause==false) + { +@@ -1493,20 +1510,34 @@ + FlipPage(); + GamePaused=true; + } ++ ++ + s=savedscreen; +- for (i=0;i<320;i+=2) +- { +-#ifdef DOS +- VGAREADMAP(i&3); +- b=(byte *)bufferofs+(i>>2); +- for (j=0;j<100;j++,s++,b+=SCREENBWIDE<<1) +- *s=*b; +-#else +- b=(byte *)bufferofs+i; +- for (j=0;j<100;j++,s++,b+=(MAXSCREENWIDTH<<1)) +- *s=*b; +-#endif +- } ++ ++ ++ ++ if (iGLOBAL_SCREENWIDTH == 320) { ++ for (i=0;i= 640) { ++ for (i=0;i>2); +- for (j=0;j<100;j++,s++,b+=SCREENBWIDE<<1) ++ for (j=0;j<100;j++,s++,b+=iGLOBAL_SCREENBWIDE<<1) + *s=*b; + #else + b=(byte *)bufferofs+i; +- for (j=0;j<100;j++,s++,b+=(MAXSCREENWIDTH<<1)) ++ for (j=0;j<100;j++,s++,b+=(iGLOBAL_SCREENWIDTH<<1)) + *s=*b; + #endif + } +@@ -4969,6 +5012,7 @@ + + void DoMainMenu (void) + { ++ StrechScreen=true;//bna++ shut on streech mode + SetAlternateMenuBuf(); + ClearMenuBuf(); + DrawMainMenu(); +@@ -5258,6 +5428,93 @@ + DisplayInfo (0); + FlipMenuBuf(); + } ++//**************************************************************************** ++// ++// DrawExtOptionsMenu () () bna added ++// ++//**************************************************************************** ++ ++void DrawExtOptionsMenu (void) ++{ ++ MenuNum = 1; ++ ++ SetAlternateMenuBuf(); ++ ClearMenuBuf(); ++ SetMenuTitle ("Extended User Options"); ++ ++ MN_GetCursorLocation( &ExtOptionsItems, &ExtOptionsMenu[ 0 ] ); ++ DrawMenu (&ExtOptionsItems, &ExtOptionsMenu[0]); ++ DrawExtOptionsButtons (); ++ DisplayInfo (0); ++ ++ FlipMenuBuf(); ++} ++extern long inverse_mouse; ++extern boolean usemouselook; ++extern int iG_aimCross; ++extern boolean usejump; ++ ++void CP_ExtOptionsMenu (void) ++{ ++ int which; ++ ++ DrawExtOptionsMenu(); ++ ++ do ++ { ++ which = HandleMenu (&ExtOptionsItems, &ExtOptionsMenu[0], NULL); ++ ++ switch (which) ++ { ++ case 0: usemouselook ^= 1; DrawExtOptionsButtons (); break; ++ case 1: if (inverse_mouse == 1){ ++ inverse_mouse = -1; ++ }else{ ++ inverse_mouse = 1; ++ } ++ DrawExtOptionsButtons (); ++ break; ++ case 2: iG_aimCross ^= 1; DrawExtOptionsButtons (); break; ++ case 3: usejump ^= 1; DrawExtOptionsButtons (); break; ++ } ++ ++ } while (which >= 0); ++ ++ DrawControlMenu(); ++} ++void DrawExtOptionsButtons (void) ++{ ++ int i, ++ on; ++ int button_on; ++ int button_off; ++ ++ button_on = W_GetNumForName ("snd_on"); ++ button_off = W_GetNumForName ("snd_off"); ++ ++ for (i = 0; i < ExtOptionsItems.amount; i++) ++ if (ExtOptionsMenu[i].active != CP_Active3) ++ { ++ // ++ // DRAW SELECTED/NOT SELECTED GRAPHIC BUTTONS ++ // ++ ++ on = 0; ++ ++ switch (i) ++ { ++ case 0: if (usemouselook == 1) on = 1; break; ++ case 1: if (inverse_mouse == -1)on = 1; break; ++ case 2: if (iG_aimCross == 1) on = 1; break; ++ case 3: if (usejump == 1) on = 1; break; ++ } ++ ++ if (on) ++ DrawMenuBufItem (20+22, ExtOptionsItems.y+i*14-1, button_on); ++ else ++ DrawMenuBufItem (20+22, ExtOptionsItems.y+i*14-1, button_off); ++ } ++} + + //**************************************************************************** + // +@@ -5542,6 +5586,7 @@ + if ( status ) + { + StartGame = true; ++ StrechScreen=false; + handlewhich = -2; + playstate = ex_resetgame; + BATTLEMODE = true; +@@ -6996,13 +7041,12 @@ + + #endif + +-void CP_ModemGameMessage +- ( +- int player +- ) ++void CP_ModemGameMessage (int player ) + + { + int i; ++ StrechScreen=true; ++ // SetTextMode ( ); + + SetAlternateMenuBuf(); + ClearMenuBuf(); +@@ -7053,6 +7097,8 @@ + + FlipMenuBuf(); + RefreshMenuBuf (0); ++ ++ StrechScreen=false; + } + + +diff -urN rott-1.0.orig/rott/rt_msg.c rott-1.0/rott/rt_msg.c +--- rott-1.0.orig/rott/rt_msg.c 2002-12-24 06:17:13.000000000 +0100 ++++ rott-1.0/rott/rt_msg.c 2007-05-06 22:34:18.000000000 +0200 +@@ -335,6 +335,12 @@ + int length; + boolean found; + ++ if (iGLOBAL_SCREENWIDTH >= 640){ ++ CurrentFont = newfont1;//smallfont; ++ }else{ ++ CurrentFont = smallfont; ++ } ++ + + length = StringLength( text ); + +@@ -460,15 +466,15 @@ + ==================== + */ + +-void DisplayMessage +- ( +- int num, +- int position +- ) +- ++void DisplayMessage (int num,int position) + { + PrintX = 1; +- PrintY = 2 + ( position * 9 ); ++ if (iGLOBAL_SCREENWIDTH > 320){ ++ PrintY = 2 + ( position * (9*2) ); ++ }else{ ++ PrintY = 2 + ( position * (9*1) ); ++ } ++ + + if ( SHOW_TOP_STATUS_BAR() ) + { +@@ -509,7 +515,14 @@ + case MSG_MODEM: + fontcolor = egacolor[ LIGHTBLUE ]; + DrawIString( PrintX, PrintY, "Message>", Messages[ num ].flags ); +- PrintX += 8 * 8; ++ if ( iGLOBAL_SCREENWIDTH == 320) { ++ PrintX += 8 * 8; ++ }else if ( iGLOBAL_SCREENWIDTH == 640) { ++ PrintX += 8 * 8*2; ++ }else if ( iGLOBAL_SCREENWIDTH == 800) { ++ PrintX += 8 * 8*2; ++ } ++ + fontcolor = egacolor[ LIGHTGRAY ]; + break; + +@@ -572,8 +585,14 @@ + EraseMessage[ i ]--; + if ( viewsize < 15 ) + { +- shape = W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); +- DrawTiledRegion( 0, y, 320, 9, 0, y, shape ); ++ shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );//w=32 h=8 ++ //SetTextMode ( ); ++ //DrawTiledRegion( 0, y, 320, 9, 0, y, shape );KILLS_HEIGHT bna-- ++ DrawTiledRegion( 0, y, iGLOBAL_SCREENWIDTH, 9, 0, y, shape ); ++ DrawTiledRegion( 0, y+8, iGLOBAL_SCREENWIDTH, 9, 0, y, shape ); ++ DrawTiledRegion( 0, y+16, iGLOBAL_SCREENWIDTH, 9, 0, y, shape ); ++ ++ //DrawTiledRegion( 0, y, iGLOBAL_SCREENWIDTH, 212, 0, y, shape ); + } + if ( viewsize == 0 ) + { +diff -urN rott-1.0.orig/rott/rt_playr.c rott-1.0/rott/rt_playr.c +--- rott-1.0.orig/rott/rt_playr.c 2002-12-28 06:26:44.000000000 +0100 ++++ rott-1.0/rott/rt_playr.c 2007-05-06 22:43:28.000000000 +0200 +@@ -71,6 +71,9 @@ + #include "rt_str.h" + #endif + ++extern boolean usejump; ++ ++ + specials CurrentSpecialsTimes = + { + 60*VBLCOUNTER, // god +@@ -251,6 +254,7 @@ + void PlayerMissileAttack(objtype* ); + void Cmd_Use(objtype*); + //void ComError (char *error, ...); ++int FinddTopYZANGLELIMITvalue(objtype *ob); + + statetype s_free = {false,0,0,T_Free,0,&s_free}; + statetype s_inelevator = {false,0,420,T_Player,0,&s_player}; +@@ -1546,6 +1550,12 @@ + =============== + */ + ++boolean AreJumping = false;//bna added ++int oldzval; ++int donttilt=0; ++ ++ ++ + void Cmd_Use (objtype*ob) + { + int checkx,checky,doorn, +@@ -1634,6 +1644,27 @@ + if (doorn == (elevatorstart + 6)) + return; + ++ //bna ++ jumpmode ++ //SetTextMode ( ); ++ if (!BATTLEMODE){//dont use jump in battle, spoils sync ++ if (usejump == true){ ++ if (pstate->buttonheld[bt_use]){ ++ if ((AreJumping == false)&&(ob->z > 0)&&(doorn==0)){ ++ oldzval = ob->z; ++ ob->z -= 15; ++ ob->momentumz += GRAVITY; ++ AreJumping = true; ++ donttilt=10; ++ return; ++ } ++ AreJumping = false; ++ return; ++ } ++ } ++ } ++ //bna ++ ++ + if (pstate->buttonheld[bt_use]) + return; + +@@ -1799,8 +1830,28 @@ + + } + } +- else if ((tempwall) && (tempwall->which == WALL) && (ob==player)) ++ else if ((tempwall) && (tempwall->which == WALL) && (ob==player)){ + PlayNoWaySound(); ++ //bna ++ jumpmode ++ //SetTextMode ( ); ++ if (!BATTLEMODE){//dint use jump in battle, spoils sync ++ if (usejump == true){ ++ if (pstate->buttonheld[bt_use]){ ++ if ((AreJumping == false)&&(ob->z > 0)&&(doorn==0)){ ++ oldzval = ob->z; ++ ob->z -= 15; ++ ob->momentumz += GRAVITY; ++ AreJumping = true; ++ donttilt=10; ++ return; ++ } ++ AreJumping = false; ++ return; ++ } ++ } ++ } ++ //bna ++ } + // else + // SD_PlaySoundRTP (SD_NOWAYSND,ob->x,ob->y); + // pstate->buttonheld[bt_use] = true; +@@ -1843,7 +1894,7 @@ + // PollMouseButtons + // + //****************************************************************************** +- ++extern boolean usemouselook; + void PollMouseButtons (void) + { + int i; +@@ -1859,12 +1910,22 @@ + press = buttons & mask; + + if ( press ) +- { ++ {//SetTextMode ( ); + // if ( ( buttonmouse[ i ] != bt_nobutton ) && + // ( DoubleClickCount[ i ] != 2 ) ) + if ( buttonmouse[ i ] != bt_nobutton ) + { + buttonpoll[ buttonmouse[ i ] ] = true; ++ //bna added ++ if ((i == 1)&&(usemouselook == true)){ ++ //if rightclick set horizon to 512 (normall) ++ playertype * pstate; ++ pstate=&PLAYERSTATE[consoleplayer]; ++ pstate->horizon = 512; ++ // SetNormalHorizon(PLAYER[0]); ++ } ++ //bna added ++ + } + } + +@@ -2116,7 +2177,7 @@ + //#define MOUSE_RY_SHIFT 12 + //#define MOUSE_TZ_SHIFT 3 + #define MOUSE_TZ_SENSITIVITY_SCALE 65535 +-#define MOUSE_RY_SENSITIVITY_SCALE 18725 ++#define MOUSE_RY_SENSITIVITY_SCALE 18725*2 + //#define MOUSE_RY_INPUT_SCALE 6000 + #define MOUSE_TZ_INPUT_SCALE 20 + int mouse_ry_input_scale = 5000; +@@ -2125,17 +2186,36 @@ + { + 0,1,2,3,4,5,6,8,11,13,15,18,12,13,14 + }; +- + //#define MOUSE_RY_SCALE 65535 +- + //#define MOUSE_TZ_SCALE 65535 + #define MAXMOUSETURN 7000000 + ++/* use SDL mouse */ ++#define USESDLMOUSE 1 ++ ++ ++extern int inverse_mouse; ++ double Y_MouseSpeed=70; ++ + void PollMouseMove (void) + { + int mousexmove, mouseymove; ++ double Ys; ++//SetTextMode(); ++ ++ Ys=(Y_MouseSpeed/100); ++// ++ ++// const long inverse_mouse = 1; //set to -1 to invert mouse ++// inverse_mouse def moved to RT_CFG.C + ++#ifdef USESDLMOUSE + INL_GetMouseDelta(&mousexmove, &mouseymove); ++#else ++ PollMouse();//Uses DirectInput mouse in DInput.cpp ++ mousexmove=MX; ++ mouseymove=MY; ++#endif + + if (abs(mousexmove)>abs(mouseymove)) + mouseymove/=2; +@@ -2146,31 +2226,60 @@ + + + if ((abs (mouseymove)) >= threshold) +- { ++ {// + MY = MOUSE_TZ_INPUT_SCALE*mouseymove; ++ MY *= inverse_mouse; ++ if (usemouselook == true){ ++ if (MY > 0){ ++ playertype * pstate; ++ pstate=&PLAYERSTATE[consoleplayer]; ++ //if (pstate->horizon > 512){ ++ pstate->horizon -= Ys * (2*sensitivity_scalar[mouseadjustment]); ++ //} ++ } ++ else if (MY < 0){ ++ playertype * pstate; ++ pstate=&PLAYERSTATE[consoleplayer]; ++ //SetTextMode ( ); ++ pstate->horizon += Ys * (2*sensitivity_scalar[mouseadjustment]); ++ //buttonpoll[ bt_horizonup ] = true; ++ } ++ MY = 0; ++ }else{ ++ // MY += FixedMul(MY,mouseadjustment*MOUSE_TZ_SENSITIVITY_SCALE); ++ if (abs(mouseymove)>200) ++ { ++ buttonpoll[bt_run]=true; ++ // buttonpoll[ bt_lookup ] = true; ++ } ++ } ++ } + +- // MY += FixedMul(MY,mouseadjustment*MOUSE_TZ_SENSITIVITY_SCALE); +- if (abs(mouseymove)>200) +- { +- buttonpoll[bt_run]=true; +- } +- } ++ ++ ++ + + if ((abs (mousexmove)) >= threshold) +- { ++ { + //MX = -MOUSE_RY_INPUT_SCALE*mousexmove; + MX = -mouse_ry_input_scale*mousexmove; + MX += FixedMul(MX,sensitivity_scalar[mouseadjustment]*MOUSE_RY_SENSITIVITY_SCALE); + // if (abs(MX) > MAXMOUSETURN) + // MX = MAXMOUSETURN*SGN(MX); +- if (abs(mouseymove)>10) +- { +- buttonpoll[bt_run]=true; +- } +- } +- ++ if (usemouselook == true){ ++ if (abs(mouseymove)>10) ++ { ++ buttonpoll[bt_run]=true; ++ //buttonpoll[ bt_lookdown ] = true; ++ } ++ } ++ } + // if (MY > 0) + // MX -= (MX/2); ++ ++// MX=0; ++// MY=0; ++ + } + + +@@ -2853,8 +2962,25 @@ + AddPauseStateCommand(COM_PAUSE); + } + } +- if (Keyboard[sc_Insert] && Keyboard[sc_X]) +- AddExitCommand(); ++ if (Keyboard[sc_Insert] && Keyboard[sc_X]){ ++ AddExitCommand(); ++ } ++//bna section ++ if (Keyboard[sc_5]){ ++ // SetTextMode ( ); ++ weaponscale += 1000; ++ //testval++; ++ } ++ if (Keyboard[sc_6]){ ++ // SetTextMode ( ); ++ weaponscale -= 1000; ++ // testval--; ++ } ++//bna section end ++ ++ ++ ++ + + for (i = (NUMTXBUTTONS-1); i >= 0; i--) + { +@@ -3761,15 +3887,23 @@ + + index = touchindices[ob->tilex][ob->tiley]; + if (index && (abs(ob->z - nominalheight) < 5)) +- {if (!TRIGGER[index-1]) +- {if (touchplate[index-1]->complete) +- SD_PlaySoundRTP(SD_BADTOUCHSND,ob->x,ob->y); +- else +- { +- SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y); +- if (ob == player) +- AddMessage("Touchplate triggered.",MSG_GAME); } +- } ++ {if (!TRIGGER[index-1]){ ++#if (BNACRASHPREVENT == 1) ++ if (touchplate[index-1] != 0) { // CRASH IN SHAREWARE 'ride em cowboy' BNA FIX ++ //SetTextMode ( ); qwert // DONT ALLOW BAD touchplate ( == 0 ) see rt_door.c ++#endif ++ if (touchplate[index-1]->complete) ++ SD_PlaySoundRTP(SD_BADTOUCHSND,ob->x,ob->y); ++ else { ++ SD_PlaySoundRTP(SD_TOUCHPLATESND,ob->x,ob->y); ++ if (ob == player) ++ AddMessage("Touchplate triggered.",MSG_GAME); ++ } ++#if (BNACRASHPREVENT == 1) ++ }else{SD_PlaySoundRTP(SD_BADTOUCHSND,ob->x,ob->y);} ++ // CRASH IN SHAREWARE 'ride em cowboy' BNA FIX ++#endif ++ } + TRIGGER[index-1] = 1; + } + +@@ -4022,13 +4156,20 @@ + = + =================== + */ +- ++extern int iG_playerTilt; ++extern double dTopYZANGLELIMIT; + void PlayerTiltHead (objtype * ob) + { + playertype * pstate; + int dyz=0; + int yzangle; + ++//bna++ jumpmode ++ if ((donttilt > 0)){ ++ donttilt--; ++ return; ++ } ++ + M_LINKSTATE(ob,pstate); + + yzangle=ob->yzangle+HORIZONYZOFFSET; +@@ -4158,22 +4299,139 @@ + if ((abs(yzangle-pstate->horizon))horizon; + } ++//SetTextMode(); ++ ++ if (yzangle != 512){ ++ FinddTopYZANGLELIMITvalue(ob); ++ } ++ ++ + yzangle+=dyz; + if (yzangle-HORIZONYZOFFSET>YZANGLELIMIT) + yzangle=HORIZONYZOFFSET+YZANGLELIMIT; +- else if (yzangle-HORIZONYZOFFSET<-YZANGLELIMIT) +- yzangle=HORIZONYZOFFSET-YZANGLELIMIT; +- ++/* else if (yzangle-HORIZONYZOFFSET<-TopYZANGLELIMIT)//bnafix ++ yzangle=HORIZONYZOFFSET-TopYZANGLELIMIT;//bnafix ++dTopYZANGLELIMIT*/ ++ else if (yzangle-HORIZONYZOFFSET<-dTopYZANGLELIMIT)//bnafix ++ yzangle=HORIZONYZOFFSET-dTopYZANGLELIMIT;//bnafix + ob->yzangle=yzangle-HORIZONYZOFFSET; + Fix(ob->yzangle); ++ ++ iG_playerTilt = ob->yzangle; ++ + } + ++//---------------------------------------------------------------------- ++// bna added function ++// if a player is to close to wall, looking down max ++//,this func limit the dTopYZANGLELIMIT value when ++// facing a wall ++#define SMALLANGLE 90 ++//there is small angles where didnt work ++//so we check for them to = 90/2048 = aprox, 15 degrees ++int FinddTopYZANGLELIMITvalue(objtype *ob) ++{/* ++ ++ ++checkx = ob->tilex + 1; ++checky = ob->tiley + 1; ++if (actorat[checkx][checky]){ ++ return 0; ++} ++return 1; ++ ++checkx = ob->tilex ; ++checky = ob->tiley; ++ ++// find which direction the player is facing ++//and check if it is a wall ++ ++*/ ++ ++ //use lowest down angle ++ dTopYZANGLELIMIT = (26*FINEANGLES/360); ++ ++ if (ob->angle < 256 || ob->angle > 1792) { ++ if ((tilemap[ob->tilex + 1][ob->tiley])!=0){ ++ ++ return 0; ++ } ++ //ob->dir = east; ++ }else if (ob->angle < 768) { ++ if ((tilemap[ob->tilex][ob->tiley-1])!=0){ ++ return 0; ++ } ++ }else if (ob->angle < 1280) { ++ if ((tilemap[ob->tilex-1][ob->tiley])!=0){ ++ return 0; ++ } ++ }else{ ++ if ((tilemap[ob->tilex][ob->tiley+1])!=0){ ++ return 0; ++ } ++ } ++ ++ ++ //use middle down angle ++ dTopYZANGLELIMIT = (42*FINEANGLES/360); ++ ++ if ((ob->angle > 768-SMALLANGLE)&&(ob->angle <= 768)) { ++ if ((tilemap[ob->tilex -1][ob->tiley])!=0){//ob->tiley-1 ++ return 0; ++ } ++ } ++ if ((ob->angle < 1280+SMALLANGLE)&&(ob->angle >= 1280)) { ++ if ((tilemap[ob->tilex - 1][ob->tiley])!=0){//ob->tiley+1 ++ return 0; ++ } ++ } ++ if ((ob->angle > 256)&&(ob->angle <= 256+SMALLANGLE)) { ++ if ((tilemap[ob->tilex + 1][ob->tiley])!=0){//ob->tiley-1 ++ return 0; ++ } ++ } ++ if ((ob->angle < 1792)&&(ob->angle >= 1792-SMALLANGLE)) { ++ if ((tilemap[ob->tilex + 1][ob->tiley])!=0){//ob->tiley+1 ++ return 0; ++ } ++ } ++ if ((ob->angle < 1280)&&(ob->angle >= 1280-SMALLANGLE)) { ++ if ((tilemap[ob->tilex ][ob->tiley+1])!=0){//ob->tilex-1 ++ return 0; ++ } ++ } ++ if ((ob->angle > 1792)&&(ob->angle <= 1792+SMALLANGLE)) { ++ if ((tilemap[ob->tilex ][ob->tiley+1])!=0){//ob->tiley+1 ++ return 0; ++ } ++ } ++ if ((ob->angle > 768)&&(ob->angle <= 768+SMALLANGLE)) { ++ if ((tilemap[ob->tilex][ob->tiley-1])!=0){//ob->tiley-1 ++ return 0; ++ } ++ } ++ if ((ob->angle < 256)&&(ob->angle >= 256-SMALLANGLE)) { ++ if ((tilemap[ob->tilex][ob->tiley-1])!=0){//ob->tiley-1 ++ return 0; ++ } ++ } ++ ++ //use max down angle ++ dTopYZANGLELIMIT = (90*FINEANGLES/360); ++ return 1; ++} ++// bna added function end ++//---------------------------------------------------------------------- ++ ++ ++ ++ + /* + =================== + = + = UpdatePlayers + = +-=================== ++=================== QWERTYU + */ + void UpdatePlayers ( void ) + { +@@ -4182,6 +4440,11 @@ + + for (obj = FIRSTACTOR; obj->obclass==playerobj; obj = obj->next) + { ++ ++//ErrorDontQuit("obj->next = ",obj->next); ++#if (BNACRASHPREVENT == 1)//crashed here when oscuro and larves were all killed ++ if (obj->next == 0){return;} ++#endif + obj->speed=FindDistance(obj->momentumx, obj->momentumy); + // M_LINKSTATE(obj,pstate); + // pstate->steptime-=obj->speed; +diff -urN rott-1.0.orig/rott/rt_scale.c rott-1.0/rott/rt_scale.c +--- rott-1.0.orig/rott/rt_scale.c 2002-12-25 04:23:47.000000000 +0100 ++++ rott-1.0/rott/rt_scale.c 2007-05-06 22:34:18.000000000 +0200 +@@ -1107,18 +1107,26 @@ + = + ================= + */ ++extern int G_gmasklump; + void DrawScreenSizedSprite (int lump) + { +- byte *shape; ++ //draws gasmask among other things zxcv ++ byte *shape,*src; + int frac; + patch_t *p; + int x1,x2; + int tx; +- int plane; ++// int plane; + byte * b; + int startfrac; + ++ int offset; ++ int length; ++ int topscreen; ++ int bottomscreen; ++ byte *cnt,*Ycnt; + ++ // SetTextMode ( ); + whereami=39; + shadingtable=colormap+(1<<12); + shape=W_CacheLumpNum(lump,PU_CACHE, Cvt_patch_t, 1); +@@ -1126,6 +1134,7 @@ + dc_invscale=(viewwidth<<16)/p->origsize; + tx=-p->leftoffset; + centeryclipped=viewheight>>1; ++ //centeryclipped=(viewheight>>1)+43; + // + // calculate edges of the shape + // +@@ -1149,27 +1158,43 @@ + + startfrac=0; + +-#ifdef DOS +- for (plane=0;plane<4;plane++,startfrac+=dc_iscale) +-#endif +- + { + frac=startfrac; +- +-#ifdef DOS +- b=(byte *)bufferofs+(plane>>2); +- VGAWRITEMAP(plane&3); +-#else + b=(byte *)bufferofs; +-#endif + +-#ifdef DOS +- for (x1=plane;x1<=x2;x1+=4, frac += (dc_iscale<<2),b++) +-#else ++ ///////////// BNA PATCH ////////////////////////////////////////////////////////// ++ //gmasklump=W_GetNumForName("p_gmask"); //=783 ++ //perhaps I should have painted the mask in a seperate buffer ++ //and streched it and copyet it back, but that would demand ++ //a new buffer (size=800x600) and slowed the game down so ? ++ ++ // if its the gasmask, paint black patches at hires ++ if ((lump == G_gmasklump)&&(iGLOBAL_SCREENWIDTH>320)) { ++ src = ((p->collumnofs[frac>>SFRACBITS])+shape); ++ offset=*(src++); ++ length=*(src++); ++ topscreen = sprtopoffset + (dc_invscale*offset); ++ bottomscreen = topscreen + (dc_invscale*length); ++ dc_yl = (topscreen+SFRACUNIT-1)>>SFRACBITS;//=41 viewheight=584 ++ dc_yh = ((bottomscreen-1)>>SFRACBITS);//=540 viewwidth =800 ++ //paint upper black patch in gasmask ++ for (cnt=b;cntcollumnofs[frac>>SFRACBITS])+shape),b); ++ ScaleClippedPost(((p->collumnofs[frac>>SFRACBITS])+shape),b); + } + } + } +@@ -1298,9 +1323,9 @@ + shape = W_CacheLumpNum (shapenum, PU_CACHE, Cvt_patch_t, 1); + p = (patch_t *)shape; + +- if (((x-p->leftoffset)<0) || ((x-p->leftoffset+p->width)>320)) ++ if (((x-p->leftoffset)<0) || ((x-p->leftoffset+p->width)>iGLOBAL_SCREENWIDTH)) + Error ("DrawNormalSprite: x is out of range x=%ld\n",x-p->leftoffset+p->width); +- if (((y-p->topoffset)<0) || ((y-p->topoffset+p->height)>200)) ++ if (((y-p->topoffset)<0) || ((y-p->topoffset+p->height)>iGLOBAL_SCREENHEIGHT)) + Error ("DrawNormalSprite: y is out of range y=%ld\n",y-p->topoffset+p->height); + + startx=x-p->leftoffset; +@@ -1344,8 +1369,9 @@ + frac = dc_texturemid + (dc_yl-centery)*fracstep; + + while (count--) { ++ //*dest = test++; + *dest = shadingtable[dc_source[(frac>>SFRACBITS)]]; +- dest += MAXSCREENWIDTH; ++ dest += iGLOBAL_SCREENWIDTH; + frac += fracstep; + } + } +@@ -1363,7 +1389,7 @@ + while (count--) + { + *dest = shadingtable[*dest]; +- dest += MAXSCREENWIDTH; ++ dest += iGLOBAL_SCREENWIDTH; + } + } + +@@ -1385,30 +1411,33 @@ + fracstep <<= 10; + + while (count--) { ++ //*dest = 6; + *dest = shadingtable[dc_source[(((unsigned)frac)>>26)]]; +- dest += MAXSCREENWIDTH; ++ dest += iGLOBAL_SCREENWIDTH; + frac += fracstep; + } + } + + void R_DrawClippedColumn (byte * buf) + { +- // This is *NOT* 100% correct - DDOI ++ // This is *NOT* 100% correct - DDOI zxcv + int count; + int frac, fracstep; + byte *dest; ++// byte *b;int y; + + count = dc_yh - dc_yl + 1; + if (count < 0) return; + +- dest = buf + ylookup[dc_yl]; ++ dest = buf + ylookup[dc_yl]; ++ + + fracstep = dc_iscale; + frac = dc_texturemid + (dc_yl-centeryclipped)*fracstep; + + while (count--) { + *dest = shadingtable[dc_source[(((unsigned)frac)>>SFRACBITS)]]; +- dest += MAXSCREENWIDTH; ++ dest += iGLOBAL_SCREENWIDTH; + frac += fracstep; + } + } +@@ -1427,7 +1456,7 @@ + while (count--) + { + *dest = (byte)color; +- dest += MAXSCREENWIDTH; ++ dest += iGLOBAL_SCREENWIDTH; + } + } + +diff -urN rott-1.0.orig/rott/rt_stat.c rott-1.0/rott/rt_stat.c +--- rott-1.0.orig/rott/rt_stat.c 2007-05-06 23:57:48.000000000 +0200 ++++ rott-1.0/rott/rt_stat.c 2007-05-06 22:34:18.000000000 +0200 +@@ -1113,7 +1113,7 @@ + */ + + +- ++int BaseMarkerZ;//bna++ + + void SpawnStatic (int tilex, int tiley, int mtype, int zoffset) + {statobj_t * temp; +@@ -1345,6 +1345,10 @@ + } + + //=====================================================================// ++ //bna added ++ // BaseMarkerZ used to adjust height in s_basemarker1 ++ // in SpawnNewObj(i,j,&s_basemarker1,inertobj); ++ BaseMarkerZ=temp->z;//bna++ BaseMarkerZ = spawnz; + + PreCacheStaticFrames(temp); + +diff -urN rott-1.0.orig/rott/rt_str.c rott-1.0/rott/rt_str.c +--- rott-1.0.orig/rott/rt_str.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/rt_str.c 2007-05-06 22:43:28.000000000 +0200 +@@ -100,14 +100,14 @@ + source = ((byte *)CurrentFont)+CurrentFont->charofs[ch]; + while (width--) + { +- if ((x>=0) && (x=0) && (x=0) && (y=0) && (y0) + #ifdef DOS +@@ -1494,28 +1494,25 @@ + // + //****************************************************************************** + +-void DrawIntensityChar +- ( +- char ch +- ) +- ++void DrawIntensityChar ( char ch ) + { ++ + byte pix; +- int width; +- int height; ++ int px1,py1; ++ int width,w1; ++ int height,h1; + int ht; +- byte *source; ++ byte *source,*src1; + byte *dest; +- byte *origdest; ++ byte *origdest,*orgdst1; + int mask; + ++ px1 = px;py1 = py; ++ + ht = IFont->height; + +-#ifdef DOS +- origdest = ( byte * )( bufferofs + ylookup[ py ] + ( px >> 2 ) ); +-#else + origdest = ( byte * )( bufferofs + ylookup[ py ] + px ); +-#endif ++ + dest = origdest; + + ch -= 31; +@@ -1524,37 +1521,62 @@ + + mask = 1 << ( px & 3 ); + +- while( width-- ) +- { +- VGAMAPMASK( mask ); +- +- height = ht; +- while( height-- ) +- { +- pix = *source; +- if ( pix != 0xFE ) +- { +- *dest = GetIntensityColor( pix ); +- } ++ if ((iGLOBAL_SCREENWIDTH <= 320)||(StrechScreen == true)){ ++ while( width-- ) ++ { ++ VGAMAPMASK( mask ); ++ ++ height = ht; ++ while( height-- ) ++ { ++ pix = *source; ++ if ( pix != 0xFE ) ++ { ++ *dest = GetIntensityColor( pix ); ++ } ++ ++ source++; ++ dest += linewidth; ++ } ++ ++ px++; ++ origdest++; ++ dest = origdest; ++ } ++ }else{//strech letter in x any direction ++ w1 = width; ++ h1 = ht; ++ orgdst1 = origdest; ++ src1 = source; ++ while( width-- ) ++ { ++ VGAMAPMASK( mask ); ++ ++ height = ht; ++ while( height-- ) ++ { ++ pix = *source; ++ if ( pix != 0xFE ) ++ { ++ *dest = GetIntensityColor( pix ); ++ *(dest+iGLOBAL_SCREENWIDTH) = GetIntensityColor( pix ); ++ ++ *(dest+1) = GetIntensityColor( pix ); ++ *(dest+1+iGLOBAL_SCREENWIDTH) = GetIntensityColor( pix ); ++ } ++ ++ source++; ++ dest += linewidth*2; ++ } ++ ++ px++;px++; ++ origdest++;origdest++; ++ dest = origdest; ++ } + +- source++; +- dest += linewidth; +- } ++ } + +- px++; +-#ifdef DOS +- mask <<= 1; +- if ( mask == 16 ) +- { +- mask = 1; +- origdest++; +- } +-#else +- origdest++; +-#endif +- dest = origdest; +- } +- } ++} + + + //****************************************************************************** +@@ -1614,14 +1636,33 @@ + temp = *string++; + temp = toupper (temp); + +- // Force fontcolor to a specific color ++ // Force fontcolor to a specific color egacolor[ RED ]; + if (temp == 'N') + { + temp = *string++; + fontcolor = GetColor (temp); + oldfontcolor = fontcolor; + } +- ++ //bna added ++ else if (temp == 'X') ++ { ++ temp = *string; ++ fontcolor = egacolor[ RED ]; ++ oldfontcolor = fontcolor; ++ } ++ else if (temp == 'Y') ++ { ++ temp = *string; ++ fontcolor = egacolor[ YELLOW ]; ++ oldfontcolor = fontcolor; ++ } ++ else if (temp == 'Z') ++ { ++ temp = *string; ++ fontcolor = egacolor[ GREEN ]; ++ oldfontcolor = fontcolor; ++ } ++ //bna added end + // Restore fontcolor to a previous color + else if (temp == 'O') + { +diff -urN rott-1.0.orig/rott/rt_ted.c rott-1.0/rott/rt_ted.c +--- rott-1.0.orig/rott/rt_ted.c 2007-05-06 23:57:48.000000000 +0200 ++++ rott-1.0/rott/rt_ted.c 2007-05-06 23:45:11.000000000 +0200 +@@ -74,7 +74,9 @@ + // GLOBAL VARIABLES + //======================================== + +- ++extern char *tmpPICbuf; ++extern int iXmas; ++extern boolean UseBaseMarker; + + teamtype TEAM[MAXPLAYERS]; + int numareatiles[NUMAREAS+1]; +@@ -1141,6 +1143,23 @@ + int ticdelay; + byte *tempbuf; + ++ double Gs; ++ Gs = (iGLOBAL_SCREENWIDTH*100/320); ++ Gs = Gs / 100; ++ ++//SetTextMode ( ); ++ ++/* ++#define PRECACHEBARX 28 ++#define PRECACHEBARY 178 ++ ++#define PRECACHELED1X 9 ++#define PRECACHELED1Y 8 ++ ++#define PRECACHELED2X 9 ++#define PRECACHELED2Y 12 ++*/ ++ + #if defined(PLATFORM_MACOSX) || defined(__sparc__) + #warning "Precaching is disabled. Fix." + // Precaching confuses the byteswapping code, since we have +@@ -1177,18 +1196,47 @@ + newheap=Z_UsedHeap(); + currentmem=(newheap*MAXLEDS)/maxheapsize; + while (lastmem<=currentmem) +- { +- DrawNormalSprite (PRECACHEBARX+PRECACHELED1X+(lastmem<<2), ++ {//SetTextMode ( ); ++ if ( iGLOBAL_SCREENWIDTH == 320) { ++ DrawNormalSprite (PRECACHEBARX+PRECACHELED1X+(lastmem<<2), + PRECACHEBARY+PRECACHELED1Y, +- W_GetNumForName ("led1")); ++ W_GetNumForName ("led1"));//led1 progressbar ++ }else if ( iGLOBAL_SCREENWIDTH == 640) { ++ DrawNormalSprite (72+(Gs*(lastmem<<2)),446,W_GetNumForName ("led1"));//led1 progressbar ++ DrawNormalSprite (72+(Gs*(lastmem<<2)),446+3,W_GetNumForName ("led1"));//led1 progressbar ++ DrawNormalSprite (72+3+(Gs*(lastmem<<2)),446,W_GetNumForName ("led1"));//led1 progressbar ++ DrawNormalSprite (72+3+(Gs*(lastmem<<2)),446+3,W_GetNumForName ("led1"));//led1 progressbar ++ }else if ( iGLOBAL_SCREENWIDTH == 800) { ++ DrawNormalSprite (91+(Gs*(lastmem<<2)),559,W_GetNumForName ("led1"));//led1 progressbar ++ DrawNormalSprite (91+(Gs*(lastmem<<2)),559+3,W_GetNumForName ("led1"));//led1 progressbar ++ DrawNormalSprite (91+3+(Gs*(lastmem<<2)),559,W_GetNumForName ("led1"));//led1 progressbar ++ DrawNormalSprite (91+3+(Gs*(lastmem<<2)),559+3,W_GetNumForName ("led1"));//led1 progressbar ++ } ++ + lastmem++; + } + currentcache=(i*MAXLEDS)/(cacheindex+1); + while (lastcache<=currentcache) + { +- DrawNormalSprite (PRECACHEBARX+PRECACHELED2X+(lastcache<<2), ++ ++ if ( iGLOBAL_SCREENWIDTH == 320) { ++ DrawNormalSprite (PRECACHEBARX+PRECACHELED2X+(lastcache<<2), + PRECACHEBARY+PRECACHELED2Y, +- W_GetNumForName ("led2")); ++ W_GetNumForName ("led2"));//led2 progressbar ++ }else if ( iGLOBAL_SCREENWIDTH == 640) { ++ DrawNormalSprite (72+(Gs*(lastcache<<2)),458,W_GetNumForName ("led2"));//led2 progressbar ++ DrawNormalSprite (72+(Gs*(lastcache<<2)),458+3,W_GetNumForName ("led2"));//led2 progressbar ++ DrawNormalSprite (72+3+(Gs*(lastcache<<2)),458,W_GetNumForName ("led2"));//led2 progressbar ++ DrawNormalSprite (72+3+(Gs*(lastcache<<2)),458+3,W_GetNumForName ("led2"));//led2 progressbar ++ ++ }else if ( iGLOBAL_SCREENWIDTH == 800) { ++ DrawNormalSprite (91+(Gs*(lastcache<<2)),573,W_GetNumForName ("led2"));//led2 progressbar ++ DrawNormalSprite (91+(Gs*(lastcache<<2)),573+3,W_GetNumForName ("led2"));//led2 progressbar ++ DrawNormalSprite (91+3+(Gs*(lastcache<<2)),573,W_GetNumForName ("led2"));//led2 progressbar ++ DrawNormalSprite (91+3+(Gs*(lastcache<<2)),573+3,W_GetNumForName ("led2"));//led2 progressbar ++ } ++ StrechScreen=false;//bna++ ++ VW_UpdateScreen ();//bna++ + lastcache++; + ticdelay--; + if (ticdelay==0) +@@ -1203,28 +1251,41 @@ + } + } + } ++ StrechScreen=false;//bna++ ++ VW_UpdateScreen ();//bna++ ++ //I_Delay(200); + bufferofs=tempbuf; + ShutdownPreCache (); + + if ( BATTLEMODE ) + { + int width,height; +- char buf[30]; ++ char buf[30];//byte * shape; ++ double WHratio = 16200/200; ++ WHratio = WHratio/100; ++/// iGLOBAL_SCREENWIDTH = 640; ++// iGLOBAL_SCREENHEIGHT = 480; ++StrechScreen=false; ++ ++ // Cache in fonts ++// shape = W_CacheLumpNum (W_GetNumForName ("newfnt1"), PU_STATIC, Cvt_font_t, 1); ++// bigfont = (font_t *)shape; ++ CurrentFont = newfont1;//smallfont; + +- CurrentFont = smallfont; + strcpy( buf, "Press Any Key" ); + US_MeasureStr (&width, &height, &buf[ 0 ] ); +- PrintX = (320-width) / 2; +- PrintY = 162; +- VWB_TBar (PrintX-2, PrintY-2, width+4, height+4); ++ PrintX = (iGLOBAL_SCREENWIDTH-(width)) / 2; ++ PrintY = WHratio*iGLOBAL_SCREENHEIGHT;//162; ++ //VWB_TBar (PrintX-2, PrintY-2, width+4, height+4); + US_BufPrint (&buf[0]); ++ + VW_UpdateScreen(); + + IN_StartAck(); + while (!IN_CheckAck ()) + ; + } +- ++ // StrechScreen=true; + #if (DEVELOPMENT == 1) + tempbuf=bufferofs; + bufferofs=displayofs; +diff -urN rott-1.0.orig/rott/rt_vid.c rott-1.0/rott/rt_vid.c +--- rott-1.0.orig/rott/rt_vid.c 2007-05-06 23:57:48.000000000 +0200 ++++ rott-1.0/rott/rt_vid.c 2007-05-06 22:34:18.000000000 +0200 +@@ -123,12 +123,67 @@ + destline = (byte *)(bufferofs+ylookup[y+j]+x); + + for (i = 0; i < width; i++) { +- *(destline + i*4 + plane) = *ptr++; ++// if (ptr < bufferofs + toplimit) { //bnafix zxcvb ++ *(destline + i*4 + plane) = *ptr++; ++// } + } + } + } + #endif + } ++// bna function start ++void VL_MemToScreenClipped (byte *source, int width, int height, int x, int y); ++void VL_MemToScreenClipped (byte *source, int width, int height, int x, int y) ++{ ++ byte *ptr, *destline; ++ int plane, i, j;//,toplimit; ++ ptr = source; ++ for (plane = 0; plane < 4; plane++) { ++ for (j = 0; j < height; j++) { ++ destline = (byte *)(bufferofs+ylookup[y+j]+x); ++ for (i = 0; i < width; i++) { ++ if (*ptr != 255){ ++ *(destline + i*4 + plane) = *ptr++; ++ }else{ptr++;} ++ } ++ } ++ } ++} ++ ++//copy picture to mem (bufferofs) in doublesize ++void VL_MemStrechedToScreen (byte *source, int width, int height, int x, int y) ++{ ++ byte *ptr, *destline,*tmp,*o; ++ int plane, i, j; ++ ++ tmp = bufferofs; ++ ptr = source; ++ ++ for (plane = 0; plane < 4; plane++) { ++ for (j = 0; j < height; j++) { ++ destline = (byte *)(bufferofs+(iGLOBAL_SCREENWIDTH*j)+ylookup[y+j]+x); ++ o = ptr; ++ for (i = 0; i < width; i+=1) { ++ *(destline + i*4 + plane) = *ptr; ++ destline++; ++ *(destline + i*4 + plane) = *ptr++; ++ } ++ ptr = o; ++ ++ destline = (byte *)(bufferofs+iGLOBAL_SCREENWIDTH+(iGLOBAL_SCREENWIDTH*j)+ylookup[y+j]+x); ++ for (i = 0; i < width; i+=1) { ++ *(destline + i*4 + plane) = *ptr; ++ destline++; ++ *(destline + i*4 + plane) = *ptr++; ++ ++ } ++ ++ } ++ } ++ bufferofs = tmp; ++} ++// bna function end ++ + + //************************************************************************* + // +@@ -229,9 +284,9 @@ + } + + #ifdef DOS +- origdest += SCREENBWIDE; ++ origdest += iGLOBAL_SCREENBWIDE; + #else +- origdest += MAXSCREENWIDTH; ++ origdest += iGLOBAL_SCREENWIDTH; + #endif + + sourceoff += sourcewidth; +@@ -1050,22 +1105,20 @@ + byte *source = (byte *)&lbminfo->data; + byte *buf; + int ht = lbminfo->height; +-#ifdef DOS +- int planes; +- byte writemask; +-#endif ++ + int x = 0; + int y; + byte *origbuf; + byte pal[768]; + +-#ifdef DOS +- writemask = 1 << (x&3); +-#endif +- orig = screen; + +- buf = (byte *) SafeMalloc (64000); ++ orig = screen; + ++ if (iGLOBAL_SCREENWIDTH <= 320){ ++ buf = (byte *) SafeMalloc (64000); ++ }else{ ++ buf = (byte *) SafeMalloc (iGLOBAL_SCREENWIDTH*iGLOBAL_SCREENHEIGHT); ++ } + origbuf = buf; + + VL_ClearBuffer (displayofs, 0); +@@ -1104,48 +1157,40 @@ + count += rept; + + } while (count < lbminfo->width); ++ if (iGLOBAL_SCREENWIDTH > 320){ ++ buf += (iGLOBAL_SCREENWIDTH-320); //eg 800 - 320) ++ } + } ++ //SetTextMode ( ); //12345678 + +-#ifdef DOS +- for (planes = 0; planes < 4; planes++) +-#endif + { + int cnt; + + cnt = 0; +- screen = orig; ++ screen = orig; + buf = origbuf; + VGAMAPMASK (writemask); + +-#ifdef DOS +- for (y = 0; y < (lbminfo->height*lbminfo->width)>>2; y++) +-#else +- for (y = 0; y < (lbminfo->height*lbminfo->width); y++) +-#endif +- { +-#ifdef DOS +- *screen++ = *(buf+(y*4)+planes); +-#else +- *screen++ = *(buf+y); +-#endif +-#ifdef DOS +- cnt++; ++ //bna section start ++ if (iGLOBAL_SCREENWIDTH <= 320){ ++ for (y = 0; y < (lbminfo->height*lbminfo->width); y++) ++ ++ { ++ *screen++ = *(buf+y); ++ } ++ }else{ ++ for (y = 0; y < (lbminfo->height); y++){ ++ for (x = 0; x < iGLOBAL_SCREENWIDTH; x++){ ++ *screen++ = *(buf++); ++ } ++ } ++ } ++ // bna section end + +- if (cnt == 80) +- { +- screen += 16; +- cnt = 0; +- } +-#endif +- } +- +-#ifdef DOS +- writemask <<= 1; +-#endif + } + + SafeFree(origbuf); +- ++ StrechScreen=true;//bna++ shut on streech mode + if (flip==true) + VW_UpdateScreen (); + +@@ -1161,6 +1206,40 @@ + + void SetBorderColor (int color) + { ++ // bna section start ++ ++ byte *cnt,*Ycnt,*b; ++ ++ b=(byte *)bufferofs; ++ ++ // color 56 could be used ++ ++ //paint top red line ++ for (cnt=b;cnt>HEIGHTFRACTION +@@ -285,14 +295,57 @@ + int screenx; + int screeny; + int topy; ++ /* ++ if (size>=10){ ++ ++ SetTextMode ( ); ++ screenx=screenx; ++ return; ++ } ++*/ ++ ++ if ( iGLOBAL_SCREENWIDTH == 640) { ++ height = 0;//we use height as dummy cnt ++ viewsizes[height++]= 380; viewsizes[height++]= 336; ++ viewsizes[height++]= 428; viewsizes[height++]= 352; ++ viewsizes[height++]= 460; viewsizes[height++]= 368; ++ viewsizes[height++]= 492; viewsizes[height++]= 384; ++ viewsizes[height++]= 524; viewsizes[height++]= 400; ++ viewsizes[height++]= 556; viewsizes[height++]= 416; ++ viewsizes[height++]= 588; viewsizes[height++]= 432; ++ viewsizes[height++]= 640; viewsizes[height++]= 448; ++ viewsizes[height++]= 640; viewsizes[height++]= 464; ++ viewsizes[height++]= 640; viewsizes[height++]= 480; ++ viewsizes[height++]= 640; viewsizes[height++]= 480; ++ }else if ( iGLOBAL_SCREENWIDTH == 800) { ++ height = 0; ++ viewsizes[height++]= 556; viewsizes[height++]= 488; ++ viewsizes[height++]= 588; viewsizes[height++]= 504; ++ viewsizes[height++]= 620; viewsizes[height++]= 520; ++ viewsizes[height++]= 652; viewsizes[height++]= 536; ++ viewsizes[height++]= 684; viewsizes[height++]= 552; ++ viewsizes[height++]= 716; viewsizes[height++]= 568; ++ viewsizes[height++]= 748; viewsizes[height++]= 584; ++ viewsizes[height++]= 800; viewsizes[height++]= 600; ++ viewsizes[height++]= 800; viewsizes[height++]= 600; ++ viewsizes[height++]= 800; viewsizes[height++]= 600; ++ viewsizes[height++]= 800; viewsizes[height++]= 600; ++ } ++ ++ ++ if ((size<0) || (size>=MAXVIEWSIZES)){//bna added ++ printf("Illegal screen size = %d\n",size); ++ size = 8;//set default value ++ viewsize = 8; ++ } + +- if ((size<0) || (size>=MAXVIEWSIZES)) +- Error("Illegal screen size = %ld\n",size); ++ //if ((size<0) || (size>=MAXVIEWSIZES)) ++ // Error("Illegal screen size = %ld\n",size); + + viewwidth = viewsizes[ size << 1 ]; // must be divisable by 16 + viewheight = viewsizes[ ( size << 1 ) + 1 ]; // must be even + +- maxheight = 200; ++ maxheight = iGLOBAL_SCREENHEIGHT; + topy = 0; + + // Only keep the kills flag +@@ -314,33 +367,48 @@ + topy += 16; + } + ++// if ( size == 7 ){maxheight -= 16;}//bna++ ++// if ( size <= 6 ){topy -= 8;}//bna++ ++ + if ( size < 8 ) + { + // Turn on health and ammo bar + StatusBar |= BOTTOM_STATUS_BAR; ++ + maxheight -= 16; ++ + } + else if ( size < 10 ) + { + // Turn on transparent health and ammo bar + StatusBar |= STATUS_PLAYER_STATS; + } +- ++ // SetTextMode ( ); ++ // viewheight=viewheight; + height = viewheight; + if ( height > 168 ) +- { +- // Prevent weapon from being scaled too big +- height = 168; +- } ++ { ++ // Prevent weapon from being scaled too big ++ height = 168; ++ if ( iGLOBAL_SCREENWIDTH == 640) { ++ height = 260; ++ }else if ( iGLOBAL_SCREENWIDTH == 800) { ++ height = 360; ++ } ++ } ++ ++ if ((G_weaponscale > 150)&&(G_weaponscale <600)){height = G_weaponscale;} ++ if ( iGLOBAL_SCREENWIDTH == 320) {G_weaponscale=G_weaponscale/2;} ++ weaponscale = ( height << 16 ) / 168;//( height << 16 ) = 170 * 65536 + +- weaponscale = ( height << 16 ) / 168; ++ + centerx = viewwidth >> 1; + centery = viewheight >> 1; + centeryfrac = (centery << 16); +- yzangleconverter = ( 0xaf85 * viewheight ) / 200; ++ yzangleconverter = ( 0xaf85 * viewheight ) / iGLOBAL_SCREENHEIGHT; + + // Center the view horizontally +- screenx = ( 320 - viewwidth ) >> 1; ++ screenx = ( iGLOBAL_SCREENWIDTH - viewwidth ) >> 1; + + if ( viewheight >= maxheight ) + { +@@ -370,7 +438,9 @@ + // Already being called in ResetFocalWidth + // SetViewDelta(); + +- CalcProjection(); ++ ++ CalcProjection(); ++ + } + + +@@ -410,10 +480,12 @@ + pic_t *shape; + + SetViewSize(viewsize); ++ + if ( viewsize < 7 ) + { +- shape = W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); +- DrawTiledRegion( 0, 16, 320, 200 - 32, 0, 16, shape ); ++ shape = ( pic_t * )W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 ); ++ //DrawTiledRegion( 0, 16, 320, 200 - 32, 0, 16, shape ); ++ DrawTiledRegion( 0, 16, iGLOBAL_SCREENWIDTH, iGLOBAL_SCREENHEIGHT - 32, 0, 16, shape );//bna++ + } + + if ( viewsize == 0 ) +diff -urN rott-1.0.orig/rott/rt_view.h rott-1.0/rott/rt_view.h +--- rott-1.0.orig/rott/rt_view.h 2003-01-01 10:24:39.000000000 +0100 ++++ rott-1.0/rott/rt_view.h 2007-05-06 22:34:18.000000000 +0200 +@@ -30,8 +30,9 @@ + #define HEIGHTFRACTION 6 + #define MAXVIEWSIZES 11 + +-#define FOCALWIDTH 160 +-#define FPFOCALWIDTH 160.0 ++//#define FOCALWIDTH 160//160 ++//#define FPFOCALWIDTH 160.0//160.0 ++ + + #define NUMGAMMALEVELS 8 + #define GAMMAENTRIES (64*8) +@@ -74,7 +75,8 @@ + } playercolors; + + extern byte * playermaps[MAXPLAYERCOLORS]; +-extern short pixelangle[MAXVIEWWIDTH]; ++//extern short pixelangle[MAXVIEWWIDTH]; ++extern short pixelangle[800]; + extern byte gammatable[GAMMAENTRIES]; + extern int gammaindex; + extern byte uniformcolors[MAXPLAYERCOLORS]; +diff -urN rott-1.0.orig/rott/states.h rott-1.0/rott/states.h +--- rott-1.0.orig/rott/states.h 2002-12-20 21:15:28.000000000 +0100 ++++ rott-1.0/rott/states.h 2007-05-06 22:34:18.000000000 +0200 +@@ -23,9 +23,9 @@ + #include "develop.h" + + #if (SHAREWARE == 0) +-#define MAXSTATES 1300 ++#define MAXSTATES 1300+17+8+32+32 + #else +-#define MAXSTATES 660 ++#define MAXSTATES 660+17+8+32+32 + #endif + + #define SF_CLOSE 0x01 +diff -urN rott-1.0.orig/rott/winrott.c rott-1.0/rott/winrott.c +--- rott-1.0.orig/rott/winrott.c 1970-01-01 01:00:00.000000000 +0100 ++++ rott-1.0/rott/winrott.c 2007-05-06 23:56:31.000000000 +0200 +@@ -0,0 +1,164 @@ ++/* Routines from winrott needed for the highres support for the SDL port */ ++#include ++#include ++#include "WinRott.h" ++#include "modexlib.h" ++ ++//typedef unsigned char byte; ++ ++int iGLOBAL_SCREENWIDTH;//bna val 800 ++int iGLOBAL_SCREENHEIGHT;//bna val 600 ++int iGLOBAL_SCREENBWIDE ; ++int iG_SCREENWIDTH;// default screen width in bytes ++ ++int iGLOBAL_HEALTH_X; ++int iGLOBAL_HEALTH_Y; ++int iGLOBAL_AMMO_X; ++int iGLOBAL_AMMO_Y; ++ ++int iGLOBAL_FOCALWIDTH; ++double dGLOBAL_FPFOCALWIDTH; ++ ++double dTopYZANGLELIMIT; ++ ++int iG_X_center; ++int iG_Y_center; ++ ++char *tmpPICbuf;//used to strech and schrink mem pictures ++ ++int iG_aimCross = 0; ++ ++extern int viewheight; ++extern int viewwidth; ++ ++//---------------------------------------------------------------------- ++#define FINEANGLES 2048 ++void SetRottScreenRes (int Width, int Height) ++{ ++ ++ iGLOBAL_SCREENWIDTH = Width; ++ iGLOBAL_SCREENHEIGHT = Height; ++ ++ ++ iGLOBAL_SCREENBWIDE = iGLOBAL_SCREENWIDTH*(96/320); ++ iG_SCREENWIDTH = iGLOBAL_SCREENWIDTH*(96/320);;// default screen width in bytes ++ ++ if (iGLOBAL_SCREENWIDTH == 320) { ++ iGLOBAL_FOCALWIDTH = 160; ++ dGLOBAL_FPFOCALWIDTH = 160.0; ++ iGLOBAL_HEALTH_X = 20; ++ iGLOBAL_HEALTH_Y = 185; ++ iGLOBAL_AMMO_X = 300; ++ iGLOBAL_AMMO_Y = 184; ++ ++ dTopYZANGLELIMIT = (44*FINEANGLES/360);; ++ } ++ if (iGLOBAL_SCREENWIDTH == 640) { ++ iGLOBAL_FOCALWIDTH = 180; ++ dGLOBAL_FPFOCALWIDTH = 180.0 ; ++ iGLOBAL_HEALTH_X = 40;//20*2; ++ iGLOBAL_HEALTH_Y = 466;//(185*2)+16; ++ iGLOBAL_AMMO_X = 600;//300*2; ++ iGLOBAL_AMMO_Y = 464;//480-16; ++ ++ dTopYZANGLELIMIT = (42*FINEANGLES/360);; ++ } ++ if (iGLOBAL_SCREENWIDTH == 800) { ++ iGLOBAL_FOCALWIDTH = 200; ++ dGLOBAL_FPFOCALWIDTH = 200.0 ; ++ iGLOBAL_HEALTH_X = 40;//20*2; ++ iGLOBAL_HEALTH_Y = 585;//(185/200)*600; ++ iGLOBAL_AMMO_X = 750;//(300/320)*800; ++ iGLOBAL_AMMO_Y = 584;//600-16; ++ ++ dTopYZANGLELIMIT = (90*FINEANGLES/360);; ++ } ++ ++ tmpPICbuf = malloc(iGLOBAL_SCREENHEIGHT*iGLOBAL_SCREENWIDTH); ++ ++ //dYZANGLELIMIT = (12*FINEANGLES/360); ++ //#define YZANGLELIMIT (12*FINEANGLES/360)//bna--(30*FINEANGLES/360) ++ ++ //#define TopYZANGLELIMIT (44*FINEANGLES/360)//bna added ++ ++// GetCurrentDirectory(sizeof(ApogeePath),ApogeePath);// curent directory name ++ ++} ++ ++//---------------------------------------------------------------------- ++//luckey for me that I am not programmin a 386 or the next ++//4 function would never have worked. bna++ ++extern int viewsize; ++void MoveScreenUpLeft() ++{ ++ int startX,startY,startoffset; ++ byte *Ycnt,*b; ++// SetTextMode ( ); ++ b=(byte *)bufferofs; ++ b += (((iGLOBAL_SCREENHEIGHT-viewheight)/2)*iGLOBAL_SCREENWIDTH)+((iGLOBAL_SCREENWIDTH-viewwidth)/2); ++ if (viewsize == 8) {b += 8*iGLOBAL_SCREENWIDTH;} ++ startX = 3; //take 3 pixels to the right ++ startY = 3; //take 3 lines down ++ startoffset = (startY*iGLOBAL_SCREENWIDTH)+startX; ++ ++ for (Ycnt=b;Ycntb;Ycnt-=iGLOBAL_SCREENWIDTH){ ++ memcpy(Ycnt+startoffset,Ycnt+startX,viewwidth-startX); ++ } ++} ++//---------------------------------------------------------------------- ++void MoveScreenUpRight() ++{ ++ int startX,startY,startoffset; ++ byte *Ycnt,*b; ++// SetTextMode ( ); ++ b=(byte *)bufferofs; ++ ++ b += (((iGLOBAL_SCREENHEIGHT-viewheight)/2)*iGLOBAL_SCREENWIDTH)+((iGLOBAL_SCREENWIDTH-viewwidth)/2); ++ if (viewsize == 8) {b += 8*iGLOBAL_SCREENWIDTH;} ++ startX = 3; //take 3 pixels to the right ++ startY = 3; //take 3 lines down ++ startoffset = (startY*iGLOBAL_SCREENWIDTH);//+startX; ++ ++ for (Ycnt=b;Ycntb;Ycnt-=iGLOBAL_SCREENWIDTH){ ++ memcpy(Ycnt+startoffset,Ycnt,viewwidth-startX); ++ } ++} ++ ++ +diff -urN rott-1.0.orig/rott/z_zone.c rott-1.0/rott/z_zone.c +--- rott-1.0.orig/rott/z_zone.c 2007-05-06 22:30:08.000000000 +0200 ++++ rott-1.0/rott/z_zone.c 2007-05-06 22:42:39.000000000 +0200 +@@ -287,14 +287,9 @@ + // scan through the block list looking for the first free block + // of sufficient size, throwing out any purgable blocks along the way + // +- size += sizeof(memblock_t); // account for size of block header ++// size += sizeof(memblock_t); // account for size of block header ++ size = (size + sizeof(memblock_t) + 3)&~3; // account for size of block header + +-#if defined(__sparc__) +- /* ensure word alignment */ +- if (size % 4) { +- size = size + (4 - size % 4); +- } +-#endif + + // + // if there is a free block behind the rover, back up over them +@@ -392,7 +387,8 @@ + // scan through the block list looking for the first free block + // of sufficient size, throwing out any purgable blocks along the way + // +- size += sizeof(memblock_t); // account for size of block header ++// size += sizeof(memblock_t); // account for size of block header ++ size = (size + sizeof(memblock_t) + 3)&~3; // account for size of block header + + + // +diff -ur rott-1.0/rott/_rt_menu.h winrot-1.26/rott/_rt_menu.h +--- rott-1.0/rott/_rt_menu.h 2002-12-21 01:12:18.000000000 +0100 ++++ winrot-1.26/rott/_rt_menu.h 2007-05-05 23:23:29.000000000 +0200 +@@ -303,8 +303,11 @@ + void DrawControlMenu (void); + void CP_ControlMenu (void); + void DrawOptionsMenu (void); ++void DrawExtOptionsMenu (void); ++void CP_ExtOptionsMenu (void); + void CP_OptionsMenu (void); + void DrawOptionsButtons (void); ++void DrawExtOptionsButtons (void); + void MenuFlipSpeed (void); + void DrawDetailMenu (void); + void CP_DetailMenu (void); +diff -ur rott-1.0/rott/rt_build.c winrot-1.26/rott/rt_build.c +--- rott-1.0/rott/rt_build.c 2002-12-25 05:40:39.000000000 +0100 ++++ winrot-1.26/rott/rt_build.c 2007-05-05 23:23:29.000000000 +0200 +@@ -575,7 +578,8 @@ + + for (i=0;i<=time;i+=tics) + { +- PositionMenuBuf (0,NORMALVIEW,false); ++ //PositionMenuBuf (0,NORMALVIEW,false); ++ PositionMenuBuf (0,NORMALVIEW,true);//bna++ in not true bg in menu is no redrawn + } + } + +diff -ur rott-1.0/rott/develop.h winrot-1.26/rott/develop.h +--- rott-1.0/rott/develop.h 2003-01-07 07:31:51.000000000 +0100 ++++ winrot-1.26/rott/develop.h 2007-05-05 23:23:29.000000000 +0200 +@@ -39,6 +39,7 @@ + #define DELUXE 0 + #define LOWCOST 0 + ++#define BNACRASHPREVENT 1 //bna added + // Make sure only one of the following are on at one time + #define SHAREWARE 1 + #define SUPERROTT 0 +diff -ur rott-1.0/rott/rt_actor.c winrot-1.26/rott/rt_actor.c +--- rott-1.0/rott/rt_actor.c 2003-01-07 07:31:51.000000000 +0100 ++++ winrot-1.26/rott/rt_actor.c 2007-05-05 23:23:29.000000000 +0200 +@@ -1066,7 +1072,9 @@ + // for(i=0;istate == 0){return;} ++#endif + ApplyGravity(ob); + M_CheckDoor(ob); + M_CheckBossSounds(ob); +@@ -1185,10 +1193,17 @@ + ) + ) + ob->state = &s_altexplosion1; +- else ++ else{ ++#if (BNACRASHPREVENT == 1)//crashed here when oscuro and larves were all killed ++ if (ob == 0){return;} ++#endif + ob->state = newstate; +- ++ } + SetVisiblePosition(ob,ob->x,ob->y); ++#if (BNACRASHPREVENT == 1) ++ if (ob->state == 0){return;} ++#endif ++ + ob->ticcount = (ob->state->tictime>>1); + ob->shapenum = ob->state->shapenum + ob->shapeoffset; + +@@ -10898,6 +11092,11 @@ + doorobj_t*tdoor; + + ob = (objtype*)object; ++ ++#if (BNACRASHPREVENT == 1)// ++ if (ob == 0){return;} ++#endif ++ + ob->flags |= FL_ACTIVE; + if (ob->obclass == bladeobj) + { +diff -ur rott-1.0/rott/rt_door.c winrot-1.26/rott/rt_door.c +--- rott-1.0/rott/rt_door.c 2002-12-24 06:16:27.000000000 +0100 ++++ winrot-1.26/rott/rt_door.c 2007-05-05 23:23:29.000000000 +0200 +@@ -745,7 +745,12 @@ + break; + } + } +- ++#if (BNACRASHPREVENT == 1) ++ //SetTextMode ( ); qwert ++ // CRASH IN SHAREWARE 'ride em cowboy' BNA FIX ++ // DONT ALLOW BAD touchplate ( == 0 ) see rt_playr.c ++ if (touchplate[i] == 0) {continue;} ++#endif + + if (!TRIGGER[i]) + continue; +diff -ur rott-1.0/rott/w_wad.c winrot-1.26/rott/w_wad.c +--- rott-1.0/rott/w_wad.c 2002-12-29 05:30:29.000000000 +0100 ++++ winrot-1.26/rott/w_wad.c 2007-05-05 23:23:29.000000000 +0200 +@@ -84,14 +86,26 @@ + wadinfo_t header; + lumpinfo_t *lump_p; + unsigned i; +- int handle, length; +- int startlump; ++ int handle, length; ++ int startlump; + filelump_t *fileinfo, singleinfo; + + char filename[MAX_PATH]; ++ char buf[MAX_PATH+100];//bna++ ++ + strncpy(filename, _filename, sizeof (filename)); + filename[sizeof (filename) - 1] = '\0'; + FixFilePath(filename); ++ ++ //bna section start ++ if (access (filename, 0) != 0) { ++ strcpy (buf,"Error, Could not find User file '"); ++ strcat (buf,filename); ++ strcat (buf,"', ignoring file"); ++ printf(buf); ++ } ++ //bna section end ++ + // + // read the entire file in + // FIXME: shared opens diff --git a/rott-registered.desktop b/rott-registered.desktop new file mode 100644 index 0000000..0212bae --- /dev/null +++ b/rott-registered.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Rise of the Triad (Registered) +Comment=RotT Registered launch script, this requires the registered data files +Exec=rott-registered +StartupNotify=false +Terminal=false +Type=Application +Icon=rott.png +Categories=Game;ActionGame; diff --git a/rott-registered.sh b/rott-registered.sh new file mode 100644 index 0000000..bfd4714 --- /dev/null +++ b/rott-registered.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e + +if [ ! -f ~/.rott/registered/*.WAD -a ! -f ~/.rott/registered/*.wad ]; then + zenity --info --text='In order to play the registered version of Rise of the Triad (ROTT), An Apogee Game, the original registered ROTT datafiles are needed. + +If you posess the registered version, copy all the datafiles of this version to [home folder]/.rott/registered and start ROTT Registered again.' + exit 1 +fi + +cd ~/.rott/registered +exec rott-registered.bin "$@" diff --git a/rott-shareware.desktop b/rott-shareware.desktop new file mode 100644 index 0000000..2dff597 --- /dev/null +++ b/rott-shareware.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Rise of the Triad +Comment=RotT Shareware launcher, will automatically download the needed data-files +Exec=rott-shareware +StartupNotify=false +Terminal=false +Type=Application +Icon=rott.png +Categories=Game;ActionGame; diff --git a/rott-shareware.sh b/rott-shareware.sh new file mode 100644 index 0000000..2b8fde9 --- /dev/null +++ b/rott-shareware.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +set -e + +mkdir -p $HOME/.rott +cd $HOME/.rott + +if [ ! -f REMOTE1.RTS ]; then + set +e + /usr/share/autodl/AutoDL.py /usr/share/rott/rott.autodlrc + STATUS=$? + set -e + # status 2 means download was ok, but the user choice not to start the game + if [ "$STATUS" = "0" -o "$STATUS" = "2" ]; then + unzip -u 1rott13.zip ROTTSW13.SHR + unzip -u ROTTSW13.SHR VENDOR.DOC 'HUNTBGIN.*' REMOTE1.RTS 'DEMO*.DMO' + rm 1rott13.zip ROTTSW13.SHR + fi + if [ "$STATUS" != "0" ]; then + exit $STATUS + fi +fi + +exec /usr/bin/rott-shareware.bin "$@" diff --git a/rott.autodlrc b/rott.autodlrc new file mode 100644 index 0000000..86db035 --- /dev/null +++ b/rott.autodlrc @@ -0,0 +1,114 @@ +[MESSAGELIST] +[MESSAGE] + [TITLE]Please click 'Accept' to allow internet access.[/TITLE] + [TEXT]In order to play Rise of the Triad (ROTT), An Apogee Game, the original ROTT datafiles are needed. + +Click Accept, to download the shareware version of the ROTT datafiles, which can be freely downloaded from the internet. + +If you posess the full version you can use that instead: Make sure you've installed the rott-registered package, put all the datafiles of the full version in a directory, and then run rott-registered from this directory. + +Please click Accept to allow ROTT to access the internet to download the necessary datafiles.[/TEXT] +[/MESSAGE] +[MESSAGE] + [TITLE]License Information[/TITLE] + [TEXT]"Rise of the Triad: The HUNT Begins" Copyright 1994, 1995 Apogee Software, Ltd. P.O. Box 496389, Garland, TX 75049, TEL: 972-271-1765 ("Apogee") + +BY COPYING, USING OR DISTRIBUTING THIS SHAREWARE PROGRAM, YOU INDICATE YOUR AGREEMENT TO THE TERMS OF THIS vendor.doc. + +===================== +KEY POINTS +===================== + +[*] If you want to distribute it in a retail location (such as on a rack), or as part of a hardware or software bundle, or on CD-ROM you must get PRIOR signed written permission from Apogee. Apogee reserves its right to withhold permission. + +[*] Everyone can -- and is encouraged! -- to copy, upload and generally pass around this Program without charging for it. + +[*] If you want to distribute it as provided in this Vendor.doc by catalog, advertisement, BBS, on-line service, or direct mail, no written permission is needed. Apogee highly recommends, however, that distribution be made from a copy from Apogee or from one of its authorized sources, such as our home BBS (Software Creations BBS: 508-365-2359) to prevent the sale of older versions. + +[*] All advertising of the Program must include "Apogee" in the description. + +[*] The Program is marked "Shareware" and contains "episode #1". No right is given by this Vendor.Doc to copy, use or distribute any other version, including any version that is registered, or not marked shareware, or that contains any episode other than #1. + +====================== +LICENSE +====================== + +[1] DEFINITIONS: "Program" means Rise of the Triad and its related files, including this one. The "Trademarks" consists of "Apogee", the Apogee "comet logo", "Rise of the Triad", and "The HUNT Begins. + +[2] OWNERSHIP: Except to the extent expressly licensed, Apogee owns and reserves the exclusive right to distribute the Program, and to use the Trademarks in connection with it. Its content, layout and format are the property of Apogee to the extent permitted by law. + +[3] GRANT AND CONDITIONS: Apogee grants a non-exclusive license to distribute the Program on IBM compatible media under the Trademarks subject to the following conditions: + + [A] CONDITIONS FOR ALL DISTRIBUTION + + [1] All of the Program's files, including this one, as released by us must be included without modification. The following files must always be included to constitute a legal version for shareware distribution: + + * demo1_3 dmo 08-01-95 1:30p + * demo2_3 dmo 08-01-95 1:30p + * huntbgin rtc 08-01-95 1:30p + * huntbgin rtl 08-01-95 1:30p + * huntbgin wad 08-01-95 1:30p + * modem pck 08-01-95 1:30p + * readme exe 08-01-95 1:30p + * remote1 rts 08-01-95 1:30p + * rott exe 08-01-95 1:30p + * rotthelp exe 08-01-95 1:30p + * rottipx exe 08-01-95 1:30p + * rottser exe 08-01-95 1:30p + * setup exe 08-01-95 1:30p + * sndsetup exe 08-01-95 1:30p + + [2] No copyright or trademark information may be removed. + + [3] You must not [a] distribute any version of the Program with unauthorized changes, such as additional or different levels, or changed characters or mazes; or [b] characterize such versions as an "add-on" or "extension" of any Apogee product; or [c] distribute any unauthorized third party utility designed to alter any Apogee game, game level, game episode or saved game. + + [B] ADDITIONAL CONDITIONS IF YOU CHARGE: If your distribution involves a disk or other physical medium, you must also: + + [1] Clearly market the Program as shareware, which requires (among other things) using "try before you buy" or similar words on packaging for the Programs. + + [2] Include "Apogee" and the "comet" logo (we encourage use of the 4 color version) on the front cover of the package. + + [3] Include the your name, address and phone number on the packaging and in any added documentation. This can be imprinted on the package or may be in the form of a label affixed to the box, carton or folder. + + [4] Any description of the Program included in a re-sellers catalog, sales brochure, on special packaging or handouts, must include "An Apogee Game", "Released by Apogee" or "Published by Apogee" if the word count of the description is more than 14 words in length. + + [5] Distribute copies only after the programs on newly created master diskettes have been thoroughly tested. Always use high quality media and duplication technology. + + [6] Try to sell only the most current version of the Program. + + [7] Although Apogee discourages the practice, you may add an installation routine if it does not interfere with the proper operation or installation of the Program. + + [8] Program updates, recommended descriptions and "screenshots" will be provided upon request, and are available in the re-seller / dealer conference of Apogee's main BBS. + + [C] ADDITIONAL CONDITIONS FOR BUNDLES, CD-ROMS, AND RACKS: +If you wish to distribute in a retail location (such as on a rack), or as part of a hardware or software bundle, or on CD-ROM, you must get PRIOR signed written permission from Apogee, which is in Apogee's discretion and may be subject to royalty or other conditions. + +[4] TERM: Unless terminated for cause, your grants under this VENDOR.DOC terminate 30 days after you receive written notice, or such longer period as the notice may provide. Following such termination, you may distribute the Program only until the earlier of 60 days after the termination date in the notice, or distribution of the copies you have in stock. Sections [2], [5], and [6] survive termination. + +[5] LIMITED WARRANTY AND LIMITATION OF REMEDIES: If Apogee provides a physically defective copy of the Program, Apogee will replace it upon submission of the defective one. Aside from this, the Program IS PROVIDED "AS-IS", AND NO WARRANTIES OF ANY KIND (INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE), EXPRESS OR IMPLIED, ARE MADE AS TO IT OR ANY MEDIUM IT MAY BE ON. OUR ENTIRE LIABILITY AND YOUR EXCLUSIVE REMEDY IS SUCH REPLACEMENT, AND UNDER NO CIRCUMSTANCES WILL WE PROVIDE ANY OTHER REMEDY FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, PUNITIVE, INCIDENTAL OR OTHER DAMAGES ARISING FROM IT, INCLUDING SUCH FROM NEGLIGENCE, STRICT LIABILITY, OR BREACH OF WARRANTY OR CONTRACT, EVEN AFTER NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. + +[6] MISCELLANY + + [A] Since we would be irreparably damaged if Section [3], [4] or [6][D] were not specifically enforced, we will be entitled without bond, other security or proof of damages, to appropriate equitable remedies with respect to breaches of such sections, in addition to such other remedies as we may have. + + [B] You will hold us, our partners, contractors, employees and agents harmless from damage, loss and expense arising directly or indirectly from your acts and omissions in copying and distributing the Program, including from any installation routine that you may add. + + [C] With respect to every matter arising under this, you consent to the exclusive jurisdiction and venue of the state and federal courts sitting in Dallas, Texas, and to service by certified mail, return receipt requested, or as otherwise permitted by law. + + [D] You will not modify, reverse compile, disassemble, or reverse engineer the Program, or use or disclose any confidential information that it contains. + +[V.07.15.94][/TEXT] +[/MESSAGE] +[/MESSAGELIST] + +[FILELIST] +[FILE] + [FILENAME]1rott13.zip[/FILENAME] + [MD5]0fafd6b629eab80278fc726e31f9cf41[/MD5] + [PATH]$HOME/.rott[/PATH] + [MIRRORS] + [URL]ftp://ftp.3drealms.com/share/1rott13.zip[/URL] + [URL]http://www.dosgamesarchive.com/download/download2.php?id=14[/URL] + [/MIRRORS] +[/FILE] +[/FILELIST] diff --git a/rott.png b/rott.png new file mode 100644 index 0000000..1676579 Binary files /dev/null and b/rott.png differ diff --git a/rott.spec b/rott.spec new file mode 100644 index 0000000..5f937db --- /dev/null +++ b/rott.spec @@ -0,0 +1,164 @@ +Name: rott +Version: 1.0 +Release: 3%{?dist} +Summary: Rise of the Triad +Group: Amusements/Games +License: GPL +URL: http://icculus.org/rott/ +Source0: http://icculus.org/rott/releases/rott-1.0.tar.gz +Source1: rott-shareware.sh +Source2: rott-registered.sh +Source3: rott.autodlrc +Source4: rott-shareware.desktop +Source5: rott-registered.desktop +# Notice this is made from an edited screenshot and thus derived from the non- +# free datafiles. I believe this constitues fair-use. If anyone disagrees let +# me know and I'll remove it +Source6: rott.png +Patch0: rott-1.0-cvs-fixes.patch +Patch1: rott-1.0-compile.patch +Patch2: rott-1.0-fixes.patch +Patch3: rott-1.0-64bit.patch +Patch4: rott-1.0-winrott.patch +Patch5: rott-1.0-winrott-fixes.patch +Patch6: rott-1.0-more-fixes.patch +# Note: this gets applied during build, not during prep! +Patch99: rott-1.0-registered.patch +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: SDL_mixer-devel desktop-file-utils + +%description +This is the icculus.org Linux port of Apogee's classic 3d shooter Rise of the +Triad, which has been released under the GPL by Apogee. This version is +enhanced with the "high" resolution rendering from the winrott port. + + +%package shareware +Summary: Rise of the Triad shareware version +Group: Amusements/Games +Requires: hicolor-icon-theme autodownloader + +%description shareware +This is the icculus.org Linux port of Apogee's classic 3d shooter Rise of the +Triad (RotT), which has been released under the GPL by Apogee. This version is +enhanced with the "high" resolution rendering from the winrott port. + +This package contains the engine for the shareware version of RotT. In order to +play the shareware version, you will need the shareware datafiles. Which can +be freely downloaded from Apogee/3DRealms, but cannot be distributed as a part +of Fedora. When you start RotT for the first time it will offer to download +the datafiles for you. + + +%package registered +Summary: Rise of the Triad registered version +Group: Amusements/Games +Requires: hicolor-icon-theme zenity + +%description registered +This is the icculus.org Linux port of Apogee's classic 3d shooter Rise of the +Triad (RotT), which has been released under the GPL by Apogee. This version is +enhanced with the "high" resolution rendering from the winrott port. + +This package contains the engine for the registered version of RotT. If you own +the registered version, this allows you to play the registered version under +Linux. Place the registered RotT datafiles in a dir and start rott-registered +from this dir. + + +%prep +%setup -q +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 + + +%build +pushd rott +make %{?_smp_mflags} EXTRACFLAGS="$RPM_OPT_FLAGS -Wno-unused -Wno-pointer-sign" +mv rott rott-shareware.bin + +patch -p2 < %{PATCH99} +make clean +make %{?_smp_mflags} EXTRACFLAGS="$RPM_OPT_FLAGS -Wno-unused -Wno-pointer-sign" +mv rott rott-registered.bin +popd + + +%install +rm -rf $RPM_BUILD_ROOT +#no make install target, DIY +mkdir -p $RPM_BUILD_ROOT%{_bindir} +mkdir -p $RPM_BUILD_ROOT%{_datadir}/%{name} +install -m 755 rott/rott-* $RPM_BUILD_ROOT%{_bindir} +install -p -m 755 %{SOURCE1} $RPM_BUILD_ROOT%{_bindir}/%{name}-shareware +install -p -m 755 %{SOURCE2} $RPM_BUILD_ROOT%{_bindir}/%{name}-registered +install -p -m 644 %{SOURCE3} $RPM_BUILD_ROOT%{_datadir}/%{name} + +# below is the desktop file and icon stuff. +mkdir -p $RPM_BUILD_ROOT%{_datadir}/applications +desktop-file-install --vendor fedora \ + --dir $RPM_BUILD_ROOT%{_datadir}/applications \ + %{SOURCE4} +mkdir -p $RPM_BUILD_ROOT%{_datadir}/applications +desktop-file-install --vendor fedora \ + --dir $RPM_BUILD_ROOT%{_datadir}/applications \ + %{SOURCE5} +mkdir -p $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/64x64/apps +install -p -m 644 %{SOURCE6} \ + $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/64x64/apps/ + + +%clean +rm -rf $RPM_BUILD_ROOT + + +%post shareware +touch --no-create %{_datadir}/icons/hicolor || : +%{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || : + +%postun shareware +touch --no-create %{_datadir}/icons/hicolor || : +%{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || : + +%post registered +touch --no-create %{_datadir}/icons/hicolor || : +%{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || : + +%postun registered +touch --no-create %{_datadir}/icons/hicolor || : +%{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || : + + +%files shareware +%defattr(-,root,root,-) +%doc README gpl.txt readme.txt +%{_bindir}/rott-shareware* +%{_datadir}/%{name} +%{_datadir}/applications/fedora-%{name}-shareware.desktop +%{_datadir}/icons/hicolor/64x64/apps/%{name}.png + + +%files registered +%defattr(-,root,root,-) +%doc README gpl.txt readme.txt +%{_bindir}/rott-registered* +%{_datadir}/%{name} +%{_datadir}/applications/fedora-%{name}-registered.desktop +%{_datadir}/icons/hicolor/64x64/apps/%{name}.png + + +%changelog +* Fri May 11 2007 Hans de Goede 1.0-3 +- Add missing autodownloader Requires to rott-shareware + +* Fri May 11 2007 Hans de Goede 1.0-2 +- Add desktop entry and userfriendly launcher script for registered package +- Add a patch fixing crashes with "long" usernames + +* Fri May 11 2007 Hans de Goede 1.0-1 +- Initial Fedora Extras package diff --git a/sources b/sources index e69de29..e6760ac 100644 --- a/sources +++ b/sources @@ -0,0 +1 @@ +c1c6cbecf00f2229cf2e0053334dcfc1 rott-1.0.tar.gz