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.h"
28 #include "FAPOBase.h"
29 #include <stdarg.h>
30 
31 #ifdef FAUDIO_UNKNOWN_PLATFORM
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include <assert.h>
37 #include <inttypes.h>
38 
39 #define FAudio_malloc malloc
40 #define FAudio_realloc realloc
41 #define FAudio_free free
42 #define FAudio_alloca(x) alloca(uint8_t, x)
43 #define FAudio_dealloca(x) dealloca(x)
44 #define FAudio_zero(ptr, size) memset(ptr, '\0', size)
45 #define FAudio_memset(ptr, val, size) memset(ptr, val, size)
46 #define FAudio_memcpy(dst, src, size) memcpy(dst, src, size)
47 #define FAudio_memmove(dst, src, size) memmove(dst, src, size)
48 #define FAudio_memcmp(ptr1, ptr2, size) memcmp(ptr1, ptr2, size)
49 
50 #define FAudio_strlen(ptr) strlen(ptr)
51 #define FAudio_strcmp(str1, str2) strcmp(str1, str2)
52 #define FAudio_strlcpy(ptr1, ptr2, size) strlcpy(ptr1, ptr2, size)
53 
54 #define FAudio_pow(x, y) pow(x, y)
55 #define FAudio_log(x) log(x)
56 #define FAudio_log10(x) log10(x)
57 #define FAudio_sin(x) sin(x)
58 #define FAudio_cos(x) cos(x)
59 #define FAudio_tan(x) tan(x)
60 #define FAudio_acos(x) acos(x)
61 #define FAudio_ceil(x) ceil(x)
62 #define FAudio_floor(x) floor(x)
63 #define FAudio_abs(x) abs(x)
64 #define FAudio_ldexp(v, e) ldexp(v, e)
65 #define FAudio_exp(x) exp(x)
66 
67 #define FAudio_cosf(x) cosf(x)
68 #define FAudio_sinf(x) sinf(x)
69 #define FAudio_sqrtf(x) sqrtf(x)
70 #define FAudio_acosf(x) acosf(x)
71 #define FAudio_atan2f(y, x) atan2f(y, x)
72 #define FAudio_fabsf(x) fabsf(x)
73 
74 #define FAudio_qsort qsort
75 
76 #define FAudio_assert assert
77 #define FAudio_snprintf snprintf
78 #define FAudio_vsnprintf vsnprintf
79 #define FAudio_Log(msg) fprintf(stderr, "%s\n", msg)
80 #define FAudio_getenv getenv
81 #define FAudio_PRIu64 PRIu64
82 #define FAudio_PRIx64 PRIx64
83 
84 /* FIXME: Assuming little-endian! */
85 #define FAudio_swap16LE(x) (x)
86 #define FAudio_swap16BE(x) \
87 	((x >> 8)	& 0x00FF) | \
88 	((x << 8)	& 0xFF00)
89 #define FAudio_swap32LE(x) (x)
90 #define FAudio_swap32BE(x) \
91 	((x >> 24)	& 0x000000FF) | \
92 	((x >> 8)	& 0x0000FF00) | \
93 	((x << 8)	& 0x00FF0000) | \
94 	((x << 24)	& 0xFF000000)
95 #define FAudio_swap64LE(x) (x)
96 #define FAudio_swap64BE(x) \
97 	((x >> 32)	& 0x00000000000000FF) | \
98 	((x >> 24)	& 0x000000000000FF00) | \
99 	((x >> 16)	& 0x0000000000FF0000) | \
100 	((x >> 8)	& 0x00000000FF000000) | \
101 	((x << 8)	& 0x000000FF00000000) | \
102 	((x << 16)	& 0x0000FF0000000000) | \
103 	((x << 24)	& 0x00FF000000000000) | \
104 	((x << 32)	& 0xFF00000000000000)
105 #else
106 #include <SDL_stdinc.h>
107 #include <SDL_assert.h>
108 #include <SDL_endian.h>
109 #include <SDL_log.h>
110 
111 #define FAudio_malloc SDL_malloc
112 #define FAudio_realloc SDL_realloc
113 #define FAudio_free SDL_free
114 #define FAudio_alloca(x) SDL_stack_alloc(uint8_t, x)
115 #define FAudio_dealloca(x) SDL_stack_free(x)
116 #define FAudio_zero(ptr, size) SDL_memset(ptr, '\0', size)
117 #define FAudio_memset(ptr, val, size) SDL_memset(ptr, val, size)
118 #define FAudio_memcpy(dst, src, size) SDL_memcpy(dst, src, size)
119 #define FAudio_memmove(dst, src, size) SDL_memmove(dst, src, size)
120 #define FAudio_memcmp(ptr1, ptr2, size) SDL_memcmp(ptr1, ptr2, size)
121 
122 #define FAudio_strlen(ptr) SDL_strlen(ptr)
123 #define FAudio_strcmp(str1, str2) SDL_strcmp(str1, str2)
124 #define FAudio_strlcpy(ptr1, ptr2, size) SDL_strlcpy(ptr1, ptr2, size)
125 
126 #define FAudio_pow(x, y) SDL_pow(x, y)
127 #define FAudio_log(x) SDL_log(x)
128 #define FAudio_log10(x) SDL_log10(x)
129 #define FAudio_sin(x) SDL_sin(x)
130 #define FAudio_cos(x) SDL_cos(x)
131 #define FAudio_tan(x) SDL_tan(x)
132 #define FAudio_acos(x) SDL_acos(x)
133 #define FAudio_ceil(x) SDL_ceil(x)
134 #define FAudio_floor(x) SDL_floor(x)
135 #define FAudio_abs(x) SDL_abs(x)
136 #define FAudio_ldexp(v, e) SDL_scalbn(v, e)
137 #define FAudio_exp(x) SDL_exp(x)
138 
139 #define FAudio_cosf(x) SDL_cosf(x)
140 #define FAudio_sinf(x) SDL_sinf(x)
141 #define FAudio_sqrtf(x) SDL_sqrtf(x)
142 #define FAudio_acosf(x) SDL_acosf(x)
143 #define FAudio_atan2f(y, x) SDL_atan2f(y, x)
144 #define FAudio_fabsf(x) SDL_fabsf(x)
145 
146 #define FAudio_qsort SDL_qsort
147 
148 #ifdef FAUDIO_LOG_ASSERTIONS
149 #define FAudio_assert(condition) \
150 	{ \
151 		static uint8_t logged = 0; \
152 		if (!(condition) && !logged) \
153 		{ \
154 			SDL_Log("Assertion failed: %s", #condition); \
155 			logged = 1; \
156 		} \
157 	}
158 #else
159 #define FAudio_assert SDL_assert
160 #endif
161 #define FAudio_snprintf SDL_snprintf
162 #define FAudio_vsnprintf SDL_vsnprintf
163 #define FAudio_Log(msg) SDL_Log("%s", msg)
164 #define FAudio_getenv SDL_getenv
165 #define FAudio_PRIu64 SDL_PRIu64
166 #define FAudio_PRIx64 SDL_PRIx64
167 
168 #define FAudio_swap16LE(x) SDL_SwapLE16(x)
169 #define FAudio_swap16BE(x) SDL_SwapBE16(x)
170 #define FAudio_swap32LE(x) SDL_SwapLE32(x)
171 #define FAudio_swap32BE(x) SDL_SwapBE32(x)
172 #define FAudio_swap64LE(x) SDL_SwapLE64(x)
173 #define FAudio_swap64BE(x) SDL_SwapBE64(x)
174 #endif
175 
176 /* Easy Macros */
177 #define FAudio_min(val1, val2) \
178 	(val1 < val2 ? val1 : val2)
179 #define FAudio_max(val1, val2) \
180 	(val1 > val2 ? val1 : val2)
181 #define FAudio_clamp(val, min, max) \
182 	(val > max ? max : (val < min ? min : val))
183 
184 /* Windows/Visual Studio cruft */
185 #ifdef _WIN32
186 	#ifdef __cplusplus
187 		/* C++ should have `inline`, but not `restrict` */
188 		#define restrict
189 	#else
190 		#define inline __inline
191 		#if defined(_MSC_VER)
192 			#if (_MSC_VER >= 1700) /* VS2012+ */
193 				#define restrict __restrict
194 			#else /* VS2010- */
195 				#define restrict
196 			#endif
197 		#endif
198 	#endif
199 #endif
200 
201 /* C++ does not have restrict (though VS2012+ does have __restrict) */
202 #if defined(__cplusplus) && !defined(restrict)
203 #define restrict
204 #endif
205 
206 /* Threading Types */
207 
208 typedef void* FAudioThread;
209 typedef void* FAudioMutex;
210 typedef int32_t (FAUDIOCALL * FAudioThreadFunc)(void* data);
211 typedef enum FAudioThreadPriority
212 {
213 	FAUDIO_THREAD_PRIORITY_LOW,
214 	FAUDIO_THREAD_PRIORITY_NORMAL,
215 	FAUDIO_THREAD_PRIORITY_HIGH,
216 } FAudioThreadPriority;
217 
218 /* Linked Lists */
219 
220 typedef struct LinkedList LinkedList;
221 struct LinkedList
222 {
223 	void* entry;
224 	LinkedList *next;
225 };
226 void LinkedList_AddEntry(
227 	LinkedList **start,
228 	void* toAdd,
229 	FAudioMutex lock,
230 	FAudioMallocFunc pMalloc
231 );
232 void LinkedList_PrependEntry(
233 	LinkedList **start,
234 	void* toAdd,
235 	FAudioMutex lock,
236 	FAudioMallocFunc pMalloc
237 );
238 void LinkedList_RemoveEntry(
239 	LinkedList **start,
240 	void* toRemove,
241 	FAudioMutex lock,
242 	FAudioFreeFunc pFree
243 );
244 
245 /* Internal FAudio Types */
246 
247 typedef enum FAudioVoiceType
248 {
249 	FAUDIO_VOICE_SOURCE,
250 	FAUDIO_VOICE_SUBMIX,
251 	FAUDIO_VOICE_MASTER
252 } FAudioVoiceType;
253 
254 typedef struct FAudioBufferEntry FAudioBufferEntry;
255 struct FAudioBufferEntry
256 {
257 	FAudioBuffer buffer;
258 	FAudioBufferWMA bufferWMA;
259 	FAudioBufferEntry *next;
260 };
261 
262 typedef void (FAUDIOCALL * FAudioDecodeCallback)(
263 	FAudioVoice *voice,
264 	FAudioBuffer *buffer,	/* Buffer to decode */
265 	float *decodeCache,	/* Decode into here */
266 	uint32_t samples	/* Samples to decode */
267 );
268 
269 typedef void (FAUDIOCALL * FAudioResampleCallback)(
270 	float *restrict dCache,
271 	float *restrict resampleCache,
272 	uint64_t *resampleOffset,
273 	uint64_t resampleStep,
274 	uint64_t toResample,
275 	uint8_t channels
276 );
277 
278 typedef void (FAUDIOCALL * FAudioMixCallback)(
279 	uint32_t toMix,
280 	uint32_t srcChans,
281 	uint32_t dstChans,
282 	float *restrict srcData,
283 	float *restrict dstData,
284 	float *restrict coefficients
285 );
286 
287 typedef float FAudioFilterState[4];
288 
289 /* Operation Sets, original implementation by Tyler Glaiel */
290 
291 typedef struct FAudio_OPERATIONSET_Operation FAudio_OPERATIONSET_Operation;
292 
293 void FAudio_OPERATIONSET_Commit(FAudio *audio, uint32_t OperationSet);
294 void FAudio_OPERATIONSET_CommitAll(FAudio *audio);
295 void FAudio_OPERATIONSET_Execute(FAudio *audio);
296 
297 void FAudio_OPERATIONSET_ClearAll(FAudio *audio);
298 void FAudio_OPERATIONSET_ClearAllForVoice(FAudioVoice *voice);
299 
300 void FAudio_OPERATIONSET_QueueEnableEffect(
301 	FAudioVoice *voice,
302 	uint32_t EffectIndex,
303 	uint32_t OperationSet
304 );
305 void FAudio_OPERATIONSET_QueueDisableEffect(
306 	FAudioVoice *voice,
307 	uint32_t EffectIndex,
308 	uint32_t OperationSet
309 );
310 void FAudio_OPERATIONSET_QueueSetEffectParameters(
311 	FAudioVoice *voice,
312 	uint32_t EffectIndex,
313 	const void *pParameters,
314 	uint32_t ParametersByteSize,
315 	uint32_t OperationSet
316 );
317 void FAudio_OPERATIONSET_QueueSetFilterParameters(
318 	FAudioVoice *voice,
319 	const FAudioFilterParameters *pParameters,
320 	uint32_t OperationSet
321 );
322 void FAudio_OPERATIONSET_QueueSetOutputFilterParameters(
323 	FAudioVoice *voice,
324 	FAudioVoice *pDestinationVoice,
325 	const FAudioFilterParameters *pParameters,
326 	uint32_t OperationSet
327 );
328 void FAudio_OPERATIONSET_QueueSetVolume(
329 	FAudioVoice *voice,
330 	float Volume,
331 	uint32_t OperationSet
332 );
333 void FAudio_OPERATIONSET_QueueSetChannelVolumes(
334 	FAudioVoice *voice,
335 	uint32_t Channels,
336 	const float *pVolumes,
337 	uint32_t OperationSet
338 );
339 void FAudio_OPERATIONSET_QueueSetOutputMatrix(
340 	FAudioVoice *voice,
341 	FAudioVoice *pDestinationVoice,
342 	uint32_t SourceChannels,
343 	uint32_t DestinationChannels,
344 	const float *pLevelMatrix,
345 	uint32_t OperationSet
346 );
347 void FAudio_OPERATIONSET_QueueStart(
348 	FAudioSourceVoice *voice,
349 	uint32_t Flags,
350 	uint32_t OperationSet
351 );
352 void FAudio_OPERATIONSET_QueueStop(
353 	FAudioSourceVoice *voice,
354 	uint32_t Flags,
355 	uint32_t OperationSet
356 );
357 void FAudio_OPERATIONSET_QueueExitLoop(
358 	FAudioSourceVoice *voice,
359 	uint32_t OperationSet
360 );
361 void FAudio_OPERATIONSET_QueueSetFrequencyRatio(
362 	FAudioSourceVoice *voice,
363 	float Ratio,
364 	uint32_t OperationSet
365 );
366 
367 /* Public FAudio Types */
368 
369 struct FAudio
370 {
371 	uint8_t version;
372 	uint8_t active;
373 	uint32_t refcount;
374 	uint32_t initFlags;
375 	uint32_t updateSize;
376 	FAudioMasteringVoice *master;
377 	LinkedList *sources;
378 	LinkedList *submixes;
379 	LinkedList *callbacks;
380 	FAudioMutex sourceLock;
381 	FAudioMutex submixLock;
382 	FAudioMutex callbackLock;
383 	FAudioMutex operationLock;
384 	FAudioWaveFormatExtensible mixFormat;
385 
386 	FAudio_OPERATIONSET_Operation *queuedOperations;
387 	FAudio_OPERATIONSET_Operation *committedOperations;
388 
389 	/* Used to prevent destroying an active voice */
390 	FAudioSourceVoice *processingSource;
391 
392 	/* Temp storage for processing, interleaved PCM32F */
393 	#define EXTRA_DECODE_PADDING 2
394 	uint32_t decodeSamples;
395 	uint32_t resampleSamples;
396 	uint32_t effectChainSamples;
397 	float *decodeCache;
398 	float *resampleCache;
399 	float *effectChainCache;
400 
401 	/* Allocator callbacks */
402 	FAudioMallocFunc pMalloc;
403 	FAudioFreeFunc pFree;
404 	FAudioReallocFunc pRealloc;
405 
406 	/* EngineProcedureEXT */
407 	void *clientEngineUser;
408 	FAudioEngineProcedureEXT pClientEngineProc;
409 
410 #ifndef FAUDIO_DISABLE_DEBUGCONFIGURATION
411 	/* Debug Information */
412 	FAudioDebugConfiguration debug;
413 #endif /* FAUDIO_DISABLE_DEBUGCONFIGURATION */
414 
415 	/* Platform opaque pointer */
416 	void *platform;
417 };
418 
419 struct FAudioVoice
420 {
421 	FAudio *audio;
422 	uint32_t flags;
423 	FAudioVoiceType type;
424 
425 	FAudioVoiceSends sends;
426 	float **sendCoefficients;
427 	float **mixCoefficients;
428 	FAudioMixCallback *sendMix;
429 	FAudioFilterParameters *sendFilter;
430 	FAudioFilterState **sendFilterState;
431 	struct
432 	{
433 		FAPOBufferFlags state;
434 		uint32_t count;
435 		FAudioEffectDescriptor *desc;
436 		void **parameters;
437 		uint32_t *parameterSizes;
438 		uint8_t *parameterUpdates;
439 		uint8_t *inPlaceProcessing;
440 	} effects;
441 	FAudioFilterParameters filter;
442 	FAudioFilterState *filterState;
443 	FAudioMutex sendLock;
444 	FAudioMutex effectLock;
445 	FAudioMutex filterLock;
446 
447 	float volume;
448 	float *channelVolume;
449 	uint32_t outputChannels;
450 	FAudioMutex volumeLock;
451 
452 	FAUDIONAMELESS union
453 	{
454 		struct
455 		{
456 			/* Sample storage */
457 			uint32_t decodeSamples;
458 			uint32_t resampleSamples;
459 
460 			/* Resampler */
461 			float resampleFreq;
462 			uint64_t resampleStep;
463 			uint64_t resampleOffset;
464 			uint64_t curBufferOffsetDec;
465 			uint32_t curBufferOffset;
466 
467 			/* GStreamer */
468 #ifdef HAVE_GSTREAMER
469 			struct FAudioGSTREAMER *gstreamer;
470 #endif /* HAVE_GSTREAMER*/
471 
472 			/* Read-only */
473 			float maxFreqRatio;
474 			FAudioWaveFormatEx *format;
475 			FAudioDecodeCallback decode;
476 			FAudioResampleCallback resample;
477 			FAudioVoiceCallback *callback;
478 
479 			/* Dynamic */
480 			uint8_t active;
481 			float freqRatio;
482 			uint8_t newBuffer;
483 			uint64_t totalSamples;
484 			FAudioBufferEntry *bufferList;
485 			FAudioBufferEntry *flushList;
486 			FAudioMutex bufferLock;
487 		} src;
488 		struct
489 		{
490 			/* Sample storage */
491 			uint32_t inputSamples;
492 			uint32_t outputSamples;
493 			float *inputCache;
494 			uint64_t resampleStep;
495 			FAudioResampleCallback resample;
496 
497 			/* Read-only */
498 			uint32_t inputChannels;
499 			uint32_t inputSampleRate;
500 			uint32_t processingStage;
501 		} mix;
502 		struct
503 		{
504 			/* Output stream, allocated by Platform */
505 			float *output;
506 
507 			/* Needed when inputChannels != outputChannels */
508 			float *effectCache;
509 
510 			/* Read-only */
511 			uint32_t inputChannels;
512 			uint32_t inputSampleRate;
513 		} master;
514 	};
515 };
516 
517 /* Internal Functions */
518 void FAudio_INTERNAL_InsertSubmixSorted(
519 	LinkedList **start,
520 	FAudioSubmixVoice *toAdd,
521 	FAudioMutex lock,
522 	FAudioMallocFunc pMalloc
523 );
524 void FAudio_INTERNAL_UpdateEngine(FAudio *audio, float *output);
525 void FAudio_INTERNAL_ResizeDecodeCache(FAudio *audio, uint32_t size);
526 void FAudio_INTERNAL_AllocEffectChain(
527 	FAudioVoice *voice,
528 	const FAudioEffectChain *pEffectChain
529 );
530 void FAudio_INTERNAL_FreeEffectChain(FAudioVoice *voice);
531 uint32_t FAudio_INTERNAL_VoiceOutputFrequency(
532 	FAudioVoice *voice,
533 	const FAudioVoiceSends *pSendList
534 );
535 extern const float FAUDIO_INTERNAL_MATRIX_DEFAULTS[8][8][64];
536 
537 /* Debug */
538 
539 #ifdef FAUDIO_DISABLE_DEBUGCONFIGURATION
540 
541 #define LOG_ERROR(engine, fmt, ...)
542 #define LOG_WARNING(engine, fmt, ...)
543 #define LOG_INFO(engine, fmt, ...)
544 #define LOG_DETAIL(engine, fmt, ...)
545 #define LOG_API_ENTER(engine)
546 #define LOG_API_EXIT(engine)
547 #define LOG_FUNC_ENTER(engine)
548 #define LOG_FUNC_EXIT(engine)
549 /* TODO: LOG_TIMING */
550 #define LOG_MUTEX_CREATE(engine, mutex)
551 #define LOG_MUTEX_DESTROY(engine, mutex)
552 #define LOG_MUTEX_LOCK(engine, mutex)
553 #define LOG_MUTEX_UNLOCK(engine, mutex)
554 /* TODO: LOG_MEMORY */
555 /* TODO: LOG_STREAMING */
556 
557 #define LOG_FORMAT(engine, waveFormat)
558 
559 #else
560 
561 #if defined(_MSC_VER)
562 /* VC doesn't support __attribute__ at all, and there's no replacement for format. */
563 void FAudio_INTERNAL_debug(
564 	FAudio *audio,
565 	const char *file,
566 	uint32_t line,
567 	const char *func,
568 	const char *fmt,
569 	...
570 );
571 #if _MSC_VER <= 1700 /* <=2012 also doesn't support __func__ */
572 #define __func__ __FUNCTION__
573 #endif
574 #else
575 void FAudio_INTERNAL_debug(
576 	FAudio *audio,
577 	const char *file,
578 	uint32_t line,
579 	const char *func,
580 	const char *fmt,
581 	...
582 ) __attribute__((format(printf,5,6)));
583 #endif
584 void FAudio_INTERNAL_debug_fmt(
585 	FAudio *audio,
586 	const char *file,
587 	uint32_t line,
588 	const char *func,
589 	const FAudioWaveFormatEx *fmt
590 );
591 
592 #define PRINT_DEBUG(engine, cond, type, fmt, ...) \
593 	if (engine->debug.TraceMask & FAUDIO_LOG_##cond) \
594 	{ \
595 		FAudio_INTERNAL_debug( \
596 			engine, \
597 			__FILE__, \
598 			__LINE__, \
599 			__func__, \
600 			type ": " fmt, \
601 			__VA_ARGS__ \
602 		); \
603 	}
604 
605 #define LOG_ERROR(engine, fmt, ...) PRINT_DEBUG(engine, ERRORS, "ERROR", fmt, __VA_ARGS__)
606 #define LOG_WARNING(engine, fmt, ...) PRINT_DEBUG(engine, WARNINGS, "WARNING", fmt, __VA_ARGS__)
607 #define LOG_INFO(engine, fmt, ...) PRINT_DEBUG(engine, INFO, "INFO", fmt, __VA_ARGS__)
608 #define LOG_DETAIL(engine, fmt, ...) PRINT_DEBUG(engine, DETAIL, "DETAIL", fmt, __VA_ARGS__)
609 #define LOG_API_ENTER(engine) PRINT_DEBUG(engine, API_CALLS, "API Enter", "%s", __func__)
610 #define LOG_API_EXIT(engine) PRINT_DEBUG(engine, API_CALLS, "API Exit", "%s", __func__)
611 #define LOG_FUNC_ENTER(engine) PRINT_DEBUG(engine, FUNC_CALLS, "FUNC Enter", "%s", __func__)
612 #define LOG_FUNC_EXIT(engine) PRINT_DEBUG(engine, FUNC_CALLS, "FUNC Exit", "%s", __func__)
613 /* TODO: LOG_TIMING */
614 #define LOG_MUTEX_CREATE(engine, mutex) PRINT_DEBUG(engine, LOCKS, "Mutex Create", "%p", mutex)
615 #define LOG_MUTEX_DESTROY(engine, mutex) PRINT_DEBUG(engine, LOCKS, "Mutex Destroy", "%p", mutex)
616 #define LOG_MUTEX_LOCK(engine, mutex) PRINT_DEBUG(engine, LOCKS, "Mutex Lock", "%p", mutex)
617 #define LOG_MUTEX_UNLOCK(engine, mutex) PRINT_DEBUG(engine, LOCKS, "Mutex Unlock", "%p", mutex)
618 /* TODO: LOG_MEMORY */
619 /* TODO: LOG_STREAMING */
620 
621 #define LOG_FORMAT(engine, waveFormat) \
622 	if (engine->debug.TraceMask & FAUDIO_LOG_INFO) \
623 	{ \
624 		FAudio_INTERNAL_debug_fmt( \
625 			engine, \
626 			__FILE__, \
627 			__LINE__, \
628 			__func__, \
629 			waveFormat \
630 		); \
631 	}
632 
633 #endif /* FAUDIO_DISABLE_DEBUGCONFIGURATION */
634 
635 /* FAPOFX Creators */
636 
637 #define CREATE_FAPOFX_FUNC(effect) \
638 	extern uint32_t FAPOFXCreate##effect( \
639 		FAPO **pEffect, \
640 		const void *pInitData, \
641 		uint32_t InitDataByteSize, \
642 		FAudioMallocFunc customMalloc, \
643 		FAudioFreeFunc customFree, \
644 		FAudioReallocFunc customRealloc, \
645 		uint8_t legacy \
646 	);
647 CREATE_FAPOFX_FUNC(EQ)
648 CREATE_FAPOFX_FUNC(MasteringLimiter)
649 CREATE_FAPOFX_FUNC(Reverb)
650 CREATE_FAPOFX_FUNC(Echo)
651 #undef CREATE_FAPOFX_FUNC
652 
653 /* SIMD Stuff */
654 
655 /* Callbacks declared as functions (rather than function pointers) are
656  * scalar-only, for now. SIMD versions should be possible for these.
657  */
658 
659 extern void (*FAudio_INTERNAL_Convert_U8_To_F32)(
660 	const uint8_t *restrict src,
661 	float *restrict dst,
662 	uint32_t len
663 );
664 extern void (*FAudio_INTERNAL_Convert_S16_To_F32)(
665 	const int16_t *restrict src,
666 	float *restrict dst,
667 	uint32_t len
668 );
669 extern void (*FAudio_INTERNAL_Convert_S32_To_F32)(
670 	const int32_t *restrict src,
671 	float *restrict dst,
672 	uint32_t len
673 );
674 
675 extern FAudioResampleCallback FAudio_INTERNAL_ResampleMono;
676 extern FAudioResampleCallback FAudio_INTERNAL_ResampleStereo;
677 extern void FAudio_INTERNAL_ResampleGeneric(
678 	float *restrict dCache,
679 	float *restrict resampleCache,
680 	uint64_t *resampleOffset,
681 	uint64_t resampleStep,
682 	uint64_t toResample,
683 	uint8_t channels
684 );
685 
686 extern void (*FAudio_INTERNAL_Amplify)(
687 	float *output,
688 	uint32_t totalSamples,
689 	float volume
690 );
691 
692 extern FAudioMixCallback FAudio_INTERNAL_Mix_Generic;
693 
694 #define MIX_FUNC(type) \
695 	extern void FAudio_INTERNAL_Mix_##type##_Scalar( \
696 		uint32_t toMix, \
697 		uint32_t srcChans, \
698 		uint32_t dstChans, \
699 		float *restrict srcData, \
700 		float *restrict dstData, \
701 		float *restrict coefficients \
702 	);
703 MIX_FUNC(Generic)
704 MIX_FUNC(1in_1out)
705 MIX_FUNC(1in_2out)
706 MIX_FUNC(1in_6out)
707 MIX_FUNC(1in_8out)
708 MIX_FUNC(2in_1out)
709 MIX_FUNC(2in_2out)
710 MIX_FUNC(2in_6out)
711 MIX_FUNC(2in_8out)
712 #undef MIX_FUNC
713 
714 void FAudio_INTERNAL_InitSIMDFunctions(uint8_t hasSSE2, uint8_t hasNEON);
715 
716 /* Decoders */
717 
718 #define DECODE_FUNC(type) \
719 	extern void FAudio_INTERNAL_Decode##type( \
720 		FAudioVoice *voice, \
721 		FAudioBuffer *buffer, \
722 		float *decodeCache, \
723 		uint32_t samples \
724 	);
725 DECODE_FUNC(PCM8)
726 DECODE_FUNC(PCM16)
727 DECODE_FUNC(PCM24)
728 DECODE_FUNC(PCM32)
729 DECODE_FUNC(PCM32F)
730 DECODE_FUNC(MonoMSADPCM)
731 DECODE_FUNC(StereoMSADPCM)
732 DECODE_FUNC(WMAERROR)
733 #undef DECODE_FUNC
734 
735 /* GStreamer */
736 
737 #ifdef HAVE_GSTREAMER
738 uint32_t FAudio_GSTREAMER_init(FAudioSourceVoice *pSourceVoice, uint32_t type);
739 void FAudio_GSTREAMER_free(FAudioSourceVoice *voice);
740 void FAudio_GSTREAMER_end_buffer(FAudioSourceVoice *voice);
741 #endif /* HAVE_GSTREAMER */
742 
743 /* Platform Functions */
744 
745 void FAudio_PlatformAddRef(void);
746 void FAudio_PlatformRelease(void);
747 void FAudio_PlatformInit(
748 	FAudio *audio,
749 	uint32_t flags,
750 	uint32_t deviceIndex,
751 	FAudioWaveFormatExtensible *mixFormat,
752 	uint32_t *updateSize,
753 	void** platformDevice
754 );
755 void FAudio_PlatformQuit(void* platformDevice);
756 
757 uint32_t FAudio_PlatformGetDeviceCount(void);
758 uint32_t FAudio_PlatformGetDeviceDetails(
759 	uint32_t index,
760 	FAudioDeviceDetails *details
761 );
762 
763 /* Threading */
764 
765 FAudioThread FAudio_PlatformCreateThread(
766 	FAudioThreadFunc func,
767 	const char *name,
768 	void* data
769 );
770 void FAudio_PlatformWaitThread(FAudioThread thread, int32_t *retval);
771 void FAudio_PlatformThreadPriority(FAudioThreadPriority priority);
772 uint64_t FAudio_PlatformGetThreadID(void);
773 FAudioMutex FAudio_PlatformCreateMutex(void);
774 void FAudio_PlatformDestroyMutex(FAudioMutex mutex);
775 void FAudio_PlatformLockMutex(FAudioMutex mutex);
776 void FAudio_PlatformUnlockMutex(FAudioMutex mutex);
777 void FAudio_sleep(uint32_t ms);
778 
779 /* Time */
780 
781 uint32_t FAudio_timems(void);
782 
783 /* WaveFormatExtensible Helpers */
784 
GetMask(uint16_t channels)785 static inline uint32_t GetMask(uint16_t channels)
786 {
787 	if (channels == 1) return SPEAKER_MONO;
788 	if (channels == 2) return SPEAKER_STEREO;
789 	if (channels == 3) return SPEAKER_2POINT1;
790 	if (channels == 4) return SPEAKER_QUAD;
791 	if (channels == 5) return SPEAKER_4POINT1;
792 	if (channels == 6) return SPEAKER_5POINT1;
793 	if (channels == 8) return SPEAKER_7POINT1;
794 	FAudio_assert(0 && "Unrecognized speaker layout!");
795 	return 0;
796 }
797 
WriteWaveFormatExtensible(FAudioWaveFormatExtensible * fmt,int channels,int samplerate,const FAudioGUID * subformat)798 static inline void WriteWaveFormatExtensible(
799 	FAudioWaveFormatExtensible *fmt,
800 	int channels,
801 	int samplerate,
802 	const FAudioGUID *subformat
803 ) {
804 	FAudio_assert(fmt != NULL);
805 	fmt->Format.wBitsPerSample = 32;
806 	fmt->Format.wFormatTag = FAUDIO_FORMAT_EXTENSIBLE;
807 	fmt->Format.nChannels = channels;
808 	fmt->Format.nSamplesPerSec = samplerate;
809 	fmt->Format.nBlockAlign = (
810 		fmt->Format.nChannels *
811 		(fmt->Format.wBitsPerSample / 8)
812 	);
813 	fmt->Format.nAvgBytesPerSec = (
814 		fmt->Format.nSamplesPerSec *
815 		fmt->Format.nBlockAlign
816 	);
817 	fmt->Format.cbSize = sizeof(FAudioWaveFormatExtensible) - sizeof(FAudioWaveFormatEx);
818 	fmt->Samples.wValidBitsPerSample = 32;
819 	fmt->dwChannelMask = GetMask(fmt->Format.nChannels);
820 	FAudio_memcpy(&fmt->SubFormat, subformat, sizeof(FAudioGUID));
821 }
822 
823 /* Resampling */
824 
825 /* Okay, so here's what all this fixed-point goo is for:
826  *
827  * Inevitably you're going to run into weird sample rates,
828  * both from WaveBank data and from pitch shifting changes.
829  *
830  * How we deal with this is by calculating a fixed "step"
831  * value that steps from sample to sample at the speed needed
832  * to get the correct output sample rate, and the offset
833  * is stored as separate integer and fraction values.
834  *
835  * This allows us to do weird fractional steps between samples,
836  * while at the same time not letting it drift off into death
837  * thanks to floating point madness.
838  *
839  * Steps are stored in fixed-point with 32 bits for the fraction:
840  *
841  * 00000000000000000000000000000000 00000000000000000000000000000000
842  * ^ Integer block (32)             ^ Fraction block (32)
843  *
844  * For example, to get 1.5:
845  * 00000000000000000000000000000001 10000000000000000000000000000000
846  *
847  * The Integer block works exactly like you'd expect.
848  * The Fraction block is divided by the Integer's "One" value.
849  * So, the above Fraction represented visually...
850  *   1 << 31
851  *   -------
852  *   1 << 32
853  * ... which, simplified, is...
854  *   1 << 0
855  *   ------
856  *   1 << 1
857  * ... in other words, 1 / 2, or 0.5.
858  */
859 #define FIXED_PRECISION		32
860 #define FIXED_ONE		(1LL << FIXED_PRECISION)
861 
862 /* Quick way to drop parts */
863 #define FIXED_FRACTION_MASK	(FIXED_ONE - 1)
864 #define FIXED_INTEGER_MASK	~FIXED_FRACTION_MASK
865 
866 /* Helper macros to convert fixed to float */
867 #define DOUBLE_TO_FIXED(dbl) \
868 	((uint64_t) (dbl * FIXED_ONE + 0.5))
869 #define FIXED_TO_DOUBLE(fxd) ( \
870 	(double) (fxd >> FIXED_PRECISION) + /* Integer part */ \
871 	((fxd & FIXED_FRACTION_MASK) * (1.0 / FIXED_ONE)) /* Fraction part */ \
872 )
873 #define FIXED_TO_FLOAT(fxd) ( \
874 	(float) (fxd >> FIXED_PRECISION) + /* Integer part */ \
875 	((fxd & FIXED_FRACTION_MASK) * (1.0f / FIXED_ONE)) /* Fraction part */ \
876 )
877 
878 #ifdef FAUDIO_DUMP_VOICES
879 /* File writing structure */
880 typedef size_t (FAUDIOCALL * FAudio_writefunc)(
881 	void *data,
882 	const void *src,
883 	size_t size,
884 	size_t count
885 );
886 typedef size_t (FAUDIOCALL * FAudio_sizefunc)(
887 	void *data
888 );
889 typedef struct FAudioIOStreamOut
890 {
891 	void *data;
892 	FAudio_readfunc read;
893 	FAudio_writefunc write;
894 	FAudio_seekfunc seek;
895 	FAudio_sizefunc size;
896 	FAudio_closefunc close;
897 	void *lock;
898 } FAudioIOStreamOut;
899 
900 FAudioIOStreamOut* FAudio_fopen_out(const char *path, const char *mode);
901 void FAudio_close_out(FAudioIOStreamOut *io);
902 #endif /* FAUDIO_DUMP_VOICES */
903 
904 /* vim: set noexpandtab shiftwidth=8 tabstop=8: */
905