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