Mercurial > audio-send
view Alc/mixer.c @ 14:63312ec4a2bf
limit to 16bit mono for now.
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Mon, 31 Oct 2011 08:01:08 -0700 |
parents | f9476ff7637e |
children |
line wrap: on
line source
1 /**2 * OpenAL cross platform audio library3 * Copyright (C) 1999-2007 by authors.4 * This library is free software; you can redistribute it and/or5 * modify it under the terms of the GNU Library General Public6 * License as published by the Free Software Foundation; either7 * version 2 of the License, or (at your option) any later version.8 *9 * This library is distributed in the hope that it will be useful,10 * but WITHOUT ANY WARRANTY; without even the implied warranty of11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12 * Library General Public License for more details.13 *14 * You should have received a copy of the GNU Library General Public15 * License along with this library; if not, write to the16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,17 * Boston, MA 02111-1307, USA.18 * Or go to http://www.gnu.org/copyleft/lgpl.html19 */21 #include "config.h"23 #include <math.h>24 #include <stdlib.h>25 #include <string.h>26 #include <ctype.h>27 #include <assert.h>29 #include "alMain.h"30 #include "AL/al.h"31 #include "AL/alc.h"32 #include "alSource.h"33 #include "alBuffer.h"34 #include "alListener.h"35 #include "alAuxEffectSlot.h"36 #include "alu.h"37 #include "bs2b.h"40 static __inline ALdouble point32(const ALfloat *vals, ALint step, ALint frac)41 { return vals[0]; (void)step; (void)frac; }42 static __inline ALdouble lerp32(const ALfloat *vals, ALint step, ALint frac)43 { return lerp(vals[0], vals[step], frac * (1.0/FRACTIONONE)); }44 static __inline ALdouble cubic32(const ALfloat *vals, ALint step, ALint frac)45 { return cubic(vals[-step], vals[0], vals[step], vals[step+step],46 frac * (1.0/FRACTIONONE)); }48 static __inline ALdouble point16(const ALshort *vals, ALint step, ALint frac)49 { return vals[0] * (1.0/32767.0); (void)step; (void)frac; }50 static __inline ALdouble lerp16(const ALshort *vals, ALint step, ALint frac)51 { return lerp(vals[0], vals[step], frac * (1.0/FRACTIONONE)) * (1.0/32767.0); }52 static __inline ALdouble cubic16(const ALshort *vals, ALint step, ALint frac)53 { return cubic(vals[-step], vals[0], vals[step], vals[step+step],54 frac * (1.0/FRACTIONONE)) * (1.0/32767.0); }56 static __inline ALdouble point8(const ALbyte *vals, ALint step, ALint frac)57 { return vals[0] * (1.0/127.0); (void)step; (void)frac; }58 static __inline ALdouble lerp8(const ALbyte *vals, ALint step, ALint frac)59 { return lerp(vals[0], vals[step], frac * (1.0/FRACTIONONE)) * (1.0/127.0); }60 static __inline ALdouble cubic8(const ALbyte *vals, ALint step, ALint frac)61 { return cubic(vals[-step], vals[0], vals[step], vals[step+step],62 frac * (1.0/FRACTIONONE)) * (1.0/127.0); }64 #ifdef __GNUC__65 #define LIKELY(x) __builtin_expect(!!(x), 1)66 #define UNLIKELY(x) __builtin_expect(!!(x), 0)67 #else68 #define LIKELY(x) (x)69 #define UNLIKELY(x) (x)70 #endif72 #if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_H)73 #include <arm_neon.h>75 static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2],76 ALfloat (*RESTRICT Coeffs)[2],77 ALfloat left, ALfloat right)78 {79 ALuint c;80 float32x4_t leftright4;81 {82 float32x2_t leftright2 = vdup_n_f32(0.0);83 leftright2 = vset_lane_f32(left, leftright2, 0);84 leftright2 = vset_lane_f32(right, leftright2, 1);85 leftright4 = vcombine_f32(leftright2, leftright2);86 }87 for(c = 0;c < HRIR_LENGTH;c += 2)88 {89 const ALuint o0 = (Offset+c)&HRIR_MASK;90 const ALuint o1 = (o0+1)&HRIR_MASK;91 float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]),92 vld1_f32((float32_t*)&Values[o1][0]));93 float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]);95 vals = vmlaq_f32(vals, coefs, leftright4);97 vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals));98 vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals));99 }100 }102 #else104 static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2],105 ALfloat (*RESTRICT Coeffs)[2],106 ALfloat left, ALfloat right)107 {108 ALuint c;109 for(c = 0;c < HRIR_LENGTH;c++)110 {111 const ALuint off = (Offset+c)&HRIR_MASK;112 Values[off][0] += Coeffs[c][0] * left;113 Values[off][1] += Coeffs[c][1] * right;114 }115 }117 #endif119 #define DECL_TEMPLATE(T, sampler) \120 static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \121 const ALvoid *srcdata, ALuint *DataPosInt, ALuint *DataPosFrac, \122 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \123 { \124 const ALuint NumChannels = Source->NumChannels; \125 const T *RESTRICT data = srcdata; \126 const ALint *RESTRICT DelayStep = Source->Params.HrtfDelayStep; \127 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS]; \128 ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \129 ALfloat (*RESTRICT CoeffStep)[2] = Source->Params.HrtfCoeffStep; \130 ALuint pos, frac; \131 FILTER *DryFilter; \132 ALuint BufferIdx; \133 ALuint increment; \134 ALuint i, out, c; \135 ALfloat value; \136 \137 increment = Source->Params.Step; \138 \139 DryBuffer = Device->DryBuffer; \140 ClickRemoval = Device->ClickRemoval; \141 PendingClicks = Device->PendingClicks; \142 DryFilter = &Source->Params.iirFilter; \143 \144 pos = 0; \145 frac = *DataPosFrac; \146 \147 for(i = 0;i < NumChannels;i++) \148 { \149 ALfloat (*RESTRICT TargetCoeffs)[2] = Source->Params.HrtfCoeffs[i]; \150 ALuint *RESTRICT TargetDelay = Source->Params.HrtfDelay[i]; \151 ALfloat *RESTRICT History = Source->HrtfHistory[i]; \152 ALfloat (*RESTRICT Values)[2] = Source->HrtfValues[i]; \153 ALint Counter = maxu(Source->HrtfCounter, OutPos) - OutPos; \154 ALuint Offset = Source->HrtfOffset + OutPos; \155 ALfloat Coeffs[HRIR_LENGTH][2]; \156 ALuint Delay[2]; \157 ALfloat left, right; \158 \159 pos = 0; \160 frac = *DataPosFrac; \161 \162 for(c = 0;c < HRIR_LENGTH;c++) \163 { \164 Coeffs[c][0] = TargetCoeffs[c][0] - (CoeffStep[c][0]*Counter); \165 Coeffs[c][1] = TargetCoeffs[c][1] - (CoeffStep[c][1]*Counter); \166 } \167 \168 Delay[0] = TargetDelay[0] - (DelayStep[0]*Counter) + 32768; \169 Delay[1] = TargetDelay[1] - (DelayStep[1]*Counter) + 32768; \170 \171 if(LIKELY(OutPos == 0)) \172 { \173 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \174 value = lpFilter2PC(DryFilter, i, value); \175 \176 History[Offset&SRC_HISTORY_MASK] = value; \177 left = History[(Offset-(Delay[0]>>16))&SRC_HISTORY_MASK]; \178 right = History[(Offset-(Delay[1]>>16))&SRC_HISTORY_MASK]; \179 \180 ClickRemoval[FRONT_LEFT] -= Values[(Offset+1)&HRIR_MASK][0] + \181 Coeffs[0][0] * left; \182 ClickRemoval[FRONT_RIGHT] -= Values[(Offset+1)&HRIR_MASK][1] + \183 Coeffs[0][1] * right; \184 } \185 for(BufferIdx = 0;BufferIdx < BufferSize && Counter > 0;BufferIdx++) \186 { \187 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \188 value = lpFilter2P(DryFilter, i, value); \189 \190 History[Offset&SRC_HISTORY_MASK] = value; \191 left = History[(Offset-(Delay[0]>>16))&SRC_HISTORY_MASK]; \192 right = History[(Offset-(Delay[1]>>16))&SRC_HISTORY_MASK]; \193 \194 Delay[0] += DelayStep[0]; \195 Delay[1] += DelayStep[1]; \196 \197 Values[Offset&HRIR_MASK][0] = 0.0f; \198 Values[Offset&HRIR_MASK][1] = 0.0f; \199 Offset++; \200 \201 for(c = 0;c < HRIR_LENGTH;c++) \202 { \203 const ALuint off = (Offset+c)&HRIR_MASK; \204 Values[off][0] += Coeffs[c][0] * left; \205 Values[off][1] += Coeffs[c][1] * right; \206 Coeffs[c][0] += CoeffStep[c][0]; \207 Coeffs[c][1] += CoeffStep[c][1]; \208 } \209 \210 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \211 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \212 \213 frac += increment; \214 pos += frac>>FRACTIONBITS; \215 frac &= FRACTIONMASK; \216 OutPos++; \217 Counter--; \218 } \219 \220 Delay[0] >>= 16; \221 Delay[1] >>= 16; \222 for(;BufferIdx < BufferSize;BufferIdx++) \223 { \224 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \225 value = lpFilter2P(DryFilter, i, value); \226 \227 History[Offset&SRC_HISTORY_MASK] = value; \228 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \229 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \230 \231 Values[Offset&HRIR_MASK][0] = 0.0f; \232 Values[Offset&HRIR_MASK][1] = 0.0f; \233 Offset++; \234 \235 ApplyCoeffs(Offset, Values, Coeffs, left, right); \236 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \237 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \238 \239 frac += increment; \240 pos += frac>>FRACTIONBITS; \241 frac &= FRACTIONMASK; \242 OutPos++; \243 } \244 if(LIKELY(OutPos == SamplesToDo)) \245 { \246 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \247 value = lpFilter2PC(DryFilter, i, value); \248 \249 History[Offset&SRC_HISTORY_MASK] = value; \250 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \251 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \252 \253 PendingClicks[FRONT_LEFT] += Values[(Offset+1)&HRIR_MASK][0] + \254 Coeffs[0][0] * left; \255 PendingClicks[FRONT_RIGHT] += Values[(Offset+1)&HRIR_MASK][1] + \256 Coeffs[0][1] * right; \257 } \258 OutPos -= BufferSize; \259 } \260 \261 for(out = 0;out < Device->NumAuxSends;out++) \262 { \263 ALeffectslot *Slot = Source->Params.Send[out].Slot; \264 ALfloat WetSend; \265 ALfloat *RESTRICT WetBuffer; \266 ALfloat *RESTRICT WetClickRemoval; \267 ALfloat *RESTRICT WetPendingClicks; \268 FILTER *WetFilter; \269 \270 if(!Slot || Slot->effect.type == AL_EFFECT_NULL) \271 continue; \272 \273 WetBuffer = Slot->WetBuffer; \274 WetClickRemoval = Slot->ClickRemoval; \275 WetPendingClicks = Slot->PendingClicks; \276 WetFilter = &Source->Params.Send[out].iirFilter; \277 WetSend = Source->Params.Send[out].WetGain; \278 \279 for(i = 0;i < NumChannels;i++) \280 { \281 pos = 0; \282 frac = *DataPosFrac; \283 \284 if(LIKELY(OutPos == 0)) \285 { \286 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\287 value = lpFilter1PC(WetFilter, i, value); \288 \289 WetClickRemoval[0] -= value * WetSend; \290 } \291 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \292 { \293 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\294 value = lpFilter1P(WetFilter, i, value); \295 \296 WetBuffer[OutPos] += value * WetSend; \297 \298 frac += increment; \299 pos += frac>>FRACTIONBITS; \300 frac &= FRACTIONMASK; \301 OutPos++; \302 } \303 if(LIKELY(OutPos == SamplesToDo)) \304 { \305 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\306 value = lpFilter1PC(WetFilter, i, value); \307 \308 WetPendingClicks[0] += value * WetSend; \309 } \310 OutPos -= BufferSize; \311 } \312 } \313 *DataPosInt += pos; \314 *DataPosFrac = frac; \315 }317 DECL_TEMPLATE(ALfloat, point32)318 DECL_TEMPLATE(ALfloat, lerp32)319 DECL_TEMPLATE(ALfloat, cubic32)321 DECL_TEMPLATE(ALshort, point16)322 DECL_TEMPLATE(ALshort, lerp16)323 DECL_TEMPLATE(ALshort, cubic16)325 DECL_TEMPLATE(ALbyte, point8)326 DECL_TEMPLATE(ALbyte, lerp8)327 DECL_TEMPLATE(ALbyte, cubic8)329 #undef DECL_TEMPLATE332 #define DECL_TEMPLATE(T, sampler) \333 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, \334 const ALvoid *srcdata, ALuint *DataPosInt, ALuint *DataPosFrac, \335 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \336 { \337 const ALuint NumChannels = Source->NumChannels; \338 const T *RESTRICT data = srcdata; \339 ALfloat (*DryBuffer)[MAXCHANNELS]; \340 ALfloat *ClickRemoval, *PendingClicks; \341 ALuint pos, frac; \342 ALfloat DrySend[MAXCHANNELS][MAXCHANNELS]; \343 FILTER *DryFilter; \344 ALuint BufferIdx; \345 ALuint increment; \346 ALuint i, out, c; \347 ALfloat value; \348 \349 increment = Source->Params.Step; \350 \351 DryBuffer = Device->DryBuffer; \352 ClickRemoval = Device->ClickRemoval; \353 PendingClicks = Device->PendingClicks; \354 DryFilter = &Source->Params.iirFilter; \355 for(i = 0;i < NumChannels;i++) \356 { \357 for(c = 0;c < MAXCHANNELS;c++) \358 DrySend[i][c] = Source->Params.DryGains[i][c]; \359 } \360 \361 pos = 0; \362 frac = *DataPosFrac; \363 \364 for(i = 0;i < NumChannels;i++) \365 { \366 pos = 0; \367 frac = *DataPosFrac; \368 \369 if(OutPos == 0) \370 { \371 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \372 \373 value = lpFilter2PC(DryFilter, i, value); \374 for(c = 0;c < MAXCHANNELS;c++) \375 ClickRemoval[c] -= value*DrySend[i][c]; \376 } \377 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \378 { \379 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \380 \381 value = lpFilter2P(DryFilter, i, value); \382 for(c = 0;c < MAXCHANNELS;c++) \383 DryBuffer[OutPos][c] += value*DrySend[i][c]; \384 \385 frac += increment; \386 pos += frac>>FRACTIONBITS; \387 frac &= FRACTIONMASK; \388 OutPos++; \389 } \390 if(OutPos == SamplesToDo) \391 { \392 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \393 \394 value = lpFilter2PC(DryFilter, i, value); \395 for(c = 0;c < MAXCHANNELS;c++) \396 PendingClicks[c] += value*DrySend[i][c]; \397 } \398 OutPos -= BufferSize; \399 } \400 \401 for(out = 0;out < Device->NumAuxSends;out++) \402 { \403 ALeffectslot *Slot = Source->Params.Send[out].Slot; \404 ALfloat WetSend; \405 ALfloat *WetBuffer; \406 ALfloat *WetClickRemoval; \407 ALfloat *WetPendingClicks; \408 FILTER *WetFilter; \409 \410 if(!Slot || Slot->effect.type == AL_EFFECT_NULL) \411 continue; \412 \413 WetBuffer = Slot->WetBuffer; \414 WetClickRemoval = Slot->ClickRemoval; \415 WetPendingClicks = Slot->PendingClicks; \416 WetFilter = &Source->Params.Send[out].iirFilter; \417 WetSend = Source->Params.Send[out].WetGain; \418 \419 for(i = 0;i < NumChannels;i++) \420 { \421 pos = 0; \422 frac = *DataPosFrac; \423 \424 if(OutPos == 0) \425 { \426 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\427 \428 value = lpFilter1PC(WetFilter, i, value); \429 WetClickRemoval[0] -= value * WetSend; \430 } \431 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \432 { \433 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\434 \435 value = lpFilter1P(WetFilter, i, value); \436 WetBuffer[OutPos] += value * WetSend; \437 \438 frac += increment; \439 pos += frac>>FRACTIONBITS; \440 frac &= FRACTIONMASK; \441 OutPos++; \442 } \443 if(OutPos == SamplesToDo) \444 { \445 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\446 \447 value = lpFilter1PC(WetFilter, i, value); \448 WetPendingClicks[0] += value * WetSend; \449 } \450 OutPos -= BufferSize; \451 } \452 } \453 *DataPosInt += pos; \454 *DataPosFrac = frac; \455 }457 DECL_TEMPLATE(ALfloat, point32)458 DECL_TEMPLATE(ALfloat, lerp32)459 DECL_TEMPLATE(ALfloat, cubic32)461 DECL_TEMPLATE(ALshort, point16)462 DECL_TEMPLATE(ALshort, lerp16)463 DECL_TEMPLATE(ALshort, cubic16)465 DECL_TEMPLATE(ALbyte, point8)466 DECL_TEMPLATE(ALbyte, lerp8)467 DECL_TEMPLATE(ALbyte, cubic8)469 #undef DECL_TEMPLATE472 #define DECL_TEMPLATE(sampler) \473 static MixerFunc Select_##sampler(enum FmtType FmtType) \474 { \475 switch(FmtType) \476 { \477 case FmtByte: \478 return Mix_ALbyte_##sampler##8; \479 case FmtShort: \480 return Mix_ALshort_##sampler##16; \481 case FmtFloat: \482 return Mix_ALfloat_##sampler##32; \483 } \484 return NULL; \485 }487 DECL_TEMPLATE(point)488 DECL_TEMPLATE(lerp)489 DECL_TEMPLATE(cubic)491 #undef DECL_TEMPLATE493 MixerFunc SelectMixer(ALbuffer *Buffer, enum Resampler Resampler)494 {495 switch(Resampler)496 {497 case POINT_RESAMPLER:498 return Select_point(Buffer->FmtType);499 case LINEAR_RESAMPLER:500 return Select_lerp(Buffer->FmtType);501 case CUBIC_RESAMPLER:502 return Select_cubic(Buffer->FmtType);503 case RESAMPLER_MIN:504 case RESAMPLER_MAX:505 break;506 }507 return NULL;508 }510 #define DECL_TEMPLATE(sampler) \511 static MixerFunc Select_Hrtf_##sampler(enum FmtType FmtType) \512 { \513 switch(FmtType) \514 { \515 case FmtByte: \516 return Mix_Hrtf_ALbyte_##sampler##8; \517 case FmtShort: \518 return Mix_Hrtf_ALshort_##sampler##16; \519 case FmtFloat: \520 return Mix_Hrtf_ALfloat_##sampler##32; \521 } \522 return NULL; \523 }525 DECL_TEMPLATE(point)526 DECL_TEMPLATE(lerp)527 DECL_TEMPLATE(cubic)529 #undef DECL_TEMPLATE531 MixerFunc SelectHrtfMixer(ALbuffer *Buffer, enum Resampler Resampler)532 {533 switch(Resampler)534 {535 case POINT_RESAMPLER:536 return Select_Hrtf_point(Buffer->FmtType);537 case LINEAR_RESAMPLER:538 return Select_Hrtf_lerp(Buffer->FmtType);539 case CUBIC_RESAMPLER:540 return Select_Hrtf_cubic(Buffer->FmtType);541 case RESAMPLER_MIN:542 case RESAMPLER_MAX:543 break;544 }545 return NULL;546 }549 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)550 {551 ALbufferlistitem *BufferListItem;552 ALuint DataPosInt, DataPosFrac;553 ALuint BuffersPlayed;554 ALboolean Looping;555 ALuint increment;556 enum Resampler Resampler;557 ALenum State;558 ALuint OutPos;559 ALuint FrameSize;560 ALint64 DataSize64;561 ALuint i;563 /* Get source info */564 State = Source->state;565 BuffersPlayed = Source->BuffersPlayed;566 DataPosInt = Source->position;567 DataPosFrac = Source->position_fraction;568 Looping = Source->bLooping;569 increment = Source->Params.Step;570 Resampler = Source->Resampler;571 FrameSize = Source->NumChannels * Source->SampleSize;573 /* Get current buffer queue item */574 BufferListItem = Source->queue;575 for(i = 0;i < BuffersPlayed;i++)576 BufferListItem = BufferListItem->next;578 OutPos = 0;579 do {580 const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];581 const ALuint BufferPadding = ResamplerPadding[Resampler];582 ALubyte StackData[STACK_DATA_SIZE];583 ALubyte *SrcData = StackData;584 ALuint SrcDataSize = 0;585 ALuint BufferSize;587 /* Figure out how many buffer bytes will be needed */588 DataSize64 = SamplesToDo-OutPos+1;589 DataSize64 *= increment;590 DataSize64 += DataPosFrac+FRACTIONMASK;591 DataSize64 >>= FRACTIONBITS;592 DataSize64 += BufferPadding+BufferPrePadding;593 DataSize64 *= FrameSize;595 BufferSize = ((DataSize64 > STACK_DATA_SIZE) ? STACK_DATA_SIZE : DataSize64);596 BufferSize -= BufferSize%FrameSize;598 if(Source->lSourceType == AL_STATIC)599 {600 const ALbuffer *ALBuffer = Source->Buffer;601 const ALubyte *Data = ALBuffer->data;602 ALuint DataSize;603 ALuint pos;605 /* If current pos is beyond the loop range, do not loop */606 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)607 {608 Looping = AL_FALSE;610 if(DataPosInt >= BufferPrePadding)611 pos = (DataPosInt-BufferPrePadding)*FrameSize;612 else613 {614 DataSize = (BufferPrePadding-DataPosInt)*FrameSize;615 DataSize = minu(BufferSize, DataSize);617 memset(&SrcData[SrcDataSize], 0, DataSize);618 SrcDataSize += DataSize;619 BufferSize -= DataSize;621 pos = 0;622 }624 /* Copy what's left to play in the source buffer, and clear the625 * rest of the temp buffer */626 DataSize = ALBuffer->size - pos;627 DataSize = minu(BufferSize, DataSize);629 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);630 SrcDataSize += DataSize;631 BufferSize -= DataSize;633 memset(&SrcData[SrcDataSize], 0, BufferSize);634 SrcDataSize += BufferSize;635 BufferSize -= BufferSize;636 }637 else638 {639 ALuint LoopStart = ALBuffer->LoopStart;640 ALuint LoopEnd = ALBuffer->LoopEnd;642 if(DataPosInt >= LoopStart)643 {644 pos = DataPosInt-LoopStart;645 while(pos < BufferPrePadding)646 pos += LoopEnd-LoopStart;647 pos -= BufferPrePadding;648 pos += LoopStart;649 pos *= FrameSize;650 }651 else if(DataPosInt >= BufferPrePadding)652 pos = (DataPosInt-BufferPrePadding)*FrameSize;653 else654 {655 DataSize = (BufferPrePadding-DataPosInt)*FrameSize;656 DataSize = minu(BufferSize, DataSize);658 memset(&SrcData[SrcDataSize], 0, DataSize);659 SrcDataSize += DataSize;660 BufferSize -= DataSize;662 pos = 0;663 }665 /* Copy what's left of this loop iteration, then copy repeats666 * of the loop section */667 DataSize = LoopEnd*FrameSize - pos;668 DataSize = minu(BufferSize, DataSize);670 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);671 SrcDataSize += DataSize;672 BufferSize -= DataSize;674 DataSize = (LoopEnd-LoopStart) * FrameSize;675 while(BufferSize > 0)676 {677 DataSize = minu(BufferSize, DataSize);679 memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize);680 SrcDataSize += DataSize;681 BufferSize -= DataSize;682 }683 }684 }685 else686 {687 /* Crawl the buffer queue to fill in the temp buffer */688 ALbufferlistitem *BufferListIter = BufferListItem;689 ALuint pos;691 if(DataPosInt >= BufferPrePadding)692 pos = (DataPosInt-BufferPrePadding)*FrameSize;693 else694 {695 pos = (BufferPrePadding-DataPosInt)*FrameSize;696 while(pos > 0)697 {698 if(!BufferListIter->prev && !Looping)699 {700 ALuint DataSize = minu(BufferSize, pos);702 memset(&SrcData[SrcDataSize], 0, DataSize);703 SrcDataSize += DataSize;704 BufferSize -= DataSize;706 pos = 0;707 break;708 }710 if(BufferListIter->prev)711 BufferListIter = BufferListIter->prev;712 else713 {714 while(BufferListIter->next)715 BufferListIter = BufferListIter->next;716 }718 if(BufferListIter->buffer)719 {720 if((ALuint)BufferListIter->buffer->size > pos)721 {722 pos = BufferListIter->buffer->size - pos;723 break;724 }725 pos -= BufferListIter->buffer->size;726 }727 }728 }730 while(BufferListIter && BufferSize > 0)731 {732 const ALbuffer *ALBuffer;733 if((ALBuffer=BufferListIter->buffer) != NULL)734 {735 const ALubyte *Data = ALBuffer->data;736 ALuint DataSize = ALBuffer->size;738 /* Skip the data already played */739 if(DataSize <= pos)740 pos -= DataSize;741 else742 {743 Data += pos;744 DataSize -= pos;745 pos -= pos;747 DataSize = minu(BufferSize, DataSize);748 memcpy(&SrcData[SrcDataSize], Data, DataSize);749 SrcDataSize += DataSize;750 BufferSize -= DataSize;751 }752 }753 BufferListIter = BufferListIter->next;754 if(!BufferListIter && Looping)755 BufferListIter = Source->queue;756 else if(!BufferListIter)757 {758 memset(&SrcData[SrcDataSize], 0, BufferSize);759 SrcDataSize += BufferSize;760 BufferSize -= BufferSize;761 }762 }763 }765 /* Figure out how many samples we can mix. */766 DataSize64 = SrcDataSize / FrameSize;767 DataSize64 -= BufferPadding+BufferPrePadding;768 DataSize64 <<= FRACTIONBITS;769 DataSize64 -= increment;770 DataSize64 -= DataPosFrac;772 BufferSize = (ALuint)((DataSize64+(increment-1)) / increment);773 BufferSize = minu(BufferSize, (SamplesToDo-OutPos));775 SrcData += BufferPrePadding*FrameSize;776 Source->Params.DoMix(Source, Device, SrcData, &DataPosInt, &DataPosFrac,777 OutPos, SamplesToDo, BufferSize);778 OutPos += BufferSize;780 /* Handle looping sources */781 while(1)782 {783 const ALbuffer *ALBuffer;784 ALuint DataSize = 0;785 ALuint LoopStart = 0;786 ALuint LoopEnd = 0;788 if((ALBuffer=BufferListItem->buffer) != NULL)789 {790 DataSize = ALBuffer->size / FrameSize;791 LoopStart = ALBuffer->LoopStart;792 LoopEnd = ALBuffer->LoopEnd;793 if(LoopEnd > DataPosInt)794 break;795 }797 if(Looping && Source->lSourceType == AL_STATIC)798 {799 BufferListItem = Source->queue;800 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;801 break;802 }804 if(DataSize > DataPosInt)805 break;807 if(BufferListItem->next)808 {809 BufferListItem = BufferListItem->next;810 BuffersPlayed++;811 }812 else if(Looping)813 {814 BufferListItem = Source->queue;815 BuffersPlayed = 0;816 }817 else818 {819 State = AL_STOPPED;820 BufferListItem = Source->queue;821 BuffersPlayed = Source->BuffersInQueue;822 DataPosInt = 0;823 DataPosFrac = 0;824 break;825 }827 DataPosInt -= DataSize;828 }829 } while(State == AL_PLAYING && OutPos < SamplesToDo);831 /* Update source info */832 Source->state = State;833 Source->BuffersPlayed = BuffersPlayed;834 Source->position = DataPosInt;835 Source->position_fraction = DataPosFrac;836 Source->Buffer = BufferListItem->buffer;837 Source->HrtfOffset += OutPos;838 if(State == AL_PLAYING)839 {840 Source->HrtfCounter = maxu(Source->HrtfCounter, OutPos) - OutPos;841 Source->HrtfMoving = AL_TRUE;842 }843 else844 {845 Source->HrtfCounter = 0;846 Source->HrtfMoving = AL_FALSE;847 }848 }