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
->audio
->sourceLock
);
387 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
389 voice
->src
.callback
->OnBufferStart(
394 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
395 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
399 /* Check for end-of-buffer */
400 end
= (buffer
->LoopCount
> 0) ?
401 (buffer
->LoopBegin
+ buffer
->LoopLength
) :
402 buffer
->PlayBegin
+ buffer
->PlayLength
;
403 endRead
= FAudio_min(
404 end
- voice
->src
.curBufferOffset
,
412 voice
->audio
->decodeCache
+ (
413 decoded
* voice
->src
.format
->nChannels
420 "Voice %p, buffer %p, decoded %u samples from [%u,%u)",
424 voice
->src
.curBufferOffset
,
425 voice
->src
.curBufferOffset
+ endRead
429 voice
->src
.curBufferOffset
+= endRead
;
430 voice
->src
.totalSamples
+= endRead
;
432 /* End-of-buffer behavior */
433 if (endRead
< decoding
)
435 if (buffer
->LoopCount
> 0)
437 voice
->src
.curBufferOffset
= buffer
->LoopBegin
;
438 if (buffer
->LoopCount
< FAUDIO_LOOP_INFINITE
)
440 buffer
->LoopCount
-= 1;
442 if ( voice
->src
.callback
!= NULL
&&
443 voice
->src
.callback
->OnLoopEnd
!= NULL
)
445 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
446 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
448 voice
->src
.callback
->OnLoopEnd(
453 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
454 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
460 if (voice
->src
.wmadec
!= NULL
)
462 FAudio_WMADEC_end_buffer(voice
);
464 #endif /* HAVE_WMADEC */
465 /* For EOS we can stop storing fraction offsets */
466 if (buffer
->Flags
& FAUDIO_END_OF_STREAM
)
468 voice
->src
.curBufferOffsetDec
= 0;
469 voice
->src
.totalSamples
= 0;
474 "Voice %p, finished with buffer %p",
479 /* Change active buffer, delete finished buffer */
480 toDelete
= voice
->src
.bufferList
;
481 voice
->src
.bufferList
= voice
->src
.bufferList
->next
;
482 if (voice
->src
.bufferList
!= NULL
)
484 buffer
= &voice
->src
.bufferList
->buffer
;
485 voice
->src
.curBufferOffset
= buffer
->PlayBegin
;
491 /* FIXME: I keep going past the buffer so fuck it */
493 voice
->audio
->decodeCache
+ (
495 voice
->src
.format
->nChannels
498 (*toDecode
- decoded
) *
499 voice
->src
.format
->nChannels
505 if (voice
->src
.callback
!= NULL
)
507 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
508 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
510 if (voice
->src
.callback
->OnBufferEnd
!= NULL
)
512 voice
->src
.callback
->OnBufferEnd(
514 toDelete
->buffer
.pContext
517 if ( toDelete
->buffer
.Flags
& FAUDIO_END_OF_STREAM
&&
518 voice
->src
.callback
->OnStreamEnd
!= NULL
)
520 voice
->src
.callback
->OnStreamEnd(
525 /* One last chance at redemption */
526 if (buffer
== NULL
&& voice
->src
.bufferList
!= NULL
)
528 buffer
= &voice
->src
.bufferList
->buffer
;
529 voice
->src
.curBufferOffset
= buffer
->PlayBegin
;
532 if (buffer
!= NULL
&& voice
->src
.callback
->OnBufferStart
!= NULL
)
534 voice
->src
.callback
->OnBufferStart(
540 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
541 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
544 voice
->audio
->pFree(toDelete
);
549 /* ... FIXME: I keep going past the buffer so fuck it */
552 end
= (buffer
->LoopCount
> 0) ?
553 (buffer
->LoopBegin
+ buffer
->LoopLength
) :
554 buffer
->PlayBegin
+ buffer
->PlayLength
;
555 endRead
= FAudio_min(
556 end
- voice
->src
.curBufferOffset
,
563 voice
->audio
->decodeCache
+ (
564 decoded
* voice
->src
.format
->nChannels
568 /* Do NOT increment curBufferOffset! */
570 if (endRead
< EXTRA_DECODE_PADDING
)
573 voice
->audio
->decodeCache
+ (
574 decoded
* voice
->src
.format
->nChannels
577 (EXTRA_DECODE_PADDING
- endRead
) *
578 voice
->src
.format
->nChannels
586 voice
->audio
->decodeCache
+ (
587 decoded
* voice
->src
.format
->nChannels
590 EXTRA_DECODE_PADDING
*
591 voice
->src
.format
->nChannels
597 LOG_FUNC_EXIT(voice
->audio
)
600 static inline void FAudio_INTERNAL_FilterVoice(
602 const FAudioFilterParametersEXT
*filter
,
603 FAudioFilterState
*filterState
,
610 LOG_FUNC_ENTER(audio
)
612 /* Apply a digital state-variable filter to the voice.
613 * The difference equations of the filter are:
615 * Yl(n) = F Yb(n - 1) + Yl(n - 1)
616 * Yh(n) = x(n) - Yl(n) - OneOverQ Yb(n - 1)
617 * Yb(n) = F Yh(n) + Yb(n - 1)
618 * Yn(n) = Yl(n) + Yh(n)
620 * Please note that FAudioFilterParameters.Frequency is defined as:
622 * (2 * sin(pi * (desired filter cutoff frequency) / sampleRate))
627 for (j
= 0; j
< numSamples
; j
+= 1)
628 for (ci
= 0; ci
< numChannels
; ci
+= 1)
630 filterState
[ci
][FAudioLowPassFilter
] = filterState
[ci
][FAudioLowPassFilter
] + (filter
->Frequency
* filterState
[ci
][FAudioBandPassFilter
]);
631 filterState
[ci
][FAudioHighPassFilter
] = samples
[j
* numChannels
+ ci
] - filterState
[ci
][FAudioLowPassFilter
] - (filter
->OneOverQ
* filterState
[ci
][FAudioBandPassFilter
]);
632 filterState
[ci
][FAudioBandPassFilter
] = (filter
->Frequency
* filterState
[ci
][FAudioHighPassFilter
]) + filterState
[ci
][FAudioBandPassFilter
];
633 filterState
[ci
][FAudioNotchFilter
] = filterState
[ci
][FAudioHighPassFilter
] + filterState
[ci
][FAudioLowPassFilter
];
634 samples
[j
* numChannels
+ ci
] = filterState
[ci
][filter
->Type
] * filter
->WetDryMix
+ samples
[j
* numChannels
+ ci
] * (1.0 - filter
->WetDryMix
);
640 static void FAudio_INTERNAL_ResizeEffectChainCache(FAudio
*audio
, uint32_t samples
)
642 LOG_FUNC_ENTER(audio
)
643 if (samples
> audio
->effectChainSamples
)
645 audio
->effectChainSamples
= samples
;
646 audio
->effectChainCache
= (float*) audio
->pRealloc(
647 audio
->effectChainCache
,
648 sizeof(float) * audio
->effectChainSamples
654 static inline float *FAudio_INTERNAL_ProcessEffectChain(
661 FAPOProcessBufferParameters srcParams
, dstParams
;
663 LOG_FUNC_ENTER(voice
->audio
)
665 /* Set up the buffer to be written into */
666 srcParams
.pBuffer
= buffer
;
667 srcParams
.BufferFlags
= FAPO_BUFFER_SILENT
;
668 srcParams
.ValidFrameCount
= *samples
;
669 for (i
= 0; i
< srcParams
.ValidFrameCount
; i
+= 1)
671 if (buffer
[i
] != 0.0f
) /* Arbitrary! */
673 srcParams
.BufferFlags
= FAPO_BUFFER_VALID
;
678 /* Initialize output parameters to something sane */
679 dstParams
.pBuffer
= srcParams
.pBuffer
;
680 dstParams
.BufferFlags
= FAPO_BUFFER_VALID
;
681 dstParams
.ValidFrameCount
= srcParams
.ValidFrameCount
;
683 /* Update parameters, process! */
684 for (i
= 0; i
< voice
->effects
.count
; i
+= 1)
686 fapo
= voice
->effects
.desc
[i
].pEffect
;
688 if (!voice
->effects
.inPlaceProcessing
[i
])
690 if (dstParams
.pBuffer
== buffer
)
692 FAudio_INTERNAL_ResizeEffectChainCache(
694 voice
->effects
.desc
[i
].OutputChannels
* srcParams
.ValidFrameCount
696 dstParams
.pBuffer
= voice
->audio
->effectChainCache
;
700 /* FIXME: What if this is smaller because
701 * inputChannels < desc[i].OutputChannels?
703 dstParams
.pBuffer
= buffer
;
708 voice
->effects
.desc
[i
].OutputChannels
* srcParams
.ValidFrameCount
* sizeof(float)
712 if (voice
->effects
.parameterUpdates
[i
])
716 voice
->effects
.parameters
[i
],
717 voice
->effects
.parameterSizes
[i
]
719 voice
->effects
.parameterUpdates
[i
] = 0;
728 voice
->effects
.desc
[i
].InitialState
731 FAudio_memcpy(&srcParams
, &dstParams
, sizeof(dstParams
));
734 *samples
= dstParams
.ValidFrameCount
;
736 /* Save the output buffer-flags so the mixer-function can determine when it's save to stop processing the effect chain */
737 voice
->effects
.state
= dstParams
.BufferFlags
;
739 LOG_FUNC_EXIT(voice
->audio
)
740 return (float*) dstParams
.pBuffer
;
743 static void FAudio_INTERNAL_ResizeResampleCache(FAudio
*audio
, uint32_t samples
)
745 LOG_FUNC_ENTER(audio
)
746 if (samples
> audio
->resampleSamples
)
748 audio
->resampleSamples
= samples
;
749 audio
->resampleCache
= (float*) audio
->pRealloc(
750 audio
->resampleCache
,
751 sizeof(float) * audio
->resampleSamples
757 static void FAudio_INTERNAL_MixSource(FAudioSourceVoice
*voice
)
761 /* Decode/Resample variables */
764 /* Output mix variables */
773 LOG_FUNC_ENTER(voice
->audio
)
775 FAudio_PlatformLockMutex(voice
->sendLock
);
776 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
778 /* Calculate the resample stepping value */
779 if (voice
->src
.resampleFreq
!= voice
->src
.freqRatio
* voice
->src
.format
->nSamplesPerSec
)
781 out
= (voice
->sends
.SendCount
== 0) ?
782 voice
->audio
->master
: /* Barf */
783 voice
->sends
.pSends
->pOutputVoice
;
784 outputRate
= (out
->type
== FAUDIO_VOICE_MASTER
) ?
785 out
->master
.inputSampleRate
:
786 out
->mix
.inputSampleRate
;
788 voice
->src
.freqRatio
*
789 (double) voice
->src
.format
->nSamplesPerSec
/
792 voice
->src
.resampleStep
= DOUBLE_TO_FIXED(stepd
);
793 voice
->src
.resampleFreq
= voice
->src
.freqRatio
* voice
->src
.format
->nSamplesPerSec
;
796 if (voice
->src
.active
== 2)
798 /* We're just playing tails, skip all buffer stuff */
799 FAudio_INTERNAL_ResizeResampleCache(
801 voice
->src
.resampleSamples
* voice
->src
.format
->nChannels
803 mixed
= voice
->src
.resampleSamples
;
805 voice
->audio
->resampleCache
,
806 mixed
* voice
->src
.format
->nChannels
* sizeof(float)
808 finalSamples
= voice
->audio
->resampleCache
;
812 /* Base decode size, int to fixed... */
813 toDecode
= voice
->src
.resampleSamples
* voice
->src
.resampleStep
;
814 /* ... rounded up based on current offset... */
815 toDecode
+= voice
->src
.curBufferOffsetDec
+ FIXED_FRACTION_MASK
;
816 /* ... fixed to int, truncating extra fraction from rounding. */
817 toDecode
>>= FIXED_PRECISION
;
819 /* First voice callback */
820 if ( voice
->src
.callback
!= NULL
&&
821 voice
->src
.callback
->OnVoiceProcessingPassStart
!= NULL
)
823 FAudio_PlatformUnlockMutex(voice
->sendLock
);
824 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
826 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
827 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
829 voice
->src
.callback
->OnVoiceProcessingPassStart(
831 FAudio_INTERNAL_GetBytesRequested(voice
, (uint32_t) toDecode
)
834 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
835 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
837 FAudio_PlatformLockMutex(voice
->sendLock
);
838 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
841 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
842 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
845 if (voice
->src
.bufferList
== NULL
)
847 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
848 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
850 if (voice
->effects
.count
> 0 && voice
->effects
.state
!= FAPO_BUFFER_SILENT
)
852 /* do not stop while the effect chain generates a non-silent buffer */
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 FAudio_PlatformUnlockMutex(voice
->sendLock
);
867 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
869 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
870 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
872 if ( voice
->src
.callback
!= NULL
&&
873 voice
->src
.callback
->OnVoiceProcessingPassEnd
!= NULL
)
875 voice
->src
.callback
->OnVoiceProcessingPassEnd(
880 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
881 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
883 LOG_FUNC_EXIT(voice
->audio
)
888 FAudio_INTERNAL_DecodeBuffers(voice
, &toDecode
);
890 /* Subtract any padding samples from the total, if applicable */
891 if ( voice
->src
.curBufferOffsetDec
> 0 &&
892 voice
->src
.totalSamples
> 0 )
894 voice
->src
.totalSamples
-= 1;
897 /* Okay, we're done messing with client data */
898 if ( voice
->src
.callback
!= NULL
&&
899 voice
->src
.callback
->OnVoiceProcessingPassEnd
!= NULL
)
901 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
902 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
904 FAudio_PlatformUnlockMutex(voice
->sendLock
);
905 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
907 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
908 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
910 voice
->src
.callback
->OnVoiceProcessingPassEnd(
914 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
915 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
917 FAudio_PlatformLockMutex(voice
->sendLock
);
918 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
920 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
921 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
924 /* Nothing to resample? */
927 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
928 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
930 FAudio_PlatformUnlockMutex(voice
->sendLock
);
931 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
933 LOG_FUNC_EXIT(voice
->audio
)
937 /* int to fixed... */
938 toResample
= toDecode
<< FIXED_PRECISION
;
939 /* ... round back down based on current offset... */
940 toResample
-= voice
->src
.curBufferOffsetDec
;
941 /* ... but also ceil for any fraction value... */
942 toResample
+= FIXED_FRACTION_MASK
;
943 /* ... undo step size, fixed to int. */
944 toResample
/= voice
->src
.resampleStep
;
945 /* Add the padding, for some reason this helps? */
946 toResample
+= EXTRA_DECODE_PADDING
;
947 /* FIXME: I feel like this should be an assert but I suck */
948 toResample
= FAudio_min(toResample
, voice
->src
.resampleSamples
);
951 if (voice
->src
.resampleStep
== FIXED_ONE
)
953 /* Actually, just use the existing buffer... */
954 finalSamples
= voice
->audio
->decodeCache
;
958 FAudio_INTERNAL_ResizeResampleCache(
960 voice
->src
.resampleSamples
* voice
->src
.format
->nChannels
963 voice
->audio
->decodeCache
,
964 voice
->audio
->resampleCache
,
965 &voice
->src
.resampleOffset
,
966 voice
->src
.resampleStep
,
968 (uint8_t) voice
->src
.format
->nChannels
970 finalSamples
= voice
->audio
->resampleCache
;
973 /* Update buffer offsets */
974 if (voice
->src
.bufferList
!= NULL
)
976 /* Increment fixed offset by resample size, int to fixed... */
977 voice
->src
.curBufferOffsetDec
+= toResample
* voice
->src
.resampleStep
;
978 /* ... chop off any ints we got from the above increment */
979 voice
->src
.curBufferOffsetDec
&= FIXED_FRACTION_MASK
;
981 /* Dec >0? We need one frame from the past...
982 * FIXME: We can't go back to a prev buffer though?
984 if ( voice
->src
.curBufferOffsetDec
> 0 &&
985 voice
->src
.curBufferOffset
> 0 )
987 voice
->src
.curBufferOffset
-= 1;
992 voice
->src
.curBufferOffsetDec
= 0;
993 voice
->src
.curBufferOffset
= 0;
996 /* Done with buffers, finally. */
997 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
998 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
999 mixed
= (uint32_t) toResample
;
1004 if (voice
->flags
& FAUDIO_VOICE_USEFILTER
)
1006 FAudio_PlatformLockMutex(voice
->filterLock
);
1007 LOG_MUTEX_LOCK(voice
->audio
, voice
->filterLock
)
1008 FAudio_INTERNAL_FilterVoice(
1014 voice
->src
.format
->nChannels
1016 FAudio_PlatformUnlockMutex(voice
->filterLock
);
1017 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->filterLock
)
1020 /* Process effect chain */
1021 FAudio_PlatformLockMutex(voice
->effectLock
);
1022 LOG_MUTEX_LOCK(voice
->audio
, voice
->effectLock
)
1023 if (voice
->effects
.count
> 0)
1025 /* If we didn't get the full size of the update, we have to fill
1026 * it with silence so the effect can process a whole update
1028 if (mixed
< voice
->src
.resampleSamples
)
1031 finalSamples
+ (mixed
* voice
->src
.format
->nChannels
),
1032 (voice
->src
.resampleSamples
- mixed
) * voice
->src
.format
->nChannels
* sizeof(float)
1034 mixed
= voice
->src
.resampleSamples
;
1036 finalSamples
= FAudio_INTERNAL_ProcessEffectChain(
1042 FAudio_PlatformUnlockMutex(voice
->effectLock
);
1043 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->effectLock
)
1045 /* Nowhere to send it? Just skip the rest...*/
1046 if (voice
->sends
.SendCount
== 0)
1048 FAudio_PlatformUnlockMutex(voice
->sendLock
);
1049 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
1050 LOG_FUNC_EXIT(voice
->audio
)
1054 /* Send float cache to sends */
1055 FAudio_PlatformLockMutex(voice
->volumeLock
);
1056 LOG_MUTEX_LOCK(voice
->audio
, voice
->volumeLock
)
1057 for (i
= 0; i
< voice
->sends
.SendCount
; i
+= 1)
1059 out
= voice
->sends
.pSends
[i
].pOutputVoice
;
1060 if (out
->type
== FAUDIO_VOICE_MASTER
)
1062 stream
= out
->master
.output
;
1063 oChan
= out
->master
.inputChannels
;
1067 stream
= out
->mix
.inputCache
;
1068 oChan
= out
->mix
.inputChannels
;
1073 voice
->outputChannels
,
1077 voice
->mixCoefficients
[i
]
1080 if (voice
->sends
.pSends
[i
].Flags
& FAUDIO_SEND_USEFILTER
)
1082 FAudio_INTERNAL_FilterVoice(
1084 &voice
->sendFilter
[i
],
1085 voice
->sendFilterState
[i
],
1092 FAudio_PlatformUnlockMutex(voice
->volumeLock
);
1093 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->volumeLock
)
1095 FAudio_PlatformUnlockMutex(voice
->sendLock
);
1096 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
1097 LOG_FUNC_EXIT(voice
->audio
)
1100 static void FAudio_INTERNAL_MixSubmix(FAudioSubmixVoice
*voice
)
1107 uint64_t resampleOffset
= 0;
1108 float *finalSamples
;
1110 LOG_FUNC_ENTER(voice
->audio
)
1111 FAudio_PlatformLockMutex(voice
->sendLock
);
1112 LOG_MUTEX_LOCK(voice
->audio
, voice
->sendLock
)
1115 if (voice
->mix
.resampleStep
== FIXED_ONE
)
1117 /* Actually, just use the existing buffer... */
1118 finalSamples
= voice
->mix
.inputCache
;
1122 FAudio_INTERNAL_ResizeResampleCache(
1124 voice
->mix
.outputSamples
* voice
->mix
.inputChannels
1126 voice
->mix
.resample(
1127 voice
->mix
.inputCache
,
1128 voice
->audio
->resampleCache
,
1130 voice
->mix
.resampleStep
,
1131 voice
->mix
.outputSamples
,
1132 (uint8_t) voice
->mix
.inputChannels
1134 finalSamples
= voice
->audio
->resampleCache
;
1136 resampled
= voice
->mix
.outputSamples
* voice
->mix
.inputChannels
;
1138 /* Submix overall volume is applied _before_ effects/filters, blech! */
1139 if (voice
->volume
!= 1.0f
)
1141 FAudio_INTERNAL_Amplify(
1147 resampled
/= voice
->mix
.inputChannels
;
1150 if (voice
->flags
& FAUDIO_VOICE_USEFILTER
)
1152 FAudio_PlatformLockMutex(voice
->filterLock
);
1153 LOG_MUTEX_LOCK(voice
->audio
, voice
->filterLock
)
1154 FAudio_INTERNAL_FilterVoice(
1160 voice
->mix
.inputChannels
1162 FAudio_PlatformUnlockMutex(voice
->filterLock
);
1163 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->filterLock
)
1166 /* Process effect chain */
1167 FAudio_PlatformLockMutex(voice
->effectLock
);
1168 LOG_MUTEX_LOCK(voice
->audio
, voice
->effectLock
)
1169 if (voice
->effects
.count
> 0)
1171 finalSamples
= FAudio_INTERNAL_ProcessEffectChain(
1177 FAudio_PlatformUnlockMutex(voice
->effectLock
);
1178 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->effectLock
)
1180 /* Nothing more to do? */
1181 if (voice
->sends
.SendCount
== 0)
1186 /* Send float cache to sends */
1187 FAudio_PlatformLockMutex(voice
->volumeLock
);
1188 LOG_MUTEX_LOCK(voice
->audio
, voice
->volumeLock
)
1189 for (i
= 0; i
< voice
->sends
.SendCount
; i
+= 1)
1191 out
= voice
->sends
.pSends
[i
].pOutputVoice
;
1192 if (out
->type
== FAUDIO_VOICE_MASTER
)
1194 stream
= out
->master
.output
;
1195 oChan
= out
->master
.inputChannels
;
1199 stream
= out
->mix
.inputCache
;
1200 oChan
= out
->mix
.inputChannels
;
1205 voice
->outputChannels
,
1209 voice
->mixCoefficients
[i
]
1212 if (voice
->sends
.pSends
[i
].Flags
& FAUDIO_SEND_USEFILTER
)
1214 FAudio_INTERNAL_FilterVoice(
1216 &voice
->sendFilter
[i
],
1217 voice
->sendFilterState
[i
],
1224 FAudio_PlatformUnlockMutex(voice
->volumeLock
);
1225 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->volumeLock
)
1227 /* Zero this at the end, for the next update */
1229 FAudio_PlatformUnlockMutex(voice
->sendLock
);
1230 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->sendLock
)
1232 voice
->mix
.inputCache
,
1233 sizeof(float) * voice
->mix
.inputSamples
1235 LOG_FUNC_EXIT(voice
->audio
)
1238 static void FAudio_INTERNAL_FlushPendingBuffers(FAudioSourceVoice
*voice
)
1240 FAudioBufferEntry
*entry
;
1242 FAudio_PlatformLockMutex(voice
->src
.bufferLock
);
1243 LOG_MUTEX_LOCK(voice
->audio
, voice
->src
.bufferLock
)
1245 /* Remove pending flushed buffers and send an event for each one */
1246 while (voice
->src
.flushList
!= NULL
)
1248 entry
= voice
->src
.flushList
;
1249 voice
->src
.flushList
= voice
->src
.flushList
->next
;
1251 if (voice
->src
.callback
!= NULL
&& voice
->src
.callback
->OnBufferEnd
!= NULL
)
1253 FAudio_PlatformUnlockMutex(voice
->audio
->sourceLock
);
1254 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->audio
->sourceLock
)
1256 voice
->src
.callback
->OnBufferEnd(
1257 voice
->src
.callback
,
1258 entry
->buffer
.pContext
1261 FAudio_PlatformLockMutex(voice
->audio
->sourceLock
);
1262 LOG_MUTEX_LOCK(voice
->audio
, voice
->audio
->sourceLock
)
1264 voice
->audio
->pFree(entry
);
1267 FAudio_PlatformUnlockMutex(voice
->src
.bufferLock
);
1268 LOG_MUTEX_UNLOCK(voice
->audio
, voice
->src
.bufferLock
)
1271 static void FAUDIOCALL
FAudio_INTERNAL_GenerateOutput(FAudio
*audio
, float *output
)
1273 uint32_t totalSamples
;
1276 FAudioEngineCallback
*callback
;
1278 LOG_FUNC_ENTER(audio
)
1281 LOG_FUNC_EXIT(audio
)
1285 /* Apply any committed changes */
1286 FAudio_OPERATIONSET_Execute(audio
);
1288 /* ProcessingPassStart callbacks */
1289 FAudio_PlatformLockMutex(audio
->callbackLock
);
1290 LOG_MUTEX_LOCK(audio
, audio
->callbackLock
)
1291 list
= audio
->callbacks
;
1292 while (list
!= NULL
)
1294 callback
= (FAudioEngineCallback
*) list
->entry
;
1295 if (callback
->OnProcessingPassStart
!= NULL
)
1297 callback
->OnProcessingPassStart(
1303 FAudio_PlatformUnlockMutex(audio
->callbackLock
);
1304 LOG_MUTEX_UNLOCK(audio
, audio
->callbackLock
)
1306 /* Writes to master will directly write to output, but ONLY if there
1307 * isn't any channel-changing effect processing to do first.
1309 if (audio
->master
->master
.effectCache
!= NULL
)
1311 audio
->master
->master
.output
= audio
->master
->master
.effectCache
;
1313 audio
->master
->master
.effectCache
,
1317 audio
->master
->master
.inputChannels
1323 audio
->master
->master
.output
= output
;
1327 FAudio_PlatformLockMutex(audio
->sourceLock
);
1328 LOG_MUTEX_LOCK(audio
, audio
->sourceLock
)
1329 list
= audio
->sources
;
1330 while (list
!= NULL
)
1332 audio
->processingSource
= (FAudioSourceVoice
*) list
->entry
;
1334 FAudio_INTERNAL_FlushPendingBuffers(audio
->processingSource
);
1335 if (audio
->processingSource
->src
.active
)
1337 FAudio_INTERNAL_MixSource(audio
->processingSource
);
1338 FAudio_INTERNAL_FlushPendingBuffers(audio
->processingSource
);
1343 audio
->processingSource
= NULL
;
1344 FAudio_PlatformUnlockMutex(audio
->sourceLock
);
1345 LOG_MUTEX_UNLOCK(audio
, audio
->sourceLock
)
1347 /* Mix submixes, ordered by processing stage */
1348 FAudio_PlatformLockMutex(audio
->submixLock
);
1349 LOG_MUTEX_LOCK(audio
, audio
->submixLock
)
1350 list
= audio
->submixes
;
1351 while (list
!= NULL
)
1353 FAudio_INTERNAL_MixSubmix((FAudioSubmixVoice
*) list
->entry
);
1356 FAudio_PlatformUnlockMutex(audio
->submixLock
);
1357 LOG_MUTEX_UNLOCK(audio
, audio
->submixLock
)
1359 /* Apply master volume */
1360 if (audio
->master
->volume
!= 1.0f
)
1362 FAudio_INTERNAL_Amplify(
1363 audio
->master
->master
.output
,
1364 audio
->updateSize
* audio
->master
->master
.inputChannels
,
1365 audio
->master
->volume
1369 /* Process master effect chain */
1370 FAudio_PlatformLockMutex(audio
->master
->effectLock
);
1371 LOG_MUTEX_LOCK(audio
, audio
->master
->effectLock
)
1372 if (audio
->master
->effects
.count
> 0)
1374 totalSamples
= audio
->updateSize
;
1375 effectOut
= FAudio_INTERNAL_ProcessEffectChain(
1377 audio
->master
->master
.output
,
1381 if (effectOut
!= output
)
1386 totalSamples
* audio
->master
->outputChannels
* sizeof(float)
1389 if (totalSamples
< audio
->updateSize
)
1392 output
+ (totalSamples
* audio
->master
->outputChannels
),
1393 (audio
->updateSize
- totalSamples
) * sizeof(float)
1397 FAudio_PlatformUnlockMutex(audio
->master
->effectLock
);
1398 LOG_MUTEX_UNLOCK(audio
, audio
->master
->effectLock
)
1400 /* OnProcessingPassEnd callbacks */
1401 FAudio_PlatformLockMutex(audio
->callbackLock
);
1402 LOG_MUTEX_LOCK(audio
, audio
->callbackLock
)
1403 list
= audio
->callbacks
;
1404 while (list
!= NULL
)
1406 callback
= (FAudioEngineCallback
*) list
->entry
;
1407 if (callback
->OnProcessingPassEnd
!= NULL
)
1409 callback
->OnProcessingPassEnd(
1415 FAudio_PlatformUnlockMutex(audio
->callbackLock
);
1416 LOG_MUTEX_UNLOCK(audio
, audio
->callbackLock
)
1418 LOG_FUNC_EXIT(audio
)
1421 void FAudio_INTERNAL_UpdateEngine(FAudio
*audio
, float *output
)
1423 LOG_FUNC_ENTER(audio
)
1424 if (audio
->pClientEngineProc
)
1426 audio
->pClientEngineProc(
1427 &FAudio_INTERNAL_GenerateOutput
,
1430 audio
->clientEngineUser
1435 FAudio_INTERNAL_GenerateOutput(audio
, output
);
1437 LOG_FUNC_EXIT(audio
)
1440 void FAudio_INTERNAL_ResizeDecodeCache(FAudio
*audio
, uint32_t samples
)
1442 LOG_FUNC_ENTER(audio
)
1443 FAudio_PlatformLockMutex(audio
->sourceLock
);
1444 LOG_MUTEX_LOCK(audio
, audio
->sourceLock
)
1445 if (samples
> audio
->decodeSamples
)
1447 audio
->decodeSamples
= samples
;
1448 audio
->decodeCache
= (float*) audio
->pRealloc(
1450 sizeof(float) * audio
->decodeSamples
1453 FAudio_PlatformUnlockMutex(audio
->sourceLock
);
1454 LOG_MUTEX_UNLOCK(audio
, audio
->sourceLock
)
1455 LOG_FUNC_EXIT(audio
)
1458 void FAudio_INTERNAL_AllocEffectChain(
1460 const FAudioEffectChain
*pEffectChain
1464 LOG_FUNC_ENTER(voice
->audio
)
1465 voice
->effects
.state
= FAPO_BUFFER_VALID
;
1466 voice
->effects
.count
= pEffectChain
->EffectCount
;
1467 if (voice
->effects
.count
== 0)
1469 LOG_FUNC_EXIT(voice
->audio
)
1473 for (i
= 0; i
< pEffectChain
->EffectCount
; i
+= 1)
1475 pEffectChain
->pEffectDescriptors
[i
].pEffect
->AddRef(pEffectChain
->pEffectDescriptors
[i
].pEffect
);
1478 voice
->effects
.desc
= (FAudioEffectDescriptor
*) voice
->audio
->pMalloc(
1479 voice
->effects
.count
* sizeof(FAudioEffectDescriptor
)
1482 voice
->effects
.desc
,
1483 pEffectChain
->pEffectDescriptors
,
1484 voice
->effects
.count
* sizeof(FAudioEffectDescriptor
)
1486 #define ALLOC_EFFECT_PROPERTY(prop, type) \
1487 voice->effects.prop = (type*) voice->audio->pMalloc( \
1488 voice->effects.count * sizeof(type) \
1491 voice->effects.prop, \
1492 voice->effects.count * sizeof(type) \
1494 ALLOC_EFFECT_PROPERTY(parameters
, void*)
1495 ALLOC_EFFECT_PROPERTY(parameterSizes
, uint32_t)
1496 ALLOC_EFFECT_PROPERTY(parameterUpdates
, uint8_t)
1497 ALLOC_EFFECT_PROPERTY(inPlaceProcessing
, uint8_t)
1498 #undef ALLOC_EFFECT_PROPERTY
1499 LOG_FUNC_EXIT(voice
->audio
)
1502 void FAudio_INTERNAL_FreeEffectChain(FAudioVoice
*voice
)
1506 LOG_FUNC_ENTER(voice
->audio
)
1507 if (voice
->effects
.count
== 0)
1509 LOG_FUNC_EXIT(voice
->audio
)
1513 for (i
= 0; i
< voice
->effects
.count
; i
+= 1)
1515 voice
->effects
.desc
[i
].pEffect
->UnlockForProcess(voice
->effects
.desc
[i
].pEffect
);
1516 voice
->effects
.desc
[i
].pEffect
->Release(voice
->effects
.desc
[i
].pEffect
);
1519 voice
->audio
->pFree(voice
->effects
.desc
);
1520 voice
->audio
->pFree(voice
->effects
.parameters
);
1521 voice
->audio
->pFree(voice
->effects
.parameterSizes
);
1522 voice
->audio
->pFree(voice
->effects
.parameterUpdates
);
1523 voice
->audio
->pFree(voice
->effects
.inPlaceProcessing
);
1524 LOG_FUNC_EXIT(voice
->audio
)
1527 uint32_t FAudio_INTERNAL_VoiceOutputFrequency(
1529 const FAudioVoiceSends
*pSendList
1531 uint32_t outSampleRate
;
1532 uint32_t newResampleSamples
;
1533 uint64_t resampleSanityCheck
;
1535 LOG_FUNC_ENTER(voice
->audio
)
1537 if ((pSendList
== NULL
) || (pSendList
->SendCount
== 0))
1539 /* When we're deliberately given no sends, use master rate! */
1540 outSampleRate
= voice
->audio
->master
->master
.inputSampleRate
;
1544 outSampleRate
= pSendList
->pSends
[0].pOutputVoice
->type
== FAUDIO_VOICE_MASTER
?
1545 pSendList
->pSends
[0].pOutputVoice
->master
.inputSampleRate
:
1546 pSendList
->pSends
[0].pOutputVoice
->mix
.inputSampleRate
;
1548 newResampleSamples
= (uint32_t) FAudio_ceil(
1549 voice
->audio
->updateSize
*
1550 (double) outSampleRate
/
1551 (double) voice
->audio
->master
->master
.inputSampleRate
1553 if (voice
->type
== FAUDIO_VOICE_SOURCE
)
1555 if ( (voice
->src
.resampleSamples
!= 0) &&
1556 (newResampleSamples
!= voice
->src
.resampleSamples
) &&
1557 (voice
->effects
.count
> 0) )
1559 LOG_FUNC_EXIT(voice
->audio
)
1560 return FAUDIO_E_INVALID_CALL
;
1562 voice
->src
.resampleSamples
= newResampleSamples
;
1564 else /* (voice->type == FAUDIO_VOICE_SUBMIX) */
1566 if ( (voice
->mix
.outputSamples
!= 0) &&
1567 (newResampleSamples
!= voice
->mix
.outputSamples
) &&
1568 (voice
->effects
.count
> 0) )
1570 LOG_FUNC_EXIT(voice
->audio
)
1571 return FAUDIO_E_INVALID_CALL
;
1573 voice
->mix
.outputSamples
= newResampleSamples
;
1575 voice
->mix
.resampleStep
= DOUBLE_TO_FIXED((
1576 (double) voice
->mix
.inputSampleRate
/
1577 (double) outSampleRate
1580 /* Because we used ceil earlier, there's a chance that
1581 * downsampling submixes will go past the number of samples
1582 * available. Sources can do this thanks to padding, but we
1583 * don't have that luxury for submixes, so unfortunately we
1584 * just have to undo the ceil and turn it into a floor.
1587 resampleSanityCheck
= (
1588 voice
->mix
.resampleStep
* voice
->mix
.outputSamples
1589 ) >> FIXED_PRECISION
;
1590 if (resampleSanityCheck
> (voice
->mix
.inputSamples
/ voice
->mix
.inputChannels
))
1592 voice
->mix
.outputSamples
-= 1;
1596 LOG_FUNC_EXIT(voice
->audio
)
1600 const float FAUDIO_INTERNAL_MATRIX_DEFAULTS
[8][8][64] =
1602 #include "matrix_defaults.inl"
1607 void FAudio_INTERNAL_DecodePCM8(
1609 FAudioBuffer
*buffer
,
1613 LOG_FUNC_ENTER(voice
->audio
)
1614 FAudio_INTERNAL_Convert_U8_To_F32(
1615 ((uint8_t*) buffer
->pAudioData
) + (
1616 voice
->src
.curBufferOffset
* voice
->src
.format
->nChannels
1619 samples
* voice
->src
.format
->nChannels
1621 LOG_FUNC_EXIT(voice
->audio
)
1624 void FAudio_INTERNAL_DecodePCM16(
1626 FAudioBuffer
*buffer
,
1630 LOG_FUNC_ENTER(voice
->audio
)
1631 FAudio_INTERNAL_Convert_S16_To_F32(
1632 ((int16_t*) buffer
->pAudioData
) + (
1633 voice
->src
.curBufferOffset
* voice
->src
.format
->nChannels
1636 samples
* voice
->src
.format
->nChannels
1638 LOG_FUNC_EXIT(voice
->audio
)
1641 void FAudio_INTERNAL_DecodePCM24(
1643 FAudioBuffer
*buffer
,
1649 LOG_FUNC_ENTER(voice
->audio
)
1651 /* FIXME: Uh... is this something that can be SIMD-ified? */
1652 buf
= buffer
->pAudioData
+ (
1653 voice
->src
.curBufferOffset
* voice
->src
.format
->nBlockAlign
1655 for (i
= 0; i
< samples
; i
+= 1, buf
+= voice
->src
.format
->nBlockAlign
)
1656 for (j
= 0; j
< voice
->src
.format
->nChannels
; j
+= 1)
1658 *decodeCache
++ = ((int32_t) (
1659 ((uint32_t) buf
[(j
* 3) + 2] << 24) |
1660 ((uint32_t) buf
[(j
* 3) + 1] << 16) |
1661 ((uint32_t) buf
[(j
* 3) + 0] << 8)
1662 ) >> 8) / 8388607.0f
;
1665 LOG_FUNC_EXIT(voice
->audio
)
1668 void FAudio_INTERNAL_DecodePCM32(
1670 FAudioBuffer
*buffer
,
1674 LOG_FUNC_ENTER(voice
->audio
)
1675 FAudio_INTERNAL_Convert_S32_To_F32(
1676 ((int32_t*) buffer
->pAudioData
) + (
1677 voice
->src
.curBufferOffset
* voice
->src
.format
->nChannels
1680 samples
* voice
->src
.format
->nChannels
1682 LOG_FUNC_EXIT(voice
->audio
)
1685 void FAudio_INTERNAL_DecodePCM32F(
1687 FAudioBuffer
*buffer
,
1691 LOG_FUNC_ENTER(voice
->audio
)
1694 ((float*) buffer
->pAudioData
) + (
1695 voice
->src
.curBufferOffset
* voice
->src
.format
->nChannels
1697 sizeof(float) * samples
* voice
->src
.format
->nChannels
1699 LOG_FUNC_EXIT(voice
->audio
)
1702 /* MSADPCM Decoding */
1704 static inline int16_t FAudio_INTERNAL_ParseNibble(
1711 static const int32_t AdaptionTable
[16] =
1713 230, 230, 230, 230, 307, 409, 512, 614,
1714 768, 614, 512, 409, 307, 230, 230, 230
1716 static const int32_t AdaptCoeff_1
[7] =
1718 256, 512, 0, 192, 240, 460, 392
1720 static const int32_t AdaptCoeff_2
[7] =
1722 0, -256, 0, 64, 0, -208, -232
1725 int8_t signedNibble
;
1729 signedNibble
= (int8_t) nibble
;
1730 if (signedNibble
& 0x08)
1732 signedNibble
-= 0x10;
1736 (*sample1
* AdaptCoeff_1
[predictor
]) +
1737 (*sample2
* AdaptCoeff_2
[predictor
])
1739 sampleInt
+= signedNibble
* (*delta
);
1740 sample
= FAudio_clamp(sampleInt
, -32768, 32767);
1742 *sample2
= *sample1
;
1744 *delta
= (int16_t) (AdaptionTable
[nibble
] * (int32_t) (*delta
) / 256);
1752 #define READ(item, type) \
1753 item = *((type*) *buf); \
1754 *buf += sizeof(type);
1756 static inline void FAudio_INTERNAL_DecodeMonoMSADPCMBlock(
1758 int16_t *blockCache
,
1763 /* Temp storage for ADPCM blocks */
1770 READ(predictor
, uint8_t)
1771 READ(delta
, int16_t)
1772 READ(sample1
, int16_t)
1773 READ(sample2
, int16_t)
1777 *blockCache
++ = sample2
;
1778 *blockCache
++ = sample1
;
1779 for (i
= 0; i
< align
; i
+= 1, *buf
+= 1)
1781 *blockCache
++ = FAudio_INTERNAL_ParseNibble(
1788 *blockCache
++ = FAudio_INTERNAL_ParseNibble(
1798 static inline void FAudio_INTERNAL_DecodeStereoMSADPCMBlock(
1800 int16_t *blockCache
,
1805 /* Temp storage for ADPCM blocks */
1806 uint8_t l_predictor
;
1807 uint8_t r_predictor
;
1816 READ(l_predictor
, uint8_t)
1817 READ(r_predictor
, uint8_t)
1818 READ(l_delta
, int16_t)
1819 READ(r_delta
, int16_t)
1820 READ(l_sample1
, int16_t)
1821 READ(r_sample1
, int16_t)
1822 READ(l_sample2
, int16_t)
1823 READ(r_sample2
, int16_t)
1827 *blockCache
++ = l_sample2
;
1828 *blockCache
++ = r_sample2
;
1829 *blockCache
++ = l_sample1
;
1830 *blockCache
++ = r_sample1
;
1831 for (i
= 0; i
< align
; i
+= 1, *buf
+= 1)
1833 *blockCache
++ = FAudio_INTERNAL_ParseNibble(
1840 *blockCache
++ = FAudio_INTERNAL_ParseNibble(
1852 void FAudio_INTERNAL_DecodeMonoMSADPCM(
1854 FAudioBuffer
*buffer
,
1858 /* Loop variables */
1859 uint32_t copy
, done
= 0;
1865 /* PCM block cache */
1866 int16_t *blockCache
;
1869 uint32_t bsize
= ((FAudioADPCMWaveFormat
*) voice
->src
.format
)->wSamplesPerBlock
;
1871 LOG_FUNC_ENTER(voice
->audio
)
1873 /* Where are we starting? */
1874 buf
= (uint8_t*) buffer
->pAudioData
+ (
1875 (voice
->src
.curBufferOffset
/ bsize
) *
1876 voice
->src
.format
->nBlockAlign
1879 /* Are we starting in the middle? */
1880 midOffset
= (voice
->src
.curBufferOffset
% bsize
);
1882 /* Read in each block directly to the decode cache */
1883 blockCache
= (int16_t*) FAudio_alloca(bsize
* sizeof(int16_t));
1884 while (done
< samples
)
1886 copy
= FAudio_min(samples
- done
, bsize
- midOffset
);
1887 FAudio_INTERNAL_DecodeMonoMSADPCMBlock(
1890 voice
->src
.format
->nBlockAlign
1892 FAudio_INTERNAL_Convert_S16_To_F32(
1893 blockCache
+ midOffset
,
1897 decodeCache
+= copy
;
1901 FAudio_dealloca(blockCache
);
1902 LOG_FUNC_EXIT(voice
->audio
)
1905 void FAudio_INTERNAL_DecodeStereoMSADPCM(
1907 FAudioBuffer
*buffer
,
1911 /* Loop variables */
1912 uint32_t copy
, done
= 0;
1918 /* PCM block cache */
1919 int16_t *blockCache
;
1921 /* Align, block size */
1922 uint32_t bsize
= ((FAudioADPCMWaveFormat
*) voice
->src
.format
)->wSamplesPerBlock
;
1924 LOG_FUNC_ENTER(voice
->audio
)
1926 /* Where are we starting? */
1927 buf
= (uint8_t*) buffer
->pAudioData
+ (
1928 (voice
->src
.curBufferOffset
/ bsize
) *
1929 voice
->src
.format
->nBlockAlign
1932 /* Are we starting in the middle? */
1933 midOffset
= (voice
->src
.curBufferOffset
% bsize
);
1935 /* Read in each block directly to the decode cache */
1936 blockCache
= (int16_t*) FAudio_alloca(bsize
* 2 * sizeof(int16_t));
1937 while (done
< samples
)
1939 copy
= FAudio_min(samples
- done
, bsize
- midOffset
);
1940 FAudio_INTERNAL_DecodeStereoMSADPCMBlock(
1943 voice
->src
.format
->nBlockAlign
1945 FAudio_INTERNAL_Convert_S16_To_F32(
1946 blockCache
+ (midOffset
* 2),
1950 decodeCache
+= copy
* 2;
1954 FAudio_dealloca(blockCache
);
1955 LOG_FUNC_EXIT(voice
->audio
)
1958 /* Fallback WMA decoder, get ready for spam! */
1960 void FAudio_INTERNAL_DecodeWMAERROR(
1962 FAudioBuffer
*buffer
,
1966 LOG_FUNC_ENTER(voice
->audio
)
1967 LOG_ERROR(voice
->audio
, "%s", "WMA IS NOT SUPPORTED IN THIS BUILD!")
1968 FAudio_zero(decodeCache
, samples
* voice
->src
.format
->nChannels
* sizeof(float));
1969 LOG_FUNC_EXIT(voice
->audio
)
1972 /* vim: set noexpandtab shiftwidth=8 tabstop=8: */