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 "FACT.h"
28 #include "FACT3D.h"
29 #include "FAudio_internal.h"
30 
31 /* Internal AudioEngine Types */
32 
33 typedef struct FACTAudioCategory
34 {
35 	uint8_t instanceLimit;
36 	uint16_t fadeInMS;
37 	uint16_t fadeOutMS;
38 	uint8_t maxInstanceBehavior;
39 	int16_t parentCategory;
40 	float volume;
41 	uint8_t visibility;
42 
43 	uint8_t instanceCount;
44 	float currentVolume;
45 } FACTAudioCategory;
46 
47 typedef struct FACTVariable
48 {
49 	uint8_t accessibility;
50 	float initialValue;
51 	float minValue;
52 	float maxValue;
53 } FACTVariable;
54 
55 typedef struct FACTRPCPoint
56 {
57 	float x;
58 	float y;
59 	uint8_t type;
60 } FACTRPCPoint;
61 
62 typedef enum FACTRPCParameter
63 {
64 	RPC_PARAMETER_VOLUME,
65 	RPC_PARAMETER_PITCH,
66 	RPC_PARAMETER_REVERBSEND,
67 	RPC_PARAMETER_FILTERFREQUENCY,
68 	RPC_PARAMETER_FILTERQFACTOR,
69 	RPC_PARAMETER_COUNT /* If >=, DSP Parameter! */
70 } FACTRPCParameter;
71 
72 typedef struct FACTRPC
73 {
74 	uint16_t variable;
75 	uint8_t pointCount;
76 	uint16_t parameter;
77 	FACTRPCPoint *points;
78 } FACTRPC;
79 
80 typedef struct FACTDSPParameter
81 {
82 	uint8_t type;
83 	float value;
84 	float minVal;
85 	float maxVal;
86 	uint16_t unknown;
87 } FACTDSPParameter;
88 
89 typedef struct FACTDSPPreset
90 {
91 	uint8_t accessibility;
92 	uint32_t parameterCount;
93 	FACTDSPParameter *parameters;
94 } FACTDSPPreset;
95 
96 typedef enum FACTNoticationsFlags
97 {
98 	NOTIFY_CUEDESTROY        = 0x0001,
99 	NOTIFY_SOUNDBANKDESTROY  = 0x0002,
100 	NOTIFY_WAVEBANKDESTROY   = 0x0004,
101 	NOTIFY_WAVEDESTROY       = 0x0008,
102 	NOTIFY_WAVESTOP          = 0x0010,
103 } FACTNoticationsFlags;
104 
105 /* Internal SoundBank Types */
106 
107 typedef enum
108 {
109 	FACTEVENT_STOP =				0,
110 	FACTEVENT_PLAYWAVE =				1,
111 	FACTEVENT_PLAYWAVETRACKVARIATION =		3,
112 	FACTEVENT_PLAYWAVEEFFECTVARIATION =		4,
113 	FACTEVENT_PLAYWAVETRACKEFFECTVARIATION =	6,
114 	FACTEVENT_PITCH =				7,
115 	FACTEVENT_VOLUME =				8,
116 	FACTEVENT_MARKER =				9,
117 	FACTEVENT_PITCHREPEATING =			16,
118 	FACTEVENT_VOLUMEREPEATING =			17,
119 	FACTEVENT_MARKERREPEATING =			18
120 } FACTEventType;
121 
122 typedef struct FACTEvent
123 {
124 	uint16_t type;
125 	uint16_t timestamp;
126 	uint16_t randomOffset;
127 	FAUDIONAMELESS union
128 	{
129 		/* Play Wave Event */
130 		struct
131 		{
132 			uint8_t flags;
133 			uint8_t loopCount;
134 			uint16_t position;
135 			uint16_t angle;
136 
137 			/* Track Variation */
138 			uint8_t isComplex;
139 			FAUDIONAMELESS union
140 			{
141 				struct
142 				{
143 					uint16_t track;
144 					uint8_t wavebank;
145 				} simple;
146 				struct
147 				{
148 					uint16_t variation;
149 					uint16_t trackCount;
150 					uint16_t *tracks;
151 					uint8_t *wavebanks;
152 					uint8_t *weights;
153 				} complex;
154 			};
155 
156 			/* Effect Variation */
157 			int16_t minPitch;
158 			int16_t maxPitch;
159 			float minVolume;
160 			float maxVolume;
161 			float minFrequency;
162 			float maxFrequency;
163 			float minQFactor;
164 			float maxQFactor;
165 			uint16_t variationFlags;
166 		} wave;
167 		/* Set Pitch/Volume Event */
168 		struct
169 		{
170 			uint8_t settings;
171 			uint16_t repeats;
172 			uint16_t frequency;
173 			FAUDIONAMELESS union
174 			{
175 				struct
176 				{
177 					float initialValue;
178 					float initialSlope;
179 					float slopeDelta;
180 					uint16_t duration;
181 				} ramp;
182 				struct
183 				{
184 					uint8_t flags;
185 					float value1;
186 					float value2;
187 				} equation;
188 			};
189 		} value;
190 		/* Stop Event */
191 		struct
192 		{
193 			uint8_t flags;
194 		} stop;
195 		/* Marker Event */
196 		struct
197 		{
198 			uint32_t marker;
199 			uint16_t repeats;
200 			uint16_t frequency;
201 		} marker;
202 	};
203 } FACTEvent;
204 
205 typedef struct FACTTrack
206 {
207 	uint32_t code;
208 
209 	float volume;
210 	uint8_t filter;
211 	uint8_t qfactor;
212 	uint16_t frequency;
213 
214 	uint8_t rpcCodeCount;
215 	uint32_t *rpcCodes;
216 
217 	uint8_t eventCount;
218 	FACTEvent *events;
219 } FACTTrack;
220 
221 typedef struct FACTSound
222 {
223 	uint8_t flags;
224 	uint16_t category;
225 	float volume;
226 	int16_t pitch;
227 	uint8_t priority;
228 
229 	uint8_t trackCount;
230 	uint8_t rpcCodeCount;
231 	uint8_t dspCodeCount;
232 
233 	FACTTrack *tracks;
234 	uint32_t *rpcCodes;
235 	uint32_t *dspCodes;
236 } FACTSound;
237 
238 typedef struct FACTCueData
239 {
240 	uint8_t flags;
241 	uint32_t sbCode;
242 	uint32_t transitionOffset;
243 	uint8_t instanceLimit;
244 	uint16_t fadeInMS;
245 	uint16_t fadeOutMS;
246 	uint8_t maxInstanceBehavior;
247 	uint8_t instanceCount;
248 } FACTCueData;
249 
250 typedef struct FACTVariation
251 {
252 	FAUDIONAMELESS union
253 	{
254 		struct
255 		{
256 			uint16_t track;
257 			uint8_t wavebank;
258 		} simple;
259 		uint32_t soundCode;
260 	};
261 	float minWeight;
262 	float maxWeight;
263 	uint32_t linger;
264 } FACTVariation;
265 
266 typedef struct FACTVariationTable
267 {
268 	uint8_t flags;
269 	int16_t variable;
270 	uint8_t isComplex;
271 
272 	uint16_t entryCount;
273 	FACTVariation *entries;
274 } FACTVariationTable;
275 
276 typedef struct FACTTransition
277 {
278 	int32_t soundCode;
279 	uint32_t srcMarkerMin;
280 	uint32_t srcMarkerMax;
281 	uint32_t dstMarkerMin;
282 	uint32_t dstMarkerMax;
283 	uint16_t fadeIn;
284 	uint16_t fadeOut;
285 	uint16_t flags;
286 } FACTTransition;
287 
288 typedef struct FACTTransitionTable
289 {
290 	uint32_t entryCount;
291 	FACTTransition *entries;
292 } FACTTransitionTable;
293 
294 /* Internal WaveBank Types */
295 
296 typedef struct FACTSeekTable
297 {
298 	uint32_t entryCount;
299 	uint32_t *entries;
300 } FACTSeekTable;
301 
302 /* Internal Cue Types */
303 
304 typedef struct FACTInstanceRPCData
305 {
306 	float rpcVolume;
307 	float rpcPitch;
308 	float rpcReverbSend;
309 	float rpcFilterFreq;
310 	float rpcFilterQFactor;
311 } FACTInstanceRPCData;
312 
313 typedef struct FACTEventInstance
314 {
315 	uint32_t timestamp;
316 	uint16_t loopCount;
317 	uint8_t finished;
318 	FAUDIONAMELESS union
319 	{
320 		float value;
321 		uint32_t valuei;
322 	};
323 } FACTEventInstance;
324 
325 typedef struct FACTTrackInstance
326 {
327 	/* Tracks which events have fired */
328 	FACTEventInstance *events;
329 
330 	/* RPC instance data */
331 	FACTInstanceRPCData rpcData;
332 
333 	/* SetPitch/SetVolume data */
334 	float evtPitch;
335 	float evtVolume;
336 
337 	/* Wave playback */
338 	struct
339 	{
340 		FACTWave *wave;
341 		float baseVolume;
342 		int16_t basePitch;
343 		float baseQFactor;
344 		float baseFrequency;
345 	} activeWave, upcomingWave;
346 	FACTEvent *waveEvt;
347 	FACTEventInstance *waveEvtInst;
348 } FACTTrackInstance;
349 
350 typedef struct FACTSoundInstance
351 {
352 	/* Base Sound reference */
353 	FACTSound *sound;
354 
355 	/* Per-instance track information */
356 	FACTTrackInstance *tracks;
357 
358 	/* RPC instance data */
359 	FACTInstanceRPCData rpcData;
360 
361 	/* Fade data */
362 	uint32_t fadeStart;
363 	uint16_t fadeTarget;
364 	uint8_t fadeType; /* In (1), Out (2), Release RPC (3) */
365 
366 	/* Engine references */
367 	FACTCue *parentCue;
368 } FACTSoundInstance;
369 
370 /* Internal Wave Types */
371 
372 typedef struct FACTWaveCallback
373 {
374 	FAudioVoiceCallback callback;
375 	FACTWave *wave;
376 } FACTWaveCallback;
377 
378 /* Public XACT Types */
379 
380 struct FACTAudioEngine
381 {
382 	uint32_t refcount;
383 	FACTNotificationCallback notificationCallback;
384 	FACTReadFileCallback pReadFile;
385 	FACTGetOverlappedResultCallback pGetOverlappedResult;
386 
387 	uint16_t categoryCount;
388 	uint16_t variableCount;
389 	uint16_t rpcCount;
390 	uint16_t dspPresetCount;
391 	uint16_t dspParameterCount;
392 
393 	char **categoryNames;
394 	char **variableNames;
395 	uint32_t *rpcCodes;
396 	uint32_t *dspPresetCodes;
397 
398 	FACTAudioCategory *categories;
399 	FACTVariable *variables;
400 	FACTRPC *rpcs;
401 	FACTDSPPreset *dspPresets;
402 
403 	/* Engine references */
404 	LinkedList *sbList;
405 	LinkedList *wbList;
406 	FAudioMutex sbLock;
407 	FAudioMutex wbLock;
408 	float *globalVariableValues;
409 
410 	/* FAudio references */
411 	FAudio *audio;
412 	FAudioMasteringVoice *master;
413 	FAudioSubmixVoice *reverbVoice;
414 
415 	/* Engine thread */
416 	FAudioThread apiThread;
417 	FAudioMutex apiLock;
418 	uint8_t initialized;
419 
420 	/* Allocator callbacks */
421 	FAudioMallocFunc pMalloc;
422 	FAudioFreeFunc pFree;
423 	FAudioReallocFunc pRealloc;
424 
425 	/* Peristent Notifications */
426 	FACTNoticationsFlags notifications;
427 	void *cue_context;
428 	void *sb_context;
429 	void *wb_context;
430 	void *wave_context;
431 };
432 
433 struct FACTSoundBank
434 {
435 	/* Engine references */
436 	FACTAudioEngine *parentEngine;
437 	FACTCue *cueList;
438 	uint8_t notifyOnDestroy;
439 	void *usercontext;
440 
441 	/* Array sizes */
442 	uint16_t cueCount;
443 	uint8_t wavebankCount;
444 	uint16_t soundCount;
445 	uint16_t variationCount;
446 	uint16_t transitionCount;
447 
448 	/* Strings, strings everywhere! */
449 	char **wavebankNames;
450 	char **cueNames;
451 
452 	/* Actual SoundBank information */
453 	char *name;
454 	FACTCueData *cues;
455 	FACTSound *sounds;
456 	uint32_t *soundCodes;
457 	FACTVariationTable *variations;
458 	uint32_t *variationCodes;
459 	FACTTransitionTable *transitions;
460 	uint32_t *transitionCodes;
461 };
462 
463 struct FACTWaveBank
464 {
465 	/* Engine references */
466 	FACTAudioEngine *parentEngine;
467 	LinkedList *waveList;
468 	FAudioMutex waveLock;
469 	uint8_t notifyOnDestroy;
470 	void *usercontext;
471 
472 	/* Actual WaveBank information */
473 	char *name;
474 	uint32_t entryCount;
475 	FACTWaveBankEntry *entries;
476 	uint32_t *entryRefs;
477 	FACTSeekTable *seekTables;
478 
479 	/* I/O information */
480 	uint32_t packetSize;
481 	uint16_t streaming;
482 	uint8_t *packetBuffer;
483 	uint32_t packetBufferLen;
484 	void* io;
485 };
486 
487 struct FACTWave
488 {
489 	/* Engine references */
490 	FACTWaveBank *parentBank;
491 	FACTCue *parentCue;
492 	uint16_t index;
493 	uint8_t notifyOnDestroy;
494 	void *usercontext;
495 
496 	/* Playback */
497 	uint32_t state;
498 	float volume;
499 	int16_t pitch;
500 	uint8_t loopCount;
501 
502 	/* Stream data */
503 	uint32_t streamSize;
504 	uint32_t streamOffset;
505 	uint8_t *streamCache;
506 
507 	/* FAudio references */
508 	uint16_t srcChannels;
509 	FAudioSourceVoice *voice;
510 	FACTWaveCallback callback;
511 };
512 
513 struct FACTCue
514 {
515 	/* Engine references */
516 	FACTSoundBank *parentBank;
517 	FACTCue *next;
518 	uint8_t managed;
519 	uint16_t index;
520 	uint8_t notifyOnDestroy;
521 	void *usercontext;
522 
523 	/* Sound data */
524 	FACTCueData *data;
525 	FAUDIONAMELESS union
526 	{
527 		FACTVariationTable *variation;
528 
529 		/* This is only used in scenarios where there is only one
530 		 * Sound; XACT does not generate variation tables for
531 		 * Cues with only one Sound.
532 		 */
533 		FACTSound *sound;
534 	};
535 
536 	/* Instance data */
537 	float *variableValues;
538 	float interactive;
539 
540 	/* Playback */
541 	uint32_t state;
542 	FACTWave *simpleWave;
543 	FACTSoundInstance *playingSound;
544 	FACTVariation *playingVariation;
545 	uint32_t maxRpcReleaseTime;
546 
547 	/* 3D Data */
548 	uint8_t active3D;
549 	uint32_t srcChannels;
550 	uint32_t dstChannels;
551 	float matrixCoefficients[2 * 8]; /* Stereo input, 7.1 output */
552 
553 	/* Timer */
554 	uint32_t start;
555 	uint32_t elapsed;
556 };
557 
558 /* Internal functions */
559 
560 void FACT_INTERNAL_GetNextWave(
561 	FACTCue *cue,
562 	FACTSound *sound,
563 	FACTTrack *track,
564 	FACTTrackInstance *trackInst,
565 	FACTEvent *evt,
566 	FACTEventInstance *evtInst
567 );
568 uint8_t FACT_INTERNAL_CreateSound(FACTCue *cue, uint16_t fadeInMS);
569 void FACT_INTERNAL_DestroySound(FACTSoundInstance *sound);
570 void FACT_INTERNAL_BeginFadeOut(FACTSoundInstance *sound, uint16_t fadeOutMS);
571 void FACT_INTERNAL_BeginReleaseRPC(FACTSoundInstance *sound, uint16_t releaseMS);
572 
573 /* RPC Helper Functions */
574 
575 FACTRPC* FACT_INTERNAL_GetRPC(FACTAudioEngine *engine, uint32_t code);
576 
577 /* FACT Thread */
578 
579 int32_t FAUDIOCALL FACT_INTERNAL_APIThread(void* enginePtr);
580 
581 /* FAudio callbacks */
582 
583 void FACT_INTERNAL_OnBufferEnd(FAudioVoiceCallback *callback, void* pContext);
584 void FACT_INTERNAL_OnStreamEnd(FAudioVoiceCallback *callback);
585 
586 /* FAudioIOStream functions */
587 
588 int32_t FACTCALL FACT_INTERNAL_DefaultReadFile(
589 	void *hFile,
590 	void *buffer,
591 	uint32_t nNumberOfBytesToRead,
592 	uint32_t *lpNumberOfBytesRead,
593 	FACTOverlapped *lpOverlapped
594 );
595 
596 int32_t FACTCALL FACT_INTERNAL_DefaultGetOverlappedResult(
597 	void *hFile,
598 	FACTOverlapped *lpOverlapped,
599 	uint32_t *lpNumberOfBytesTransferred,
600 	int32_t bWait
601 );
602 
603 /* Parsing functions */
604 
605 uint32_t FACT_INTERNAL_ParseAudioEngine(
606 	FACTAudioEngine *pEngine,
607 	const FACTRuntimeParameters *pParams
608 );
609 uint32_t FACT_INTERNAL_ParseSoundBank(
610 	FACTAudioEngine *pEngine,
611 	const void *pvBuffer,
612 	uint32_t dwSize,
613 	FACTSoundBank **ppSoundBank
614 );
615 uint32_t FACT_INTERNAL_ParseWaveBank(
616 	FACTAudioEngine *pEngine,
617 	void* io,
618 	uint32_t offset,
619 	uint32_t packetSize,
620 	FACTReadFileCallback pRead,
621 	FACTGetOverlappedResultCallback pOverlap,
622 	uint16_t isStreaming,
623 	FACTWaveBank **ppWaveBank
624 );
625 
626 /* vim: set noexpandtab shiftwidth=8 tabstop=8: */
627