diff -Nur jfduke3d_src_20051009.orig/Makefile jfduke3d_src_20051009/Makefile --- jfduke3d_src_20051009.orig/Makefile 2005-10-09 15:25:40.000000000 +0200 +++ jfduke3d_src_20051009/Makefile 2005-10-10 14:55:20.000000000 +0200 @@ -12,7 +12,7 @@ NOASM = 0 # Debugging options -RELEASE?=0 +RELEASE?=1 # build locations SRC=source/ @@ -55,11 +55,8 @@ 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 @@ -96,8 +93,15 @@ endif ifeq ($(RENDERTYPE),SDL) - override CFLAGS+= $(subst -Dmain=SDL_main,,$(shell sdl-config --cflags)) - AUDIOLIBOBJ=$(AUDIOLIB_MUSIC_STUB) $(AUDIOLIB_FX_STUB) + override 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) ifeq (1,$(HAVE_GTK2)) override CFLAGS+= -DHAVE_GTK2 $(shell pkg-config --cflags gtk+-2.0) @@ -125,11 +129,12 @@ build$(EXESUFFIX): $(EDITOROBJS) $(EOBJ)$(EDITORLIB) $(EOBJ)$(ENGINELIB) $(CC) $(CFLAGS) -o $@ $^ $(LIBS) -Wl,-Map=$@.map +AUDIOLIB=$(SRC)/jaudiolib include Makefile.deps .PHONY: enginelib editorlib enginelib editorlib: - -mkdir $(EOBJ) + -mkdir -p $(EOBJ) $(MAKE) -C $(EROOT) "OBJ=$(CURDIR)/$(EOBJ)" \ SUPERBUILD=$(SUPERBUILD) POLYMOST=$(POLYMOST) \ USE_OPENGL=$(USE_OPENGL) DYNAMIC_OPENGL=$(DYNAMIC_OPENGL) \ diff -Nur jfduke3d_src_20051009.orig/Makefile.deps jfduke3d_src_20051009/Makefile.deps --- jfduke3d_src_20051009.orig/Makefile.deps 2005-10-09 15:25:40.000000000 +0200 +++ jfduke3d_src_20051009/Makefile.deps 2005-10-10 14:55:20.000000000 +0200 @@ -33,6 +33,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 -Nur jfduke3d_src_20051009.orig/source/config.c jfduke3d_src_20051009/source/config.c --- jfduke3d_src_20051009.orig/source/config.c 2005-10-09 15:25:40.000000000 +0200 +++ jfduke3d_src_20051009/source/config.c 2005-10-10 14:55:20.000000000 +0200 @@ -203,8 +203,8 @@ int32 i,f; byte k1,k2; - FXDevice = -1; - MusicDevice = -1; + FXDevice = 1; + MusicDevice = 1; NumVoices = 4; NumChannels = 2; NumBits = 8; @@ -666,6 +666,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 -Nur jfduke3d_src_20051009.orig/source/jaudiolib/debugio.h jfduke3d_src_20051009/source/jaudiolib/debugio.h --- jfduke3d_src_20051009.orig/source/jaudiolib/debugio.h 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/debugio.h 2005-10-10 14:55:20.000000000 +0200 @@ -0,0 +1,30 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef __DEBUGIO_H +#define __DEBUGIO_H + +void DB_SetXY( int x, int y ); +void DB_PutChar( char ch ); +int DB_PrintString( char *string ); +int DB_PrintNum( int number ); +int DB_PrintUnsigned( unsigned long number, int radix ); +int DB_printf( char *fmt, ... ); + +#endif \ No newline at end of file diff -Nur jfduke3d_src_20051009.orig/source/jaudiolib/dma.h jfduke3d_src_20051009/source/jaudiolib/dma.h --- jfduke3d_src_20051009.orig/source/jaudiolib/dma.h 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/dma.h 2005-10-10 14:55:20.000000000 +0200 @@ -0,0 +1,83 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + file: DMA.H + + author: James R. Dose + date: February 4, 1994 + + Public header file for DMA.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __DMA_H +#define __DMA_H + +enum DMA_ERRORS + { + DMA_Error = -1, + DMA_Ok = 0, + DMA_ChannelOutOfRange, + DMA_InvalidChannel + }; + +enum DMA_Modes + { + DMA_SingleShotRead, + DMA_SingleShotWrite, + DMA_AutoInitRead, + DMA_AutoInitWrite + }; + +char *DMA_ErrorString + ( + int ErrorNumber + ); + +int DMA_VerifyChannel + ( + int channel + ); + +int DMA_SetupTransfer + ( + int channel, + char *address, + int length, + int mode + ); + +int DMA_EndTransfer + ( + int channel + ); + +char *DMA_GetCurrentPos + ( + int channel + ); + +int DMA_GetTransferCount + ( + int channel + ); + +#endif \ No newline at end of file diff -Nur jfduke3d_src_20051009.orig/source/jaudiolib/dpmi.h jfduke3d_src_20051009/source/jaudiolib/dpmi.h --- jfduke3d_src_20051009.orig/source/jaudiolib/dpmi.h 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/dpmi.h 2005-10-10 14:55:20.000000000 +0200 @@ -0,0 +1,43 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + 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 \ No newline at end of file diff -Nur jfduke3d_src_20051009.orig/source/jaudiolib/dsl.c jfduke3d_src_20051009/source/jaudiolib/dsl.c --- jfduke3d_src_20051009.orig/source/jaudiolib/dsl.c 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/dsl.c 2005-10-10 14:55:20.000000000 +0200 @@ -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 ) +{ +} \ No newline at end of file diff -Nur jfduke3d_src_20051009.orig/source/jaudiolib/dsl.h jfduke3d_src_20051009/source/jaudiolib/dsl.h --- jfduke3d_src_20051009.orig/source/jaudiolib/dsl.h 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/dsl.h 2005-10-10 14:55:20.000000000 +0200 @@ -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 \ No newline at end of file diff -Nur jfduke3d_src_20051009.orig/source/jaudiolib/interrup.h jfduke3d_src_20051009/source/jaudiolib/interrup.h --- jfduke3d_src_20051009.orig/source/jaudiolib/interrup.h 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/interrup.h 2005-10-10 14:55:20.000000000 +0200 @@ -0,0 +1,50 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: INTERRUP.H + + author: James R. Dose + date: March 31, 1994 + + Inline functions for disabling and restoring the interrupt flag. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __INTERRUPT_H +#define __INTERRUPT_H + +unsigned long DisableInterrupts( void ); +void RestoreInterrupts( unsigned long flags ); + +#ifdef PLAT_DOS +#pragma aux DisableInterrupts = \ + "pushfd", \ + "pop eax", \ + "cli" \ + modify [ eax ]; + +#pragma aux RestoreInterrupts = \ + "push eax", \ + "popfd" \ + parm [ eax ]; +#endif + +#endif \ No newline at end of file diff -Nur jfduke3d_src_20051009.orig/source/jaudiolib/_multivc.h jfduke3d_src_20051009/source/jaudiolib/_multivc.h --- jfduke3d_src_20051009.orig/source/jaudiolib/_multivc.h 2005-10-09 15:25:42.000000000 +0200 +++ jfduke3d_src_20051009/source/jaudiolib/_multivc.h 2005-10-10 14:55:20.000000000 +0200 @@ -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 -Nur jfduke3d_src_20051009.orig/source/jaudiolib/nodpmi.c jfduke3d_src_20051009/source/jaudiolib/nodpmi.c --- jfduke3d_src_20051009.orig/source/jaudiolib/nodpmi.c 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/nodpmi.c 2005-10-10 14:55:20.000000000 +0200 @@ -0,0 +1,50 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: 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; +} \ No newline at end of file diff -Nur jfduke3d_src_20051009.orig/source/jaudiolib/platform.h jfduke3d_src_20051009/source/jaudiolib/platform.h --- jfduke3d_src_20051009.orig/source/jaudiolib/platform.h 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/platform.h 2005-10-10 14:55:20.000000000 +0200 @@ -0,0 +1,61 @@ +#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 -Nur jfduke3d_src_20051009.orig/source/jaudiolib/sdlmusic.c jfduke3d_src_20051009/source/jaudiolib/sdlmusic.c --- jfduke3d_src_20051009.orig/source/jaudiolib/sdlmusic.c 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/sdlmusic.c 2005-10-10 14:55:20.000000000 +0200 @@ -0,0 +1,478 @@ +/* +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" + +#ifndef MAX_PATH +#define MAX_PATH 256 +#endif + +#if (defined __WATCOMC__) +// This is probably out of date. --ryan. +#include "dukesnd_watcom.h" +#endif + +#if (!defined __WATCOMC__) +#define cdecl +#endif + +#include "SDL.h" +#include "SDL_mixer.h" +#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] = "/tmp/"; + +// 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 -Nur jfduke3d_src_20051009.orig/source/jaudiolib/unixglob.c jfduke3d_src_20051009/source/jaudiolib/unixglob.c --- jfduke3d_src_20051009.orig/source/jaudiolib/unixglob.c 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/unixglob.c 2005-10-10 14:55:20.000000000 +0200 @@ -0,0 +1,149 @@ +/* +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] = "/tmp/"; + +#define PATH_SEP_CHAR '/' +#define PATH_SEP_STR "/" +#define ROOTDIR "/" +#define CURDIR "./" + +#include "duke3d.h" +#include +#include + +#ifndef MAX_PATH +#define MAX_PATH 256 +#endif + +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 -Nur jfduke3d_src_20051009.orig/source/jaudiolib/unixpitch.c jfduke3d_src_20051009/source/jaudiolib/unixpitch.c --- jfduke3d_src_20051009.orig/source/jaudiolib/unixpitch.c 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/unixpitch.c 2005-10-10 14:55:20.000000000 +0200 @@ -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 + ) + + { + } \ No newline at end of file diff -Nur jfduke3d_src_20051009.orig/source/jaudiolib/unixvoc.c jfduke3d_src_20051009/source/jaudiolib/unixvoc.c --- jfduke3d_src_20051009.orig/source/jaudiolib/unixvoc.c 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/unixvoc.c 2005-10-10 14:55:20.000000000 +0200 @@ -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. + +ou should have received a copy of the GNU General Public License +long 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 ); + } \ No newline at end of file diff -Nur jfduke3d_src_20051009.orig/source/jaudiolib/util.h jfduke3d_src_20051009/source/jaudiolib/util.h --- jfduke3d_src_20051009.orig/source/jaudiolib/util.h 1970-01-01 01:00:00.000000000 +0100 +++ jfduke3d_src_20051009/source/jaudiolib/util.h 2005-10-10 14:55:20.000000000 +0200 @@ -0,0 +1,12 @@ +#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 -Nur jfduke3d_src_20051009.orig/source/player.c jfduke3d_src_20051009/source/player.c --- jfduke3d_src_20051009.orig/source/player.c 2005-10-09 15:25:42.000000000 +0200 +++ jfduke3d_src_20051009/source/player.c 2005-10-10 14:55:17.000000000 +0200 @@ -1974,8 +1974,11 @@ info.dz = 0; } - svel -= info.dx; - vel = -info.dz>>6; + if (!running) svel -= (info.dx / 8); + else svel -= (info.dx / 4); + vel = -info.dz>>6; + if (!running) vel -= (info.dpitch / 8); + else vel -= (info.dpitch / 4); if (running) { diff -Nur jfduke3d_src_20051009.orig/source/sounds.c jfduke3d_src_20051009/source/sounds.c --- jfduke3d_src_20051009.orig/source/sounds.c 2005-10-09 15:25:42.000000000 +0200 +++ jfduke3d_src_20051009/source/sounds.c 2005-10-10 14:55:20.000000000 +0200 @@ -209,6 +209,7 @@ void playmusic(char *fn) { +#ifdef WINDOWS short fp; long l; @@ -229,6 +230,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)