mscoree: Update Wine Mono to 9.2.0.
[wine.git] / libs / faudio / src / FAudio_internal.c
blob37609ae8886a3e211b91b67b313d7eecae4c097b
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(
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';
43 /* Logging extras */
44 if (audio->debug.LogThreadID)
46 out += FAudio_snprintf(
47 out,
48 sizeof(output) - (out - output),
49 "0x%" FAudio_PRIx64 " ",
50 FAudio_PlatformGetThreadID()
53 if (audio->debug.LogFileline)
55 out += FAudio_snprintf(
56 out,
57 sizeof(output) - (out - output),
58 "%s:%u ",
59 file,
60 line
63 if (audio->debug.LogFunctionName)
65 out += FAudio_snprintf(
66 out,
67 sizeof(output) - (out - output),
68 "%s ",
69 func
72 if (audio->debug.LogTiming)
74 out += FAudio_snprintf(
75 out,
76 sizeof(output) - (out - output),
77 "%dms ",
78 FAudio_timems()
82 /* The actual message... */
83 va_start(va, fmt);
84 FAudio_vsnprintf(
85 out,
86 sizeof(output) - (out - output),
87 fmt,
90 va_end(va);
92 /* Print, finally. */
93 FAudio_Log(output);
96 static const char *get_wformattag_string(const FAudioWaveFormatEx *fmt)
98 #define FMT_STRING(suffix) \
99 if (fmt->wFormatTag == FAUDIO_FORMAT_##suffix) \
101 return #suffix; \
103 FMT_STRING(PCM)
104 FMT_STRING(MSADPCM)
105 FMT_STRING(IEEE_FLOAT)
106 FMT_STRING(XMAUDIO2)
107 FMT_STRING(WMAUDIO2)
108 FMT_STRING(WMAUDIO3)
109 FMT_STRING(EXTENSIBLE)
110 #undef FMT_STRING
111 return "UNKNOWN!";
114 static const char *get_subformat_string(const FAudioWaveFormatEx *fmt)
116 const FAudioWaveFormatExtensible *fmtex = (const FAudioWaveFormatExtensible*) fmt;
118 if (fmt->wFormatTag != FAUDIO_FORMAT_EXTENSIBLE)
120 return "N/A";
122 if (!FAudio_memcmp(&fmtex->SubFormat, &DATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(FAudioGUID)))
124 return "IEEE_FLOAT";
126 if (!FAudio_memcmp(&fmtex->SubFormat, &DATAFORMAT_SUBTYPE_PCM, sizeof(FAudioGUID)))
128 return "PCM";
130 return "UNKNOWN!";
133 void FAudio_INTERNAL_debug_fmt(
134 FAudio *audio,
135 const char *file,
136 uint32_t line,
137 const char *func,
138 const FAudioWaveFormatEx *fmt
140 FAudio_INTERNAL_debug(
141 audio,
142 file,
143 line,
144 func,
147 "wFormatTag: 0x%x %s, "
148 "nChannels: %u, "
149 "nSamplesPerSec: %u, "
150 "wBitsPerSample: %u, "
151 "nBlockAlign: %u, "
152 "SubFormat: %s"
155 fmt->wFormatTag,
156 get_wformattag_string(fmt),
157 fmt->nChannels,
158 fmt->nSamplesPerSec,
159 fmt->wBitsPerSample,
160 fmt->nBlockAlign,
161 get_subformat_string(fmt)
164 #endif /* FAUDIO_DISABLE_DEBUGCONFIGURATION */
166 void LinkedList_AddEntry(
167 LinkedList **start,
168 void* toAdd,
169 FAudioMutex lock,
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);
177 if (*start == NULL)
179 *start = newEntry;
181 else
183 latest = *start;
184 while (latest->next != NULL)
186 latest = latest->next;
188 latest->next = newEntry;
190 FAudio_PlatformUnlockMutex(lock);
193 void LinkedList_PrependEntry(
194 LinkedList **start,
195 void* toAdd,
196 FAudioMutex lock,
197 FAudioMallocFunc pMalloc
199 LinkedList *newEntry;
200 newEntry = (LinkedList*) pMalloc(sizeof(LinkedList));
201 newEntry->entry = toAdd;
202 FAudio_PlatformLockMutex(lock);
203 newEntry->next = *start;
204 *start = newEntry;
205 FAudio_PlatformUnlockMutex(lock);
208 void LinkedList_RemoveEntry(
209 LinkedList **start,
210 void* toRemove,
211 FAudioMutex lock,
212 FAudioFreeFunc pFree
214 LinkedList *latest, *prev;
215 FAudio_PlatformLockMutex(lock);
216 latest = *start;
217 prev = latest;
218 while (latest != NULL)
220 if (latest->entry == toRemove)
222 if (latest == prev) /* First in list */
224 *start = latest->next;
226 else
228 prev->next = latest->next;
230 pFree(latest);
231 FAudio_PlatformUnlockMutex(lock);
232 return;
234 prev = latest;
235 latest = latest->next;
237 FAudio_PlatformUnlockMutex(lock);
238 FAudio_assert(0 && "LinkedList element not found!");
241 void FAudio_INTERNAL_InsertSubmixSorted(
242 LinkedList **start,
243 FAudioSubmixVoice *toAdd,
244 FAudioMutex lock,
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);
252 if (*start == NULL)
254 *start = newEntry;
256 else
258 latest = *start;
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;
264 *start = newEntry;
266 else
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;
281 break;
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,
300 uint32_t decoding
302 uint32_t end, result;
303 FAudioBuffer *buffer;
304 FAudioWaveFormatExtensible *fmt;
305 FAudioBufferEntry *list = voice->src.bufferList;
307 LOG_FUNC_ENTER(voice->audio)
309 #ifdef HAVE_WMADEC
310 if (voice->src.wmadec != NULL)
312 /* Always 0, per the spec */
313 LOG_FUNC_EXIT(voice->audio)
314 return 0;
316 #endif /* HAVE_WMADEC */
317 while (list != NULL && decoding > 0)
319 buffer = &list->buffer;
320 if (buffer->LoopCount > 0)
322 end = (
323 /* Current loop... */
324 ((buffer->LoopBegin + buffer->LoopLength) - voice->src.curBufferOffset) +
325 /* Remaining loops... */
326 (buffer->LoopLength * buffer->LoopCount - 1) +
327 /* ... Final iteration */
328 buffer->PlayLength
331 else
333 end = (buffer->PlayBegin + buffer->PlayLength) - voice->src.curBufferOffset;
335 if (end > decoding)
337 decoding = 0;
338 break;
340 decoding -= end;
341 list = list->next;
344 /* Convert samples to bytes, factoring block alignment */
345 if (voice->src.format->wFormatTag == FAUDIO_FORMAT_MSADPCM)
347 fmt = (FAudioWaveFormatExtensible*) voice->src.format;
348 result = (
349 (decoding / fmt->Samples.wSamplesPerBlock) +
350 ((decoding % fmt->Samples.wSamplesPerBlock) > 0)
351 ) * voice->src.format->nBlockAlign;
353 else
355 result = decoding * voice->src.format->nBlockAlign;
358 LOG_FUNC_EXIT(voice->audio)
359 return result;
362 static void FAudio_INTERNAL_DecodeBuffers(
363 FAudioSourceVoice *voice,
364 uint64_t *toDecode
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(
396 voice->src.callback,
397 buffer->pContext
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,
417 decoding
420 /* Decode... */
421 voice->src.decode(
422 voice,
423 buffer,
424 voice->audio->decodeCache + (
425 decoded * voice->src.format->nChannels
427 endRead
430 LOG_INFO(
431 voice->audio,
432 "Voice %p, buffer %p, decoded %u samples from [%u,%u)",
433 (void*) voice,
434 (void*) buffer,
435 endRead,
436 voice->src.curBufferOffset,
437 voice->src.curBufferOffset + endRead
440 decoded += 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(
467 voice->src.callback,
468 buffer->pContext
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)
481 else
483 #ifdef HAVE_WMADEC
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;
496 LOG_INFO(
497 voice->audio,
498 "Voice %p, finished with buffer %p",
499 (void*) voice,
500 (void*) buffer
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;
511 else
513 buffer = NULL;
515 /* FIXME: I keep going past the buffer so fuck it */
516 FAudio_zero(
517 voice->audio->decodeCache + (
518 decoded *
519 voice->src.format->nChannels
521 sizeof(float) * (
522 (*toDecode - decoded) *
523 voice->src.format->nChannels
528 /* Callbacks */
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(
543 voice->src.callback,
544 toDelete->buffer.pContext
547 if ( toDelete->buffer.Flags & FAUDIO_END_OF_STREAM &&
548 voice->src.callback->OnStreamEnd != NULL )
550 voice->src.callback->OnStreamEnd(
551 voice->src.callback
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(
583 voice->src.callback,
584 buffer->pContext
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 */
604 if (buffer)
606 end = (buffer->LoopCount > 0) ?
607 (buffer->LoopBegin + buffer->LoopLength) :
608 buffer->PlayBegin + buffer->PlayLength;
609 endRead = FAudio_min(
610 end - voice->src.curBufferOffset,
611 EXTRA_DECODE_PADDING
614 voice->src.decode(
615 voice,
616 buffer,
617 voice->audio->decodeCache + (
618 decoded * voice->src.format->nChannels
620 endRead
622 /* Do NOT increment curBufferOffset! */
624 if (endRead < EXTRA_DECODE_PADDING)
626 FAudio_zero(
627 voice->audio->decodeCache + (
628 decoded * voice->src.format->nChannels
630 sizeof(float) * (
631 (EXTRA_DECODE_PADDING - endRead) *
632 voice->src.format->nChannels
637 else
639 FAudio_zero(
640 voice->audio->decodeCache + (
641 decoded * voice->src.format->nChannels
643 sizeof(float) * (
644 EXTRA_DECODE_PADDING *
645 voice->src.format->nChannels
650 *toDecode = decoded;
651 LOG_FUNC_EXIT(voice->audio)
654 static inline void FAudio_INTERNAL_FilterVoice(
655 FAudio *audio,
656 const FAudioFilterParametersEXT *filter,
657 FAudioFilterState *filterState,
658 float *samples,
659 uint32_t numSamples,
660 uint16_t numChannels
662 uint32_t j, ci;
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))
678 * - @JohanSmet
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);
691 LOG_FUNC_EXIT(audio)
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
705 LOG_FUNC_EXIT(audio)
708 static inline float *FAudio_INTERNAL_ProcessEffectChain(
709 FAudioVoice *voice,
710 float *buffer,
711 uint32_t *samples
713 uint32_t i;
714 FAPO *fapo;
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;
728 break;
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(
747 voice->audio,
748 voice->effects.desc[i].OutputChannels * srcParams.ValidFrameCount
750 dstParams.pBuffer = voice->audio->effectChainCache;
752 else
754 /* FIXME: What if this is smaller because
755 * inputChannels < desc[i].OutputChannels?
757 dstParams.pBuffer = buffer;
760 FAudio_zero(
761 dstParams.pBuffer,
762 voice->effects.desc[i].OutputChannels * srcParams.ValidFrameCount * sizeof(float)
766 if (voice->effects.parameterUpdates[i])
768 fapo->SetParameters(
769 fapo,
770 voice->effects.parameters[i],
771 voice->effects.parameterSizes[i]
773 voice->effects.parameterUpdates[i] = 0;
776 fapo->Process(
777 fapo,
779 &srcParams,
781 &dstParams,
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
808 LOG_FUNC_EXIT(audio)
811 static void FAudio_INTERNAL_MixSource(FAudioSourceVoice *voice)
813 /* Iterators */
814 uint32_t i;
815 /* Decode/Resample variables */
816 uint64_t toDecode;
817 uint64_t toResample;
818 /* Output mix variables */
819 float *stream;
820 uint32_t mixed;
821 uint32_t oChan;
822 FAudioVoice *out;
823 uint32_t outputRate;
824 double stepd;
825 float *finalSamples;
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;
841 stepd = (
842 voice->src.freqRatio *
843 (double) voice->src.format->nSamplesPerSec /
844 (double) outputRate
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(
854 voice->audio,
855 voice->src.resampleSamples * voice->src.format->nChannels
857 mixed = voice->src.resampleSamples;
858 FAudio_zero(
859 voice->audio->resampleCache,
860 mixed * voice->src.format->nChannels * sizeof(float)
862 finalSamples = voice->audio->resampleCache;
863 goto sendwork;
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(
884 voice->src.callback,
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)
898 /* Nothing to do? */
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(
908 voice->audio,
909 voice->src.resampleSamples * voice->src.format->nChannels
911 mixed = voice->src.resampleSamples;
912 FAudio_zero(
913 voice->audio->resampleCache,
914 mixed * voice->src.format->nChannels * sizeof(float)
916 finalSamples = voice->audio->resampleCache;
917 goto sendwork;
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(
930 voice->src.callback
934 FAudio_PlatformLockMutex(voice->audio->sourceLock);
935 LOG_MUTEX_LOCK(voice->audio, voice->audio->sourceLock)
937 LOG_FUNC_EXIT(voice->audio)
938 return;
941 /* Decode... */
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(
965 voice->src.callback
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? */
979 if (toDecode == 0)
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)
988 return;
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);
1004 /* Resample... */
1005 if (voice->src.resampleStep == FIXED_ONE)
1007 /* Actually, just use the existing buffer... */
1008 finalSamples = voice->audio->decodeCache;
1010 else
1012 FAudio_INTERNAL_ResizeResampleCache(
1013 voice->audio,
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,
1021 toResample,
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;
1044 else
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;
1055 sendwork:
1057 /* Filters */
1058 if (voice->flags & FAUDIO_VOICE_USEFILTER)
1060 FAudio_PlatformLockMutex(voice->filterLock);
1061 LOG_MUTEX_LOCK(voice->audio, voice->filterLock)
1062 FAudio_INTERNAL_FilterVoice(
1063 voice->audio,
1064 &voice->filter,
1065 voice->filterState,
1066 finalSamples,
1067 mixed,
1068 voice->src.format->nChannels
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)
1084 FAudio_zero(
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(
1091 voice,
1092 finalSamples,
1093 &mixed
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)
1105 return;
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;
1119 else
1121 stream = out->mix.inputCache;
1122 oChan = out->mix.inputChannels;
1125 voice->sendMix[i](
1126 mixed,
1127 voice->outputChannels,
1128 oChan,
1129 finalSamples,
1130 stream,
1131 voice->mixCoefficients[i]
1134 if (voice->sends.pSends[i].Flags & FAUDIO_SEND_USEFILTER)
1136 FAudio_INTERNAL_FilterVoice(
1137 voice->audio,
1138 &voice->sendFilter[i],
1139 voice->sendFilterState[i],
1140 stream,
1141 mixed,
1142 oChan
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)
1156 uint32_t i;
1157 float *stream;
1158 uint32_t oChan;
1159 FAudioVoice *out;
1160 uint32_t resampled;
1161 uint64_t resampleOffset = 0;
1162 float *finalSamples;
1164 LOG_FUNC_ENTER(voice->audio)
1165 FAudio_PlatformLockMutex(voice->sendLock);
1166 LOG_MUTEX_LOCK(voice->audio, voice->sendLock)
1168 /* Resample */
1169 if (voice->mix.resampleStep == FIXED_ONE)
1171 /* Actually, just use the existing buffer... */
1172 finalSamples = voice->mix.inputCache;
1174 else
1176 FAudio_INTERNAL_ResizeResampleCache(
1177 voice->audio,
1178 voice->mix.outputSamples * voice->mix.inputChannels
1180 voice->mix.resample(
1181 voice->mix.inputCache,
1182 voice->audio->resampleCache,
1183 &resampleOffset,
1184 voice->mix.resampleStep,
1185 voice->mix.outputSamples,
1186 (uint8_t) voice->mix.inputChannels
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(
1196 finalSamples,
1197 resampled,
1198 voice->volume
1201 resampled /= voice->mix.inputChannels;
1203 /* Filters */
1204 if (voice->flags & FAUDIO_VOICE_USEFILTER)
1206 FAudio_PlatformLockMutex(voice->filterLock);
1207 LOG_MUTEX_LOCK(voice->audio, voice->filterLock)
1208 FAudio_INTERNAL_FilterVoice(
1209 voice->audio,
1210 &voice->filter,
1211 voice->filterState,
1212 finalSamples,
1213 resampled,
1214 voice->mix.inputChannels
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(
1226 voice,
1227 finalSamples,
1228 &resampled
1231 FAudio_PlatformUnlockMutex(voice->effectLock);
1232 LOG_MUTEX_UNLOCK(voice->audio, voice->effectLock)
1234 /* Nothing more to do? */
1235 if (voice->sends.SendCount == 0)
1237 goto end;
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;
1251 else
1253 stream = out->mix.inputCache;
1254 oChan = out->mix.inputChannels;
1257 voice->sendMix[i](
1258 resampled,
1259 voice->outputChannels,
1260 oChan,
1261 finalSamples,
1262 stream,
1263 voice->mixCoefficients[i]
1266 if (voice->sends.pSends[i].Flags & FAUDIO_SEND_USEFILTER)
1268 FAudio_INTERNAL_FilterVoice(
1269 voice->audio,
1270 &voice->sendFilter[i],
1271 voice->sendFilterState[i],
1272 stream,
1273 resampled,
1274 oChan
1278 FAudio_PlatformUnlockMutex(voice->volumeLock);
1279 LOG_MUTEX_UNLOCK(voice->audio, voice->volumeLock)
1281 /* Zero this at the end, for the next update */
1282 end:
1283 FAudio_PlatformUnlockMutex(voice->sendLock);
1284 LOG_MUTEX_UNLOCK(voice->audio, voice->sendLock)
1285 FAudio_zero(
1286 voice->mix.inputCache,
1287 sizeof(float) * voice->mix.inputSamples
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;
1334 LinkedList *list;
1335 float *effectOut;
1336 FAudioEngineCallback *callback;
1338 LOG_FUNC_ENTER(audio)
1339 if (!audio->active)
1341 LOG_FUNC_EXIT(audio)
1342 return;
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(
1358 callback
1361 list = list->next;
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;
1372 FAudio_zero(
1373 audio->master->master.effectCache,
1375 sizeof(float) *
1376 audio->updateSize *
1377 audio->master->master.inputChannels
1381 else
1383 audio->master->master.output = output;
1386 /* Mix sources */
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);
1401 list = list->next;
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);
1414 list = list->next;
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(
1436 audio->master,
1437 audio->master->master.output,
1438 &totalSamples
1441 if (effectOut != output)
1443 FAudio_memcpy(
1444 output,
1445 effectOut,
1446 totalSamples * audio->master->outputChannels * sizeof(float)
1449 if (totalSamples < audio->updateSize)
1451 FAudio_zero(
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(
1470 callback
1473 list = list->next;
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,
1488 audio,
1489 output,
1490 audio->clientEngineUser
1493 else
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(
1509 audio->decodeCache,
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(
1519 FAudioVoice *voice,
1520 const FAudioEffectChain *pEffectChain
1522 uint32_t i;
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)
1530 return;
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)
1541 FAudio_memcpy(
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) \
1549 ); \
1550 FAudio_zero( \
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)
1564 uint32_t i;
1566 LOG_FUNC_ENTER(voice->audio)
1567 if (voice->effects.count == 0)
1569 LOG_FUNC_EXIT(voice->audio)
1570 return;
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(
1588 FAudioVoice *voice,
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;
1602 else
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.
1645 * -flibit
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)
1657 return 0;
1660 const float FAUDIO_INTERNAL_MATRIX_DEFAULTS[8][8][64] =
1662 #include "matrix_defaults.inl"
1665 /* PCM Decoding */
1667 void FAudio_INTERNAL_DecodePCM8(
1668 FAudioVoice *voice,
1669 FAudioBuffer *buffer,
1670 float *decodeCache,
1671 uint32_t samples
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
1678 decodeCache,
1679 samples * voice->src.format->nChannels
1681 LOG_FUNC_EXIT(voice->audio)
1684 void FAudio_INTERNAL_DecodePCM16(
1685 FAudioVoice *voice,
1686 FAudioBuffer *buffer,
1687 float *decodeCache,
1688 uint32_t samples
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
1695 decodeCache,
1696 samples * voice->src.format->nChannels
1698 LOG_FUNC_EXIT(voice->audio)
1701 void FAudio_INTERNAL_DecodePCM24(
1702 FAudioVoice *voice,
1703 FAudioBuffer *buffer,
1704 float *decodeCache,
1705 uint32_t samples
1707 uint32_t i, j;
1708 const uint8_t *buf;
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(
1729 FAudioVoice *voice,
1730 FAudioBuffer *buffer,
1731 float *decodeCache,
1732 uint32_t samples
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
1739 decodeCache,
1740 samples * voice->src.format->nChannels
1742 LOG_FUNC_EXIT(voice->audio)
1745 void FAudio_INTERNAL_DecodePCM32F(
1746 FAudioVoice *voice,
1747 FAudioBuffer *buffer,
1748 float *decodeCache,
1749 uint32_t samples
1751 LOG_FUNC_ENTER(voice->audio)
1752 FAudio_memcpy(
1753 decodeCache,
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(
1765 uint8_t nibble,
1766 uint8_t predictor,
1767 int16_t *delta,
1768 int16_t *sample1,
1769 int16_t *sample2
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;
1786 int32_t sampleInt;
1787 int16_t sample;
1789 signedNibble = (int8_t) nibble;
1790 if (signedNibble & 0x08)
1792 signedNibble -= 0x10;
1795 sampleInt = (
1796 (*sample1 * AdaptCoeff_1[predictor]) +
1797 (*sample2 * AdaptCoeff_2[predictor])
1798 ) / 256;
1799 sampleInt += signedNibble * (*delta);
1800 sample = FAudio_clamp(sampleInt, -32768, 32767);
1802 *sample2 = *sample1;
1803 *sample1 = sample;
1804 *delta = (int16_t) (AdaptionTable[nibble] * (int32_t) (*delta) / 256);
1805 if (*delta < 16)
1807 *delta = 16;
1809 return sample;
1812 #define READ(item, type) \
1813 item = *((type*) *buf); \
1814 *buf += sizeof(type);
1816 static inline void FAudio_INTERNAL_DecodeMonoMSADPCMBlock(
1817 uint8_t **buf,
1818 int16_t *blockCache,
1819 uint32_t align
1821 uint32_t i;
1823 /* Temp storage for ADPCM blocks */
1824 uint8_t predictor;
1825 int16_t delta;
1826 int16_t sample1;
1827 int16_t sample2;
1829 /* Preamble */
1830 READ(predictor, uint8_t)
1831 READ(delta, int16_t)
1832 READ(sample1, int16_t)
1833 READ(sample2, int16_t)
1834 align -= 7;
1836 /* Samples */
1837 *blockCache++ = sample2;
1838 *blockCache++ = sample1;
1839 for (i = 0; i < align; i += 1, *buf += 1)
1841 *blockCache++ = FAudio_INTERNAL_ParseNibble(
1842 *(*buf) >> 4,
1843 predictor,
1844 &delta,
1845 &sample1,
1846 &sample2
1848 *blockCache++ = FAudio_INTERNAL_ParseNibble(
1849 *(*buf) & 0x0F,
1850 predictor,
1851 &delta,
1852 &sample1,
1853 &sample2
1858 static inline void FAudio_INTERNAL_DecodeStereoMSADPCMBlock(
1859 uint8_t **buf,
1860 int16_t *blockCache,
1861 uint32_t align
1863 uint32_t i;
1865 /* Temp storage for ADPCM blocks */
1866 uint8_t l_predictor;
1867 uint8_t r_predictor;
1868 int16_t l_delta;
1869 int16_t r_delta;
1870 int16_t l_sample1;
1871 int16_t r_sample1;
1872 int16_t l_sample2;
1873 int16_t r_sample2;
1875 /* Preamble */
1876 READ(l_predictor, uint8_t)
1877 READ(r_predictor, uint8_t)
1878 READ(l_delta, int16_t)
1879 READ(r_delta, int16_t)
1880 READ(l_sample1, int16_t)
1881 READ(r_sample1, int16_t)
1882 READ(l_sample2, int16_t)
1883 READ(r_sample2, int16_t)
1884 align -= 14;
1886 /* Samples */
1887 *blockCache++ = l_sample2;
1888 *blockCache++ = r_sample2;
1889 *blockCache++ = l_sample1;
1890 *blockCache++ = r_sample1;
1891 for (i = 0; i < align; i += 1, *buf += 1)
1893 *blockCache++ = FAudio_INTERNAL_ParseNibble(
1894 *(*buf) >> 4,
1895 l_predictor,
1896 &l_delta,
1897 &l_sample1,
1898 &l_sample2
1900 *blockCache++ = FAudio_INTERNAL_ParseNibble(
1901 *(*buf) & 0x0F,
1902 r_predictor,
1903 &r_delta,
1904 &r_sample1,
1905 &r_sample2
1910 #undef READ
1912 void FAudio_INTERNAL_DecodeMonoMSADPCM(
1913 FAudioVoice *voice,
1914 FAudioBuffer *buffer,
1915 float *decodeCache,
1916 uint32_t samples
1918 /* Loop variables */
1919 uint32_t copy, done = 0;
1921 /* Read pointers */
1922 uint8_t *buf;
1923 int32_t midOffset;
1925 /* PCM block cache */
1926 int16_t *blockCache;
1928 /* Block size */
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(
1948 &buf,
1949 blockCache,
1950 voice->src.format->nBlockAlign
1952 FAudio_INTERNAL_Convert_S16_To_F32(
1953 blockCache + midOffset,
1954 decodeCache,
1955 copy
1957 decodeCache += copy;
1958 done += copy;
1959 midOffset = 0;
1961 FAudio_dealloca(blockCache);
1962 LOG_FUNC_EXIT(voice->audio)
1965 void FAudio_INTERNAL_DecodeStereoMSADPCM(
1966 FAudioVoice *voice,
1967 FAudioBuffer *buffer,
1968 float *decodeCache,
1969 uint32_t samples
1971 /* Loop variables */
1972 uint32_t copy, done = 0;
1974 /* Read pointers */
1975 uint8_t *buf;
1976 int32_t midOffset;
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(
2001 &buf,
2002 blockCache,
2003 voice->src.format->nBlockAlign
2005 FAudio_INTERNAL_Convert_S16_To_F32(
2006 blockCache + (midOffset * 2),
2007 decodeCache,
2008 copy * 2
2010 decodeCache += copy * 2;
2011 done += copy;
2012 midOffset = 0;
2014 FAudio_dealloca(blockCache);
2015 LOG_FUNC_EXIT(voice->audio)
2018 /* Fallback WMA decoder, get ready for spam! */
2020 void FAudio_INTERNAL_DecodeWMAERROR(
2021 FAudioVoice *voice,
2022 FAudioBuffer *buffer,
2023 float *decodeCache,
2024 uint32_t samples
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: */