Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/faudio/src/FAudio_internal.c
4389 views
1
/* FAudio - XAudio Reimplementation for FNA
2
*
3
* Copyright (c) 2011-2024 Ethan Lee, Luigi Auriemma, and the MonoGame Team
4
*
5
* This software is provided 'as-is', without any express or implied warranty.
6
* In no event will the authors be held liable for any damages arising from
7
* the use of this software.
8
*
9
* Permission is granted to anyone to use this software for any purpose,
10
* including commercial applications, and to alter it and redistribute it
11
* freely, subject to the following restrictions:
12
*
13
* 1. The origin of this software must not be misrepresented; you must not
14
* claim that you wrote the original software. If you use this software in a
15
* product, an acknowledgment in the product documentation would be
16
* appreciated but is not required.
17
*
18
* 2. Altered source versions must be plainly marked as such, and must not be
19
* misrepresented as being the original software.
20
*
21
* 3. This notice may not be removed or altered from any source distribution.
22
*
23
* Ethan "flibitijibibo" Lee <[email protected]>
24
*
25
*/
26
27
#include "FAudio_internal.h"
28
29
#ifndef FAUDIO_DISABLE_DEBUGCONFIGURATION
30
void FAudio_INTERNAL_debug(
31
FAudio *audio,
32
const char *file,
33
uint32_t line,
34
const char *func,
35
const char *fmt,
36
...
37
) {
38
char output[1024];
39
char *out = output;
40
va_list va;
41
out[0] = '\0';
42
43
/* Logging extras */
44
if (audio->debug.LogThreadID)
45
{
46
out += FAudio_snprintf(
47
out,
48
sizeof(output) - (out - output),
49
"0x%" FAudio_PRIx64 " ",
50
FAudio_PlatformGetThreadID()
51
);
52
}
53
if (audio->debug.LogFileline)
54
{
55
out += FAudio_snprintf(
56
out,
57
sizeof(output) - (out - output),
58
"%s:%u ",
59
file,
60
line
61
);
62
}
63
if (audio->debug.LogFunctionName)
64
{
65
out += FAudio_snprintf(
66
out,
67
sizeof(output) - (out - output),
68
"%s ",
69
func
70
);
71
}
72
if (audio->debug.LogTiming)
73
{
74
out += FAudio_snprintf(
75
out,
76
sizeof(output) - (out - output),
77
"%dms ",
78
FAudio_timems()
79
);
80
}
81
82
/* The actual message... */
83
va_start(va, fmt);
84
FAudio_vsnprintf(
85
out,
86
sizeof(output) - (out - output),
87
fmt,
88
va
89
);
90
va_end(va);
91
92
/* Print, finally. */
93
FAudio_Log(output);
94
}
95
96
static const char *get_wformattag_string(const FAudioWaveFormatEx *fmt)
97
{
98
#define FMT_STRING(suffix) \
99
if (fmt->wFormatTag == FAUDIO_FORMAT_##suffix) \
100
{ \
101
return #suffix; \
102
}
103
FMT_STRING(PCM)
104
FMT_STRING(MSADPCM)
105
FMT_STRING(IEEE_FLOAT)
106
FMT_STRING(XMAUDIO2)
107
FMT_STRING(WMAUDIO2)
108
FMT_STRING(WMAUDIO3)
109
FMT_STRING(EXTENSIBLE)
110
#undef FMT_STRING
111
return "UNKNOWN!";
112
}
113
114
static const char *get_subformat_string(const FAudioWaveFormatEx *fmt)
115
{
116
const FAudioWaveFormatExtensible *fmtex = (const FAudioWaveFormatExtensible*) fmt;
117
118
if (fmt->wFormatTag != FAUDIO_FORMAT_EXTENSIBLE)
119
{
120
return "N/A";
121
}
122
if (!FAudio_memcmp(&fmtex->SubFormat, &DATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(FAudioGUID)))
123
{
124
return "IEEE_FLOAT";
125
}
126
if (!FAudio_memcmp(&fmtex->SubFormat, &DATAFORMAT_SUBTYPE_PCM, sizeof(FAudioGUID)))
127
{
128
return "PCM";
129
}
130
return "UNKNOWN!";
131
}
132
133
void FAudio_INTERNAL_debug_fmt(
134
FAudio *audio,
135
const char *file,
136
uint32_t line,
137
const char *func,
138
const FAudioWaveFormatEx *fmt
139
) {
140
FAudio_INTERNAL_debug(
141
audio,
142
file,
143
line,
144
func,
145
(
146
"{"
147
"wFormatTag: 0x%x %s, "
148
"nChannels: %u, "
149
"nSamplesPerSec: %u, "
150
"wBitsPerSample: %u, "
151
"nBlockAlign: %u, "
152
"SubFormat: %s"
153
"}"
154
),
155
fmt->wFormatTag,
156
get_wformattag_string(fmt),
157
fmt->nChannels,
158
fmt->nSamplesPerSec,
159
fmt->wBitsPerSample,
160
fmt->nBlockAlign,
161
get_subformat_string(fmt)
162
);
163
}
164
#endif /* FAUDIO_DISABLE_DEBUGCONFIGURATION */
165
166
void LinkedList_AddEntry(
167
LinkedList **start,
168
void* toAdd,
169
FAudioMutex lock,
170
FAudioMallocFunc pMalloc
171
) {
172
LinkedList *newEntry, *latest;
173
newEntry = (LinkedList*) pMalloc(sizeof(LinkedList));
174
newEntry->entry = toAdd;
175
newEntry->next = NULL;
176
FAudio_PlatformLockMutex(lock);
177
if (*start == NULL)
178
{
179
*start = newEntry;
180
}
181
else
182
{
183
latest = *start;
184
while (latest->next != NULL)
185
{
186
latest = latest->next;
187
}
188
latest->next = newEntry;
189
}
190
FAudio_PlatformUnlockMutex(lock);
191
}
192
193
void LinkedList_PrependEntry(
194
LinkedList **start,
195
void* toAdd,
196
FAudioMutex lock,
197
FAudioMallocFunc pMalloc
198
) {
199
LinkedList *newEntry;
200
newEntry = (LinkedList*) pMalloc(sizeof(LinkedList));
201
newEntry->entry = toAdd;
202
FAudio_PlatformLockMutex(lock);
203
newEntry->next = *start;
204
*start = newEntry;
205
FAudio_PlatformUnlockMutex(lock);
206
}
207
208
void LinkedList_RemoveEntry(
209
LinkedList **start,
210
void* toRemove,
211
FAudioMutex lock,
212
FAudioFreeFunc pFree
213
) {
214
LinkedList *latest, *prev;
215
FAudio_PlatformLockMutex(lock);
216
latest = *start;
217
prev = latest;
218
while (latest != NULL)
219
{
220
if (latest->entry == toRemove)
221
{
222
if (latest == prev) /* First in list */
223
{
224
*start = latest->next;
225
}
226
else
227
{
228
prev->next = latest->next;
229
}
230
pFree(latest);
231
FAudio_PlatformUnlockMutex(lock);
232
return;
233
}
234
prev = latest;
235
latest = latest->next;
236
}
237
FAudio_PlatformUnlockMutex(lock);
238
FAudio_assert(0 && "LinkedList element not found!");
239
}
240
241
void FAudio_INTERNAL_InsertSubmixSorted(
242
LinkedList **start,
243
FAudioSubmixVoice *toAdd,
244
FAudioMutex lock,
245
FAudioMallocFunc pMalloc
246
) {
247
LinkedList *newEntry, *latest;
248
newEntry = (LinkedList*) pMalloc(sizeof(LinkedList));
249
newEntry->entry = toAdd;
250
newEntry->next = NULL;
251
FAudio_PlatformLockMutex(lock);
252
if (*start == NULL)
253
{
254
*start = newEntry;
255
}
256
else
257
{
258
latest = *start;
259
260
/* Special case if the new stage is lower than everyone else */
261
if (toAdd->mix.processingStage < ((FAudioSubmixVoice*) latest->entry)->mix.processingStage)
262
{
263
newEntry->next = latest;
264
*start = newEntry;
265
}
266
else
267
{
268
/* If we got here, we know that the new stage is
269
* _at least_ as high as the first submix in the list.
270
*
271
* Each loop iteration checks to see if the new stage
272
* is smaller than `latest->next`, meaning it fits
273
* between `latest` and `latest->next`.
274
*/
275
while (latest->next != NULL)
276
{
277
if (toAdd->mix.processingStage < ((FAudioSubmixVoice *) latest->next->entry)->mix.processingStage)
278
{
279
newEntry->next = latest->next;
280
latest->next = newEntry;
281
break;
282
}
283
latest = latest->next;
284
}
285
/* If newEntry didn't get a `next` value, that means
286
* it didn't fall in between any stages and `latest`
287
* is the last entry in the list. Add it to the end!
288
*/
289
if (newEntry->next == NULL)
290
{
291
latest->next = newEntry;
292
}
293
}
294
}
295
FAudio_PlatformUnlockMutex(lock);
296
}
297
298
static uint32_t FAudio_INTERNAL_GetBytesRequested(
299
FAudioSourceVoice *voice,
300
uint32_t decoding
301
) {
302
uint32_t end, result;
303
FAudioBuffer *buffer;
304
FAudioWaveFormatExtensible *fmt;
305
FAudioBufferEntry *list = voice->src.bufferList;
306
307
LOG_FUNC_ENTER(voice->audio)
308
309
#ifdef HAVE_WMADEC
310
if (voice->src.wmadec != NULL)
311
{
312
/* Always 0, per the spec */
313
LOG_FUNC_EXIT(voice->audio)
314
return 0;
315
}
316
#endif /* HAVE_WMADEC */
317
while (list != NULL && decoding > 0)
318
{
319
buffer = &list->buffer;
320
if (buffer->LoopCount > 0)
321
{
322
end = (
323
/* Current loop... */
324
((buffer->LoopBegin + buffer->LoopLength) - voice->src.curBufferOffset) +
325
/* Remaining loops... */
326
(buffer->LoopLength * buffer->LoopCount - 1) +
327
/* ... Final iteration */
328
buffer->PlayLength
329
);
330
}
331
else
332
{
333
end = (buffer->PlayBegin + buffer->PlayLength) - voice->src.curBufferOffset;
334
}
335
if (end > decoding)
336
{
337
decoding = 0;
338
break;
339
}
340
decoding -= end;
341
list = list->next;
342
}
343
344
/* Convert samples to bytes, factoring block alignment */
345
if (voice->src.format->wFormatTag == FAUDIO_FORMAT_MSADPCM)
346
{
347
fmt = (FAudioWaveFormatExtensible*) voice->src.format;
348
result = (
349
(decoding / fmt->Samples.wSamplesPerBlock) +
350
((decoding % fmt->Samples.wSamplesPerBlock) > 0)
351
) * voice->src.format->nBlockAlign;
352
}
353
else
354
{
355
result = decoding * voice->src.format->nBlockAlign;
356
}
357
358
LOG_FUNC_EXIT(voice->audio)
359
return result;
360
}
361
362
static void FAudio_INTERNAL_DecodeBuffers(
363
FAudioSourceVoice *voice,
364
uint64_t *toDecode
365
) {
366
uint32_t end, endRead, decoding, decoded = 0;
367
FAudioBuffer *buffer = &voice->src.bufferList->buffer;
368
FAudioBufferEntry *toDelete;
369
370
LOG_FUNC_ENTER(voice->audio)
371
372
/* This should never go past the max ratio size */
373
FAudio_assert(*toDecode <= voice->src.decodeSamples);
374
375
while (decoded < *toDecode && buffer != NULL)
376
{
377
decoding = (uint32_t) *toDecode - decoded;
378
379
/* Start-of-buffer behavior */
380
if (voice->src.newBuffer)
381
{
382
voice->src.newBuffer = 0;
383
if ( voice->src.callback != NULL &&
384
voice->src.callback->OnBufferStart != NULL )
385
{
386
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
387
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
388
389
FAudio_PlatformUnlockMutex(voice->sendLock);
390
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
391
392
FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
393
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
394
395
voice->src.callback->OnBufferStart(
396
voice->src.callback,
397
buffer->pContext
398
);
399
400
FAudio_PlatformLockMutex(voice->audio->sourceLock);
401
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
402
403
FAudio_PlatformLockMutex(voice->sendLock);
404
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
405
406
FAudio_PlatformLockMutex(voice->src.bufferLock);
407
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
408
}
409
}
410
411
/* Check for end-of-buffer */
412
end = (buffer->LoopCount > 0) ?
413
(buffer->LoopBegin + buffer->LoopLength) :
414
buffer->PlayBegin + buffer->PlayLength;
415
endRead = FAudio_min(
416
end - voice->src.curBufferOffset,
417
decoding
418
);
419
420
/* Decode... */
421
voice->src.decode(
422
voice,
423
buffer,
424
voice->audio->decodeCache + (
425
decoded * voice->src.format->nChannels
426
),
427
endRead
428
);
429
430
LOG_INFO(
431
voice->audio,
432
"Voice %p, buffer %p, decoded %u samples from [%u,%u)",
433
(void*) voice,
434
(void*) buffer,
435
endRead,
436
voice->src.curBufferOffset,
437
voice->src.curBufferOffset + endRead
438
)
439
440
decoded += endRead;
441
voice->src.curBufferOffset += endRead;
442
voice->src.totalSamples += endRead;
443
444
/* End-of-buffer behavior */
445
if (endRead < decoding)
446
{
447
if (buffer->LoopCount > 0)
448
{
449
voice->src.curBufferOffset = buffer->LoopBegin;
450
if (buffer->LoopCount < FAUDIO_LOOP_INFINITE)
451
{
452
buffer->LoopCount -= 1;
453
}
454
if ( voice->src.callback != NULL &&
455
voice->src.callback->OnLoopEnd != NULL )
456
{
457
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
458
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
459
460
FAudio_PlatformUnlockMutex(voice->sendLock);
461
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
462
463
FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
464
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
465
466
voice->src.callback->OnLoopEnd(
467
voice->src.callback,
468
buffer->pContext
469
);
470
471
FAudio_PlatformLockMutex(voice->audio->sourceLock);
472
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
473
474
FAudio_PlatformLockMutex(voice->sendLock);
475
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
476
477
FAudio_PlatformLockMutex(voice->src.bufferLock);
478
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
479
}
480
}
481
else
482
{
483
#ifdef HAVE_WMADEC
484
if (voice->src.wmadec != NULL)
485
{
486
FAudio_WMADEC_end_buffer(voice);
487
}
488
#endif /* HAVE_WMADEC */
489
/* For EOS we can stop storing fraction offsets */
490
if (buffer->Flags & FAUDIO_END_OF_STREAM)
491
{
492
voice->src.curBufferOffsetDec = 0;
493
voice->src.totalSamples = 0;
494
}
495
496
LOG_INFO(
497
voice->audio,
498
"Voice %p, finished with buffer %p",
499
(void*) voice,
500
(void*) buffer
501
)
502
503
/* Change active buffer, delete finished buffer */
504
toDelete = voice->src.bufferList;
505
voice->src.bufferList = voice->src.bufferList->next;
506
if (voice->src.bufferList != NULL)
507
{
508
buffer = &voice->src.bufferList->buffer;
509
voice->src.curBufferOffset = buffer->PlayBegin;
510
}
511
else
512
{
513
buffer = NULL;
514
515
/* FIXME: I keep going past the buffer so fuck it */
516
FAudio_zero(
517
voice->audio->decodeCache + (
518
decoded *
519
voice->src.format->nChannels
520
),
521
sizeof(float) * (
522
(*toDecode - decoded) *
523
voice->src.format->nChannels
524
)
525
);
526
}
527
528
/* Callbacks */
529
if (voice->src.callback != NULL)
530
{
531
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
532
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
533
534
FAudio_PlatformUnlockMutex(voice->sendLock);
535
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
536
537
FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
538
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
539
540
if (voice->src.callback->OnBufferEnd != NULL)
541
{
542
voice->src.callback->OnBufferEnd(
543
voice->src.callback,
544
toDelete->buffer.pContext
545
);
546
}
547
if ( toDelete->buffer.Flags & FAUDIO_END_OF_STREAM &&
548
voice->src.callback->OnStreamEnd != NULL )
549
{
550
voice->src.callback->OnStreamEnd(
551
voice->src.callback
552
);
553
}
554
555
FAudio_PlatformLockMutex(voice->audio->sourceLock);
556
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
557
558
FAudio_PlatformLockMutex(voice->sendLock);
559
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
560
561
FAudio_PlatformLockMutex(voice->src.bufferLock);
562
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
563
564
/* One last chance at redemption */
565
if (buffer == NULL && voice->src.bufferList != NULL)
566
{
567
buffer = &voice->src.bufferList->buffer;
568
voice->src.curBufferOffset = buffer->PlayBegin;
569
}
570
571
if (buffer != NULL && voice->src.callback->OnBufferStart != NULL)
572
{
573
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
574
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
575
576
FAudio_PlatformUnlockMutex(voice->sendLock);
577
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
578
579
FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
580
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
581
582
voice->src.callback->OnBufferStart(
583
voice->src.callback,
584
buffer->pContext
585
);
586
587
FAudio_PlatformLockMutex(voice->audio->sourceLock);
588
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
589
590
FAudio_PlatformLockMutex(voice->sendLock);
591
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
592
593
FAudio_PlatformLockMutex(voice->src.bufferLock);
594
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
595
}
596
}
597
598
voice->audio->pFree(toDelete);
599
}
600
}
601
}
602
603
/* ... FIXME: I keep going past the buffer so fuck it */
604
if (buffer)
605
{
606
end = (buffer->LoopCount > 0) ?
607
(buffer->LoopBegin + buffer->LoopLength) :
608
buffer->PlayBegin + buffer->PlayLength;
609
endRead = FAudio_min(
610
end - voice->src.curBufferOffset,
611
EXTRA_DECODE_PADDING
612
);
613
614
voice->src.decode(
615
voice,
616
buffer,
617
voice->audio->decodeCache + (
618
decoded * voice->src.format->nChannels
619
),
620
endRead
621
);
622
/* Do NOT increment curBufferOffset! */
623
624
if (endRead < EXTRA_DECODE_PADDING)
625
{
626
FAudio_zero(
627
voice->audio->decodeCache + (
628
decoded * voice->src.format->nChannels
629
),
630
sizeof(float) * (
631
(EXTRA_DECODE_PADDING - endRead) *
632
voice->src.format->nChannels
633
)
634
);
635
}
636
}
637
else
638
{
639
FAudio_zero(
640
voice->audio->decodeCache + (
641
decoded * voice->src.format->nChannels
642
),
643
sizeof(float) * (
644
EXTRA_DECODE_PADDING *
645
voice->src.format->nChannels
646
)
647
);
648
}
649
650
*toDecode = decoded;
651
LOG_FUNC_EXIT(voice->audio)
652
}
653
654
static inline void FAudio_INTERNAL_FilterVoice(
655
FAudio *audio,
656
const FAudioFilterParametersEXT *filter,
657
FAudioFilterState *filterState,
658
float *samples,
659
uint32_t numSamples,
660
uint16_t numChannels
661
) {
662
uint32_t j, ci;
663
664
LOG_FUNC_ENTER(audio)
665
666
/* Apply a digital state-variable filter to the voice.
667
* The difference equations of the filter are:
668
*
669
* Yl(n) = F Yb(n - 1) + Yl(n - 1)
670
* Yh(n) = x(n) - Yl(n) - OneOverQ Yb(n - 1)
671
* Yb(n) = F Yh(n) + Yb(n - 1)
672
* Yn(n) = Yl(n) + Yh(n)
673
*
674
* Please note that FAudioFilterParameters.Frequency is defined as:
675
*
676
* (2 * sin(pi * (desired filter cutoff frequency) / sampleRate))
677
*
678
* - @JohanSmet
679
*/
680
681
for (j = 0; j < numSamples; j += 1)
682
for (ci = 0; ci < numChannels; ci += 1)
683
{
684
filterState[ci][FAudioLowPassFilter] = filterState[ci][FAudioLowPassFilter] + (filter->Frequency * filterState[ci][FAudioBandPassFilter]);
685
filterState[ci][FAudioHighPassFilter] = samples[j * numChannels + ci] - filterState[ci][FAudioLowPassFilter] - (filter->OneOverQ * filterState[ci][FAudioBandPassFilter]);
686
filterState[ci][FAudioBandPassFilter] = (filter->Frequency * filterState[ci][FAudioHighPassFilter]) + filterState[ci][FAudioBandPassFilter];
687
filterState[ci][FAudioNotchFilter] = filterState[ci][FAudioHighPassFilter] + filterState[ci][FAudioLowPassFilter];
688
samples[j * numChannels + ci] = filterState[ci][filter->Type] * filter->WetDryMix + samples[j * numChannels + ci] * (1.0f - filter->WetDryMix);
689
}
690
691
LOG_FUNC_EXIT(audio)
692
}
693
694
static void FAudio_INTERNAL_ResizeEffectChainCache(FAudio *audio, uint32_t samples)
695
{
696
LOG_FUNC_ENTER(audio)
697
if (samples > audio->effectChainSamples)
698
{
699
audio->effectChainSamples = samples;
700
audio->effectChainCache = (float*) audio->pRealloc(
701
audio->effectChainCache,
702
sizeof(float) * audio->effectChainSamples
703
);
704
}
705
LOG_FUNC_EXIT(audio)
706
}
707
708
static inline float *FAudio_INTERNAL_ProcessEffectChain(
709
FAudioVoice *voice,
710
float *buffer,
711
uint32_t *samples
712
) {
713
uint32_t i;
714
FAPO *fapo;
715
FAPOProcessBufferParameters srcParams, dstParams;
716
717
LOG_FUNC_ENTER(voice->audio)
718
719
/* Set up the buffer to be written into */
720
srcParams.pBuffer = buffer;
721
srcParams.BufferFlags = FAPO_BUFFER_SILENT;
722
srcParams.ValidFrameCount = *samples;
723
for (i = 0; i < srcParams.ValidFrameCount; i += 1)
724
{
725
if (buffer[i] != 0.0f) /* Arbitrary! */
726
{
727
srcParams.BufferFlags = FAPO_BUFFER_VALID;
728
break;
729
}
730
}
731
732
/* Initialize output parameters to something sane */
733
dstParams.pBuffer = srcParams.pBuffer;
734
dstParams.BufferFlags = FAPO_BUFFER_VALID;
735
dstParams.ValidFrameCount = srcParams.ValidFrameCount;
736
737
/* Update parameters, process! */
738
for (i = 0; i < voice->effects.count; i += 1)
739
{
740
fapo = voice->effects.desc[i].pEffect;
741
742
if (!voice->effects.inPlaceProcessing[i])
743
{
744
if (dstParams.pBuffer == buffer)
745
{
746
FAudio_INTERNAL_ResizeEffectChainCache(
747
voice->audio,
748
voice->effects.desc[i].OutputChannels * srcParams.ValidFrameCount
749
);
750
dstParams.pBuffer = voice->audio->effectChainCache;
751
}
752
else
753
{
754
/* FIXME: What if this is smaller because
755
* inputChannels < desc[i].OutputChannels?
756
*/
757
dstParams.pBuffer = buffer;
758
}
759
760
FAudio_zero(
761
dstParams.pBuffer,
762
voice->effects.desc[i].OutputChannels * srcParams.ValidFrameCount * sizeof(float)
763
);
764
}
765
766
if (voice->effects.parameterUpdates[i])
767
{
768
fapo->SetParameters(
769
fapo,
770
voice->effects.parameters[i],
771
voice->effects.parameterSizes[i]
772
);
773
voice->effects.parameterUpdates[i] = 0;
774
}
775
776
fapo->Process(
777
fapo,
778
1,
779
&srcParams,
780
1,
781
&dstParams,
782
voice->effects.desc[i].InitialState
783
);
784
785
FAudio_memcpy(&srcParams, &dstParams, sizeof(dstParams));
786
}
787
788
*samples = dstParams.ValidFrameCount;
789
790
/* Save the output buffer-flags so the mixer-function can determine when it's save to stop processing the effect chain */
791
voice->effects.state = dstParams.BufferFlags;
792
793
LOG_FUNC_EXIT(voice->audio)
794
return (float*) dstParams.pBuffer;
795
}
796
797
static void FAudio_INTERNAL_ResizeResampleCache(FAudio *audio, uint32_t samples)
798
{
799
LOG_FUNC_ENTER(audio)
800
if (samples > audio->resampleSamples)
801
{
802
audio->resampleSamples = samples;
803
audio->resampleCache = (float*) audio->pRealloc(
804
audio->resampleCache,
805
sizeof(float) * audio->resampleSamples
806
);
807
}
808
LOG_FUNC_EXIT(audio)
809
}
810
811
static void FAudio_INTERNAL_MixSource(FAudioSourceVoice *voice)
812
{
813
/* Iterators */
814
uint32_t i;
815
/* Decode/Resample variables */
816
uint64_t toDecode;
817
uint64_t toResample;
818
/* Output mix variables */
819
float *stream;
820
uint32_t mixed;
821
uint32_t oChan;
822
FAudioVoice *out;
823
uint32_t outputRate;
824
double stepd;
825
float *finalSamples;
826
827
LOG_FUNC_ENTER(voice->audio)
828
829
FAudio_PlatformLockMutex(voice->sendLock);
830
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
831
832
/* Calculate the resample stepping value */
833
if (voice->src.resampleFreq != voice->src.freqRatio * voice->src.format->nSamplesPerSec)
834
{
835
out = (voice->sends.SendCount == 0) ?
836
voice->audio->master : /* Barf */
837
voice->sends.pSends->pOutputVoice;
838
outputRate = (out->type == FAUDIO_VOICE_MASTER) ?
839
out->master.inputSampleRate :
840
out->mix.inputSampleRate;
841
stepd = (
842
voice->src.freqRatio *
843
(double) voice->src.format->nSamplesPerSec /
844
(double) outputRate
845
);
846
voice->src.resampleStep = DOUBLE_TO_FIXED(stepd);
847
voice->src.resampleFreq = voice->src.freqRatio * voice->src.format->nSamplesPerSec;
848
}
849
850
if (voice->src.active == 2)
851
{
852
/* We're just playing tails, skip all buffer stuff */
853
FAudio_INTERNAL_ResizeResampleCache(
854
voice->audio,
855
voice->src.resampleSamples * voice->src.format->nChannels
856
);
857
mixed = voice->src.resampleSamples;
858
FAudio_zero(
859
voice->audio->resampleCache,
860
mixed * voice->src.format->nChannels * sizeof(float)
861
);
862
finalSamples = voice->audio->resampleCache;
863
goto sendwork;
864
}
865
866
/* Base decode size, int to fixed... */
867
toDecode = voice->src.resampleSamples * voice->src.resampleStep;
868
/* ... rounded up based on current offset... */
869
toDecode += voice->src.curBufferOffsetDec + FIXED_FRACTION_MASK;
870
/* ... fixed to int, truncating extra fraction from rounding. */
871
toDecode >>= FIXED_PRECISION;
872
873
/* First voice callback */
874
if ( voice->src.callback != NULL &&
875
voice->src.callback->OnVoiceProcessingPassStart != NULL )
876
{
877
FAudio_PlatformUnlockMutex(voice->sendLock);
878
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
879
880
FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
881
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
882
883
voice->src.callback->OnVoiceProcessingPassStart(
884
voice->src.callback,
885
FAudio_INTERNAL_GetBytesRequested(voice, (uint32_t) toDecode)
886
);
887
888
FAudio_PlatformLockMutex(voice->audio->sourceLock);
889
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
890
891
FAudio_PlatformLockMutex(voice->sendLock);
892
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
893
}
894
895
FAudio_PlatformLockMutex(voice->src.bufferLock);
896
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
897
898
/* Nothing to do? */
899
if (voice->src.bufferList == NULL)
900
{
901
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
902
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
903
904
if (voice->effects.count > 0 && voice->effects.state != FAPO_BUFFER_SILENT)
905
{
906
/* do not stop while the effect chain generates a non-silent buffer */
907
FAudio_INTERNAL_ResizeResampleCache(
908
voice->audio,
909
voice->src.resampleSamples * voice->src.format->nChannels
910
);
911
mixed = voice->src.resampleSamples;
912
FAudio_zero(
913
voice->audio->resampleCache,
914
mixed * voice->src.format->nChannels * sizeof(float)
915
);
916
finalSamples = voice->audio->resampleCache;
917
goto sendwork;
918
}
919
920
FAudio_PlatformUnlockMutex(voice->sendLock);
921
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
922
923
FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
924
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
925
926
if ( voice->src.callback != NULL &&
927
voice->src.callback->OnVoiceProcessingPassEnd != NULL)
928
{
929
voice->src.callback->OnVoiceProcessingPassEnd(
930
voice->src.callback
931
);
932
}
933
934
FAudio_PlatformLockMutex(voice->audio->sourceLock);
935
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
936
937
LOG_FUNC_EXIT(voice->audio)
938
return;
939
}
940
941
/* Decode... */
942
FAudio_INTERNAL_DecodeBuffers(voice, &toDecode);
943
944
/* Subtract any padding samples from the total, if applicable */
945
if ( voice->src.curBufferOffsetDec > 0 &&
946
voice->src.totalSamples > 0 )
947
{
948
voice->src.totalSamples -= 1;
949
}
950
951
/* Okay, we're done messing with client data */
952
if ( voice->src.callback != NULL &&
953
voice->src.callback->OnVoiceProcessingPassEnd != NULL)
954
{
955
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
956
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
957
958
FAudio_PlatformUnlockMutex(voice->sendLock);
959
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
960
961
FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
962
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
963
964
voice->src.callback->OnVoiceProcessingPassEnd(
965
voice->src.callback
966
);
967
968
FAudio_PlatformLockMutex(voice->audio->sourceLock);
969
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
970
971
FAudio_PlatformLockMutex(voice->sendLock);
972
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
973
974
FAudio_PlatformLockMutex(voice->src.bufferLock);
975
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
976
}
977
978
/* Nothing to resample? */
979
if (toDecode == 0)
980
{
981
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
982
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
983
984
FAudio_PlatformUnlockMutex(voice->sendLock);
985
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
986
987
LOG_FUNC_EXIT(voice->audio)
988
return;
989
}
990
991
/* int to fixed... */
992
toResample = toDecode << FIXED_PRECISION;
993
/* ... round back down based on current offset... */
994
toResample -= voice->src.curBufferOffsetDec;
995
/* ... but also ceil for any fraction value... */
996
toResample += FIXED_FRACTION_MASK;
997
/* ... undo step size, fixed to int. */
998
toResample /= voice->src.resampleStep;
999
/* Add the padding, for some reason this helps? */
1000
toResample += EXTRA_DECODE_PADDING;
1001
/* FIXME: I feel like this should be an assert but I suck */
1002
toResample = FAudio_min(toResample, voice->src.resampleSamples);
1003
1004
/* Resample... */
1005
if (voice->src.resampleStep == FIXED_ONE)
1006
{
1007
/* Actually, just use the existing buffer... */
1008
finalSamples = voice->audio->decodeCache;
1009
}
1010
else
1011
{
1012
FAudio_INTERNAL_ResizeResampleCache(
1013
voice->audio,
1014
voice->src.resampleSamples * voice->src.format->nChannels
1015
);
1016
voice->src.resample(
1017
voice->audio->decodeCache,
1018
voice->audio->resampleCache,
1019
&voice->src.resampleOffset,
1020
voice->src.resampleStep,
1021
toResample,
1022
(uint8_t) voice->src.format->nChannels
1023
);
1024
finalSamples = voice->audio->resampleCache;
1025
}
1026
1027
/* Update buffer offsets */
1028
if (voice->src.bufferList != NULL)
1029
{
1030
/* Increment fixed offset by resample size, int to fixed... */
1031
voice->src.curBufferOffsetDec += toResample * voice->src.resampleStep;
1032
/* ... chop off any ints we got from the above increment */
1033
voice->src.curBufferOffsetDec &= FIXED_FRACTION_MASK;
1034
1035
/* Dec >0? We need one frame from the past...
1036
* FIXME: We can't go back to a prev buffer though?
1037
*/
1038
if ( voice->src.curBufferOffsetDec > 0 &&
1039
voice->src.curBufferOffset > 0 )
1040
{
1041
voice->src.curBufferOffset -= 1;
1042
}
1043
}
1044
else
1045
{
1046
voice->src.curBufferOffsetDec = 0;
1047
voice->src.curBufferOffset = 0;
1048
}
1049
1050
/* Done with buffers, finally. */
1051
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
1052
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
1053
mixed = (uint32_t) toResample;
1054
1055
sendwork:
1056
1057
/* Filters */
1058
if (voice->flags & FAUDIO_VOICE_USEFILTER)
1059
{
1060
FAudio_PlatformLockMutex(voice->filterLock);
1061
LOG_MUTEX_LOCK(voice->audio, voice->filterLock)
1062
FAudio_INTERNAL_FilterVoice(
1063
voice->audio,
1064
&voice->filter,
1065
voice->filterState,
1066
finalSamples,
1067
mixed,
1068
voice->src.format->nChannels
1069
);
1070
FAudio_PlatformUnlockMutex(voice->filterLock);
1071
LOG_MUTEX_UNLOCK(voice->audio, voice->filterLock)
1072
}
1073
1074
/* Process effect chain */
1075
FAudio_PlatformLockMutex(voice->effectLock);
1076
LOG_MUTEX_LOCK(voice->audio, voice->effectLock)
1077
if (voice->effects.count > 0)
1078
{
1079
/* If we didn't get the full size of the update, we have to fill
1080
* it with silence so the effect can process a whole update
1081
*/
1082
if (mixed < voice->src.resampleSamples)
1083
{
1084
FAudio_zero(
1085
finalSamples + (mixed * voice->src.format->nChannels),
1086
(voice->src.resampleSamples - mixed) * voice->src.format->nChannels * sizeof(float)
1087
);
1088
mixed = voice->src.resampleSamples;
1089
}
1090
finalSamples = FAudio_INTERNAL_ProcessEffectChain(
1091
voice,
1092
finalSamples,
1093
&mixed
1094
);
1095
}
1096
FAudio_PlatformUnlockMutex(voice->effectLock);
1097
LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
1098
1099
/* Nowhere to send it? Just skip the rest...*/
1100
if (voice->sends.SendCount == 0)
1101
{
1102
FAudio_PlatformUnlockMutex(voice->sendLock);
1103
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
1104
LOG_FUNC_EXIT(voice->audio)
1105
return;
1106
}
1107
1108
/* Send float cache to sends */
1109
FAudio_PlatformLockMutex(voice->volumeLock);
1110
LOG_MUTEX_LOCK(voice->audio, voice->volumeLock)
1111
for (i = 0; i < voice->sends.SendCount; i += 1)
1112
{
1113
out = voice->sends.pSends[i].pOutputVoice;
1114
if (out->type == FAUDIO_VOICE_MASTER)
1115
{
1116
stream = out->master.output;
1117
oChan = out->master.inputChannels;
1118
}
1119
else
1120
{
1121
stream = out->mix.inputCache;
1122
oChan = out->mix.inputChannels;
1123
}
1124
1125
voice->sendMix[i](
1126
mixed,
1127
voice->outputChannels,
1128
oChan,
1129
finalSamples,
1130
stream,
1131
voice->mixCoefficients[i]
1132
);
1133
1134
if (voice->sends.pSends[i].Flags & FAUDIO_SEND_USEFILTER)
1135
{
1136
FAudio_INTERNAL_FilterVoice(
1137
voice->audio,
1138
&voice->sendFilter[i],
1139
voice->sendFilterState[i],
1140
stream,
1141
mixed,
1142
oChan
1143
);
1144
}
1145
}
1146
FAudio_PlatformUnlockMutex(voice->volumeLock);
1147
LOG_MUTEX_UNLOCK(voice->audio, voice->volumeLock)
1148
1149
FAudio_PlatformUnlockMutex(voice->sendLock);
1150
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
1151
LOG_FUNC_EXIT(voice->audio)
1152
}
1153
1154
static void FAudio_INTERNAL_MixSubmix(FAudioSubmixVoice *voice)
1155
{
1156
uint32_t i;
1157
float *stream;
1158
uint32_t oChan;
1159
FAudioVoice *out;
1160
uint32_t resampled;
1161
uint64_t resampleOffset = 0;
1162
float *finalSamples;
1163
1164
LOG_FUNC_ENTER(voice->audio)
1165
FAudio_PlatformLockMutex(voice->sendLock);
1166
LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
1167
1168
/* Resample */
1169
if (voice->mix.resampleStep == FIXED_ONE)
1170
{
1171
/* Actually, just use the existing buffer... */
1172
finalSamples = voice->mix.inputCache;
1173
}
1174
else
1175
{
1176
FAudio_INTERNAL_ResizeResampleCache(
1177
voice->audio,
1178
voice->mix.outputSamples * voice->mix.inputChannels
1179
);
1180
voice->mix.resample(
1181
voice->mix.inputCache,
1182
voice->audio->resampleCache,
1183
&resampleOffset,
1184
voice->mix.resampleStep,
1185
voice->mix.outputSamples,
1186
(uint8_t) voice->mix.inputChannels
1187
);
1188
finalSamples = voice->audio->resampleCache;
1189
}
1190
resampled = voice->mix.outputSamples * voice->mix.inputChannels;
1191
1192
/* Submix overall volume is applied _before_ effects/filters, blech! */
1193
if (voice->volume != 1.0f)
1194
{
1195
FAudio_INTERNAL_Amplify(
1196
finalSamples,
1197
resampled,
1198
voice->volume
1199
);
1200
}
1201
resampled /= voice->mix.inputChannels;
1202
1203
/* Filters */
1204
if (voice->flags & FAUDIO_VOICE_USEFILTER)
1205
{
1206
FAudio_PlatformLockMutex(voice->filterLock);
1207
LOG_MUTEX_LOCK(voice->audio, voice->filterLock)
1208
FAudio_INTERNAL_FilterVoice(
1209
voice->audio,
1210
&voice->filter,
1211
voice->filterState,
1212
finalSamples,
1213
resampled,
1214
voice->mix.inputChannels
1215
);
1216
FAudio_PlatformUnlockMutex(voice->filterLock);
1217
LOG_MUTEX_UNLOCK(voice->audio, voice->filterLock)
1218
}
1219
1220
/* Process effect chain */
1221
FAudio_PlatformLockMutex(voice->effectLock);
1222
LOG_MUTEX_LOCK(voice->audio, voice->effectLock)
1223
if (voice->effects.count > 0)
1224
{
1225
finalSamples = FAudio_INTERNAL_ProcessEffectChain(
1226
voice,
1227
finalSamples,
1228
&resampled
1229
);
1230
}
1231
FAudio_PlatformUnlockMutex(voice->effectLock);
1232
LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
1233
1234
/* Nothing more to do? */
1235
if (voice->sends.SendCount == 0)
1236
{
1237
goto end;
1238
}
1239
1240
/* Send float cache to sends */
1241
FAudio_PlatformLockMutex(voice->volumeLock);
1242
LOG_MUTEX_LOCK(voice->audio, voice->volumeLock)
1243
for (i = 0; i < voice->sends.SendCount; i += 1)
1244
{
1245
out = voice->sends.pSends[i].pOutputVoice;
1246
if (out->type == FAUDIO_VOICE_MASTER)
1247
{
1248
stream = out->master.output;
1249
oChan = out->master.inputChannels;
1250
}
1251
else
1252
{
1253
stream = out->mix.inputCache;
1254
oChan = out->mix.inputChannels;
1255
}
1256
1257
voice->sendMix[i](
1258
resampled,
1259
voice->outputChannels,
1260
oChan,
1261
finalSamples,
1262
stream,
1263
voice->mixCoefficients[i]
1264
);
1265
1266
if (voice->sends.pSends[i].Flags & FAUDIO_SEND_USEFILTER)
1267
{
1268
FAudio_INTERNAL_FilterVoice(
1269
voice->audio,
1270
&voice->sendFilter[i],
1271
voice->sendFilterState[i],
1272
stream,
1273
resampled,
1274
oChan
1275
);
1276
}
1277
}
1278
FAudio_PlatformUnlockMutex(voice->volumeLock);
1279
LOG_MUTEX_UNLOCK(voice->audio, voice->volumeLock)
1280
1281
/* Zero this at the end, for the next update */
1282
end:
1283
FAudio_PlatformUnlockMutex(voice->sendLock);
1284
LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
1285
FAudio_zero(
1286
voice->mix.inputCache,
1287
sizeof(float) * voice->mix.inputSamples
1288
);
1289
LOG_FUNC_EXIT(voice->audio)
1290
}
1291
1292
static void FAudio_INTERNAL_FlushPendingBuffers(FAudioSourceVoice *voice)
1293
{
1294
FAudioBufferEntry *entry;
1295
1296
FAudio_PlatformLockMutex(voice->src.bufferLock);
1297
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
1298
1299
/* Remove pending flushed buffers and send an event for each one */
1300
while (voice->src.flushList != NULL)
1301
{
1302
entry = voice->src.flushList;
1303
voice->src.flushList = voice->src.flushList->next;
1304
1305
if (voice->src.callback != NULL && voice->src.callback->OnBufferEnd != NULL)
1306
{
1307
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
1308
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
1309
1310
FAudio_PlatformUnlockMutex(voice->audio->sourceLock);
1311
LOG_MUTEX_UNLOCK(voice->audio, voice->audio->sourceLock)
1312
1313
voice->src.callback->OnBufferEnd(
1314
voice->src.callback,
1315
entry->buffer.pContext
1316
);
1317
1318
FAudio_PlatformLockMutex(voice->audio->sourceLock);
1319
LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
1320
1321
FAudio_PlatformLockMutex(voice->src.bufferLock);
1322
LOG_MUTEX_LOCK(voice->audio, voice->src.bufferLock)
1323
}
1324
voice->audio->pFree(entry);
1325
}
1326
1327
FAudio_PlatformUnlockMutex(voice->src.bufferLock);
1328
LOG_MUTEX_UNLOCK(voice->audio, voice->src.bufferLock)
1329
}
1330
1331
static void FAUDIOCALL FAudio_INTERNAL_GenerateOutput(FAudio *audio, float *output)
1332
{
1333
uint32_t totalSamples;
1334
LinkedList *list;
1335
float *effectOut;
1336
FAudioEngineCallback *callback;
1337
1338
LOG_FUNC_ENTER(audio)
1339
if (!audio->active)
1340
{
1341
LOG_FUNC_EXIT(audio)
1342
return;
1343
}
1344
1345
/* Apply any committed changes */
1346
FAudio_OPERATIONSET_Execute(audio);
1347
1348
/* ProcessingPassStart callbacks */
1349
FAudio_PlatformLockMutex(audio->callbackLock);
1350
LOG_MUTEX_LOCK(audio, audio->callbackLock)
1351
list = audio->callbacks;
1352
while (list != NULL)
1353
{
1354
callback = (FAudioEngineCallback*) list->entry;
1355
if (callback->OnProcessingPassStart != NULL)
1356
{
1357
callback->OnProcessingPassStart(
1358
callback
1359
);
1360
}
1361
list = list->next;
1362
}
1363
FAudio_PlatformUnlockMutex(audio->callbackLock);
1364
LOG_MUTEX_UNLOCK(audio, audio->callbackLock)
1365
1366
/* Writes to master will directly write to output, but ONLY if there
1367
* isn't any channel-changing effect processing to do first.
1368
*/
1369
if (audio->master->master.effectCache != NULL)
1370
{
1371
audio->master->master.output = audio->master->master.effectCache;
1372
FAudio_zero(
1373
audio->master->master.effectCache,
1374
(
1375
sizeof(float) *
1376
audio->updateSize *
1377
audio->master->master.inputChannels
1378
)
1379
);
1380
}
1381
else
1382
{
1383
audio->master->master.output = output;
1384
}
1385
1386
/* Mix sources */
1387
FAudio_PlatformLockMutex(audio->sourceLock);
1388
LOG_MUTEX_LOCK(audio, audio->sourceLock)
1389
list = audio->sources;
1390
while (list != NULL)
1391
{
1392
audio->processingSource = (FAudioSourceVoice*) list->entry;
1393
1394
FAudio_INTERNAL_FlushPendingBuffers(audio->processingSource);
1395
if (audio->processingSource->src.active)
1396
{
1397
FAudio_INTERNAL_MixSource(audio->processingSource);
1398
FAudio_INTERNAL_FlushPendingBuffers(audio->processingSource);
1399
}
1400
1401
list = list->next;
1402
}
1403
audio->processingSource = NULL;
1404
FAudio_PlatformUnlockMutex(audio->sourceLock);
1405
LOG_MUTEX_UNLOCK(audio, audio->sourceLock)
1406
1407
/* Mix submixes, ordered by processing stage */
1408
FAudio_PlatformLockMutex(audio->submixLock);
1409
LOG_MUTEX_LOCK(audio, audio->submixLock)
1410
list = audio->submixes;
1411
while (list != NULL)
1412
{
1413
FAudio_INTERNAL_MixSubmix((FAudioSubmixVoice*) list->entry);
1414
list = list->next;
1415
}
1416
FAudio_PlatformUnlockMutex(audio->submixLock);
1417
LOG_MUTEX_UNLOCK(audio, audio->submixLock)
1418
1419
/* Apply master volume */
1420
if (audio->master->volume != 1.0f)
1421
{
1422
FAudio_INTERNAL_Amplify(
1423
audio->master->master.output,
1424
audio->updateSize * audio->master->master.inputChannels,
1425
audio->master->volume
1426
);
1427
}
1428
1429
/* Process master effect chain */
1430
FAudio_PlatformLockMutex(audio->master->effectLock);
1431
LOG_MUTEX_LOCK(audio, audio->master->effectLock)
1432
if (audio->master->effects.count > 0)
1433
{
1434
totalSamples = audio->updateSize;
1435
effectOut = FAudio_INTERNAL_ProcessEffectChain(
1436
audio->master,
1437
audio->master->master.output,
1438
&totalSamples
1439
);
1440
1441
if (effectOut != output)
1442
{
1443
FAudio_memcpy(
1444
output,
1445
effectOut,
1446
totalSamples * audio->master->outputChannels * sizeof(float)
1447
);
1448
}
1449
if (totalSamples < audio->updateSize)
1450
{
1451
FAudio_zero(
1452
output + (totalSamples * audio->master->outputChannels),
1453
(audio->updateSize - totalSamples) * sizeof(float)
1454
);
1455
}
1456
}
1457
FAudio_PlatformUnlockMutex(audio->master->effectLock);
1458
LOG_MUTEX_UNLOCK(audio, audio->master->effectLock)
1459
1460
/* OnProcessingPassEnd callbacks */
1461
FAudio_PlatformLockMutex(audio->callbackLock);
1462
LOG_MUTEX_LOCK(audio, audio->callbackLock)
1463
list = audio->callbacks;
1464
while (list != NULL)
1465
{
1466
callback = (FAudioEngineCallback*) list->entry;
1467
if (callback->OnProcessingPassEnd != NULL)
1468
{
1469
callback->OnProcessingPassEnd(
1470
callback
1471
);
1472
}
1473
list = list->next;
1474
}
1475
FAudio_PlatformUnlockMutex(audio->callbackLock);
1476
LOG_MUTEX_UNLOCK(audio, audio->callbackLock)
1477
1478
LOG_FUNC_EXIT(audio)
1479
}
1480
1481
void FAudio_INTERNAL_UpdateEngine(FAudio *audio, float *output)
1482
{
1483
LOG_FUNC_ENTER(audio)
1484
if (audio->pClientEngineProc)
1485
{
1486
audio->pClientEngineProc(
1487
&FAudio_INTERNAL_GenerateOutput,
1488
audio,
1489
output,
1490
audio->clientEngineUser
1491
);
1492
}
1493
else
1494
{
1495
FAudio_INTERNAL_GenerateOutput(audio, output);
1496
}
1497
LOG_FUNC_EXIT(audio)
1498
}
1499
1500
void FAudio_INTERNAL_ResizeDecodeCache(FAudio *audio, uint32_t samples)
1501
{
1502
LOG_FUNC_ENTER(audio)
1503
FAudio_PlatformLockMutex(audio->sourceLock);
1504
LOG_MUTEX_LOCK(audio, audio->sourceLock)
1505
if (samples > audio->decodeSamples)
1506
{
1507
audio->decodeSamples = samples;
1508
audio->decodeCache = (float*) audio->pRealloc(
1509
audio->decodeCache,
1510
sizeof(float) * audio->decodeSamples
1511
);
1512
}
1513
FAudio_PlatformUnlockMutex(audio->sourceLock);
1514
LOG_MUTEX_UNLOCK(audio, audio->sourceLock)
1515
LOG_FUNC_EXIT(audio)
1516
}
1517
1518
void FAudio_INTERNAL_AllocEffectChain(
1519
FAudioVoice *voice,
1520
const FAudioEffectChain *pEffectChain
1521
) {
1522
uint32_t i;
1523
1524
LOG_FUNC_ENTER(voice->audio)
1525
voice->effects.state = FAPO_BUFFER_VALID;
1526
voice->effects.count = pEffectChain->EffectCount;
1527
if (voice->effects.count == 0)
1528
{
1529
LOG_FUNC_EXIT(voice->audio)
1530
return;
1531
}
1532
1533
for (i = 0; i < pEffectChain->EffectCount; i += 1)
1534
{
1535
pEffectChain->pEffectDescriptors[i].pEffect->AddRef(pEffectChain->pEffectDescriptors[i].pEffect);
1536
}
1537
1538
voice->effects.desc = (FAudioEffectDescriptor*) voice->audio->pMalloc(
1539
voice->effects.count * sizeof(FAudioEffectDescriptor)
1540
);
1541
FAudio_memcpy(
1542
voice->effects.desc,
1543
pEffectChain->pEffectDescriptors,
1544
voice->effects.count * sizeof(FAudioEffectDescriptor)
1545
);
1546
#define ALLOC_EFFECT_PROPERTY(prop, type) \
1547
voice->effects.prop = (type*) voice->audio->pMalloc( \
1548
voice->effects.count * sizeof(type) \
1549
); \
1550
FAudio_zero( \
1551
voice->effects.prop, \
1552
voice->effects.count * sizeof(type) \
1553
);
1554
ALLOC_EFFECT_PROPERTY(parameters, void*)
1555
ALLOC_EFFECT_PROPERTY(parameterSizes, uint32_t)
1556
ALLOC_EFFECT_PROPERTY(parameterUpdates, uint8_t)
1557
ALLOC_EFFECT_PROPERTY(inPlaceProcessing, uint8_t)
1558
#undef ALLOC_EFFECT_PROPERTY
1559
LOG_FUNC_EXIT(voice->audio)
1560
}
1561
1562
void FAudio_INTERNAL_FreeEffectChain(FAudioVoice *voice)
1563
{
1564
uint32_t i;
1565
1566
LOG_FUNC_ENTER(voice->audio)
1567
if (voice->effects.count == 0)
1568
{
1569
LOG_FUNC_EXIT(voice->audio)
1570
return;
1571
}
1572
1573
for (i = 0; i < voice->effects.count; i += 1)
1574
{
1575
voice->effects.desc[i].pEffect->UnlockForProcess(voice->effects.desc[i].pEffect);
1576
voice->effects.desc[i].pEffect->Release(voice->effects.desc[i].pEffect);
1577
}
1578
1579
voice->audio->pFree(voice->effects.desc);
1580
voice->audio->pFree(voice->effects.parameters);
1581
voice->audio->pFree(voice->effects.parameterSizes);
1582
voice->audio->pFree(voice->effects.parameterUpdates);
1583
voice->audio->pFree(voice->effects.inPlaceProcessing);
1584
LOG_FUNC_EXIT(voice->audio)
1585
}
1586
1587
uint32_t FAudio_INTERNAL_VoiceOutputFrequency(
1588
FAudioVoice *voice,
1589
const FAudioVoiceSends *pSendList
1590
) {
1591
uint32_t outSampleRate;
1592
uint32_t newResampleSamples;
1593
uint64_t resampleSanityCheck;
1594
1595
LOG_FUNC_ENTER(voice->audio)
1596
1597
if ((pSendList == NULL) || (pSendList->SendCount == 0))
1598
{
1599
/* When we're deliberately given no sends, use master rate! */
1600
outSampleRate = voice->audio->master->master.inputSampleRate;
1601
}
1602
else
1603
{
1604
outSampleRate = pSendList->pSends[0].pOutputVoice->type == FAUDIO_VOICE_MASTER ?
1605
pSendList->pSends[0].pOutputVoice->master.inputSampleRate :
1606
pSendList->pSends[0].pOutputVoice->mix.inputSampleRate;
1607
}
1608
newResampleSamples = (uint32_t) FAudio_ceil(
1609
voice->audio->updateSize *
1610
(double) outSampleRate /
1611
(double) voice->audio->master->master.inputSampleRate
1612
);
1613
if (voice->type == FAUDIO_VOICE_SOURCE)
1614
{
1615
if ( (voice->src.resampleSamples != 0) &&
1616
(newResampleSamples != voice->src.resampleSamples) &&
1617
(voice->effects.count > 0) )
1618
{
1619
LOG_FUNC_EXIT(voice->audio)
1620
return FAUDIO_E_INVALID_CALL;
1621
}
1622
voice->src.resampleSamples = newResampleSamples;
1623
}
1624
else /* (voice->type == FAUDIO_VOICE_SUBMIX) */
1625
{
1626
if ( (voice->mix.outputSamples != 0) &&
1627
(newResampleSamples != voice->mix.outputSamples) &&
1628
(voice->effects.count > 0) )
1629
{
1630
LOG_FUNC_EXIT(voice->audio)
1631
return FAUDIO_E_INVALID_CALL;
1632
}
1633
voice->mix.outputSamples = newResampleSamples;
1634
1635
voice->mix.resampleStep = DOUBLE_TO_FIXED((
1636
(double) voice->mix.inputSampleRate /
1637
(double) outSampleRate
1638
));
1639
1640
/* Because we used ceil earlier, there's a chance that
1641
* downsampling submixes will go past the number of samples
1642
* available. Sources can do this thanks to padding, but we
1643
* don't have that luxury for submixes, so unfortunately we
1644
* just have to undo the ceil and turn it into a floor.
1645
* -flibit
1646
*/
1647
resampleSanityCheck = (
1648
voice->mix.resampleStep * voice->mix.outputSamples
1649
) >> FIXED_PRECISION;
1650
if (resampleSanityCheck > (voice->mix.inputSamples / voice->mix.inputChannels))
1651
{
1652
voice->mix.outputSamples -= 1;
1653
}
1654
}
1655
1656
LOG_FUNC_EXIT(voice->audio)
1657
return 0;
1658
}
1659
1660
const float FAUDIO_INTERNAL_MATRIX_DEFAULTS[8][8][64] =
1661
{
1662
#include "matrix_defaults.inl"
1663
};
1664
1665
/* PCM Decoding */
1666
1667
void FAudio_INTERNAL_DecodePCM8(
1668
FAudioVoice *voice,
1669
FAudioBuffer *buffer,
1670
float *decodeCache,
1671
uint32_t samples
1672
) {
1673
LOG_FUNC_ENTER(voice->audio)
1674
FAudio_INTERNAL_Convert_U8_To_F32(
1675
((uint8_t*) buffer->pAudioData) + (
1676
voice->src.curBufferOffset * voice->src.format->nChannels
1677
),
1678
decodeCache,
1679
samples * voice->src.format->nChannels
1680
);
1681
LOG_FUNC_EXIT(voice->audio)
1682
}
1683
1684
void FAudio_INTERNAL_DecodePCM16(
1685
FAudioVoice *voice,
1686
FAudioBuffer *buffer,
1687
float *decodeCache,
1688
uint32_t samples
1689
) {
1690
LOG_FUNC_ENTER(voice->audio)
1691
FAudio_INTERNAL_Convert_S16_To_F32(
1692
((int16_t*) buffer->pAudioData) + (
1693
voice->src.curBufferOffset * voice->src.format->nChannels
1694
),
1695
decodeCache,
1696
samples * voice->src.format->nChannels
1697
);
1698
LOG_FUNC_EXIT(voice->audio)
1699
}
1700
1701
void FAudio_INTERNAL_DecodePCM24(
1702
FAudioVoice *voice,
1703
FAudioBuffer *buffer,
1704
float *decodeCache,
1705
uint32_t samples
1706
) {
1707
uint32_t i, j;
1708
const uint8_t *buf;
1709
LOG_FUNC_ENTER(voice->audio)
1710
1711
/* FIXME: Uh... is this something that can be SIMD-ified? */
1712
buf = buffer->pAudioData + (
1713
voice->src.curBufferOffset * voice->src.format->nBlockAlign
1714
);
1715
for (i = 0; i < samples; i += 1, buf += voice->src.format->nBlockAlign)
1716
for (j = 0; j < voice->src.format->nChannels; j += 1)
1717
{
1718
*decodeCache++ = ((int32_t) (
1719
((uint32_t) buf[(j * 3) + 2] << 24) |
1720
((uint32_t) buf[(j * 3) + 1] << 16) |
1721
((uint32_t) buf[(j * 3) + 0] << 8)
1722
) >> 8) / 8388607.0f;
1723
}
1724
1725
LOG_FUNC_EXIT(voice->audio)
1726
}
1727
1728
void FAudio_INTERNAL_DecodePCM32(
1729
FAudioVoice *voice,
1730
FAudioBuffer *buffer,
1731
float *decodeCache,
1732
uint32_t samples
1733
) {
1734
LOG_FUNC_ENTER(voice->audio)
1735
FAudio_INTERNAL_Convert_S32_To_F32(
1736
((int32_t*) buffer->pAudioData) + (
1737
voice->src.curBufferOffset * voice->src.format->nChannels
1738
),
1739
decodeCache,
1740
samples * voice->src.format->nChannels
1741
);
1742
LOG_FUNC_EXIT(voice->audio)
1743
}
1744
1745
void FAudio_INTERNAL_DecodePCM32F(
1746
FAudioVoice *voice,
1747
FAudioBuffer *buffer,
1748
float *decodeCache,
1749
uint32_t samples
1750
) {
1751
LOG_FUNC_ENTER(voice->audio)
1752
FAudio_memcpy(
1753
decodeCache,
1754
((float*) buffer->pAudioData) + (
1755
voice->src.curBufferOffset * voice->src.format->nChannels
1756
),
1757
sizeof(float) * samples * voice->src.format->nChannels
1758
);
1759
LOG_FUNC_EXIT(voice->audio)
1760
}
1761
1762
/* MSADPCM Decoding */
1763
1764
static inline int16_t FAudio_INTERNAL_ParseNibble(
1765
uint8_t nibble,
1766
uint8_t predictor,
1767
int16_t *delta,
1768
int16_t *sample1,
1769
int16_t *sample2
1770
) {
1771
static const int32_t AdaptionTable[16] =
1772
{
1773
230, 230, 230, 230, 307, 409, 512, 614,
1774
768, 614, 512, 409, 307, 230, 230, 230
1775
};
1776
static const int32_t AdaptCoeff_1[7] =
1777
{
1778
256, 512, 0, 192, 240, 460, 392
1779
};
1780
static const int32_t AdaptCoeff_2[7] =
1781
{
1782
0, -256, 0, 64, 0, -208, -232
1783
};
1784
1785
int8_t signedNibble;
1786
int32_t sampleInt;
1787
int16_t sample;
1788
1789
signedNibble = (int8_t) nibble;
1790
if (signedNibble & 0x08)
1791
{
1792
signedNibble -= 0x10;
1793
}
1794
1795
sampleInt = (
1796
(*sample1 * AdaptCoeff_1[predictor]) +
1797
(*sample2 * AdaptCoeff_2[predictor])
1798
) / 256;
1799
sampleInt += signedNibble * (*delta);
1800
sample = FAudio_clamp(sampleInt, -32768, 32767);
1801
1802
*sample2 = *sample1;
1803
*sample1 = sample;
1804
*delta = (int16_t) (AdaptionTable[nibble] * (int32_t) (*delta) / 256);
1805
if (*delta < 16)
1806
{
1807
*delta = 16;
1808
}
1809
return sample;
1810
}
1811
1812
#define READ(item, type) \
1813
item = *((type*) *buf); \
1814
*buf += sizeof(type);
1815
1816
static inline void FAudio_INTERNAL_DecodeMonoMSADPCMBlock(
1817
uint8_t **buf,
1818
int16_t *blockCache,
1819
uint32_t align
1820
) {
1821
uint32_t i;
1822
1823
/* Temp storage for ADPCM blocks */
1824
uint8_t predictor;
1825
int16_t delta;
1826
int16_t sample1;
1827
int16_t sample2;
1828
1829
/* Preamble */
1830
READ(predictor, uint8_t)
1831
READ(delta, int16_t)
1832
READ(sample1, int16_t)
1833
READ(sample2, int16_t)
1834
align -= 7;
1835
1836
/* Samples */
1837
*blockCache++ = sample2;
1838
*blockCache++ = sample1;
1839
for (i = 0; i < align; i += 1, *buf += 1)
1840
{
1841
*blockCache++ = FAudio_INTERNAL_ParseNibble(
1842
*(*buf) >> 4,
1843
predictor,
1844
&delta,
1845
&sample1,
1846
&sample2
1847
);
1848
*blockCache++ = FAudio_INTERNAL_ParseNibble(
1849
*(*buf) & 0x0F,
1850
predictor,
1851
&delta,
1852
&sample1,
1853
&sample2
1854
);
1855
}
1856
}
1857
1858
static inline void FAudio_INTERNAL_DecodeStereoMSADPCMBlock(
1859
uint8_t **buf,
1860
int16_t *blockCache,
1861
uint32_t align
1862
) {
1863
uint32_t i;
1864
1865
/* Temp storage for ADPCM blocks */
1866
uint8_t l_predictor;
1867
uint8_t r_predictor;
1868
int16_t l_delta;
1869
int16_t r_delta;
1870
int16_t l_sample1;
1871
int16_t r_sample1;
1872
int16_t l_sample2;
1873
int16_t r_sample2;
1874
1875
/* Preamble */
1876
READ(l_predictor, uint8_t)
1877
READ(r_predictor, uint8_t)
1878
READ(l_delta, int16_t)
1879
READ(r_delta, int16_t)
1880
READ(l_sample1, int16_t)
1881
READ(r_sample1, int16_t)
1882
READ(l_sample2, int16_t)
1883
READ(r_sample2, int16_t)
1884
align -= 14;
1885
1886
/* Samples */
1887
*blockCache++ = l_sample2;
1888
*blockCache++ = r_sample2;
1889
*blockCache++ = l_sample1;
1890
*blockCache++ = r_sample1;
1891
for (i = 0; i < align; i += 1, *buf += 1)
1892
{
1893
*blockCache++ = FAudio_INTERNAL_ParseNibble(
1894
*(*buf) >> 4,
1895
l_predictor,
1896
&l_delta,
1897
&l_sample1,
1898
&l_sample2
1899
);
1900
*blockCache++ = FAudio_INTERNAL_ParseNibble(
1901
*(*buf) & 0x0F,
1902
r_predictor,
1903
&r_delta,
1904
&r_sample1,
1905
&r_sample2
1906
);
1907
}
1908
}
1909
1910
#undef READ
1911
1912
void FAudio_INTERNAL_DecodeMonoMSADPCM(
1913
FAudioVoice *voice,
1914
FAudioBuffer *buffer,
1915
float *decodeCache,
1916
uint32_t samples
1917
) {
1918
/* Loop variables */
1919
uint32_t copy, done = 0;
1920
1921
/* Read pointers */
1922
uint8_t *buf;
1923
int32_t midOffset;
1924
1925
/* PCM block cache */
1926
int16_t *blockCache;
1927
1928
/* Block size */
1929
uint32_t bsize = ((FAudioADPCMWaveFormat*) voice->src.format)->wSamplesPerBlock;
1930
1931
LOG_FUNC_ENTER(voice->audio)
1932
1933
/* Where are we starting? */
1934
buf = (uint8_t*) buffer->pAudioData + (
1935
(voice->src.curBufferOffset / bsize) *
1936
voice->src.format->nBlockAlign
1937
);
1938
1939
/* Are we starting in the middle? */
1940
midOffset = (voice->src.curBufferOffset % bsize);
1941
1942
/* Read in each block directly to the decode cache */
1943
blockCache = (int16_t*) FAudio_alloca(bsize * sizeof(int16_t));
1944
while (done < samples)
1945
{
1946
copy = FAudio_min(samples - done, bsize - midOffset);
1947
FAudio_INTERNAL_DecodeMonoMSADPCMBlock(
1948
&buf,
1949
blockCache,
1950
voice->src.format->nBlockAlign
1951
);
1952
FAudio_INTERNAL_Convert_S16_To_F32(
1953
blockCache + midOffset,
1954
decodeCache,
1955
copy
1956
);
1957
decodeCache += copy;
1958
done += copy;
1959
midOffset = 0;
1960
}
1961
FAudio_dealloca(blockCache);
1962
LOG_FUNC_EXIT(voice->audio)
1963
}
1964
1965
void FAudio_INTERNAL_DecodeStereoMSADPCM(
1966
FAudioVoice *voice,
1967
FAudioBuffer *buffer,
1968
float *decodeCache,
1969
uint32_t samples
1970
) {
1971
/* Loop variables */
1972
uint32_t copy, done = 0;
1973
1974
/* Read pointers */
1975
uint8_t *buf;
1976
int32_t midOffset;
1977
1978
/* PCM block cache */
1979
int16_t *blockCache;
1980
1981
/* Align, block size */
1982
uint32_t bsize = ((FAudioADPCMWaveFormat*) voice->src.format)->wSamplesPerBlock;
1983
1984
LOG_FUNC_ENTER(voice->audio)
1985
1986
/* Where are we starting? */
1987
buf = (uint8_t*) buffer->pAudioData + (
1988
(voice->src.curBufferOffset / bsize) *
1989
voice->src.format->nBlockAlign
1990
);
1991
1992
/* Are we starting in the middle? */
1993
midOffset = (voice->src.curBufferOffset % bsize);
1994
1995
/* Read in each block directly to the decode cache */
1996
blockCache = (int16_t*) FAudio_alloca(bsize * 2 * sizeof(int16_t));
1997
while (done < samples)
1998
{
1999
copy = FAudio_min(samples - done, bsize - midOffset);
2000
FAudio_INTERNAL_DecodeStereoMSADPCMBlock(
2001
&buf,
2002
blockCache,
2003
voice->src.format->nBlockAlign
2004
);
2005
FAudio_INTERNAL_Convert_S16_To_F32(
2006
blockCache + (midOffset * 2),
2007
decodeCache,
2008
copy * 2
2009
);
2010
decodeCache += copy * 2;
2011
done += copy;
2012
midOffset = 0;
2013
}
2014
FAudio_dealloca(blockCache);
2015
LOG_FUNC_EXIT(voice->audio)
2016
}
2017
2018
/* Fallback WMA decoder, get ready for spam! */
2019
2020
void FAudio_INTERNAL_DecodeWMAERROR(
2021
FAudioVoice *voice,
2022
FAudioBuffer *buffer,
2023
float *decodeCache,
2024
uint32_t samples
2025
) {
2026
LOG_FUNC_ENTER(voice->audio)
2027
LOG_ERROR(voice->audio, "%s", "WMA IS NOT SUPPORTED IN THIS BUILD!")
2028
FAudio_zero(decodeCache, samples * voice->src.format->nChannels * sizeof(float));
2029
LOG_FUNC_EXIT(voice->audio)
2030
}
2031
2032
/* vim: set noexpandtab shiftwidth=8 tabstop=8: */
2033
2034