diff options
author | Chris Robinson <[email protected]> | 2010-11-26 17:47:43 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2010-11-26 17:47:43 -0800 |
commit | facb922f3e1d39af8514916c990acd9ff9d8baae (patch) | |
tree | 9547190fa5d1a07dbfb7acc773e483b0d476130e | |
parent | d7987677ac5748576626b0ed7f47d2e607bb4e77 (diff) |
Properly clamp high pitch values
-rw-r--r-- | Alc/ALu.c | 59 | ||||
-rw-r--r-- | Alc/mixer.c | 17 | ||||
-rw-r--r-- | OpenAL32/Include/alu.h | 15 |
3 files changed, 49 insertions, 42 deletions
@@ -104,34 +104,40 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext) SourceVolume = ALSource->flGain; MinVolume = ALSource->flMinGain; MaxVolume = ALSource->flMaxGain; + Pitch = ALSource->flPitch; //1. Multi-channel buffers always play "normal" Channels = 0; - Pitch = ALSource->flPitch; BufferListItem = ALSource->queue; while(BufferListItem != NULL) { ALbuffer *ALBuffer; if((ALBuffer=BufferListItem->buffer) != NULL) { - Channels = aluChannelsFromFormat(ALBuffer->format); + ALint maxstep = STACK_DATA_SIZE / + aluFrameSizeFromFormat(ALBuffer->format); + maxstep -= ResamplerPadding[ALSource->Resampler] + + ResamplerPrePadding[ALSource->Resampler] + 1; + maxstep = min(maxstep, INT_MAX>>FRACTIONBITS); + Pitch = Pitch * ALBuffer->frequency / Frequency; + if(Pitch > (ALfloat)maxstep) + ALSource->Params.Step = maxstep<<FRACTIONBITS; + else + { + ALSource->Params.Step = Pitch*FRACTIONONE; + if(ALSource->Params.Step == 0) + ALSource->Params.Step = 1; + else if(ALSource->Params.Step > maxstep) + ALSource->Params.Step = maxstep; + } + + Channels = aluChannelsFromFormat(ALBuffer->format); break; } BufferListItem = BufferListItem->next; } - if(Pitch > (float)MAX_PITCH) - ALSource->Params.Step = MAX_PITCH<<FRACTIONBITS; - else if(!(Pitch > 0.0f)) - ALSource->Params.Step = FRACTIONONE; - else - { - ALSource->Params.Step = Pitch*FRACTIONONE; - if(ALSource->Params.Step == 0) - ALSource->Params.Step = 1; - } - DryGain = SourceVolume; DryGain = __min(DryGain,MaxVolume); DryGain = __max(DryGain,MinVolume); @@ -587,23 +593,28 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext) ALbuffer *ALBuffer; if((ALBuffer=BufferListItem->buffer) != NULL) { + ALint maxstep = STACK_DATA_SIZE / + aluFrameSizeFromFormat(ALBuffer->format); + maxstep -= ResamplerPadding[ALSource->Resampler] + + ResamplerPrePadding[ALSource->Resampler] + 1; + maxstep = min(maxstep, INT_MAX>>FRACTIONBITS); + Pitch = Pitch * ALBuffer->frequency / Frequency; + if(Pitch > (ALfloat)maxstep) + ALSource->Params.Step = maxstep<<FRACTIONBITS; + else + { + ALSource->Params.Step = Pitch*FRACTIONONE; + if(ALSource->Params.Step == 0) + ALSource->Params.Step = 1; + else if(ALSource->Params.Step > maxstep) + ALSource->Params.Step = maxstep; + } break; } BufferListItem = BufferListItem->next; } - if(Pitch > (float)MAX_PITCH) - ALSource->Params.Step = MAX_PITCH<<FRACTIONBITS; - else if(!(Pitch > 0.0f)) - ALSource->Params.Step = FRACTIONONE; - else - { - ALSource->Params.Step = Pitch*FRACTIONONE; - if(ALSource->Params.Step == 0) - ALSource->Params.Step = 1; - } - // Use energy-preserving panning algorithm for multi-speaker playback length = __max(OrigDist, MinDist); if(length > 0.0f) diff --git a/Alc/mixer.c b/Alc/mixer.c index 53ba4aca..18c93b84 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -612,12 +612,6 @@ DECL_TEMPLATE(ALubyte, cubic8) #undef DECL_TEMPLATE -/* Stack data size can be whatever. Larger values need more stack, while - * smaller values may need more iterations */ -#ifndef STACK_DATA_SIZE -#define STACK_DATA_SIZE 16384 -#endif - ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo) { ALbufferlistitem *BufferListItem; @@ -859,17 +853,6 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo) BufferSize = (ALuint)((DataSize64+(increment-1)) / increment); BufferSize = min(BufferSize, (SamplesToDo-OutPos)); - if(BufferSize == 0) - { - AL_PRINT("No samples to mix! Pitch too high (%u, %g)?\n", - increment, increment/(double)FRACTIONONE); - State = AL_STOPPED; - BufferListItem = Source->queue; - BuffersPlayed = Source->BuffersInQueue; - DataPosInt = 0; - DataPosFrac = 0; - break; - } SrcData += BufferPrePadding*FrameSize; switch(Resampler) diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 31d42ea9..c157a529 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -80,7 +80,20 @@ typedef enum { #define FRACTIONBITS (14) #define FRACTIONONE (1<<FRACTIONBITS) #define FRACTIONMASK (FRACTIONONE-1) -#define MAX_PITCH (INT_MAX & ~FRACTIONMASK) + +/* Size for temporary stack storage of buffer data. Larger values need more + * stack, while smaller values may need more iterations. The value needs to be + * a sensible size, however, as it constrains the max stepping value used for + * mixing. + * The mixer requires being able to do two samplings per mixing loop. A 16KB + * buffer can hold 512 sample frames for a 7.1 float buffer. With the cubic + * resampler (which requires 3 padding sample frames), this limits the maximum + * step to about 508. This means that buffer_freq*source_pitch cannot exceed + * device_freq*508 for an 8-channel 32-bit buffer. */ +#ifndef STACK_DATA_SIZE +#define STACK_DATA_SIZE 16384 +#endif + /* NOTE: The AL_FORMAT_REAR* enums aren't handled here because they're * converted to AL_FORMAT_QUAD* when loaded */ |