AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data) { ALCdevice *device; ALCcontext *context; ALbuffer *albuf; ALsizei align; context = GetContextRef(); if(!context) return; device = context->Device; LockBuffersRead(device); if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(!(samples >= 0 && offset >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); if(IsValidType(type) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); ReadLock(&albuf->lock); align = ATOMIC_LOAD_SEQ(&albuf->PackAlign); if(SanitizeAlignment(type, &align) == AL_FALSE) { ReadUnlock(&albuf->lock); SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); } if(channels != (ALenum)albuf->FmtChannels) { ReadUnlock(&albuf->lock); SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } if(offset > albuf->SampleLen || samples > albuf->SampleLen-offset) { ReadUnlock(&albuf->lock); SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); } if((samples%align) != 0) { ReadUnlock(&albuf->lock); SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); } /* offset -> byte offset */ offset *= FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType); ConvertData(data, type, (char*)albuf->data+offset, (enum UserFmtType)albuf->FmtType, ChannelsFromFmt(albuf->FmtChannels), samples, align); ReadUnlock(&albuf->lock); done: UnlockBuffersRead(device); ALCcontext_DecRef(context); }
AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value) { ALCdevice *device; ALCcontext *context; ALbuffer *albuf; context = GetContextRef(); if(!context) return; device = context->Device; if((albuf=LookupBuffer(device, buffer)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); if(!(value)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch(param) { case AL_FREQUENCY: *value = albuf->Frequency; break; case AL_BITS: *value = BytesFromFmt(albuf->FmtType) * 8; break; case AL_CHANNELS: *value = ChannelsFromFmt(albuf->FmtChannels); break; case AL_SIZE: ReadLock(&albuf->lock); *value = albuf->SampleLen * FrameSizeFromFmt(albuf->FmtChannels, albuf->FmtType); ReadUnlock(&albuf->lock); break; case AL_INTERNAL_FORMAT_SOFT: *value = albuf->Format; break; case AL_BYTE_LENGTH_SOFT: *value = albuf->OriginalSize; break; case AL_SAMPLE_LENGTH_SOFT: *value = albuf->SampleLen; break; case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: *value = albuf->UnpackAlign; break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: *value = albuf->PackAlign; break; default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } done: ALCcontext_DecRef(context); }
ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo) { ALbufferlistitem *BufferListItem; ALuint DataPosInt, DataPosFrac; enum FmtChannels FmtChannels; enum FmtType FmtType; ALuint BuffersPlayed; ALboolean Looping; ALuint increment; resampler_t Resampler; ALenum State; ALuint OutPos; ALuint FrameSize; ALint64 DataSize64; ALuint i; /* Get source info */ State = Source->state; BuffersPlayed = Source->BuffersPlayed; DataPosInt = Source->position; DataPosFrac = Source->position_fraction; Looping = Source->bLooping; increment = Source->Params.Step; Resampler = (increment == FRACTIONONE) ? POINT_RESAMPLER : Source->Resampler; /* Get buffer info */ FrameSize = 0; FmtChannels = FmtMono; FmtType = FmtUByte; BufferListItem = Source->queue; for(i = 0;i < Source->BuffersInQueue;i++) { const ALbuffer *ALBuffer; if((ALBuffer=BufferListItem->buffer) != NULL) { FmtChannels = ALBuffer->FmtChannels; FmtType = ALBuffer->FmtType; FrameSize = FrameSizeFromFmt(FmtChannels, FmtType); break; } BufferListItem = BufferListItem->next; } /* Get current buffer queue item */ BufferListItem = Source->queue; for(i = 0;i < BuffersPlayed;i++) BufferListItem = BufferListItem->next; OutPos = 0; do { const ALuint BufferPrePadding = ResamplerPrePadding[Resampler]; const ALuint BufferPadding = ResamplerPadding[Resampler]; ALubyte StackData[STACK_DATA_SIZE]; ALubyte *SrcData = StackData; ALuint SrcDataSize = 0; ALuint BufferSize; /* Figure out how many buffer bytes will be needed */ DataSize64 = SamplesToDo-OutPos+1; DataSize64 *= increment; DataSize64 += DataPosFrac+FRACTIONMASK; DataSize64 >>= FRACTIONBITS; DataSize64 += BufferPadding+BufferPrePadding; DataSize64 *= FrameSize; BufferSize = min(DataSize64, STACK_DATA_SIZE); BufferSize -= BufferSize%FrameSize; if(Source->lSourceType == AL_STATIC) { const ALbuffer *ALBuffer = Source->Buffer; const ALubyte *Data = ALBuffer->data; ALuint DataSize; ALuint pos; /* If current pos is beyond the loop range, do not loop */ if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd) { Looping = AL_FALSE; if(DataPosInt >= BufferPrePadding) pos = (DataPosInt-BufferPrePadding)*FrameSize; else { DataSize = (BufferPrePadding-DataPosInt)*FrameSize; DataSize = min(BufferSize, DataSize); memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize); SrcDataSize += DataSize; BufferSize -= DataSize; pos = 0; } /* Copy what's left to play in the source buffer, and clear the * rest of the temp buffer */ DataSize = ALBuffer->size - pos; DataSize = min(BufferSize, DataSize); memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize); SrcDataSize += DataSize; BufferSize -= DataSize; memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, BufferSize); SrcDataSize += BufferSize; BufferSize -= BufferSize; } else { ALuint LoopStart = ALBuffer->LoopStart; ALuint LoopEnd = ALBuffer->LoopEnd; if(DataPosInt >= LoopStart) { pos = DataPosInt-LoopStart; while(pos < BufferPrePadding) pos += LoopEnd-LoopStart; pos -= BufferPrePadding; pos += LoopStart; pos *= FrameSize; } else if(DataPosInt >= BufferPrePadding) pos = (DataPosInt-BufferPrePadding)*FrameSize; else { DataSize = (BufferPrePadding-DataPosInt)*FrameSize; DataSize = min(BufferSize, DataSize); memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize); SrcDataSize += DataSize; BufferSize -= DataSize; pos = 0; } /* Copy what's left of this loop iteration, then copy repeats * of the loop section */ DataSize = LoopEnd*FrameSize - pos; DataSize = min(BufferSize, DataSize); memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize); SrcDataSize += DataSize; BufferSize -= DataSize; DataSize = (LoopEnd-LoopStart) * FrameSize; while(BufferSize > 0) { DataSize = min(BufferSize, DataSize); memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize); SrcDataSize += DataSize; BufferSize -= DataSize; } } } else { /* Crawl the buffer queue to fill in the temp buffer */ ALbufferlistitem *BufferListIter = BufferListItem; ALuint pos; if(DataPosInt >= BufferPrePadding) pos = (DataPosInt-BufferPrePadding)*FrameSize; else { pos = (BufferPrePadding-DataPosInt)*FrameSize; while(pos > 0) { if(!BufferListIter->prev && !Looping) { ALuint DataSize = min(BufferSize, pos); memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize); SrcDataSize += DataSize; BufferSize -= DataSize; pos = 0; break; } if(BufferListIter->prev) BufferListIter = BufferListIter->prev; else { while(BufferListIter->next) BufferListIter = BufferListIter->next; } if(BufferListIter->buffer) { if((ALuint)BufferListIter->buffer->size > pos) { pos = BufferListIter->buffer->size - pos; break; } pos -= BufferListIter->buffer->size; } } } while(BufferListIter && BufferSize > 0) { const ALbuffer *ALBuffer; if((ALBuffer=BufferListIter->buffer) != NULL) { const ALubyte *Data = ALBuffer->data; ALuint DataSize = ALBuffer->size; /* Skip the data already played */ if(DataSize <= pos) pos -= DataSize; else { Data += pos; DataSize -= pos; pos -= pos; DataSize = min(BufferSize, DataSize); memcpy(&SrcData[SrcDataSize], Data, DataSize); SrcDataSize += DataSize; BufferSize -= DataSize; } } BufferListIter = BufferListIter->next; if(!BufferListIter && Looping) BufferListIter = Source->queue; else if(!BufferListIter) { memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, BufferSize); SrcDataSize += BufferSize; BufferSize -= BufferSize; } } } /* Figure out how many samples we can mix. */ DataSize64 = SrcDataSize / FrameSize; DataSize64 -= BufferPadding+BufferPrePadding; DataSize64 <<= FRACTIONBITS; DataSize64 -= increment; DataSize64 -= DataPosFrac; BufferSize = (ALuint)((DataSize64+(increment-1)) / increment); BufferSize = min(BufferSize, (SamplesToDo-OutPos)); SrcData += BufferPrePadding*FrameSize; switch(Resampler) { case POINT_RESAMPLER: Mix_point(Source, Device, FmtChannels, FmtType, SrcData, &DataPosInt, &DataPosFrac, OutPos, SamplesToDo, BufferSize); break; case LINEAR_RESAMPLER: Mix_lerp(Source, Device, FmtChannels, FmtType, SrcData, &DataPosInt, &DataPosFrac, OutPos, SamplesToDo, BufferSize); break; case CUBIC_RESAMPLER: Mix_cubic(Source, Device, FmtChannels, FmtType, SrcData, &DataPosInt, &DataPosFrac, OutPos, SamplesToDo, BufferSize); break; case RESAMPLER_MIN: case RESAMPLER_MAX: break; } OutPos += BufferSize; /* Handle looping sources */ while(1) { const ALbuffer *ALBuffer; ALuint DataSize = 0; ALuint LoopStart = 0; ALuint LoopEnd = 0; if((ALBuffer=BufferListItem->buffer) != NULL) { DataSize = ALBuffer->size / FrameSize; LoopStart = ALBuffer->LoopStart; LoopEnd = ALBuffer->LoopEnd; if(LoopEnd > DataPosInt) break; } if(Looping && Source->lSourceType == AL_STATIC) { BufferListItem = Source->queue; DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; break; } if(DataSize > DataPosInt) break; if(BufferListItem->next) { BufferListItem = BufferListItem->next; BuffersPlayed++; } else if(Looping) { BufferListItem = Source->queue; BuffersPlayed = 0; } else { State = AL_STOPPED; BufferListItem = Source->queue; BuffersPlayed = Source->BuffersInQueue; DataPosInt = 0; DataPosFrac = 0; break; } DataPosInt -= DataSize; } } while(State == AL_PLAYING && OutPos < SamplesToDo); /* Update source info */ Source->state = State; Source->BuffersPlayed = BuffersPlayed; Source->position = DataPosInt; Source->position_fraction = DataPosFrac; Source->Buffer = BufferListItem->buffer; }