~ubuntu-branches/ubuntu/saucy/openal-soft/saucy

« back to all changes in this revision

Viewing changes to Alc/mixer.c

  • Committer: Bazaar Package Importer
  • Author(s): Andres Mejia
  • Date: 2011-04-22 18:30:58 UTC
  • mfrom: (7.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110422183058-pgxqd8022xk3vwao
Tags: 1:1.13-2
Don't build with ALSA compatibility on non-Linux architectures.

Show diffs side-by-side

added added

removed removed

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