annotate Alc/mixer.c @ 29:cdf320cb5949

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