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