diff -wruN ./Makefile ../jfduke3d_src_20041013-linux/Makefile --- ./Makefile 2004-10-13 12:21:22.000000000 -0500 +++ ../jfduke3d_src_20041013-linux/Makefile 2004-12-01 00:00:54.000000000 -0600 @@ -14,7 +14,7 @@ # debugging enabled #debug=-ggdb # debugging disabled -debug=-ggdb -fomit-frame-pointer +debug=-fomit-frame-pointer DXROOT=c:/sdks/msc/dx61 @@ -24,7 +24,7 @@ CC=gcc # -Werror-implicit-function-declaration -CFLAGS=$(debug) -W -Wall -Werror-implicit-function-declaration \ +CFLAGS=$(debug) -O2 -W -Wall -Werror-implicit-function-declaration \ -Wno-char-subscripts -Wno-unused \ -march=pentium -funsigned-char -Dmain=app_main -DNO_GCC_BUILTINS \ -I$(INC) -I$(EINC) -I$(SRC)jmact -I$(SRC)jaudiolib -I../jfaud/inc \ @@ -44,15 +44,11 @@ AUDIOLIB_FX_STUB=$(OBJ)audiolib_fxstub.$o AUDIOLIB_MUSIC_STUB=$(OBJ)audiolib_musicstub.$o -#AUDIOLIB_FX=$(OBJ)audiolib_fx_fmod.$o AUDIOLIB_FX=$(OBJ)mv_mix.$o \ $(OBJ)mv_mix16.$o \ $(OBJ)mvreverb.$o \ - $(OBJ)pitch.$o \ - $(OBJ)multivoc.$o \ $(OBJ)ll_man.$o \ - $(OBJ)fx_man.$o \ - $(OBJ)dsoundout.$o + $(OBJ)fx_man.$o AUDIOLIB_MUSIC=$(OBJ)midi.$o \ $(OBJ)mpu401.$o \ $(OBJ)music.$o @@ -102,14 +98,24 @@ #GAMEOBJS+= $(EOBJ)sdlayer.$o #EDITOROBJS+= $(EOBJ)sdlayer.$o - override CFLAGS+= $(subst -Dmain=SDL_main,,$(shell sdl-config --cflags)) - LIBS+= $(shell sdl-config --libs) - AUDIOLIBOBJ=$(AUDIOLIB_MUSIC_STUB) $(AUDIOLIB_FX_STUB) + CFLAGS+= $(subst -Dmain=SDL_main,,$(shell sdl-config --cflags) -D__cdecl=" ") + LIBS+= $(shell sdl-config --libs) -lSDL_mixer + AUDIOLIB_FX+= $(OBJ)dsl.$o \ + $(OBJ)nodpmi.$o \ + $(OBJ)unixpitch.$o \ + $(OBJ)unixvoc.$o + + AUDIOLIB_MUSIC=$(OBJ)sdlmusic.$o $(OBJ)unixglob.$o + AUDIOLIBOBJ=$(AUDIOLIB_MUSIC) $(AUDIOLIB_FX) else ifeq ($(RENDERTYPE),WIN) #GAMEOBJS+= $(EOBJ)winlayer.$o #EDITOROBJS+= $(EOBJ)winlayer.$o + AUDIOLIB_FX+= $(OBJ)audiolib_fx_fmod.$o \ + $(OBJ)dsoundout.$o \ + $(OBJ)pitch.$o \ + $(OBJ)multivoc.$o AUDIOLIBOBJ=$(AUDIOLIB_MUSIC) $(AUDIOLIB_FX) endif endif @@ -124,24 +130,25 @@ duke3d$(EXESUFFIX): $(GAMEOBJS) $(EOBJ)$(ENGINELIB) $(CC) $(CFLAGS) -o $@ $^ $(LIBS) - -rm duke3d.sym$(EXESUFFIX) + -rm -f duke3d.sym$(EXESUFFIX) cp duke3d$(EXESUFFIX) duke3d.sym$(EXESUFFIX) strip duke3d$(EXESUFFIX) build$(EXESUFFIX): $(EDITOROBJS) $(EOBJ)$(EDITORLIB) $(EOBJ)$(ENGINELIB) $(CC) $(CFLAGS) -o $@ $^ $(LIBS) - -rm build.sym$(EXESUFFIX) + -rm -f build.sym$(EXESUFFIX) cp build$(EXESUFFIX) build.sym$(EXESUFFIX) strip build$(EXESUFFIX) +AUDIOLIB=$(SRC)/jaudiolib include Makefile.deps $(EOBJ)$(ENGINELIB): - -mkdir $(EOBJ) + -mkdir -p $(EOBJ) $(MAKE) -C $(EROOT) "OBJ=$(CURDIR)/$(EOBJ)" "CFLAGS=$(ENGINEOPTS)" enginelib $(EOBJ)$(EDITORLIB): - -mkdir $(EOBJ) + -mkdir -p $(EOBJ) $(MAKE) -C $(EROOT) "OBJ=$(CURDIR)/$(EOBJ)" "CFLAGS=$(ENGINEOPTS)" editorlib # RULES diff -wruN ./Makefile.deps ../jfduke3d_src_20041013-linux/Makefile.deps --- ./Makefile.deps 2004-10-13 12:21:22.000000000 -0500 +++ ../jfduke3d_src_20041013-linux/Makefile.deps 2004-11-30 23:26:54.000000000 -0600 @@ -31,6 +31,11 @@ $(OBJ)scriplib.$o: $(SRC)jmact/scriplib.c $(SRC)jmact/scriplib.h $(SRC)jmact/util_lib.h $(SRC)jmact/_scrplib.h $(INC)types.h $(EINC)compat.h # jAudioLib objects +$(OBJ)dsl.$o: $(SRC)jaudiolib/dsl.c $(SRC)jaudiolib/util.h +$(OBJ)nodpmi.$o: $(SRC)jaudiolib/nodpmi.c $(SRC)jaudiolib/dpmi.h +$(OBJ)unixpitch.$o: $(SRC)jaudiolib/unixpitch.c $(SRC)jaudiolib/pitch.h +$(OBJ)unixvoc.$o: $(SRC)jaudiolib/unixvoc.c $(SRC)jaudiolib/usrhooks.h $(SRC)jaudiolib/linklist.h $(SRC)jaudiolib/pitch.h $(SRC)jaudiolib/multivoc.h $(SRC)jaudiolib/_multivc.h + $(OBJ)audiolib_fxstub.$o: $(SRC)jaudiolib/audiolib_fxstub.c $(SRC)jaudiolib/fx_man.h $(OBJ)audiolib_musicstub.$o: $(SRC)jaudiolib/audiolib_musicstub.c $(SRC)jaudiolib/music.h diff -wruN ./Makefile.deps.diff ../jfduke3d_src_20041013-linux/Makefile.deps.diff --- ./Makefile.deps.diff 2004-12-01 00:31:48.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/Makefile.deps.diff 1969-12-31 18:00:00.000000000 -0600 @@ -1,14 +0,0 @@ ---- Makefile.deps 2004-10-13 12:21:22.000000000 -0500 -+++ ../jfduke3d_src_20041013-linux/Makefile.deps 2004-11-30 23:26:54.984461624 -0600 -@@ -31,6 +31,11 @@ - $(OBJ)scriplib.$o: $(SRC)jmact/scriplib.c $(SRC)jmact/scriplib.h $(SRC)jmact/util_lib.h $(SRC)jmact/_scrplib.h $(INC)types.h $(EINC)compat.h - - # jAudioLib objects -+$(OBJ)dsl.$o: $(SRC)jaudiolib/dsl.c $(SRC)jaudiolib/util.h -+$(OBJ)nodpmi.$o: $(SRC)jaudiolib/nodpmi.c $(SRC)jaudiolib/dpmi.h -+$(OBJ)unixpitch.$o: $(SRC)jaudiolib/unixpitch.c $(SRC)jaudiolib/pitch.h -+$(OBJ)unixvoc.$o: $(SRC)jaudiolib/unixvoc.c $(SRC)jaudiolib/usrhooks.h $(SRC)jaudiolib/linklist.h $(SRC)jaudiolib/pitch.h $(SRC)jaudiolib/multivoc.h $(SRC)jaudiolib/_multivc.h -+ - $(OBJ)audiolib_fxstub.$o: $(SRC)jaudiolib/audiolib_fxstub.c $(SRC)jaudiolib/fx_man.h - $(OBJ)audiolib_musicstub.$o: $(SRC)jaudiolib/audiolib_musicstub.c $(SRC)jaudiolib/music.h - diff -wruN ./Makefile.diff ../jfduke3d_src_20041013-linux/Makefile.diff --- ./Makefile.diff 2004-12-01 00:31:28.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/Makefile.diff 1969-12-31 18:00:00.000000000 -0600 @@ -1,95 +0,0 @@ ---- Makefile 2004-10-13 12:21:22.000000000 -0500 -+++ ../jfduke3d_src_20041013-linux/Makefile 2004-12-01 00:00:54.000000000 -0600 -@@ -14,7 +14,7 @@ - # debugging enabled - #debug=-ggdb - # debugging disabled --debug=-ggdb -fomit-frame-pointer -+debug=-fomit-frame-pointer - - - DXROOT=c:/sdks/msc/dx61 -@@ -24,7 +24,7 @@ - - CC=gcc - # -Werror-implicit-function-declaration --CFLAGS=$(debug) -W -Wall -Werror-implicit-function-declaration \ -+CFLAGS=$(debug) -O2 -W -Wall -Werror-implicit-function-declaration \ - -Wno-char-subscripts -Wno-unused \ - -march=pentium -funsigned-char -Dmain=app_main -DNO_GCC_BUILTINS \ - -I$(INC) -I$(EINC) -I$(SRC)jmact -I$(SRC)jaudiolib -I../jfaud/inc \ -@@ -44,15 +44,11 @@ - - AUDIOLIB_FX_STUB=$(OBJ)audiolib_fxstub.$o - AUDIOLIB_MUSIC_STUB=$(OBJ)audiolib_musicstub.$o --#AUDIOLIB_FX=$(OBJ)audiolib_fx_fmod.$o - AUDIOLIB_FX=$(OBJ)mv_mix.$o \ - $(OBJ)mv_mix16.$o \ - $(OBJ)mvreverb.$o \ -- $(OBJ)pitch.$o \ -- $(OBJ)multivoc.$o \ - $(OBJ)ll_man.$o \ -- $(OBJ)fx_man.$o \ -- $(OBJ)dsoundout.$o -+ $(OBJ)fx_man.$o - AUDIOLIB_MUSIC=$(OBJ)midi.$o \ - $(OBJ)mpu401.$o \ - $(OBJ)music.$o -@@ -102,14 +98,24 @@ - #GAMEOBJS+= $(EOBJ)sdlayer.$o - #EDITOROBJS+= $(EOBJ)sdlayer.$o - -- override CFLAGS+= $(subst -Dmain=SDL_main,,$(shell sdl-config --cflags)) -- LIBS+= $(shell sdl-config --libs) -- AUDIOLIBOBJ=$(AUDIOLIB_MUSIC_STUB) $(AUDIOLIB_FX_STUB) -+ CFLAGS+= $(subst -Dmain=SDL_main,,$(shell sdl-config --cflags) -D__cdecl=" ") -+ LIBS+= $(shell sdl-config --libs) -lSDL_mixer -+ AUDIOLIB_FX+= $(OBJ)dsl.$o \ -+ $(OBJ)nodpmi.$o \ -+ $(OBJ)unixpitch.$o \ -+ $(OBJ)unixvoc.$o -+ -+ AUDIOLIB_MUSIC=$(OBJ)sdlmusic.$o $(OBJ)unixglob.$o -+ AUDIOLIBOBJ=$(AUDIOLIB_MUSIC) $(AUDIOLIB_FX) - else - ifeq ($(RENDERTYPE),WIN) - #GAMEOBJS+= $(EOBJ)winlayer.$o - #EDITOROBJS+= $(EOBJ)winlayer.$o - -+ AUDIOLIB_FX+= $(OBJ)audiolib_fx_fmod.$o \ -+ $(OBJ)dsoundout.$o \ -+ $(OBJ)pitch.$o \ -+ $(OBJ)multivoc.$o - AUDIOLIBOBJ=$(AUDIOLIB_MUSIC) $(AUDIOLIB_FX) - endif - endif -@@ -124,24 +130,25 @@ - - duke3d$(EXESUFFIX): $(GAMEOBJS) $(EOBJ)$(ENGINELIB) - $(CC) $(CFLAGS) -o $@ $^ $(LIBS) -- -rm duke3d.sym$(EXESUFFIX) -+ -rm -f duke3d.sym$(EXESUFFIX) - cp duke3d$(EXESUFFIX) duke3d.sym$(EXESUFFIX) - strip duke3d$(EXESUFFIX) - - build$(EXESUFFIX): $(EDITOROBJS) $(EOBJ)$(EDITORLIB) $(EOBJ)$(ENGINELIB) - $(CC) $(CFLAGS) -o $@ $^ $(LIBS) -- -rm build.sym$(EXESUFFIX) -+ -rm -f build.sym$(EXESUFFIX) - cp build$(EXESUFFIX) build.sym$(EXESUFFIX) - strip build$(EXESUFFIX) - -+AUDIOLIB=$(SRC)/jaudiolib - include Makefile.deps - - $(EOBJ)$(ENGINELIB): -- -mkdir $(EOBJ) -+ -mkdir -p $(EOBJ) - $(MAKE) -C $(EROOT) "OBJ=$(CURDIR)/$(EOBJ)" "CFLAGS=$(ENGINEOPTS)" enginelib - - $(EOBJ)$(EDITORLIB): -- -mkdir $(EOBJ) -+ -mkdir -p $(EOBJ) - $(MAKE) -C $(EROOT) "OBJ=$(CURDIR)/$(EOBJ)" "CFLAGS=$(ENGINEOPTS)" editorlib - - # RULES Files ./obj/game.o and ../jfduke3d_src_20041013-linux/obj/game.o differ diff -wruN ./source/config.c ../jfduke3d_src_20041013-linux/source/config.c --- ./source/config.c 2004-10-13 12:21:22.000000000 -0500 +++ ../jfduke3d_src_20041013-linux/source/config.c 2004-11-30 21:00:31.000000000 -0600 @@ -320,8 +320,8 @@ int32 i,f; byte k1,k2; - FXDevice = -1; - MusicDevice = -1; + FXDevice = 1; + MusicDevice = 1; NumVoices = 4; NumChannels = 2; NumBits = 8; @@ -931,6 +931,8 @@ SCRIPT_PutNumber( scripthandle, "Screen Setup", "GLTextureMode",gltexfiltermode,false,false); SCRIPT_PutNumber( scripthandle, "Screen Setup", "GLAnisotropy",glanisotropy,false,false); SCRIPT_PutNumber( scripthandle, "Screen Setup", "GLUseTextureCompr",glusetexcompr,false,false); + SCRIPT_PutNumber( scripthandle, "Sound Setup", "FXDevice",FXDevice,false,false); + SCRIPT_PutNumber( scripthandle, "Sound Setup", "MusicDevice",MusicDevice,false,false); SCRIPT_PutNumber( scripthandle, "Sound Setup", "FXVolume",FXVolume,false,false); SCRIPT_PutNumber( scripthandle, "Sound Setup", "MusicVolume",MusicVolume,false,false); SCRIPT_PutNumber( scripthandle, "Sound Setup", "SoundToggle",SoundToggle,false,false); diff -wruN ./source/jaudiolib/debugio.h ../jfduke3d_src_20041013-linux/source/jaudiolib/debugio.h --- ./source/jaudiolib/debugio.h 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/debugio.h 2003-04-08 18:44:19.000000000 -0500 @@ -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 -wruN ./source/jaudiolib/dma.h ../jfduke3d_src_20041013-linux/source/jaudiolib/dma.h --- ./source/jaudiolib/dma.h 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/dma.h 2003-04-08 18:44:19.000000000 -0500 @@ -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 -wruN ./source/jaudiolib/dpmi.h ../jfduke3d_src_20041013-linux/source/jaudiolib/dpmi.h --- ./source/jaudiolib/dpmi.h 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/dpmi.h 2004-11-30 22:33:35.000000000 -0600 @@ -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. + +*/ +/********************************************************************** + 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 + }; + +int DPMI_GetDOSMemory( void **ptr, int *descriptor, unsigned length ); +int DPMI_FreeDOSMemory( int descriptor ); +#endif diff -wruN ./source/jaudiolib/dsl.c ../jfduke3d_src_20041013-linux/source/jaudiolib/dsl.c --- ./source/jaudiolib/dsl.c 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/dsl.c 2004-11-30 21:15:06.000000000 -0600 @@ -0,0 +1,257 @@ +/* +Copyright (C) 2003-2004 Ryan C. Gordon. and James Bentler + +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. + +Originally written by Ryan C. Gordon. (icculus@clutteredmind.org) +Adapted to work with JonoF's port by James Bentler (bentler@cs.umn.edu) + +*/ +#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 -wruN ./source/jaudiolib/dsl.h ../jfduke3d_src_20041013-linux/source/jaudiolib/dsl.h --- ./source/jaudiolib/dsl.h 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/dsl.h 2004-11-30 21:14:40.000000000 -0600 @@ -0,0 +1,50 @@ +/* +Copyright (C) 2003-2004 Ryan C. Gordon. and James Bentler + +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. + +Originally written by Ryan C. Gordon. (icculus@clutteredmind.org) +Adapted to work with JonoF's port by James Bentler (bentler@cs.umn.edu) + +*/ +#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 -wruN ./source/jaudiolib/interrup.h ../jfduke3d_src_20041013-linux/source/jaudiolib/interrup.h --- ./source/jaudiolib/interrup.h 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/interrup.h 2003-04-08 18:44:19.000000000 -0500 @@ -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 -wruN ./source/jaudiolib/_multivc.h ../jfduke3d_src_20041013-linux/source/jaudiolib/_multivc.h --- ./source/jaudiolib/_multivc.h 2004-10-13 12:21:24.000000000 -0500 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/_multivc.h 2004-11-30 23:50:34.000000000 -0600 @@ -67,8 +67,11 @@ #define SILENCE_8BIT 0x80808080 //#define SILENCE_16BIT_PAS 0 -//#define MixBufferSize 256 +#ifdef WINDOWS #define MixBufferSize (MV_GetBufferSize(MV_RequestedMixRate)) +#else +#define MixBufferSize 256 +#endif #define NumberOfBuffers 16 #define TotalBufferSize ( MixBufferSize * NumberOfBuffers ) diff -wruN ./source/jaudiolib/nodpmi.c ../jfduke3d_src_20041013-linux/source/jaudiolib/nodpmi.c --- ./source/jaudiolib/nodpmi.c 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/nodpmi.c 2004-11-30 22:36:23.000000000 -0600 @@ -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: NODPMI.C + + Functions for faking DPMI calls. + +**********************************************************************/ + +#include +#include +#include "dpmi.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +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 -wruN ./source/jaudiolib/platform.h ../jfduke3d_src_20041013-linux/source/jaudiolib/platform.h --- ./source/jaudiolib/platform.h 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/platform.h 2004-11-30 23:07:18.000000000 -0600 @@ -0,0 +1,62 @@ +#ifndef _INCLUDE_PLATFORM_H_ +#define _INCLUDE_PLATFORM_H_ + +#if (!defined __EXPORT__) +#define __EXPORT__ +#endif + +#if (defined __WATCOMC__) +#define snprintf _snprintf +#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 +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define PLATFORM_LITTLEENDIAN 1 +#define BUILDSWAP_INTEL16(x) (x) +#define BUILDSWAP_INTEL32(x) (x) +#else +#define PLATFORM_BIGENDIAN 1 +#define BUILDSWAP_INTEL16(x) _swap16(x) +#define BUILDSWAP_INTEL32(x) _swap32(x) +#endif +#endif + +extern int has_altivec; /* PowerPC-specific. */ + +#endif /* !defined _INCLUDE_PLATFORM_H_ */ + +/* end of platform.h ... */ + + diff -wruN ./source/jaudiolib/sdlmusic.c ../jfduke3d_src_20041013-linux/source/jaudiolib/sdlmusic.c --- ./source/jaudiolib/sdlmusic.c 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/sdlmusic.c 2004-12-01 00:44:54.000000000 -0600 @@ -0,0 +1,474 @@ +/* +Copyright (C) 2003-2004 Ryan C. Gordon. and James Bentler + +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. + +Originally written by Ryan C. Gordon. (icculus@clutteredmind.org) +Adapted to work with JonoF's port by James Bentler (bentler@cs.umn.edu) + +*/ +/* + * 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. + */ + +#include +#include +#include +#include +#include + +#include "duke3d.h" +#include "cache1d.h" + +#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" +#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 + +void GetUnixPathFromEnvironment( char *fullname, int32 length, const char *filename ); + +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 + + SoundCard = 1; + + music_initialized = 1; + return(MUSIC_Ok); +} // MUSIC_Init + + +int MUSIC_Shutdown(void) +{ + musdebug("shutting down sound subsystem."); + + 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) +{ + volume = max( 0, volume ); + volume = min( volume, 255 ); + + 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); + */ + + return(MUSIC_Ok); +} // MUSIC_PlaySong + + +extern char ApogeePath[256]; + +// 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 + GetUnixPathFromEnvironment(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 +} + + +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 + + +void MUSIC_Update(void) +{ +} diff -wruN ./source/jaudiolib/unixglob.c ../jfduke3d_src_20041013-linux/source/jaudiolib/unixglob.c --- ./source/jaudiolib/unixglob.c 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/unixglob.c 2004-11-30 21:14:55.000000000 -0600 @@ -0,0 +1,145 @@ +/* +Copyright (C) 2003-2004 Ryan C. Gordon. and James Bentler + +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. + +Originally written by Ryan C. Gordon. (icculus@clutteredmind.org) +Adapted to work with JonoF's port by James Bentler (bentler@cs.umn.edu) + +*/ + +static char ApogeePath[256]; + +#define PATH_SEP_CHAR '/' +#define PATH_SEP_STR "/" +#define ROOTDIR "/" +#define CURDIR "./" + +#include "duke3d.h" +#include +#include + +void FixFilePath(char *filename) +{ + char *ptr; + char *lastsep = filename; + + if ((!filename) || (*filename == '\0')) + return; + + if (access(filename, F_OK) == 0) /* File exists; we're good to go. */ + return; + + for (ptr = filename; 1; ptr++) + { + if (*ptr == '\\') + *ptr = PATH_SEP_CHAR; + + if ((*ptr == PATH_SEP_CHAR) || (*ptr == '\0')) + { + char pch = *ptr; + struct dirent *dent = NULL; + DIR *dir; + + if ((pch == PATH_SEP_CHAR) && (*(ptr + 1) == '\0')) + return; /* eos is pathsep; we're done. */ + + if (lastsep == ptr) + continue; /* absolute path; skip to next one. */ + + *ptr = '\0'; + if (lastsep == filename) { + dir = opendir((*lastsep == PATH_SEP_CHAR) ? ROOTDIR : CURDIR); + + if (*lastsep == PATH_SEP_CHAR) { + lastsep++; + } + } + else + { + *lastsep = '\0'; + dir = opendir(filename); + *lastsep = PATH_SEP_CHAR; + lastsep++; + } + + if (dir == NULL) + { + *ptr = PATH_SEP_CHAR; + return; /* maybe dir doesn't exist? give up. */ + } + + while ((dent = readdir(dir)) != NULL) + { + if (strcasecmp(dent->d_name, lastsep) == 0) + { + /* found match; replace it. */ + strcpy(lastsep, dent->d_name); + break; + } + } + + closedir(dir); + *ptr = pch; + lastsep = ptr; + + if (dent == NULL) + return; /* no match. oh well. */ + + if (pch == '\0') /* eos? */ + return; + } + } +} + +int32 SafeOpenWrite (const char *_filename, int32 filetype) +{ + int handle; + char filename[MAX_PATH]; + strncpy(filename, _filename, sizeof (filename)); + filename[sizeof (filename) - 1] = '\0'; + FixFilePath(filename); + + handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_TRUNC + , S_IREAD | S_IWRITE); + + if (handle == -1) + Error ("Error opening %s: %s",filename,strerror(errno)); + + return handle; +} + + +void SafeWrite (int32 handle, void *buffer, int32 count) +{ + unsigned iocount; + + while (count) + { + iocount = count > 0x8000 ? 0x8000 : count; + if (write (handle,buffer,iocount) != (int)iocount) + Error ("File write failure writing %ld bytes",count); + buffer = (void *)( (byte *)buffer + iocount ); + count -= iocount; + } +} + + + +void GetUnixPathFromEnvironment( char *fullname, int32 length, const char *filename ) +{ + snprintf(fullname, length-1, "%s%s", ApogeePath, filename); +} diff -wruN ./source/jaudiolib/unixpitch.c ../jfduke3d_src_20041013-linux/source/jaudiolib/unixpitch.c --- ./source/jaudiolib/unixpitch.c 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/unixpitch.c 2004-11-30 22:30:46.000000000 -0600 @@ -0,0 +1,212 @@ +/* +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 + ) + + { + } diff -wruN ./source/jaudiolib/unixvoc.c ../jfduke3d_src_20041013-linux/source/jaudiolib/unixvoc.c --- ./source/jaudiolib/unixvoc.c 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/unixvoc.c 2004-12-01 00:25:24.000000000 -0600 @@ -0,0 +1,2877 @@ +/* +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 + +#include "util.h" +#include "dpmi.h" +#include "usrhooks.h" +#include "interrup.h" +#include "dma.h" +#include "linklist.h" +#include "dsl.h" + +#include "pitch.h" +#include "multivoc.h" +#include "_multivc.h" +#include "debugio.h" + +// platform.h is from the build engine, but I need the byteswapping macros... --ryan. +#include "platform.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 = 1; +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; + + 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_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; + +static int MV_ServiceVoc(int dummy_arg) + { + VoiceNode *voice; + VoiceNode *next; + char *buffer; + + // 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 ); + 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 ); + else + MV_16BitReverbFast( source, dest, count / 2, MV_ReverbLevel ); + } + else + { + if ( MV_ReverbTable != NULL ) + MV_8BitReverb( source, dest, (const VOLUME16 *)MV_ReverbTable, count ); + else + MV_8BitReverbFast( source, dest, 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; + + if (MV_MixFunction != NULL) + 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(0); + } + + 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(0); + } + + 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; + } + + MV_MixMode = mode; + + 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; + + 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; + + 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(); + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_StopPlayback + + Stops the sound playback engine. +---------------------------------------------------------------------*/ + +void MV_StopPlayback + ( + void + ) + + { + VoiceNode *voice; + VoiceNode *next; + unsigned flags; + + DSL_StopPlayback(); + + // 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 ) + ) + + { + MV_SetErrorCode( MV_UnsupportedCard ); + return( MV_Error ); + } + + +/*--------------------------------------------------------------------- + Function: MV_StopRecord + + Stops the sound record engine. +---------------------------------------------------------------------*/ + +void MV_StopRecord + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + 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, + 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) + { + return MV_Ok; + } + + +/*--------------------------------------------------------------------- + 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 ); + + MV_TotalMemory = Voices * sizeof( VoiceNode ) + sizeof( HARSH_CLIP_TABLE_8 ); + status = USRHOOKS_GetMem( ( void ** )&ptr, MV_TotalMemory ); + if ( status != USRHOOKS_Ok ) + { + MV_SetErrorCode( MV_NoMem ); + 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 ) + { + USRHOOKS_FreeMem( MV_Voices ); + MV_Voices = NULL; + MV_TotalMemory = 0; + + MV_SetErrorCode( MV_NoMem ); + return( MV_Error ); + } + + MV_SetReverseStereo( FALSE ); + + // Initialize the sound card + status = DSL_Init(); + if ( status != DSL_Ok ) + { + MV_SetErrorCode( MV_BlasterError ); + } + + if ( MV_ErrorCode != MV_Ok ) + { + status = MV_ErrorCode; + + USRHOOKS_FreeMem( MV_Voices ); + MV_Voices = NULL; + MV_TotalMemory = 0; + + DPMI_FreeDOSMemory( MV_BufferDescriptor ); + + 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; + + 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 + DSL_Shutdown(); + + RestoreInterrupts( flags ); + + // Free any voices we allocated + 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 ); + } diff -wruN ./source/jaudiolib/util.h ../jfduke3d_src_20041013-linux/source/jaudiolib/util.h --- ./source/jaudiolib/util.h 1969-12-31 18:00:00.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source/jaudiolib/util.h 2003-04-08 18:44:19.000000000 -0500 @@ -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 -wruN ./source/sounds.c ../jfduke3d_src_20041013-linux/source/sounds.c --- ./source/sounds.c 2004-10-13 12:21:24.000000000 -0500 +++ ../jfduke3d_src_20041013-linux/source/sounds.c 2004-12-01 02:45:20.562538648 -0600 @@ -213,6 +213,7 @@ void playmusic(char *fn) { +#ifdef WINDOWS short fp; long l; @@ -234,6 +235,15 @@ kread( fp, MusicPtr, l); kclose( fp ); MUSIC_PlaySong( MusicPtr, MUSIC_LoopSong ); +#else + void PlayMusic(char *_filename); + if(MusicToggle == 0) return; + if(MusicDevice < 0) return; + + // FIXME: I need this to get the music volume initialized (not sure why) -- Jim Bentler + MUSIC_SetVolume( MusicVolume ); + PlayMusic(fn); +#endif } char loadsound(unsigned short num) diff -wruN ./source.diff ../jfduke3d_src_20041013-linux/source.diff --- ./source.diff 2004-12-01 00:32:18.000000000 -0600 +++ ../jfduke3d_src_20041013-linux/source.diff 1969-12-31 18:00:00.000000000 -0600 @@ -1,4463 +0,0 @@ -diff -wruN source/config.c ../jfduke3d_src_20041013-linux/source/config.c ---- source/config.c 2004-10-13 12:21:22.000000000 -0500 -+++ ../jfduke3d_src_20041013-linux/source/config.c 2004-11-30 21:00:31.000000000 -0600 -@@ -320,8 +320,8 @@ - int32 i,f; - byte k1,k2; - -- FXDevice = -1; -- MusicDevice = -1; -+ FXDevice = 1; -+ MusicDevice = 1; - NumVoices = 4; - NumChannels = 2; - NumBits = 8; -@@ -931,6 +931,8 @@ - SCRIPT_PutNumber( scripthandle, "Screen Setup", "GLTextureMode",gltexfiltermode,false,false); - SCRIPT_PutNumber( scripthandle, "Screen Setup", "GLAnisotropy",glanisotropy,false,false); - SCRIPT_PutNumber( scripthandle, "Screen Setup", "GLUseTextureCompr",glusetexcompr,false,false); -+ SCRIPT_PutNumber( scripthandle, "Sound Setup", "FXDevice",FXDevice,false,false); -+ SCRIPT_PutNumber( scripthandle, "Sound Setup", "MusicDevice",MusicDevice,false,false); - SCRIPT_PutNumber( scripthandle, "Sound Setup", "FXVolume",FXVolume,false,false); - SCRIPT_PutNumber( scripthandle, "Sound Setup", "MusicVolume",MusicVolume,false,false); - SCRIPT_PutNumber( scripthandle, "Sound Setup", "SoundToggle",SoundToggle,false,false); -diff -wruN source/jaudiolib/debugio.h ../jfduke3d_src_20041013-linux/source/jaudiolib/debugio.h ---- source/jaudiolib/debugio.h 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/debugio.h 2003-04-08 18:44:19.000000000 -0500 -@@ -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 -wruN source/jaudiolib/dma.h ../jfduke3d_src_20041013-linux/source/jaudiolib/dma.h ---- source/jaudiolib/dma.h 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/dma.h 2003-04-08 18:44:19.000000000 -0500 -@@ -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 -wruN source/jaudiolib/dpmi.h ../jfduke3d_src_20041013-linux/source/jaudiolib/dpmi.h ---- source/jaudiolib/dpmi.h 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/dpmi.h 2004-11-30 22:33:35.122914000 -0600 -@@ -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. -+ -+*/ -+/********************************************************************** -+ 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 -+ }; -+ -+int DPMI_GetDOSMemory( void **ptr, int *descriptor, unsigned length ); -+int DPMI_FreeDOSMemory( int descriptor ); -+#endif -diff -wruN source/jaudiolib/dsl.c ../jfduke3d_src_20041013-linux/source/jaudiolib/dsl.c ---- source/jaudiolib/dsl.c 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/dsl.c 2004-11-30 21:15:06.000000000 -0600 -@@ -0,0 +1,257 @@ -+/* -+Copyright (C) 2003-2004 Ryan C. Gordon. and James Bentler -+ -+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. -+ -+Originally written by Ryan C. Gordon. (icculus@clutteredmind.org) -+Adapted to work with JonoF's port by James Bentler (bentler@cs.umn.edu) -+ -+*/ -+#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 -wruN source/jaudiolib/dsl.h ../jfduke3d_src_20041013-linux/source/jaudiolib/dsl.h ---- source/jaudiolib/dsl.h 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/dsl.h 2004-11-30 21:14:40.000000000 -0600 -@@ -0,0 +1,50 @@ -+/* -+Copyright (C) 2003-2004 Ryan C. Gordon. and James Bentler -+ -+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. -+ -+Originally written by Ryan C. Gordon. (icculus@clutteredmind.org) -+Adapted to work with JonoF's port by James Bentler (bentler@cs.umn.edu) -+ -+*/ -+#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 -wruN source/jaudiolib/interrup.h ../jfduke3d_src_20041013-linux/source/jaudiolib/interrup.h ---- source/jaudiolib/interrup.h 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/interrup.h 2003-04-08 18:44:19.000000000 -0500 -@@ -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 -wruN source/jaudiolib/_multivc.h ../jfduke3d_src_20041013-linux/source/jaudiolib/_multivc.h ---- source/jaudiolib/_multivc.h 2004-10-13 12:21:24.000000000 -0500 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/_multivc.h 2004-11-30 23:50:34.000000000 -0600 -@@ -67,8 +67,11 @@ - #define SILENCE_8BIT 0x80808080 - //#define SILENCE_16BIT_PAS 0 - --//#define MixBufferSize 256 -+#ifdef WINDOWS - #define MixBufferSize (MV_GetBufferSize(MV_RequestedMixRate)) -+#else -+#define MixBufferSize 256 -+#endif - - #define NumberOfBuffers 16 - #define TotalBufferSize ( MixBufferSize * NumberOfBuffers ) -diff -wruN source/jaudiolib/nodpmi.c ../jfduke3d_src_20041013-linux/source/jaudiolib/nodpmi.c ---- source/jaudiolib/nodpmi.c 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/nodpmi.c 2004-11-30 22:36:23.014391000 -0600 -@@ -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: NODPMI.C -+ -+ Functions for faking DPMI calls. -+ -+**********************************************************************/ -+ -+#include -+#include -+#include "dpmi.h" -+ -+#define TRUE ( 1 == 1 ) -+#define FALSE ( !TRUE ) -+ -+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 -wruN source/jaudiolib/platform.h ../jfduke3d_src_20041013-linux/source/jaudiolib/platform.h ---- source/jaudiolib/platform.h 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/platform.h 2004-11-30 23:07:18.626295000 -0600 -@@ -0,0 +1,62 @@ -+#ifndef _INCLUDE_PLATFORM_H_ -+#define _INCLUDE_PLATFORM_H_ -+ -+#if (!defined __EXPORT__) -+#define __EXPORT__ -+#endif -+ -+#if (defined __WATCOMC__) -+#define snprintf _snprintf -+#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 -+#if __BYTE_ORDER == __LITTLE_ENDIAN -+#define PLATFORM_LITTLEENDIAN 1 -+#define BUILDSWAP_INTEL16(x) (x) -+#define BUILDSWAP_INTEL32(x) (x) -+#else -+#define PLATFORM_BIGENDIAN 1 -+#define BUILDSWAP_INTEL16(x) _swap16(x) -+#define BUILDSWAP_INTEL32(x) _swap32(x) -+#endif -+#endif -+ -+extern int has_altivec; /* PowerPC-specific. */ -+ -+#endif /* !defined _INCLUDE_PLATFORM_H_ */ -+ -+/* end of platform.h ... */ -+ -+ -diff -wruN source/jaudiolib/sdlmusic.c ../jfduke3d_src_20041013-linux/source/jaudiolib/sdlmusic.c ---- source/jaudiolib/sdlmusic.c 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/sdlmusic.c 2004-12-01 00:18:29.342047768 -0600 -@@ -0,0 +1,475 @@ -+/* -+Copyright (C) 2003-2004 Ryan C. Gordon. and James Bentler -+ -+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. -+ -+Originally written by Ryan C. Gordon. (icculus@clutteredmind.org) -+Adapted to work with JonoF's port by James Bentler (bentler@cs.umn.edu) -+ -+*/ -+/* -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "duke3d.h" -+#include "cache1d.h" -+ -+#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" -+#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 -+ -+void GetUnixPathFromEnvironment( char *fullname, int32 length, const char *filename ); -+ -+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 -+ -+ SoundCard = 1; -+ -+ music_initialized = 1; -+ return(MUSIC_Ok); -+} // MUSIC_Init -+ -+ -+int MUSIC_Shutdown(void) -+{ -+ musdebug("shutting down sound subsystem."); -+ -+ 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) -+{ -+ volume = max( 0, volume ); -+ volume = min( volume, 255 ); -+ -+ printf("Setting Volume to %d\n", 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); -+ */ -+ -+ return(MUSIC_Ok); -+} // MUSIC_PlaySong -+ -+ -+extern char ApogeePath[256]; -+ -+// 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 -+ GetUnixPathFromEnvironment(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 -+} -+ -+ -+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 -+ -+ -+void MUSIC_Update(void) -+{ -+} -diff -wruN source/jaudiolib/unixglob.c ../jfduke3d_src_20041013-linux/source/jaudiolib/unixglob.c ---- source/jaudiolib/unixglob.c 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/unixglob.c 2004-11-30 21:14:55.000000000 -0600 -@@ -0,0 +1,145 @@ -+/* -+Copyright (C) 2003-2004 Ryan C. Gordon. and James Bentler -+ -+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. -+ -+Originally written by Ryan C. Gordon. (icculus@clutteredmind.org) -+Adapted to work with JonoF's port by James Bentler (bentler@cs.umn.edu) -+ -+*/ -+ -+static char ApogeePath[256]; -+ -+#define PATH_SEP_CHAR '/' -+#define PATH_SEP_STR "/" -+#define ROOTDIR "/" -+#define CURDIR "./" -+ -+#include "duke3d.h" -+#include -+#include -+ -+void FixFilePath(char *filename) -+{ -+ char *ptr; -+ char *lastsep = filename; -+ -+ if ((!filename) || (*filename == '\0')) -+ return; -+ -+ if (access(filename, F_OK) == 0) /* File exists; we're good to go. */ -+ return; -+ -+ for (ptr = filename; 1; ptr++) -+ { -+ if (*ptr == '\\') -+ *ptr = PATH_SEP_CHAR; -+ -+ if ((*ptr == PATH_SEP_CHAR) || (*ptr == '\0')) -+ { -+ char pch = *ptr; -+ struct dirent *dent = NULL; -+ DIR *dir; -+ -+ if ((pch == PATH_SEP_CHAR) && (*(ptr + 1) == '\0')) -+ return; /* eos is pathsep; we're done. */ -+ -+ if (lastsep == ptr) -+ continue; /* absolute path; skip to next one. */ -+ -+ *ptr = '\0'; -+ if (lastsep == filename) { -+ dir = opendir((*lastsep == PATH_SEP_CHAR) ? ROOTDIR : CURDIR); -+ -+ if (*lastsep == PATH_SEP_CHAR) { -+ lastsep++; -+ } -+ } -+ else -+ { -+ *lastsep = '\0'; -+ dir = opendir(filename); -+ *lastsep = PATH_SEP_CHAR; -+ lastsep++; -+ } -+ -+ if (dir == NULL) -+ { -+ *ptr = PATH_SEP_CHAR; -+ return; /* maybe dir doesn't exist? give up. */ -+ } -+ -+ while ((dent = readdir(dir)) != NULL) -+ { -+ if (strcasecmp(dent->d_name, lastsep) == 0) -+ { -+ /* found match; replace it. */ -+ strcpy(lastsep, dent->d_name); -+ break; -+ } -+ } -+ -+ closedir(dir); -+ *ptr = pch; -+ lastsep = ptr; -+ -+ if (dent == NULL) -+ return; /* no match. oh well. */ -+ -+ if (pch == '\0') /* eos? */ -+ return; -+ } -+ } -+} -+ -+int32 SafeOpenWrite (const char *_filename, int32 filetype) -+{ -+ int handle; -+ char filename[MAX_PATH]; -+ strncpy(filename, _filename, sizeof (filename)); -+ filename[sizeof (filename) - 1] = '\0'; -+ FixFilePath(filename); -+ -+ handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_TRUNC -+ , S_IREAD | S_IWRITE); -+ -+ if (handle == -1) -+ Error ("Error opening %s: %s",filename,strerror(errno)); -+ -+ return handle; -+} -+ -+ -+void SafeWrite (int32 handle, void *buffer, int32 count) -+{ -+ unsigned iocount; -+ -+ while (count) -+ { -+ iocount = count > 0x8000 ? 0x8000 : count; -+ if (write (handle,buffer,iocount) != (int)iocount) -+ Error ("File write failure writing %ld bytes",count); -+ buffer = (void *)( (byte *)buffer + iocount ); -+ count -= iocount; -+ } -+} -+ -+ -+ -+void GetUnixPathFromEnvironment( char *fullname, int32 length, const char *filename ) -+{ -+ snprintf(fullname, length-1, "%s%s", ApogeePath, filename); -+} -diff -wruN source/jaudiolib/unixpitch.c ../jfduke3d_src_20041013-linux/source/jaudiolib/unixpitch.c ---- source/jaudiolib/unixpitch.c 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/unixpitch.c 2004-11-30 22:30:46.212592000 -0600 -@@ -0,0 +1,212 @@ -+/* -+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 -+ ) -+ -+ { -+ } -diff -wruN source/jaudiolib/unixvoc.c ../jfduke3d_src_20041013-linux/source/jaudiolib/unixvoc.c ---- source/jaudiolib/unixvoc.c 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/unixvoc.c 2004-12-01 00:25:24.202979320 -0600 -@@ -0,0 +1,2877 @@ -+/* -+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 -+ -+#include "util.h" -+#include "dpmi.h" -+#include "usrhooks.h" -+#include "interrup.h" -+#include "dma.h" -+#include "linklist.h" -+#include "dsl.h" -+ -+#include "pitch.h" -+#include "multivoc.h" -+#include "_multivc.h" -+#include "debugio.h" -+ -+// platform.h is from the build engine, but I need the byteswapping macros... --ryan. -+#include "platform.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 = 1; -+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; -+ -+ 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_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; -+ -+static int MV_ServiceVoc(int dummy_arg) -+ { -+ VoiceNode *voice; -+ VoiceNode *next; -+ char *buffer; -+ -+ // 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 ); -+ 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 ); -+ else -+ MV_16BitReverbFast( source, dest, count / 2, MV_ReverbLevel ); -+ } -+ else -+ { -+ if ( MV_ReverbTable != NULL ) -+ MV_8BitReverb( source, dest, (const VOLUME16 *)MV_ReverbTable, count ); -+ else -+ MV_8BitReverbFast( source, dest, 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; -+ -+ if (MV_MixFunction != NULL) -+ 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(0); -+ } -+ -+ 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(0); -+ } -+ -+ 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; -+ } -+ -+ MV_MixMode = mode; -+ -+ 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; -+ -+ 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; -+ -+ 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(); -+ -+ return( MV_Ok ); -+ } -+ -+ -+/*--------------------------------------------------------------------- -+ Function: MV_StopPlayback -+ -+ Stops the sound playback engine. -+---------------------------------------------------------------------*/ -+ -+void MV_StopPlayback -+ ( -+ void -+ ) -+ -+ { -+ VoiceNode *voice; -+ VoiceNode *next; -+ unsigned flags; -+ -+ DSL_StopPlayback(); -+ -+ // 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 ) -+ ) -+ -+ { -+ MV_SetErrorCode( MV_UnsupportedCard ); -+ return( MV_Error ); -+ } -+ -+ -+/*--------------------------------------------------------------------- -+ Function: MV_StopRecord -+ -+ Stops the sound record engine. -+---------------------------------------------------------------------*/ -+ -+void MV_StopRecord -+ ( -+ void -+ ) -+ -+ { -+ } -+ -+ -+/*--------------------------------------------------------------------- -+ 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, -+ 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) -+ { -+ return MV_Ok; -+ } -+ -+ -+/*--------------------------------------------------------------------- -+ 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 ); -+ -+ MV_TotalMemory = Voices * sizeof( VoiceNode ) + sizeof( HARSH_CLIP_TABLE_8 ); -+ status = USRHOOKS_GetMem( ( void ** )&ptr, MV_TotalMemory ); -+ if ( status != USRHOOKS_Ok ) -+ { -+ MV_SetErrorCode( MV_NoMem ); -+ 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 ) -+ { -+ USRHOOKS_FreeMem( MV_Voices ); -+ MV_Voices = NULL; -+ MV_TotalMemory = 0; -+ -+ MV_SetErrorCode( MV_NoMem ); -+ return( MV_Error ); -+ } -+ -+ MV_SetReverseStereo( FALSE ); -+ -+ // Initialize the sound card -+ status = DSL_Init(); -+ if ( status != DSL_Ok ) -+ { -+ MV_SetErrorCode( MV_BlasterError ); -+ } -+ -+ if ( MV_ErrorCode != MV_Ok ) -+ { -+ status = MV_ErrorCode; -+ -+ USRHOOKS_FreeMem( MV_Voices ); -+ MV_Voices = NULL; -+ MV_TotalMemory = 0; -+ -+ DPMI_FreeDOSMemory( MV_BufferDescriptor ); -+ -+ 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; -+ -+ 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 -+ DSL_Shutdown(); -+ -+ RestoreInterrupts( flags ); -+ -+ // Free any voices we allocated -+ 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 ); -+ } -diff -wruN source/jaudiolib/util.h ../jfduke3d_src_20041013-linux/source/jaudiolib/util.h ---- source/jaudiolib/util.h 1969-12-31 18:00:00.000000000 -0600 -+++ ../jfduke3d_src_20041013-linux/source/jaudiolib/util.h 2003-04-08 18:44:19.000000000 -0500 -@@ -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 -wruN source/sounds.c ../jfduke3d_src_20041013-linux/source/sounds.c ---- source/sounds.c 2004-10-13 12:21:24.000000000 -0500 -+++ ../jfduke3d_src_20041013-linux/source/sounds.c 2004-11-30 23:48:51.151373840 -0600 -@@ -213,6 +213,7 @@ - - void playmusic(char *fn) - { -+#ifdef WINDOWS - short fp; - long l; - -@@ -234,6 +235,13 @@ - kread( fp, MusicPtr, l); - kclose( fp ); - MUSIC_PlaySong( MusicPtr, MUSIC_LoopSong ); -+#else -+ void PlayMusic(char *_filename); -+ if(MusicToggle == 0) return; -+ if(MusicDevice < 0) return; -+ -+ PlayMusic(fn); -+#endif - } - - char loadsound(unsigned short num)