diff --git a/.gitignore b/.gitignore index a0b508c..9f52f7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -rott-1.1.tar.gz -/rott-1.1.2.tar.gz +rott-1.0.tar.gz 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 index e90880e..0212bae 100644 --- a/rott-registered.desktop +++ b/rott-registered.desktop @@ -1,10 +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 +Icon=rott.png Categories=Game;ActionGame; -Keywords=game;fps;first;person;shooter;rise;triad;rott; diff --git a/rott-registered.metainfo.xml b/rott-registered.metainfo.xml deleted file mode 100644 index b479aac..0000000 --- a/rott-registered.metainfo.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - rott-registered.desktop - rott-shareware.desktop - CC0-1.0 - GPL-2.0+ - Engine for Rise of the Triad registered - - Place the registered Rise of the Triad datafiles under /usr/share/rott/ - - http://icculus.org/rott/ - jwrdegoede_at_gmail.com - diff --git a/rott-registered.sh b/rott-registered.sh index da31e8f..bfd4714 100644 --- a/rott-registered.sh +++ b/rott-registered.sh @@ -2,11 +2,6 @@ set -e -if [ -f /usr/share/rott/DARKWAR.WAD ]; then - cd /usr/share/rott - exec rott-registered.bin "$@" -fi - 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. diff --git a/rott-shareware.appdata.xml b/rott-shareware.appdata.xml deleted file mode 100644 index 5332995..0000000 --- a/rott-shareware.appdata.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - rott-shareware.desktop - CC0-1.0 - GPL-2.0+ - Rise of the Triad - Apogee's classic 3d first person shooter Rise of the Triad - -

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

-
- https://icculus.org/rott/ - - http://image.dosgamesarchive.com/screenshots/risetriad6.gif - http://image.dosgamesarchive.com/screenshots/risetriad1.gif - http://image.dosgamesarchive.com/screenshots/risetriad2.gif - http://image.dosgamesarchive.com/screenshots/risetriad3.gif - http://image.dosgamesarchive.com/screenshots/risetriad5.gif - - jwrdegoede_at_fedoraproject.org -
diff --git a/rott-shareware.desktop b/rott-shareware.desktop index ed9830c..2dff597 100644 --- a/rott-shareware.desktop +++ b/rott-shareware.desktop @@ -1,10 +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 +Icon=rott.png Categories=Game;ActionGame; -Keywords=game;fps;first;person;shooter;rise;triad;rott; diff --git a/rott-shareware.sh b/rott-shareware.sh index 1e47aa0..2b8fde9 100644 --- a/rott-shareware.sh +++ b/rott-shareware.sh @@ -2,12 +2,6 @@ set -e -# game assets installed with game-data-packager -if [ -f /usr/share/rott/REMOTE1.RTS ]; then - cd /usr/share/rott - exec /usr/bin/rott-shareware.bin "$@" -fi - mkdir -p $HOME/.rott cd $HOME/.rott diff --git a/rott.spec b/rott.spec index 128cd19..5f937db 100644 --- a/rott.spec +++ b/rott.spec @@ -1,25 +1,31 @@ Name: rott -Version: 1.1.2 -Release: 28%{?dist} +Version: 1.0 +Release: 3%{?dist} Summary: Rise of the Triad -# Automatically converted from old format: GPLv2+ - review is highly recommended. -License: GPL-2.0-or-later +Group: Amusements/Games +License: GPL URL: http://icculus.org/rott/ -Source0: http://icculus.org/rott/releases/rott-%{version}.tar.gz +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 -Source6: rott-shareware.appdata.xml -Source7: rott-registered.metainfo.xml # Notice this is made from an edited screenshot and thus derived from the non- -# free datafiles. I believe this constitutes fair-use. If anyone disagrees let +# free datafiles. I believe this constitues fair-use. If anyone disagrees let # me know and I'll remove it -Source8: rott.png -BuildRequires: make -BuildRequires: gcc -BuildRequires: SDL_mixer-devel desktop-file-utils libappstream-glib +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 @@ -29,7 +35,8 @@ enhanced with the "high" resolution rendering from the winrott port. %package shareware Summary: Rise of the Triad shareware version -Requires: hicolor-icon-theme autodownloader unzip +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 @@ -45,6 +52,7 @@ the datafiles for you. %package registered Summary: Rise of the Triad registered version +Group: Amusements/Games Requires: hicolor-icon-theme zenity %description registered @@ -60,201 +68,91 @@ from this dir. %prep %setup -q - -cp -a doc/rott.6 rott-shareware.6 -cp -a doc/rott.6 rott-registered.6 -sed -i.orig 's/rott/rott-shareware/g' rott-shareware.6 -sed -i.orig 's/rott/rott-registered/g' rott-registered.6 -touch -r rott-shareware.6.orig rott-shareware.6 -touch -r rott-registered.6.orig rott-registered.6 +%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" \ - ROTT=rott-shareware.bin -make tidy -make %{?_smp_mflags} \ - EXTRACFLAGS="$RPM_OPT_FLAGS -Wno-unused -Wno-pointer-sign" \ - ROTT=rott-registered.bin SHAREWARE=0 SUPERROTT=1 +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} -mkdir -p $RPM_BUILD_ROOT%{_mandir}/man6 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} -install -p -m 644 %{name}-shareware.6 $RPM_BUILD_ROOT%{_mandir}/man6 -install -p -m 644 %{name}-registered.6 $RPM_BUILD_ROOT%{_mandir}/man6 # below is the desktop file and icon stuff. mkdir -p $RPM_BUILD_ROOT%{_datadir}/applications -desktop-file-install --dir $RPM_BUILD_ROOT%{_datadir}/applications %{SOURCE4} -desktop-file-install --dir $RPM_BUILD_ROOT%{_datadir}/applications %{SOURCE5} -mkdir -p $RPM_BUILD_ROOT%{_datadir}/appdata -install -p -m 644 %{SOURCE6} %{SOURCE7} $RPM_BUILD_ROOT%{_datadir}/appdata -appstream-util validate-relax --nonet $RPM_BUILD_ROOT%{_datadir}/appdata/*.xml +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 %{SOURCE8} \ +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 -%doc README doc/*.txt -%license COPYING +%defattr(-,root,root,-) +%doc README gpl.txt readme.txt %{_bindir}/rott-shareware* -%{_mandir}/man6/%{name}-shareware.6* %{_datadir}/%{name} -%{_datadir}/appdata/%{name}-shareware.appdata.xml -%{_datadir}/applications/%{name}-shareware.desktop +%{_datadir}/applications/fedora-%{name}-shareware.desktop %{_datadir}/icons/hicolor/64x64/apps/%{name}.png %files registered -%doc README doc/*.txt -%license COPYING +%defattr(-,root,root,-) +%doc README gpl.txt readme.txt %{_bindir}/rott-registered* -%{_mandir}/man6/%{name}-registered.6* -%{_datadir}/appdata/%{name}-registered.metainfo.xml -%{_datadir}/applications/%{name}-registered.desktop +%{_datadir}/%{name} +%{_datadir}/applications/fedora-%{name}-registered.desktop %{_datadir}/icons/hicolor/64x64/apps/%{name}.png %changelog -* Fri Jul 25 2025 Fedora Release Engineering - 1.1.2-28 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild - -* Sat Jan 18 2025 Fedora Release Engineering - 1.1.2-27 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild - -* Fri Jul 26 2024 Miroslav Suchý - 1.1.2-26 -- convert license to SPDX - -* Fri Jul 19 2024 Fedora Release Engineering - 1.1.2-25 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild - -* Fri Jan 26 2024 Fedora Release Engineering - 1.1.2-24 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Mon Jan 22 2024 Fedora Release Engineering - 1.1.2-23 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Fri Jul 21 2023 Fedora Release Engineering - 1.1.2-22 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild - -* Fri Jan 20 2023 Fedora Release Engineering - 1.1.2-21 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild - -* Sat Jul 23 2022 Fedora Release Engineering - 1.1.2-20 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild - -* Fri Jan 21 2022 Fedora Release Engineering - 1.1.2-19 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild - -* Fri Jul 23 2021 Fedora Release Engineering - 1.1.2-18 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild - -* Wed Jan 27 2021 Fedora Release Engineering - 1.1.2-17 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild - -* Sat Aug 01 2020 Fedora Release Engineering - 1.1.2-16 -- Second attempt - Rebuilt for - https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild - -* Wed Jul 29 2020 Fedora Release Engineering - 1.1.2-15 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild - -* Thu Jan 30 2020 Fedora Release Engineering - 1.1.2-14 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild - -* Fri Jul 26 2019 Fedora Release Engineering - 1.1.2-13 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild - -* Sat Feb 02 2019 Fedora Release Engineering - 1.1.2-12 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild - -* Sat Jul 14 2018 Fedora Release Engineering - 1.1.2-11 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild - -* Fri Feb 09 2018 Fedora Release Engineering - 1.1.2-10 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild - -* Thu Jan 18 2018 Igor Gnatenko - 1.1.2-9 -- Remove obsolete scriptlets - -* Thu Aug 03 2017 Fedora Release Engineering - 1.1.2-8 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild - -* Thu Jul 27 2017 Fedora Release Engineering - 1.1.2-7 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild - -* Sat Feb 11 2017 Fedora Release Engineering - 1.1.2-6 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild - -* Thu Feb 04 2016 Fedora Release Engineering - 1.1.2-5 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild - -* Sat Jan 16 2016 Hans de Goede - 1.1.2-4 -- Add support for game-data-packager provided assets (rhbz#1295511) -- Add appdata files -- Modernize spec a bit - -* Thu Jun 18 2015 Fedora Release Engineering - 1.1.2-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild - -* Mon Aug 18 2014 Fedora Release Engineering - 1.1.2-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild - -* Sun Jun 15 2014 Hans de Goede - 1.1.2-1 -- New upstream release 1.1.2 -- Fix FTBFS (rhbz#1037308) - -* Sun Jun 08 2014 Fedora Release Engineering - 1.1-10 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild - -* Sun Aug 04 2013 Fedora Release Engineering - 1.1-9 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild - -* Mon Feb 25 2013 Toshio Kuratomi - 1.1-8 -- Remove --vendor from desktop files for F19+ https://fedorahosted.org/fesco/ticket/1077 - -* Thu Feb 14 2013 Fedora Release Engineering - 1.1-7 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild - -* Sat Jul 21 2012 Fedora Release Engineering - 1.1-6 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild - -* Sat Jan 14 2012 Fedora Release Engineering - 1.1-5 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild - -* Wed Feb 09 2011 Fedora Release Engineering - 1.1-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild - -* Sun Jul 26 2009 Fedora Release Engineering - 1.1-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild - -* Wed Feb 25 2009 Fedora Release Engineering - 1.1-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild - -* Mon Aug 4 2008 Hans de Goede 1.1-1 -- New upstream release 1.1 (incorperating all our patches!) - -* Thu Apr 10 2008 Hans de Goede 1.0-6 -- Many fixes (and a manpage) ported over from debian - -* Tue Feb 19 2008 Fedora Release Engineering - 1.0-5 -- Autorebuild for GCC 4.3 - -* Fri Aug 3 2007 Hans de Goede 1.0-4 -- Update License tag for new Licensing Guidelines compliance -- Fix 2 calls of memset with the 2nd and 3th argument swaped, - reported by Dave Jones - * Fri May 11 2007 Hans de Goede 1.0-3 - Add missing autodownloader Requires to rott-shareware diff --git a/sources b/sources index c3d62a9..e6760ac 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -d523c7c6c97f95ba84b8cf4deae7db38 rott-1.1.2.tar.gz +c1c6cbecf00f2229cf2e0053334dcfc1 rott-1.0.tar.gz