diff --git a/MacOSX/QuakeSpasm.xcodeproj/project.xcworkspace/xcshareddata/QuakeSpasm.xccheckout b/MacOSX/QuakeSpasm.xcodeproj/project.xcworkspace/xcshareddata/QuakeSpasm.xccheckout new file mode 100644 index 00000000..9cd610af --- /dev/null +++ b/MacOSX/QuakeSpasm.xcodeproj/project.xcworkspace/xcshareddata/QuakeSpasm.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 9B8B3A85-F6C1-4D37-B6BC-7F34FBF23BF8 + IDESourceControlProjectName + QuakeSpasm + IDESourceControlProjectOriginsDictionary + + 2BD2BDEE-EFDD-4965-A751-0185457382EC + https://github.com/ericwa/Quakespasm + + IDESourceControlProjectPath + MacOSX/QuakeSpasm.xcodeproj/project.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + 2BD2BDEE-EFDD-4965-A751-0185457382EC + ../../.. + + IDESourceControlProjectURL + https://github.com/ericwa/Quakespasm + IDESourceControlProjectVersion + 110 + IDESourceControlProjectWCCIdentifier + 2BD2BDEE-EFDD-4965-A751-0185457382EC + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 2BD2BDEE-EFDD-4965-A751-0185457382EC + IDESourceControlWCCName + quakespasm + + + + diff --git a/MacOSX/QuakeSpasm.xcodeproj/project.xcworkspace/xcuserdata/ericwa.xcuserdatad/UserInterfaceState.xcuserstate b/MacOSX/QuakeSpasm.xcodeproj/project.xcworkspace/xcuserdata/ericwa.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..44cf0ab3 Binary files /dev/null and b/MacOSX/QuakeSpasm.xcodeproj/project.xcworkspace/xcuserdata/ericwa.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/MacOSX/QuakeSpasm.xcodeproj/xcuserdata/ericwa.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/MacOSX/QuakeSpasm.xcodeproj/xcuserdata/ericwa.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 00000000..fe2b4541 --- /dev/null +++ b/MacOSX/QuakeSpasm.xcodeproj/xcuserdata/ericwa.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/MacOSX/QuakeSpasm.xcodeproj/xcuserdata/ericwa.xcuserdatad/xcschemes/xcschememanagement.plist b/MacOSX/QuakeSpasm.xcodeproj/xcuserdata/ericwa.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..36a83cff --- /dev/null +++ b/MacOSX/QuakeSpasm.xcodeproj/xcuserdata/ericwa.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SuppressBuildableAutocreation + + 8D1107260486CEB800E47090 + + primary + + + + + diff --git a/Quake/q_sound.h b/Quake/q_sound.h index 7e560717..eaf838df 100644 --- a/Quake/q_sound.h +++ b/Quake/q_sound.h @@ -169,6 +169,7 @@ extern vec3_t listener_up; extern cvar_t sndspeed; extern cvar_t snd_mixspeed; +extern cvar_t snd_filterquality; extern cvar_t sfxvolume; extern cvar_t loadas8bit; diff --git a/Quake/snd_dma.c b/Quake/snd_dma.c index 542a0b65..5e685c6d 100644 --- a/Quake/snd_dma.c +++ b/Quake/snd_dma.c @@ -77,6 +77,7 @@ cvar_t loadas8bit = {"loadas8bit", "0", CVAR_NONE}; cvar_t sndspeed = {"sndspeed", "11025", CVAR_NONE}; cvar_t snd_mixspeed = {"snd_mixspeed", "44100", CVAR_NONE}; +cvar_t snd_filterquality = {"snd_filterquality", "1", CVAR_NONE}; static cvar_t nosound = {"nosound", "0", CVAR_NONE}; static cvar_t ambient_level = {"ambient_level", "0.3", CVAR_NONE}; @@ -163,7 +164,8 @@ void S_Init (void) Cvar_RegisterVariable(&_snd_mixahead); Cvar_RegisterVariable(&sndspeed); Cvar_RegisterVariable(&snd_mixspeed); - + Cvar_RegisterVariable(&snd_filterquality); + if (safemode || COM_CheckParm("-nosound")) return; diff --git a/Quake/snd_mix.c b/Quake/snd_mix.c index 6d555b8a..4bdb212c 100644 --- a/Quake/snd_mix.c +++ b/Quake/snd_mix.c @@ -156,6 +156,7 @@ S_MakeBlackmanWindowKernel Based on equation 16-4 from "The Scientist and Engineer's Guide to Digital Signal Processing" +M must be even kernel has room for M+1 floats, f_c is the filter cutoff frequency, as a fraction of the samplerate ============== @@ -192,95 +193,124 @@ static void S_MakeBlackmanWindowKernel(float *kernel, int M, float f_c) } } -// must be divisible by 4 -#define FILTER_KERNEL_SIZE 384 +typedef struct { + float *memory; // kernelsize floats + float *kernel; // kernelsize floats + int kernelsize; // M+1, padded to be a multiple of 16 + int M; + int parity; // 0-3 + float f_c; +} filter_t; + +static void S_UpdateFilter(filter_t *filter, int M, float f_c) +{ + if (filter->f_c != f_c || filter->M != M) + { + if (filter->memory != NULL) free(filter->memory); + if (filter->kernel != NULL) free(filter->kernel); + + filter->M = M; + filter->f_c = f_c; + + filter->parity = 0; + if ((M + 1) % 16 == 0) + filter->kernelsize = (M + 1); + else + filter->kernelsize = (M + 1) + 16 - ((M + 1) % 16); + filter->memory = calloc(filter->kernelsize, sizeof(float)); + filter->kernel = calloc(filter->kernelsize, sizeof(float)); + + S_MakeBlackmanWindowKernel(filter->kernel, M, f_c); + } +} + +static void S_ApplyFilter(filter_t *filter, int *data, int stride, int count) +{ + int i, j; + float *input; + const int kernelsize = filter->kernelsize; + const float *kernel = filter->kernel; + int parity = 0; + + input = malloc(sizeof(float) * (filter->kernelsize + count)); + +// set up the input buffer +// memory holds the previous filter->kernelsize samples of input. + + memcpy(input, filter->memory, filter->kernelsize * sizeof(float)); + + for (i=0; ikernelsize+i] = data[i * stride] / (32768.0 * 256.0); + } + +// copy out the last filter->kernelsize samples to 'memory' for next time + + memcpy(filter->memory, input + count, filter->kernelsize * sizeof(float)); + +// apply the filter + + for (i=0; iparity = parity; + + free(input); +} /* ============== S_LowpassFilter lowpass filters 24-bit integer samples in 'data' (stored in 32-bit ints). - -f_c is the filter cutoff frequency, as a fraction of the samplerate memory must be an array of FILTER_KERNEL_SIZE floats ============== */ -static void S_LowpassFilter(float f_c, int *data, int stride, int count, - float *memory) +static void S_LowpassFilter(int *data, int stride, int count, + filter_t *memory) { - int i; + int M; + float bw; -// M is the "kernel size" parameter for makekernel() - must be even. -// FILTER_KERNEL_SIZE size is M+1, rounded up to be divisible by 4 - const int M = FILTER_KERNEL_SIZE - 2; - - float input[FILTER_KERNEL_SIZE + count]; - - static float kernel[FILTER_KERNEL_SIZE]; - static float kernel_fc; - - if (f_c <= 0 || f_c > 0.5) - return; - - if (count < FILTER_KERNEL_SIZE) + if (snd_filterquality.value == 0) { - Con_Warning("S_LowpassFilter: not enough samples"); - return; + M = 126; + bw = 0.90; + } + else + { + M = 222; + bw = 0.96; } -// prepare the kernel + float f_c = (bw * 11025 / 2.0) / 44100.0; - if (kernel_fc != f_c) - { - S_MakeBlackmanWindowKernel(kernel, M, f_c); - kernel_fc = f_c; - } + S_UpdateFilter(memory, M, f_c); -// set up the input buffer -// memory holds the previous FILTER_KERNEL_SIZE samples of input. - - for (i=0; ispeed) + if (sndspeed.value == 11025 && shm->speed == 44100) { - static float memory_l[FILTER_KERNEL_SIZE]; - static float memory_r[FILTER_KERNEL_SIZE]; - - const float cutoff_freq = (sndspeed.value * 0.5 * 0.96) / shm->speed; - - S_LowpassFilter(cutoff_freq, (int *)paintbuffer, 2, end - paintedtime, memory_l); - S_LowpassFilter(cutoff_freq, ((int *)paintbuffer) + 1, 2, end - paintedtime, memory_r); + static filter_t memory_l, memory_r; + S_LowpassFilter((int *)paintbuffer, 2, end - paintedtime, &memory_l); + S_LowpassFilter(((int *)paintbuffer) + 1, 2, end - paintedtime, &memory_r); } // paint in the music