1 /* FAudio - XAudio Reimplementation for FNA
3 * Copyright (c) 2011-2024 Ethan Lee, Luigi Auriemma, and the MonoGame Team
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.
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:
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.
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
21 * 3. This notice may not be removed or altered from any source distribution.
23 * Ethan "flibitijibibo" Lee <flibitijibibo@flibitijibibo.com>
27 #include "FAudio_internal.h"
29 #ifndef FAUDIO_DISABLE_DEBUGCONFIGURATION
30 void FAudio_INTERNAL_debug(
44 if (audio
->debug
.LogThreadID
)
46 out
+= FAudio_snprintf(
48 sizeof(output
) - (out
- output
),
49 "0x%" FAudio_PRIx64
" ",
50 FAudio_PlatformGetThreadID()
53 if (audio
->debug
.LogFileline
)
55 out
+= FAudio_snprintf(
57 sizeof(output
) - (out
- output
),
63 if (audio
->debug
.LogFunctionName
)
65 out
+= FAudio_snprintf(
67 sizeof(output
) - (out
- output
),
72 if (audio
->debug
.LogTiming
)
74 out
+= FAudio_snprintf(
76 sizeof(output
) - (out
- output
),
82 /* The actual message... */
86 sizeof(output
) - (out
- output
),
96 static const char *get_wformattag_string(const FAudioWaveFormatEx
*fmt
)
98 #define FMT_STRING(suffix) \
99 if (fmt->wFormatTag == FAUDIO_FORMAT_##suffix) \
105 FMT_STRING(IEEE_FLOAT
)
109 FMT_STRING(EXTENSIBLE
)
114 static const char *get_subformat_string(const FAudioWaveFormatEx
*fmt
)
116 const FAudioWaveFormatExtensible
*fmtex
= (const FAudioWaveFormatExtensible
*) fmt
;
118 if (fmt
->wFormatTag
!= FAUDIO_FORMAT_EXTENSIBLE
)
122 if (!FAudio_memcmp(&fmtex
->SubFormat
, &DATAFORMAT_SUBTYPE_IEEE_FLOAT
, sizeof(FAudioGUID
)))
126 if (!FAudio_memcmp(&fmtex
->SubFormat
, &DATAFORMAT_SUBTYPE_PCM
, sizeof(FAudioGUID
)))
133 void FAudio_INTERNAL_debug_fmt(
138 const FAudioWaveFormatEx
*fmt
140 FAudio_INTERNAL_debug(
147 "wFormatTag: 0x%x %s, "
149 "nSamplesPerSec: %u, "
150 "wBitsPerSample: %u, "
156 get_wformattag_string(fmt
),
161 get_subformat_string(fmt
)
164 #endif /* FAUDIO_DISABLE_DEBUGCONFIGURATION */
166 void LinkedList_AddEntry(
170 FAudioMallocFunc pMalloc
172 LinkedList
*newEntry
, *latest
;
173 newEntry
= (LinkedList
*) pMalloc(sizeof(LinkedList
));
174 newEntry
->entry
= toAdd
;
175 newEntry
->next
= NULL
;
176 FAudio_PlatformLockMutex(lock
);
184 while (latest
->next
!= NULL
)
186 latest
= latest
->next
;
188 latest
->next
= newEntry
;
190 FAudio_PlatformUnlockMutex(lock
);
193 void LinkedList_PrependEntry(
197 FAudioMallocFunc pMalloc
199 LinkedList
*newEntry
;
200 newEntry
= (LinkedList
*) pMalloc(sizeof(LinkedList
));
201 newEntry
->entry
= toAdd
;
202 FAudio_PlatformLockMutex(lock
);
203 newEntry
->next
= *start
;
205 FAudio_PlatformUnlockMutex(lock
);
208 void LinkedList_RemoveEntry(
214 LinkedList
*latest
, *prev
;
215 FAudio_PlatformLockMutex(lock
);
218 while (latest
!= NULL
)
220 if (latest
->entry
== toRemove
)
222 if (latest
== prev
) /* First in list */
224 *start
= latest
->next
;
228 prev
->next
= latest
->next
;
231 FAudio_PlatformUnlockMutex(lock
);
235 latest
= latest
->next
;
237 FAudio_PlatformUnlockMutex(lock
);
238 FAudio_assert(0 && "LinkedList element not found!");
241 void FAudio_INTERNAL_InsertSubmixSorted(
243 FAudioSubmixVoice
*toAdd
,
245 FAudioMallocFunc pMalloc
247 LinkedList
*newEntry
, *latest
;
248 newEntry
= (LinkedList
*) pMalloc(sizeof(LinkedList
));
249 newEntry
->entry
= toAdd
;
250 newEntry
->next
= NULL
;
251 FAudio_PlatformLockMutex(lock
);
260 /* Special case if the new stage is lower than everyone else */
261 if (toAdd
->mix
.processingStage
< ((FAudioSubmixVoice
*) latest
->entry
)->mix
.processingStage
)
263 newEntry
->next
= latest
;
268 /* If we got here, we know that the new stage is
269 * _at least_ as high as the first submix in the list.
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`.
275 while (latest
->next
!= NULL
)
277 if (toAdd
->mix
.processingStage
< ((FAudioSubmixVoice
*) latest
->next
->entry
)->mix
.processingStage
)
279 newEntry
->next
= latest
->next
;
280 latest
->next
= newEntry
;
283 latest
= latest
->next
;
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!
289 if (newEntry
->next
== NULL
)
291 latest
->next
= newEntry
;
295 FAudio_PlatformUnlockMutex(lock
);
298 static uint32_t FAudio_INTERNAL_GetBytesRequested(
299 FAudioSourceVoice
*voice
,
302 uint32_t end
, result
;
303 FAudioBuffer
*buffer
;
304 FAudioWaveFormatExtensible
*fmt
;
305 FAudioBufferEntry
*list
= voice
->src
.bufferList
;
307 LOG_FUNC_ENTER(voice
->audio
)
310 if (voice
->src
.wmadec
!= NULL
)
312 /* Always 0, per the spec */
313 LOG_FUNC_EXIT(voice
->audio
)
316 #endif /* HAVE_WMADEC */
317 while (list
!= NULL
&& decoding
> 0)
319 buffer
= &list
->buffer
;
320 if (buffer
->LoopCount
> 0)
323 /* Current loop... */
324 ((buffer
->LoopBegin
+ buffer
->LoopLength
) - voice
->src
.curBufferOffset
) +
325 /* Remaining loops... */
326 (buffer
->LoopLength
* buffer
->LoopCount
- 1) +
327 /* ... Final iteration */
333 end
= (buffer
->PlayBegin
+ buffer
->PlayLength
) - voice
->src
.curBufferOffset
;
344 /* Convert samples to bytes, factoring block alignment */
345 if (voice
->src
.format
->wFormatTag
== FAUDIO_FORMAT_MSADPCM
)
347 fmt
= (FAudioWaveFormatExtensible
*) voice
->src
.format
;
349 (decoding
/ fmt
->Samples
.wSamplesPerBlock
) +
350 ((decoding
% fmt
->Samples
.wSamplesPerBlock
) > 0)
351 ) * voice
->src
.format
->nBlockAlign
;
355 result
= decoding
* voice
->src
.format
->nBlockAlign
;
358 LOG_FUNC_EXIT(voice
->audio
)
362 static void FAudio_INTERNAL_DecodeBuffers(
363 FAudioSourceVoice
*voice
,
366 uint32_t end
, endRead
, decoding
, decoded
= 0;
367 FAudioBuffer
*buffer
= &voice
->src
.bufferList
->buffer
;
368 FAudioBufferEntry
*toDelete
;
370 LOG_FUNC_ENTER(voice
->audio
)
372 /* This should never go past the max ratio size */
373 FAudio_assert(*toDecode
<= voice
->src
.decodeSamples
);
375 while (decoded
< *toDecode
&& buffer
!= NULL
)
377 decoding
= (uint32_t) *toDecode
- decoded
;
379 /* Start-of-buffer behavior */
380 if (voice
->src
.newBuffer
)
382 voice
->src
.newBuffer
= 0;
383 if ( voice
->src
.callback
!= NULL
&&
384 voice
->src
.callback
->OnBufferStart
!= NULL
)
386 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
387 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
389 FAudio_PlatformUnlockMutex(voice
->sendLock
);
390 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
392 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
393 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
395 voice
->src
.callback
->OnBufferStart(
400 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
401 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
403 FAudio_PlatformLockMutex(voice
->sendLock
);
404 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
406 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
407 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
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
,
424 voice
->audio
->decodeCache
+ (
425 decoded
* voice
->src
.format
->nChannels
432 "Voice %p, buffer %p, decoded %u samples from [%u,%u)",
436 voice
->src
.curBufferOffset
,
437 voice
->src
.curBufferOffset
+ endRead
441 voice
->src
.curBufferOffset
+= endRead
;
442 voice
->src
.totalSamples
+= endRead
;
444 /* End-of-buffer behavior */
445 if (endRead
< decoding
)
447 if (buffer
->LoopCount
> 0)
449 voice
->src
.curBufferOffset
= buffer
->LoopBegin
;
450 if (buffer
->LoopCount
< FAUDIO_LOOP_INFINITE
)
452 buffer
->LoopCount
-= 1;
454 if ( voice
->src
.callback
!= NULL
&&
455 voice
->src
.callback
->OnLoopEnd
!= NULL
)
457 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
458 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
460 FAudio_PlatformUnlockMutex(voice
->sendLock
);
461 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
463 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
464 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
466 voice
->src
.callback
->OnLoopEnd(
471 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
472 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
474 FAudio_PlatformLockMutex(voice
->sendLock
);
475 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
477 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
478 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
484 if (voice
->src
.wmadec
!= NULL
)
486 FAudio_WMADEC_end_buffer(voice
);
488 #endif /* HAVE_WMADEC */
489 /* For EOS we can stop storing fraction offsets */
490 if (buffer
->Flags
& FAUDIO_END_OF_STREAM
)
492 voice
->src
.curBufferOffsetDec
= 0;
493 voice
->src
.totalSamples
= 0;
498 "Voice %p, finished with buffer %p",
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
)
508 buffer
= &voice
->src
.bufferList
->buffer
;
509 voice
->src
.curBufferOffset
= buffer
->PlayBegin
;
515 /* FIXME: I keep going past the buffer so fuck it */
517 voice
->audio
->decodeCache
+ (
519 voice
->src
.format
->nChannels
522 (*toDecode
- decoded
) *
523 voice
->src
.format
->nChannels
529 if (voice
->src
.callback
!= NULL
)
531 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
532 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
534 FAudio_PlatformUnlockMutex(voice
->sendLock
);
535 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
537 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
538 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
540 if (voice
->src
.callback
->OnBufferEnd
!= NULL
)
542 voice
->src
.callback
->OnBufferEnd(
544 toDelete
->buffer
.pContext
547 if ( toDelete
->buffer
.Flags
& FAUDIO_END_OF_STREAM
&&
548 voice
->src
.callback
->OnStreamEnd
!= NULL
)
550 voice
->src
.callback
->OnStreamEnd(
555 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
556 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
558 FAudio_PlatformLockMutex(voice
->sendLock
);
559 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
561 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
562 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
564 /* One last chance at redemption */
565 if (buffer
== NULL
&& voice
->src
.bufferList
!= NULL
)
567 buffer
= &voice
->src
.bufferList
->buffer
;
568 voice
->src
.curBufferOffset
= buffer
->PlayBegin
;
571 if (buffer
!= NULL
&& voice
->src
.callback
->OnBufferStart
!= NULL
)
573 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
574 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
576 FAudio_PlatformUnlockMutex(voice
->sendLock
);
577 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
579 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
580 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
582 voice
->src
.callback
->OnBufferStart(
587 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
588 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
590 FAudio_PlatformLockMutex(voice
->sendLock
);
591 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
593 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
594 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
598 voice
->audio
->pFree(toDelete
);
603 /* ... FIXME: I keep going past the buffer so fuck it */
606 end
= (buffer
->LoopCount
> 0) ?
607 (buffer
->LoopBegin
+ buffer
->LoopLength
) :
608 buffer
->PlayBegin
+ buffer
->PlayLength
;
609 endRead
= FAudio_min(
610 end
- voice
->src
.curBufferOffset
,
617 voice
->audio
->decodeCache
+ (
618 decoded
* voice
->src
.format
->nChannels
622 /* Do NOT increment curBufferOffset! */
624 if (endRead
< EXTRA_DECODE_PADDING
)
627 voice
->audio
->decodeCache
+ (
628 decoded
* voice
->src
.format
->nChannels
631 (EXTRA_DECODE_PADDING
- endRead
) *
632 voice
->src
.format
->nChannels
640 voice
->audio
->decodeCache
+ (
641 decoded
* voice
->src
.format
->nChannels
644 EXTRA_DECODE_PADDING
*
645 voice
->src
.format
->nChannels
651 LOG_FUNC_EXIT(voice
->audio
)
654 static inline void FAudio_INTERNAL_FilterVoice(
656 const FAudioFilterParametersEXT
*filter
,
657 FAudioFilterState
*filterState
,
664 LOG_FUNC_ENTER(audio
)
666 /* Apply a digital state-variable filter to the voice.
667 * The difference equations of the filter are:
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)
674 * Please note that FAudioFilterParameters.Frequency is defined as:
676 * (2 * sin(pi * (desired filter cutoff frequency) / sampleRate))
681 for (j
= 0; j
< numSamples
; j
+= 1)
682 for (ci
= 0; ci
< numChannels
; ci
+= 1)
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
);
694 static void FAudio_INTERNAL_ResizeEffectChainCache(FAudio
*audio
, uint32_t samples
)
696 LOG_FUNC_ENTER(audio
)
697 if (samples
> audio
->effectChainSamples
)
699 audio
->effectChainSamples
= samples
;
700 audio
->effectChainCache
= (float*) audio
->pRealloc(
701 audio
->effectChainCache
,
702 sizeof(float) * audio
->effectChainSamples
708 static inline float *FAudio_INTERNAL_ProcessEffectChain(
715 FAPOProcessBufferParameters srcParams
, dstParams
;
717 LOG_FUNC_ENTER(voice
->audio
)
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)
725 if (buffer
[i
] != 0.0f
) /* Arbitrary! */
727 srcParams
.BufferFlags
= FAPO_BUFFER_VALID
;
732 /* Initialize output parameters to something sane */
733 dstParams
.pBuffer
= srcParams
.pBuffer
;
734 dstParams
.BufferFlags
= FAPO_BUFFER_VALID
;
735 dstParams
.ValidFrameCount
= srcParams
.ValidFrameCount
;
737 /* Update parameters, process! */
738 for (i
= 0; i
< voice
->effects
.count
; i
+= 1)
740 fapo
= voice
->effects
.desc
[i
].pEffect
;
742 if (!voice
->effects
.inPlaceProcessing
[i
])
744 if (dstParams
.pBuffer
== buffer
)
746 FAudio_INTERNAL_ResizeEffectChainCache(
748 voice
->effects
.desc
[i
].OutputChannels
* srcParams
.ValidFrameCount
750 dstParams
.pBuffer
= voice
->audio
->effectChainCache
;
754 /* FIXME: What if this is smaller because
755 * inputChannels < desc[i].OutputChannels?
757 dstParams
.pBuffer
= buffer
;
762 voice
->effects
.desc
[i
].OutputChannels
* srcParams
.ValidFrameCount
* sizeof(float)
766 if (voice
->effects
.parameterUpdates
[i
])
770 voice
->effects
.parameters
[i
],
771 voice
->effects
.parameterSizes
[i
]
773 voice
->effects
.parameterUpdates
[i
] = 0;
782 voice
->effects
.desc
[i
].InitialState
785 FAudio_memcpy(&srcParams
, &dstParams
, sizeof(dstParams
));
788 *samples
= dstParams
.ValidFrameCount
;
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
;
793 LOG_FUNC_EXIT(voice
->audio
)
794 return (float*) dstParams
.pBuffer
;
797 static void FAudio_INTERNAL_ResizeResampleCache(FAudio
*audio
, uint32_t samples
)
799 LOG_FUNC_ENTER(audio
)
800 if (samples
> audio
->resampleSamples
)
802 audio
->resampleSamples
= samples
;
803 audio
->resampleCache
= (float*) audio
->pRealloc(
804 audio
->resampleCache
,
805 sizeof(float) * audio
->resampleSamples
811 static void FAudio_INTERNAL_MixSource(FAudioSourceVoice
*voice
)
815 /* Decode/Resample variables */
818 /* Output mix variables */
827 LOG_FUNC_ENTER(voice
->audio
)
829 FAudio_PlatformLockMutex(voice
->sendLock
);
830 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
832 /* Calculate the resample stepping value */
833 if (voice
->src
.resampleFreq
!= voice
->src
.freqRatio
* voice
->src
.format
->nSamplesPerSec
)
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
;
842 voice
->src
.freqRatio
*
843 (double) voice
->src
.format
->nSamplesPerSec
/
846 voice
->src
.resampleStep
= DOUBLE_TO_FIXED(stepd
);
847 voice
->src
.resampleFreq
= voice
->src
.freqRatio
* voice
->src
.format
->nSamplesPerSec
;
850 if (voice
->src
.active
== 2)
852 /* We're just playing tails, skip all buffer stuff */
853 FAudio_INTERNAL_ResizeResampleCache(
855 voice
->src
.resampleSamples
* voice
->src
.format
->nChannels
857 mixed
= voice
->src
.resampleSamples
;
859 voice
->audio
->resampleCache
,
860 mixed
* voice
->src
.format
->nChannels
* sizeof(float)
862 finalSamples
= voice
->audio
->resampleCache
;
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
;
873 /* First voice callback */
874 if ( voice
->src
.callback
!= NULL
&&
875 voice
->src
.callback
->OnVoiceProcessingPassStart
!= NULL
)
877 FAudio_PlatformUnlockMutex(voice
->sendLock
);
878 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
880 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
881 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
883 voice
->src
.callback
->OnVoiceProcessingPassStart(
885 FAudio_INTERNAL_GetBytesRequested(voice
, (uint32_t) toDecode
)
888 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
889 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
891 FAudio_PlatformLockMutex(voice
->sendLock
);
892 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
895 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
896 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
899 if (voice
->src
.bufferList
== NULL
)
901 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
902 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
904 if (voice
->effects
.count
> 0 && voice
->effects
.state
!= FAPO_BUFFER_SILENT
)
906 /* do not stop while the effect chain generates a non-silent buffer */
907 FAudio_INTERNAL_ResizeResampleCache(
909 voice
->src
.resampleSamples
* voice
->src
.format
->nChannels
911 mixed
= voice
->src
.resampleSamples
;
913 voice
->audio
->resampleCache
,
914 mixed
* voice
->src
.format
->nChannels
* sizeof(float)
916 finalSamples
= voice
->audio
->resampleCache
;
920 FAudio_PlatformUnlockMutex(voice
->sendLock
);
921 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
923 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
924 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
926 if ( voice
->src
.callback
!= NULL
&&
927 voice
->src
.callback
->OnVoiceProcessingPassEnd
!= NULL
)
929 voice
->src
.callback
->OnVoiceProcessingPassEnd(
934 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
935 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
937 LOG_FUNC_EXIT(voice
->audio
)
942 FAudio_INTERNAL_DecodeBuffers(voice
, &toDecode
);
944 /* Subtract any padding samples from the total, if applicable */
945 if ( voice
->src
.curBufferOffsetDec
> 0 &&
946 voice
->src
.totalSamples
> 0 )
948 voice
->src
.totalSamples
-= 1;
951 /* Okay, we're done messing with client data */
952 if ( voice
->src
.callback
!= NULL
&&
953 voice
->src
.callback
->OnVoiceProcessingPassEnd
!= NULL
)
955 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
956 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
958 FAudio_PlatformUnlockMutex(voice
->sendLock
);
959 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
961 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
962 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
964 voice
->src
.callback
->OnVoiceProcessingPassEnd(
968 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
969 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
971 FAudio_PlatformLockMutex(voice
->sendLock
);
972 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
974 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
975 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
978 /* Nothing to resample? */
981 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
982 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
984 FAudio_PlatformUnlockMutex(voice
->sendLock
);
985 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
987 LOG_FUNC_EXIT(voice
->audio
)
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
);
1005 if (voice
->src
.resampleStep
== FIXED_ONE
)
1007 /* Actually, just use the existing buffer... */
1008 finalSamples
= voice
->audio
->decodeCache
;
1012 FAudio_INTERNAL_ResizeResampleCache(
1014 voice
->src
.resampleSamples
* voice
->src
.format
->nChannels
1016 voice
->src
.resample(
1017 voice
->audio
->decodeCache
,
1018 voice
->audio
->resampleCache
,
1019 &voice
->src
.resampleOffset
,
1020 voice
->src
.resampleStep
,
1022 (uint8_t) voice
->src
.format
->nChannels
1024 finalSamples
= voice
->audio
->resampleCache
;
1027 /* Update buffer offsets */
1028 if (voice
->src
.bufferList
!= NULL
)
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
;
1035 /* Dec >0? We need one frame from the past...
1036 * FIXME: We can't go back to a prev buffer though?
1038 if ( voice
->src
.curBufferOffsetDec
> 0 &&
1039 voice
->src
.curBufferOffset
> 0 )
1041 voice
->src
.curBufferOffset
-= 1;
1046 voice
->src
.curBufferOffsetDec
= 0;
1047 voice
->src
.curBufferOffset
= 0;
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
;
1058 if (voice
->flags
& FAUDIO_VOICE_USEFILTER
)
1060 FAudio_PlatformLockMutex(voice
->filterLock
);
1061 LOG_MUTEX_LOCK(voice
->audio
, voice
->filterLock
)
1062 FAudio_INTERNAL_FilterVoice(
1068 voice
->src
.format
->nChannels
1070 FAudio_PlatformUnlockMutex(voice
->filterLock
);
1071 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->filterLock
)
1074 /* Process effect chain */
1075 FAudio_PlatformLockMutex(voice
->effectLock
);
1076 LOG_MUTEX_LOCK(voice
->audio
, voice
->effectLock
)
1077 if (voice
->effects
.count
> 0)
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
1082 if (mixed
< voice
->src
.resampleSamples
)
1085 finalSamples
+ (mixed
* voice
->src
.format
->nChannels
),
1086 (voice
->src
.resampleSamples
- mixed
) * voice
->src
.format
->nChannels
* sizeof(float)
1088 mixed
= voice
->src
.resampleSamples
;
1090 finalSamples
= FAudio_INTERNAL_ProcessEffectChain(
1096 FAudio_PlatformUnlockMutex(voice
->effectLock
);
1097 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->effectLock
)
1099 /* Nowhere to send it? Just skip the rest...*/
1100 if (voice
->sends
.SendCount
== 0)
1102 FAudio_PlatformUnlockMutex(voice
->sendLock
);
1103 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
1104 LOG_FUNC_EXIT(voice
->audio
)
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)
1113 out
= voice
->sends
.pSends
[i
].pOutputVoice
;
1114 if (out
->type
== FAUDIO_VOICE_MASTER
)
1116 stream
= out
->master
.output
;
1117 oChan
= out
->master
.inputChannels
;
1121 stream
= out
->mix
.inputCache
;
1122 oChan
= out
->mix
.inputChannels
;
1127 voice
->outputChannels
,
1131 voice
->mixCoefficients
[i
]
1134 if (voice
->sends
.pSends
[i
].Flags
& FAUDIO_SEND_USEFILTER
)
1136 FAudio_INTERNAL_FilterVoice(
1138 &voice
->sendFilter
[i
],
1139 voice
->sendFilterState
[i
],
1146 FAudio_PlatformUnlockMutex(voice
->volumeLock
);
1147 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->volumeLock
)
1149 FAudio_PlatformUnlockMutex(voice
->sendLock
);
1150 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
1151 LOG_FUNC_EXIT(voice
->audio
)
1154 static void FAudio_INTERNAL_MixSubmix(FAudioSubmixVoice
*voice
)
1161 uint64_t resampleOffset
= 0;
1162 float *finalSamples
;
1164 LOG_FUNC_ENTER(voice
->audio
)
1165 FAudio_PlatformLockMutex(voice
->sendLock
);
1166 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
1169 if (voice
->mix
.resampleStep
== FIXED_ONE
)
1171 /* Actually, just use the existing buffer... */
1172 finalSamples
= voice
->mix
.inputCache
;
1176 FAudio_INTERNAL_ResizeResampleCache(
1178 voice
->mix
.outputSamples
* voice
->mix
.inputChannels
1180 voice
->mix
.resample(
1181 voice
->mix
.inputCache
,
1182 voice
->audio
->resampleCache
,
1184 voice
->mix
.resampleStep
,
1185 voice
->mix
.outputSamples
,
1186 (uint8_t) voice
->mix
.inputChannels
1188 finalSamples
= voice
->audio
->resampleCache
;
1190 resampled
= voice
->mix
.outputSamples
* voice
->mix
.inputChannels
;
1192 /* Submix overall volume is applied _before_ effects/filters, blech! */
1193 if (voice
->volume
!= 1.0f
)
1195 FAudio_INTERNAL_Amplify(
1201 resampled
/= voice
->mix
.inputChannels
;
1204 if (voice
->flags
& FAUDIO_VOICE_USEFILTER
)
1206 FAudio_PlatformLockMutex(voice
->filterLock
);
1207 LOG_MUTEX_LOCK(voice
->audio
, voice
->filterLock
)
1208 FAudio_INTERNAL_FilterVoice(
1214 voice
->mix
.inputChannels
1216 FAudio_PlatformUnlockMutex(voice
->filterLock
);
1217 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->filterLock
)
1220 /* Process effect chain */
1221 FAudio_PlatformLockMutex(voice
->effectLock
);
1222 LOG_MUTEX_LOCK(voice
->audio
, voice
->effectLock
)
1223 if (voice
->effects
.count
> 0)
1225 finalSamples
= FAudio_INTERNAL_ProcessEffectChain(
1231 FAudio_PlatformUnlockMutex(voice
->effectLock
);
1232 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->effectLock
)
1234 /* Nothing more to do? */
1235 if (voice
->sends
.SendCount
== 0)
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)
1245 out
= voice
->sends
.pSends
[i
].pOutputVoice
;
1246 if (out
->type
== FAUDIO_VOICE_MASTER
)
1248 stream
= out
->master
.output
;
1249 oChan
= out
->master
.inputChannels
;
1253 stream
= out
->mix
.inputCache
;
1254 oChan
= out
->mix
.inputChannels
;
1259 voice
->outputChannels
,
1263 voice
->mixCoefficients
[i
]
1266 if (voice
->sends
.pSends
[i
].Flags
& FAUDIO_SEND_USEFILTER
)
1268 FAudio_INTERNAL_FilterVoice(
1270 &voice
->sendFilter
[i
],
1271 voice
->sendFilterState
[i
],
1278 FAudio_PlatformUnlockMutex(voice
->volumeLock
);
1279 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->volumeLock
)
1281 /* Zero this at the end, for the next update */
1283 FAudio_PlatformUnlockMutex(voice
->sendLock
);
1284 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
1286 voice
->mix
.inputCache
,
1287 sizeof(float) * voice
->mix
.inputSamples
1289 LOG_FUNC_EXIT(voice
->audio
)
1292 static void FAudio_INTERNAL_FlushPendingBuffers(FAudioSourceVoice
*voice
)
1294 FAudioBufferEntry
*entry
;
1296 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
1297 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
1299 /* Remove pending flushed buffers and send an event for each one */
1300 while (voice
->src
.flushList
!= NULL
)
1302 entry
= voice
->src
.flushList
;
1303 voice
->src
.flushList
= voice
->src
.flushList
->next
;
1305 if (voice
->src
.callback
!= NULL
&& voice
->src
.callback
->OnBufferEnd
!= NULL
)
1307 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
1308 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
1310 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
1311 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
1313 voice
->src
.callback
->OnBufferEnd(
1314 voice
->src
.callback
,
1315 entry
->buffer
.pContext
1318 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
1319 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
1321 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
1322 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
1324 voice
->audio
->pFree(entry
);
1327 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
1328 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
1331 static void FAUDIOCALL
FAudio_INTERNAL_GenerateOutput(FAudio
*audio
, float *output
)
1333 uint32_t totalSamples
;
1336 FAudioEngineCallback
*callback
;
1338 LOG_FUNC_ENTER(audio
)
1341 LOG_FUNC_EXIT(audio
)
1345 /* Apply any committed changes */
1346 FAudio_OPERATIONSET_Execute(audio
);
1348 /* ProcessingPassStart callbacks */
1349 FAudio_PlatformLockMutex(audio
->callbackLock
);
1350 LOG_MUTEX_LOCK(audio
, audio
->callbackLock
)
1351 list
= audio
->callbacks
;
1352 while (list
!= NULL
)
1354 callback
= (FAudioEngineCallback
*) list
->entry
;
1355 if (callback
->OnProcessingPassStart
!= NULL
)
1357 callback
->OnProcessingPassStart(
1363 FAudio_PlatformUnlockMutex(audio
->callbackLock
);
1364 LOG_MUTEX_UNLOCK(audio
, audio
->callbackLock
)
1366 /* Writes to master will directly write to output, but ONLY if there
1367 * isn't any channel-changing effect processing to do first.
1369 if (audio
->master
->master
.effectCache
!= NULL
)
1371 audio
->master
->master
.output
= audio
->master
->master
.effectCache
;
1373 audio
->master
->master
.effectCache
,
1377 audio
->master
->master
.inputChannels
1383 audio
->master
->master
.output
= output
;
1387 FAudio_PlatformLockMutex(audio
->sourceLock
);
1388 LOG_MUTEX_LOCK(audio
, audio
->sourceLock
)
1389 list
= audio
->sources
;
1390 while (list
!= NULL
)
1392 audio
->processingSource
= (FAudioSourceVoice
*) list
->entry
;
1394 FAudio_INTERNAL_FlushPendingBuffers(audio
->processingSource
);
1395 if (audio
->processingSource
->src
.active
)
1397 FAudio_INTERNAL_MixSource(audio
->processingSource
);
1398 FAudio_INTERNAL_FlushPendingBuffers(audio
->processingSource
);
1403 audio
->processingSource
= NULL
;
1404 FAudio_PlatformUnlockMutex(audio
->sourceLock
);
1405 LOG_MUTEX_UNLOCK(audio
, audio
->sourceLock
)
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
)
1413 FAudio_INTERNAL_MixSubmix((FAudioSubmixVoice
*) list
->entry
);
1416 FAudio_PlatformUnlockMutex(audio
->submixLock
);
1417 LOG_MUTEX_UNLOCK(audio
, audio
->submixLock
)
1419 /* Apply master volume */
1420 if (audio
->master
->volume
!= 1.0f
)
1422 FAudio_INTERNAL_Amplify(
1423 audio
->master
->master
.output
,
1424 audio
->updateSize
* audio
->master
->master
.inputChannels
,
1425 audio
->master
->volume
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)
1434 totalSamples
= audio
->updateSize
;
1435 effectOut
= FAudio_INTERNAL_ProcessEffectChain(
1437 audio
->master
->master
.output
,
1441 if (effectOut
!= output
)
1446 totalSamples
* audio
->master
->outputChannels
* sizeof(float)
1449 if (totalSamples
< audio
->updateSize
)
1452 output
+ (totalSamples
* audio
->master
->outputChannels
),
1453 (audio
->updateSize
- totalSamples
) * sizeof(float)
1457 FAudio_PlatformUnlockMutex(audio
->master
->effectLock
);
1458 LOG_MUTEX_UNLOCK(audio
, audio
->master
->effectLock
)
1460 /* OnProcessingPassEnd callbacks */
1461 FAudio_PlatformLockMutex(audio
->callbackLock
);
1462 LOG_MUTEX_LOCK(audio
, audio
->callbackLock
)
1463 list
= audio
->callbacks
;
1464 while (list
!= NULL
)
1466 callback
= (FAudioEngineCallback
*) list
->entry
;
1467 if (callback
->OnProcessingPassEnd
!= NULL
)
1469 callback
->OnProcessingPassEnd(
1475 FAudio_PlatformUnlockMutex(audio
->callbackLock
);
1476 LOG_MUTEX_UNLOCK(audio
, audio
->callbackLock
)
1478 LOG_FUNC_EXIT(audio
)
1481 void FAudio_INTERNAL_UpdateEngine(FAudio
*audio
, float *output
)
1483 LOG_FUNC_ENTER(audio
)
1484 if (audio
->pClientEngineProc
)
1486 audio
->pClientEngineProc(
1487 &FAudio_INTERNAL_GenerateOutput
,
1490 audio
->clientEngineUser
1495 FAudio_INTERNAL_GenerateOutput(audio
, output
);
1497 LOG_FUNC_EXIT(audio
)
1500 void FAudio_INTERNAL_ResizeDecodeCache(FAudio
*audio
, uint32_t samples
)
1502 LOG_FUNC_ENTER(audio
)
1503 FAudio_PlatformLockMutex(audio
->sourceLock
);
1504 LOG_MUTEX_LOCK(audio
, audio
->sourceLock
)
1505 if (samples
> audio
->decodeSamples
)
1507 audio
->decodeSamples
= samples
;
1508 audio
->decodeCache
= (float*) audio
->pRealloc(
1510 sizeof(float) * audio
->decodeSamples
1513 FAudio_PlatformUnlockMutex(audio
->sourceLock
);
1514 LOG_MUTEX_UNLOCK(audio
, audio
->sourceLock
)
1515 LOG_FUNC_EXIT(audio
)
1518 void FAudio_INTERNAL_AllocEffectChain(
1520 const FAudioEffectChain
*pEffectChain
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)
1529 LOG_FUNC_EXIT(voice
->audio
)
1533 for (i
= 0; i
< pEffectChain
->EffectCount
; i
+= 1)
1535 pEffectChain
->pEffectDescriptors
[i
].pEffect
->AddRef(pEffectChain
->pEffectDescriptors
[i
].pEffect
);
1538 voice
->effects
.desc
= (FAudioEffectDescriptor
*) voice
->audio
->pMalloc(
1539 voice
->effects
.count
* sizeof(FAudioEffectDescriptor
)
1542 voice
->effects
.desc
,
1543 pEffectChain
->pEffectDescriptors
,
1544 voice
->effects
.count
* sizeof(FAudioEffectDescriptor
)
1546 #define ALLOC_EFFECT_PROPERTY(prop, type) \
1547 voice->effects.prop = (type*) voice->audio->pMalloc( \
1548 voice->effects.count * sizeof(type) \
1551 voice->effects.prop, \
1552 voice->effects.count * sizeof(type) \
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
)
1562 void FAudio_INTERNAL_FreeEffectChain(FAudioVoice
*voice
)
1566 LOG_FUNC_ENTER(voice
->audio
)
1567 if (voice
->effects
.count
== 0)
1569 LOG_FUNC_EXIT(voice
->audio
)
1573 for (i
= 0; i
< voice
->effects
.count
; i
+= 1)
1575 voice
->effects
.desc
[i
].pEffect
->UnlockForProcess(voice
->effects
.desc
[i
].pEffect
);
1576 voice
->effects
.desc
[i
].pEffect
->Release(voice
->effects
.desc
[i
].pEffect
);
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
)
1587 uint32_t FAudio_INTERNAL_VoiceOutputFrequency(
1589 const FAudioVoiceSends
*pSendList
1591 uint32_t outSampleRate
;
1592 uint32_t newResampleSamples
;
1593 uint64_t resampleSanityCheck
;
1595 LOG_FUNC_ENTER(voice
->audio
)
1597 if ((pSendList
== NULL
) || (pSendList
->SendCount
== 0))
1599 /* When we're deliberately given no sends, use master rate! */
1600 outSampleRate
= voice
->audio
->master
->master
.inputSampleRate
;
1604 outSampleRate
= pSendList
->pSends
[0].pOutputVoice
->type
== FAUDIO_VOICE_MASTER
?
1605 pSendList
->pSends
[0].pOutputVoice
->master
.inputSampleRate
:
1606 pSendList
->pSends
[0].pOutputVoice
->mix
.inputSampleRate
;
1608 newResampleSamples
= (uint32_t) FAudio_ceil(
1609 voice
->audio
->updateSize
*
1610 (double) outSampleRate
/
1611 (double) voice
->audio
->master
->master
.inputSampleRate
1613 if (voice
->type
== FAUDIO_VOICE_SOURCE
)
1615 if ( (voice
->src
.resampleSamples
!= 0) &&
1616 (newResampleSamples
!= voice
->src
.resampleSamples
) &&
1617 (voice
->effects
.count
> 0) )
1619 LOG_FUNC_EXIT(voice
->audio
)
1620 return FAUDIO_E_INVALID_CALL
;
1622 voice
->src
.resampleSamples
= newResampleSamples
;
1624 else /* (voice->type == FAUDIO_VOICE_SUBMIX) */
1626 if ( (voice
->mix
.outputSamples
!= 0) &&
1627 (newResampleSamples
!= voice
->mix
.outputSamples
) &&
1628 (voice
->effects
.count
> 0) )
1630 LOG_FUNC_EXIT(voice
->audio
)
1631 return FAUDIO_E_INVALID_CALL
;
1633 voice
->mix
.outputSamples
= newResampleSamples
;
1635 voice
->mix
.resampleStep
= DOUBLE_TO_FIXED((
1636 (double) voice
->mix
.inputSampleRate
/
1637 (double) outSampleRate
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.
1647 resampleSanityCheck
= (
1648 voice
->mix
.resampleStep
* voice
->mix
.outputSamples
1649 ) >> FIXED_PRECISION
;
1650 if (resampleSanityCheck
> (voice
->mix
.inputSamples
/ voice
->mix
.inputChannels
))
1652 voice
->mix
.outputSamples
-= 1;
1656 LOG_FUNC_EXIT(voice
->audio
)
1660 const float FAUDIO_INTERNAL_MATRIX_DEFAULTS
[8][8][64] =
1662 #include "matrix_defaults.inl"
1667 void FAudio_INTERNAL_DecodePCM8(
1669 FAudioBuffer
*buffer
,
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
1679 samples
* voice
->src
.format
->nChannels
1681 LOG_FUNC_EXIT(voice
->audio
)
1684 void FAudio_INTERNAL_DecodePCM16(
1686 FAudioBuffer
*buffer
,
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
1696 samples
* voice
->src
.format
->nChannels
1698 LOG_FUNC_EXIT(voice
->audio
)
1701 void FAudio_INTERNAL_DecodePCM24(
1703 FAudioBuffer
*buffer
,
1709 LOG_FUNC_ENTER(voice
->audio
)
1711 /* FIXME: Uh... is this something that can be SIMD-ified? */
1712 buf
= buffer
->pAudioData
+ (
1713 voice
->src
.curBufferOffset
* voice
->src
.format
->nBlockAlign
1715 for (i
= 0; i
< samples
; i
+= 1, buf
+= voice
->src
.format
->nBlockAlign
)
1716 for (j
= 0; j
< voice
->src
.format
->nChannels
; j
+= 1)
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
;
1725 LOG_FUNC_EXIT(voice
->audio
)
1728 void FAudio_INTERNAL_DecodePCM32(
1730 FAudioBuffer
*buffer
,
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
1740 samples
* voice
->src
.format
->nChannels
1742 LOG_FUNC_EXIT(voice
->audio
)
1745 void FAudio_INTERNAL_DecodePCM32F(
1747 FAudioBuffer
*buffer
,
1751 LOG_FUNC_ENTER(voice
->audio
)
1754 ((float*) buffer
->pAudioData
) + (
1755 voice
->src
.curBufferOffset
* voice
->src
.format
->nChannels
1757 sizeof(float) * samples
* voice
->src
.format
->nChannels
1759 LOG_FUNC_EXIT(voice
->audio
)
1762 /* MSADPCM Decoding */
1764 static inline int16_t FAudio_INTERNAL_ParseNibble(
1771 static const int32_t AdaptionTable
[16] =
1773 230, 230, 230, 230, 307, 409, 512, 614,
1774 768, 614, 512, 409, 307, 230, 230, 230
1776 static const int32_t AdaptCoeff_1
[7] =
1778 256, 512, 0, 192, 240, 460, 392
1780 static const int32_t AdaptCoeff_2
[7] =
1782 0, -256, 0, 64, 0, -208, -232
1785 int8_t signedNibble
;
1789 signedNibble
= (int8_t) nibble
;
1790 if (signedNibble
& 0x08)
1792 signedNibble
-= 0x10;
1796 (*sample1
* AdaptCoeff_1
[predictor
]) +
1797 (*sample2
* AdaptCoeff_2
[predictor
])
1799 sampleInt
+= signedNibble
* (*delta
);
1800 sample
= FAudio_clamp(sampleInt
, -32768, 32767);
1802 *sample2
= *sample1
;
1804 *delta
= (int16_t) (AdaptionTable
[nibble
] * (int32_t) (*delta
) / 256);
1812 #define READ(item, type) \
1813 item = *((type*) *buf); \
1814 *buf += sizeof(type);
1816 static inline void FAudio_INTERNAL_DecodeMonoMSADPCMBlock(
1818 int16_t *blockCache
,
1823 /* Temp storage for ADPCM blocks */
1830 READ(predictor
, uint8_t)
1831 READ(delta
, int16_t)
1832 READ(sample1
, int16_t)
1833 READ(sample2
, int16_t)
1837 *blockCache
++ = sample2
;
1838 *blockCache
++ = sample1
;
1839 for (i
= 0; i
< align
; i
+= 1, *buf
+= 1)
1841 *blockCache
++ = FAudio_INTERNAL_ParseNibble(
1848 *blockCache
++ = FAudio_INTERNAL_ParseNibble(
1858 static inline void FAudio_INTERNAL_DecodeStereoMSADPCMBlock(
1860 int16_t *blockCache
,
1865 /* Temp storage for ADPCM blocks */
1866 uint8_t l_predictor
;
1867 uint8_t r_predictor
;
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)
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)
1893 *blockCache
++ = FAudio_INTERNAL_ParseNibble(
1900 *blockCache
++ = FAudio_INTERNAL_ParseNibble(
1912 void FAudio_INTERNAL_DecodeMonoMSADPCM(
1914 FAudioBuffer
*buffer
,
1918 /* Loop variables */
1919 uint32_t copy
, done
= 0;
1925 /* PCM block cache */
1926 int16_t *blockCache
;
1929 uint32_t bsize
= ((FAudioADPCMWaveFormat
*) voice
->src
.format
)->wSamplesPerBlock
;
1931 LOG_FUNC_ENTER(voice
->audio
)
1933 /* Where are we starting? */
1934 buf
= (uint8_t*) buffer
->pAudioData
+ (
1935 (voice
->src
.curBufferOffset
/ bsize
) *
1936 voice
->src
.format
->nBlockAlign
1939 /* Are we starting in the middle? */
1940 midOffset
= (voice
->src
.curBufferOffset
% bsize
);
1942 /* Read in each block directly to the decode cache */
1943 blockCache
= (int16_t*) FAudio_alloca(bsize
* sizeof(int16_t));
1944 while (done
< samples
)
1946 copy
= FAudio_min(samples
- done
, bsize
- midOffset
);
1947 FAudio_INTERNAL_DecodeMonoMSADPCMBlock(
1950 voice
->src
.format
->nBlockAlign
1952 FAudio_INTERNAL_Convert_S16_To_F32(
1953 blockCache
+ midOffset
,
1957 decodeCache
+= copy
;
1961 FAudio_dealloca(blockCache
);
1962 LOG_FUNC_EXIT(voice
->audio
)
1965 void FAudio_INTERNAL_DecodeStereoMSADPCM(
1967 FAudioBuffer
*buffer
,
1971 /* Loop variables */
1972 uint32_t copy
, done
= 0;
1978 /* PCM block cache */
1979 int16_t *blockCache
;
1981 /* Align, block size */
1982 uint32_t bsize
= ((FAudioADPCMWaveFormat
*) voice
->src
.format
)->wSamplesPerBlock
;
1984 LOG_FUNC_ENTER(voice
->audio
)
1986 /* Where are we starting? */
1987 buf
= (uint8_t*) buffer
->pAudioData
+ (
1988 (voice
->src
.curBufferOffset
/ bsize
) *
1989 voice
->src
.format
->nBlockAlign
1992 /* Are we starting in the middle? */
1993 midOffset
= (voice
->src
.curBufferOffset
% bsize
);
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
)
1999 copy
= FAudio_min(samples
- done
, bsize
- midOffset
);
2000 FAudio_INTERNAL_DecodeStereoMSADPCMBlock(
2003 voice
->src
.format
->nBlockAlign
2005 FAudio_INTERNAL_Convert_S16_To_F32(
2006 blockCache
+ (midOffset
* 2),
2010 decodeCache
+= copy
* 2;
2014 FAudio_dealloca(blockCache
);
2015 LOG_FUNC_EXIT(voice
->audio
)
2018 /* Fallback WMA decoder, get ready for spam! */
2020 void FAudio_INTERNAL_DecodeWMAERROR(
2022 FAudioBuffer
*buffer
,
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
)
2032 /* vim: set noexpandtab shiftwidth=8 tabstop=8: */