1 /* FAudio - XAudio Reimplementation for FNA
3 * Copyright (c) 2011-2024 Ethan Lee, Luigi Auriemma, and the MonoGame Team
5 * This software is provided 'as-is', without any express or implied warranty.
6 * In no event will the authors be held liable for any damages arising from
7 * the use of this software.
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software in a
15 * product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
21 * 3. This notice may not be removed or altered from any source distribution.
23 * Ethan "flibitijibibo" Lee <flibitijibibo@flibitijibibo.com>
27 #include "FACT_internal.h"
35 #define FACT_INTERNAL_rng() ((float) stb_frand())
39 #define FACT_CONTENT_VERSION_3_4 45
40 #define FACT_CONTENT_VERSION_3_1 44
41 #define FACT_CONTENT_VERSION_3_0 43
42 #define FACT_CONTENT_VERSION_2_4 41
43 #define FACT_CONTENT_VERSION_2_0 37
45 static inline int FACT_INTERNAL_SupportedContent(uint16_t version
)
47 return ( version
== FACT_CONTENT_VERSION
||
48 version
== FACT_CONTENT_VERSION_3_4
||
49 version
== FACT_CONTENT_VERSION_3_1
||
50 version
== FACT_CONTENT_VERSION_3_0
);
53 #define WAVEBANK_HEADER_VERSION 44
54 #define WAVEBANK_HEADER_VERSION_3_4 43
55 #define WAVEBANK_HEADER_VERSION_3_1 42
57 static inline int FACT_INTERNAL_SupportedWBContent(uint16_t version
)
59 return ( version
== WAVEBANK_HEADER_VERSION
||
60 version
== WAVEBANK_HEADER_VERSION_3_4
||
61 version
== WAVEBANK_HEADER_VERSION_3_1
);
64 /* Helper Functions */
66 static inline float FACT_INTERNAL_CalculateAmplitudeRatio(float decibel
)
68 return (float) FAudio_pow(10.0, decibel
/ 2000.0);
71 static inline float FACT_INTERNAL_CalculateFilterFrequency(
72 float desiredFrequency
,
75 /* This is needed to convert linear frequencies to the value
76 * FAudio_INTERNAL_FilterVoice expects, in order for it to actually
77 * filter at the correct frequency.
81 * (2 * sin(pi * (desired filter cutoff frequency) / sampleRate))
83 * ... but it behaves badly as the filter frequency gets too high as a
84 * fraction of the sample rate, hence the mins.
88 float freq
= 2 * FAudio_sin(
90 FAudio_min(desiredFrequency
/ sampleRate
, 0.5f
)
92 return FAudio_min(freq
, 1.0f
);
95 static inline void FACT_INTERNAL_ReadFile(
96 FACTReadFileCallback pReadFile
,
97 FACTGetOverlappedResultCallback pGetOverlappedResult
,
101 uint8_t **packetBuffer
,
102 uint32_t *packetBufferLen
,
103 FAudioReallocFunc pRealloc
,
108 uint32_t realOffset
, realLen
, offPacket
, lenPacket
, result
;
109 uint8_t usePacketBuffer
;
112 ovlp
.Internal
= NULL
;
113 ovlp
.InternalHigh
= NULL
;
114 ovlp
.OffsetHigh
= 0; /* I sure hope so... */
117 /* We have to read data in multiples of the sector size, or else
118 * Win32 ReadFile returns ERROR_INVALID_PARAMETER
125 offPacket
= realOffset
% packetSize
;
129 realOffset
-= offPacket
;
130 realLen
+= offPacket
;
132 lenPacket
= realLen
% packetSize
;
136 realLen
+= (packetSize
- lenPacket
);
140 /* If we're compensating for sector alignment, use a temp buffer and copy to
141 * the real destination after we're finished.
145 if (*packetBufferLen
< realLen
)
147 *packetBufferLen
= realLen
;
148 *packetBuffer
= pRealloc(*packetBuffer
, realLen
);
158 ovlp
.Offset
= realOffset
;
159 if (!pReadFile(io
, buf
, realLen
, NULL
, &ovlp
))
161 while (ovlp
.Internal
== (void*) 0x103) /* STATUS_PENDING */
163 /* Don't actually sleep, just yield the thread */
167 pGetOverlappedResult(io
, &ovlp
, &result
, 1);
169 /* Copy the subregion that we actually care about, if applicable */
172 FAudio_memcpy(dst
, *packetBuffer
+ offPacket
, len
);
176 /* Internal Functions */
178 void FACT_INTERNAL_GetNextWave(
182 FACTTrackInstance
*trackInst
,
184 FACTEventInstance
*evtInst
186 FAudioSendDescriptor reverbDesc
[2];
187 FAudioVoiceSends reverbSends
;
189 FACTWaveBank
*wb
= NULL
;
193 uint8_t loopCount
= 0;
195 uint8_t noTrackVariation
= 1;
198 /* Track Variation */
199 if (evt
->wave
.isComplex
)
201 if ( trackInst
->activeWave
.wave
== NULL
||
202 !(evt
->wave
.complex.variation
& 0x00F0) )
204 /* No-op, no variation on loop */
206 /* Ordered, Ordered From Random */
207 else if ( (evt
->wave
.complex.variation
& 0xF) == 0 ||
208 (evt
->wave
.complex.variation
& 0xF) == 1 )
210 evtInst
->valuei
+= 1;
211 if (evtInst
->valuei
>= evt
->wave
.complex.trackCount
)
217 else if ((evt
->wave
.complex.variation
& 0xF) == 2)
220 for (i
= 0; i
< evt
->wave
.complex.trackCount
; i
+= 1)
222 max
+= evt
->wave
.complex.weights
[i
];
224 next
= FACT_INTERNAL_rng() * max
;
225 for (i
= evt
->wave
.complex.trackCount
; i
> 0; i
-= 1)
227 if (next
> (max
- evt
->wave
.complex.weights
[i
- 1]))
229 evtInst
->valuei
= i
- 1;
232 max
-= evt
->wave
.complex.weights
[i
- 1];
235 /* Random (No Immediate Repeats), Shuffle */
236 else if ( (evt
->wave
.complex.variation
& 0xF) == 3 ||
237 (evt
->wave
.complex.variation
& 0xF) == 4 )
240 for (i
= 0; i
< evt
->wave
.complex.trackCount
; i
+= 1)
242 if (i
== evtInst
->valuei
)
246 max
+= evt
->wave
.complex.weights
[i
];
248 next
= FACT_INTERNAL_rng() * max
;
249 for (i
= evt
->wave
.complex.trackCount
; i
> 0; i
-= 1)
251 if (i
- 1 == evtInst
->valuei
)
255 if (next
> (max
- evt
->wave
.complex.weights
[i
- 1]))
257 evtInst
->valuei
= i
- 1;
260 max
-= evt
->wave
.complex.weights
[i
- 1];
264 if (evt
->wave
.complex.variation
& 0x00F0)
266 noTrackVariation
= 0;
269 wbIndex
= evt
->wave
.complex.wavebanks
[evtInst
->valuei
];
270 wbTrack
= evt
->wave
.complex.tracks
[evtInst
->valuei
];
274 wbIndex
= evt
->wave
.simple
.wavebank
;
275 wbTrack
= evt
->wave
.simple
.track
;
277 wbName
= cue
->parentBank
->wavebankNames
[wbIndex
];
278 list
= cue
->parentBank
->parentEngine
->wbList
;
281 wb
= (FACTWaveBank
*) list
->entry
;
282 if (FAudio_strcmp(wbName
, wb
->name
) == 0)
288 FAudio_assert(wb
!= NULL
);
290 /* Generate the Wave */
291 if ( evtInst
->loopCount
== 255 &&
293 !(evt
->wave
.variationFlags
& 0x0F00) )
295 /* For infinite loops with no variation, let Wave do the work */
298 FACTWaveBank_Prepare(
304 &trackInst
->upcomingWave
.wave
306 trackInst
->upcomingWave
.wave
->parentCue
= cue
;
307 if (sound
->dspCodeCount
> 0) /* Never more than 1...? */
309 reverbDesc
[0].Flags
= 0;
310 reverbDesc
[0].pOutputVoice
= cue
->parentBank
->parentEngine
->master
;
311 reverbDesc
[1].Flags
= 0;
312 reverbDesc
[1].pOutputVoice
= cue
->parentBank
->parentEngine
->reverbVoice
;
313 reverbSends
.SendCount
= 2;
314 reverbSends
.pSends
= reverbDesc
;
315 FAudioVoice_SetOutputVoices(
316 trackInst
->upcomingWave
.wave
->voice
,
324 FACTWave_SetMatrixCoefficients(
325 trackInst
->upcomingWave
.wave
,
328 cue
->matrixCoefficients
333 /* TODO: Position/Angle/UseCenterSpeaker */
336 /* Pitch Variation */
337 if (evt
->wave
.variationFlags
& 0x1000)
339 const int16_t rngPitch
= (int16_t) (
340 FACT_INTERNAL_rng() *
341 (evt
->wave
.maxPitch
- evt
->wave
.minPitch
)
342 ) + evt
->wave
.minPitch
;
343 if (trackInst
->activeWave
.wave
!= NULL
)
345 /* Variation on Loop */
346 if (evt
->wave
.variationFlags
& 0x0100)
349 if (evt
->wave
.variationFlags
& 0x0004)
351 trackInst
->upcomingWave
.basePitch
=
352 trackInst
->activeWave
.basePitch
+ rngPitch
;
356 trackInst
->upcomingWave
.basePitch
= rngPitch
+ sound
->pitch
;
362 /* Initial Pitch Variation */
363 trackInst
->upcomingWave
.basePitch
= rngPitch
+ sound
->pitch
;
368 trackInst
->upcomingWave
.basePitch
= sound
->pitch
;
371 /* Volume Variation */
372 if (evt
->wave
.variationFlags
& 0x2000)
374 const float rngVolume
= (
375 FACT_INTERNAL_rng() *
376 (evt
->wave
.maxVolume
- evt
->wave
.minVolume
)
377 ) + evt
->wave
.minVolume
;
378 if (trackInst
->activeWave
.wave
!= NULL
)
380 /* Variation on Loop */
381 if (evt
->wave
.variationFlags
& 0x0200)
384 if (evt
->wave
.variationFlags
& 0x0001)
386 trackInst
->upcomingWave
.baseVolume
=
387 trackInst
->activeWave
.baseVolume
+ rngVolume
;
391 trackInst
->upcomingWave
.baseVolume
= (
401 /* Initial Volume Variation */
402 trackInst
->upcomingWave
.baseVolume
= (
411 trackInst
->upcomingWave
.baseVolume
= sound
->volume
+ track
->volume
;
414 /* Filter Variation, QFactor/Freq are always together */
415 if (evt
->wave
.variationFlags
& 0xC000)
417 const float rngQFactor
= 1.0f
/ (
418 FACT_INTERNAL_rng() *
419 (evt
->wave
.maxQFactor
- evt
->wave
.minQFactor
) +
422 const float rngFrequency
= FACT_INTERNAL_CalculateFilterFrequency(
424 FACT_INTERNAL_rng() *
425 (evt
->wave
.maxFrequency
- evt
->wave
.minFrequency
) +
426 evt
->wave
.minFrequency
428 cue
->parentBank
->parentEngine
->audio
->master
->master
.inputSampleRate
430 if (trackInst
->activeWave
.wave
!= NULL
)
432 /* Variation on Loop */
433 if (evt
->wave
.variationFlags
& 0x0C00)
435 /* TODO: Add/Replace */
436 /* FIXME: Which is QFactor/Freq?
437 if (evt->wave.variationFlags & 0x0010)
443 if (evt->wave.variationFlags & 0x0040)
450 trackInst
->upcomingWave
.baseQFactor
= rngQFactor
;
451 trackInst
->upcomingWave
.baseFrequency
= rngFrequency
;
456 /* Initial Filter Variation */
457 trackInst
->upcomingWave
.baseQFactor
= rngQFactor
;
458 trackInst
->upcomingWave
.baseFrequency
= rngFrequency
;
463 trackInst
->upcomingWave
.baseQFactor
= 1.0f
/ (track
->qfactor
/ 3.0f
);
464 trackInst
->upcomingWave
.baseFrequency
= FACT_INTERNAL_CalculateFilterFrequency(
466 cue
->parentBank
->parentEngine
->audio
->master
->master
.inputSampleRate
469 /* FIXME: For some reason the 0.67 Q Factor causes problems, but it's also
470 * the only possible value until ~1 so just clamp it for now.
472 trackInst
->upcomingWave
.baseQFactor
= FAudio_min(
473 trackInst
->upcomingWave
.baseQFactor
,
478 /* Try to change loop counter at the very end */
479 if (loopCount
== 255)
481 /* For infinite loops with no variation, Wave does the work */
482 evtInst
->loopCount
= 0;
484 else if (evtInst
->loopCount
> 0)
486 evtInst
->loopCount
-= 1;
490 uint8_t FACT_INTERNAL_CreateSound(FACTCue
*cue
, uint16_t fadeInMS
)
493 float max
, next
, weight
;
495 FACTWaveBank
*wb
= NULL
;
498 FACTEventInstance
*evtInst
;
499 FACTSound
*baseSound
= NULL
;
500 FACTSoundInstance
*newSound
;
510 uint16_t categoryIndex
;
511 FACTAudioCategory
*category
;
513 if (cue
->data
->flags
& 0x04)
516 baseSound
= cue
->sound
;
518 else if (cue
->variation
)
521 if (cue
->variation
->flags
== 3)
524 if (cue
->parentBank
->parentEngine
->variables
[cue
->variation
->variable
].accessibility
& 0x04)
528 cue
->variation
->variable
,
534 FACTAudioEngine_GetGlobalVariable(
535 cue
->parentBank
->parentEngine
,
536 cue
->variation
->variable
,
540 for (i
= 0; i
< cue
->variation
->entryCount
; i
+= 1)
542 if ( next
<= cue
->variation
->entries
[i
].maxWeight
&&
543 next
>= cue
->variation
->entries
[i
].minWeight
)
549 /* This should only happen when the user control
550 * variable is none of the sound probabilities, in
551 * which case we are just silent. But, we should still
552 * claim to be "playing" in the meantime.
554 if (i
== cue
->variation
->entryCount
)
563 for (i
= 0; i
< cue
->variation
->entryCount
; i
+= 1)
566 cue
->variation
->entries
[i
].maxWeight
-
567 cue
->variation
->entries
[i
].minWeight
570 next
= FACT_INTERNAL_rng() * max
;
572 /* Use > 0, not >= 0. If we hit 0, that's it! */
573 for (i
= cue
->variation
->entryCount
- 1; i
> 0; i
-= 1)
576 cue
->variation
->entries
[i
].maxWeight
-
577 cue
->variation
->entries
[i
].minWeight
579 if (next
> (max
- weight
))
587 if (cue
->variation
->isComplex
)
589 /* Grab the Sound via the code. FIXME: Do this at load time? */
590 for (j
= 0; j
< cue
->parentBank
->soundCount
; j
+= 1)
592 if (cue
->variation
->entries
[i
].soundCode
== cue
->parentBank
->soundCodes
[j
])
594 baseSound
= &cue
->parentBank
->sounds
[j
];
601 /* Pull in the WaveBank... */
602 wbName
= cue
->parentBank
->wavebankNames
[
603 cue
->variation
->entries
[i
].simple
.wavebank
605 list
= cue
->parentBank
->parentEngine
->wbList
;
608 wb
= (FACTWaveBank
*) list
->entry
;
609 if (FAudio_strcmp(wbName
, wb
->name
) == 0)
615 FAudio_assert(wb
!= NULL
);
617 /* Generate the wave... */
618 FACTWaveBank_Prepare(
620 cue
->variation
->entries
[i
].simple
.track
,
626 cue
->simpleWave
->parentCue
= cue
;
630 /* Alloc SoundInstance variables */
631 if (baseSound
!= NULL
)
633 /* Category Instance Limits */
634 categoryIndex
= baseSound
->category
;
635 if (categoryIndex
!= FACTCATEGORY_INVALID
)
637 category
= &cue
->parentBank
->parentEngine
->categories
[categoryIndex
];
638 if (category
->instanceCount
>= category
->instanceLimit
)
641 tmp
= cue
->parentBank
->cueList
;
642 if (category
->maxInstanceBehavior
== 0) /* Fail */
644 cue
->state
|= FACT_STATE_STOPPED
;
647 FACT_STATE_STOPPING
|
652 else if (category
->maxInstanceBehavior
== 1) /* Queue */
654 /* FIXME: How is this different from Replace Oldest? */
658 tmp
->playingSound
!= NULL
&&
659 tmp
->playingSound
->sound
->category
== categoryIndex
&&
660 !(tmp
->state
& (FACT_STATE_STOPPING
| FACT_STATE_STOPPED
)) )
668 else if (category
->maxInstanceBehavior
== 2) /* Replace Oldest */
673 tmp
->playingSound
!= NULL
&&
674 tmp
->playingSound
->sound
->category
== categoryIndex
&&
675 !(tmp
->state
& (FACT_STATE_STOPPING
| FACT_STATE_STOPPED
)) )
683 else if (category
->maxInstanceBehavior
== 3) /* Replace Quietest */
685 limitmax
.maxf
= FACTVOLUME_MAX
;
689 tmp
->playingSound
!= NULL
&&
690 tmp
->playingSound
->sound
->category
== categoryIndex
&&
691 /*FIXME: tmp->playingSound->volume < limitmax.maxf &&*/
692 !(tmp
->state
& (FACT_STATE_STOPPING
| FACT_STATE_STOPPED
)) )
695 /* limitmax.maxf = tmp->playingSound->volume; */
700 else if (category
->maxInstanceBehavior
== 4) /* Replace Lowest Priority */
702 limitmax
.maxi
= 0xFF;
706 tmp
->playingSound
!= NULL
&&
707 tmp
->playingSound
->sound
->category
== categoryIndex
&&
708 tmp
->playingSound
->sound
->priority
< limitmax
.maxi
&&
709 !(tmp
->state
& (FACT_STATE_STOPPING
| FACT_STATE_STOPPED
)) )
712 limitmax
.maxi
= tmp
->playingSound
->sound
->priority
;
719 fadeInMS
= category
->fadeInMS
;
720 if (wnr
->playingSound
!= NULL
)
722 FACT_INTERNAL_BeginFadeOut(wnr
->playingSound
, category
->fadeOutMS
);
726 FACTCue_Stop(wnr
, 0);
730 category
->instanceCount
+= 1;
733 newSound
= (FACTSoundInstance
*) cue
->parentBank
->parentEngine
->pMalloc(
734 sizeof(FACTSoundInstance
)
736 newSound
->parentCue
= cue
;
737 newSound
->sound
= baseSound
;
738 newSound
->rpcData
.rpcVolume
= 0.0f
;
739 newSound
->rpcData
.rpcPitch
= 0.0f
;
740 newSound
->rpcData
.rpcReverbSend
= 0.0f
;
741 newSound
->rpcData
.rpcFilterQFactor
= FAUDIO_DEFAULT_FILTER_ONEOVERQ
;
742 newSound
->rpcData
.rpcFilterFreq
= FAUDIO_DEFAULT_FILTER_FREQUENCY
;
743 newSound
->fadeType
= (fadeInMS
> 0);
744 if (newSound
->fadeType
)
746 newSound
->fadeStart
= FAudio_timems();
747 newSound
->fadeTarget
= fadeInMS
;
751 newSound
->fadeStart
= 0;
752 newSound
->fadeTarget
= 0;
754 newSound
->tracks
= (FACTTrackInstance
*) cue
->parentBank
->parentEngine
->pMalloc(
755 sizeof(FACTTrackInstance
) * newSound
->sound
->trackCount
757 for (i
= 0; i
< newSound
->sound
->trackCount
; i
+= 1)
759 newSound
->tracks
[i
].rpcData
.rpcVolume
= 0.0f
;
760 newSound
->tracks
[i
].rpcData
.rpcPitch
= 0.0f
;
761 newSound
->tracks
[i
].rpcData
.rpcReverbSend
= 0.0f
;
762 newSound
->tracks
[i
].rpcData
.rpcFilterQFactor
= FAUDIO_DEFAULT_FILTER_ONEOVERQ
;
763 newSound
->tracks
[i
].rpcData
.rpcFilterFreq
= FAUDIO_DEFAULT_FILTER_FREQUENCY
;
765 newSound
->tracks
[i
].evtVolume
= 0.0f
;
766 newSound
->tracks
[i
].evtPitch
= 0.0f
;
768 newSound
->tracks
[i
].activeWave
.wave
= NULL
;
769 newSound
->tracks
[i
].activeWave
.baseVolume
= 0.0f
;
770 newSound
->tracks
[i
].activeWave
.basePitch
= 0;
771 newSound
->tracks
[i
].activeWave
.baseQFactor
= FAUDIO_DEFAULT_FILTER_ONEOVERQ
;
772 newSound
->tracks
[i
].activeWave
.baseFrequency
= FAUDIO_DEFAULT_FILTER_FREQUENCY
;
773 newSound
->tracks
[i
].upcomingWave
.wave
= NULL
;
774 newSound
->tracks
[i
].upcomingWave
.baseVolume
= 0.0f
;
775 newSound
->tracks
[i
].upcomingWave
.basePitch
= 0;
776 newSound
->tracks
[i
].upcomingWave
.baseQFactor
= FAUDIO_DEFAULT_FILTER_ONEOVERQ
;
777 newSound
->tracks
[i
].upcomingWave
.baseFrequency
= FAUDIO_DEFAULT_FILTER_FREQUENCY
;
779 newSound
->tracks
[i
].events
= (FACTEventInstance
*) cue
->parentBank
->parentEngine
->pMalloc(
780 sizeof(FACTEventInstance
) * newSound
->sound
->tracks
[i
].eventCount
782 for (j
= 0; j
< newSound
->sound
->tracks
[i
].eventCount
; j
+= 1)
784 evt
= &newSound
->sound
->tracks
[i
].events
[j
];
786 newSound
->tracks
[i
].events
[j
].timestamp
=
787 newSound
->sound
->tracks
[i
].events
[j
].timestamp
;
788 newSound
->tracks
[i
].events
[j
].loopCount
= 0;
789 newSound
->tracks
[i
].events
[j
].finished
= 0;
790 newSound
->tracks
[i
].events
[j
].value
= 0.0f
;
792 if ( evt
->type
== FACTEVENT_PLAYWAVE
||
793 evt
->type
== FACTEVENT_PLAYWAVETRACKVARIATION
||
794 evt
->type
== FACTEVENT_PLAYWAVEEFFECTVARIATION
||
795 evt
->type
== FACTEVENT_PLAYWAVETRACKEFFECTVARIATION
)
797 newSound
->tracks
[i
].events
[j
].loopCount
=
798 newSound
->sound
->tracks
[i
].events
[j
].wave
.loopCount
;
800 evtInst
= &newSound
->tracks
[i
].events
[j
];
801 if ( !evt
->wave
.isComplex
||
802 (evt
->wave
.complex.variation
& 0xF) == 0 )
809 for (k
= 0; k
< evt
->wave
.complex.trackCount
; k
+= 1)
811 max
+= evt
->wave
.complex.weights
[k
];
813 next
= FACT_INTERNAL_rng() * max
;
814 for (k
= evt
->wave
.complex.trackCount
- 1; k
>= 0; k
-= 1)
816 if (next
> (max
- evt
->wave
.complex.weights
[k
]))
821 max
-= evt
->wave
.complex.weights
[k
];
824 FACT_INTERNAL_GetNextWave(
827 &newSound
->sound
->tracks
[i
],
828 &newSound
->tracks
[i
],
832 newSound
->tracks
[i
].waveEvt
= evt
;
833 newSound
->tracks
[i
].waveEvtInst
= evtInst
;
835 else if ( evt
->type
== FACTEVENT_PITCHREPEATING
||
836 evt
->type
== FACTEVENT_VOLUMEREPEATING
)
838 newSound
->tracks
[i
].events
[j
].loopCount
=
839 newSound
->sound
->tracks
[i
].events
[j
].value
.repeats
;
841 else if (evt
->type
== FACTEVENT_MARKERREPEATING
)
843 newSound
->tracks
[i
].events
[j
].loopCount
=
844 newSound
->sound
->tracks
[i
].events
[j
].marker
.repeats
;
849 /* Calculate Max RPC Release Time */
850 cue
->maxRpcReleaseTime
= 0;
851 for (i
= 0; i
< newSound
->sound
->trackCount
; i
+= 1)
853 for (j
= 0; j
< newSound
->sound
->tracks
[i
].rpcCodeCount
; j
+= 1)
855 rpc
= FACT_INTERNAL_GetRPC(
856 newSound
->parentCue
->parentBank
->parentEngine
,
857 newSound
->sound
->tracks
[i
].rpcCodes
[j
]
859 if ( rpc
->parameter
== RPC_PARAMETER_VOLUME
&&
860 cue
->parentBank
->parentEngine
->variables
[rpc
->variable
].accessibility
& 0x04 )
863 newSound
->parentCue
->parentBank
->parentEngine
->variableNames
[rpc
->variable
],
866 lastX
= rpc
->points
[rpc
->pointCount
- 1].x
;
867 if (lastX
> cue
->maxRpcReleaseTime
)
869 cue
->maxRpcReleaseTime
= (uint32_t) lastX
/* bleh */;
876 cue
->playingSound
= newSound
;
882 void FACT_INTERNAL_SendCueNotification(FACTCue
*cue
, FACTNoticationsFlags flag
, uint8_t type
)
884 if (cue
->parentBank
->parentEngine
->notifications
& flag
)
886 FACTNotification note
;
889 note
.pvContext
= cue
->parentBank
->parentEngine
->cue_context
;
890 note
.cue
.cueIndex
= cue
->index
;
891 note
.cue
.pSoundBank
= cue
->parentBank
;
894 cue
->parentBank
->parentEngine
->notificationCallback(¬e
);
898 void FACT_INTERNAL_DestroySound(FACTSoundInstance
*sound
)
902 sound
->parentCue
->playingSound
= NULL
;
903 for (i
= 0; i
< sound
->sound
->trackCount
; i
+= 1)
905 if (sound
->tracks
[i
].activeWave
.wave
!= NULL
)
908 sound
->tracks
[i
].activeWave
.wave
911 if (sound
->tracks
[i
].upcomingWave
.wave
!= NULL
)
914 sound
->tracks
[i
].upcomingWave
.wave
917 sound
->parentCue
->parentBank
->parentEngine
->pFree(
918 sound
->tracks
[i
].events
921 sound
->parentCue
->parentBank
->parentEngine
->pFree(sound
->tracks
);
923 if (sound
->sound
->category
!= FACTCATEGORY_INVALID
)
925 sound
->parentCue
->parentBank
->parentEngine
->categories
[
926 sound
->sound
->category
927 ].instanceCount
-= 1;
930 /* TODO: if (sound->parentCue->playingSounds == NULL) */
932 sound
->parentCue
->state
|= FACT_STATE_STOPPED
;
933 sound
->parentCue
->state
&= ~(FACT_STATE_PLAYING
| FACT_STATE_STOPPING
);
934 sound
->parentCue
->data
->instanceCount
-= 1;
936 FACT_INTERNAL_SendCueNotification(sound
->parentCue
, NOTIFY_CUESTOP
, FACTNOTIFICATIONTYPE_CUESTOP
);
938 sound
->parentCue
->parentBank
->parentEngine
->pFree(sound
);
941 void FACT_INTERNAL_BeginFadeOut(FACTSoundInstance
*sound
, uint16_t fadeOutMS
)
945 /* No fade? Screw it, just delete us */
946 FACT_INTERNAL_DestroySound(sound
);
950 sound
->fadeType
= 2; /* Out */
951 sound
->fadeStart
= FAudio_timems();
952 sound
->fadeTarget
= fadeOutMS
;
954 sound
->parentCue
->state
|= FACT_STATE_STOPPING
;
957 void FACT_INTERNAL_BeginReleaseRPC(FACTSoundInstance
*sound
, uint16_t releaseMS
)
961 /* No release RPC? Screw it, just delete us */
962 FACT_INTERNAL_DestroySound(sound
);
966 sound
->fadeType
= 3; /* Release RPC */
967 sound
->fadeStart
= FAudio_timems();
968 sound
->fadeTarget
= releaseMS
;
970 sound
->parentCue
->state
|= FACT_STATE_STOPPING
;
973 /* RPC Helper Functions */
975 FACTRPC
* FACT_INTERNAL_GetRPC(
976 FACTAudioEngine
*engine
,
980 for (i
= 0; i
< engine
->rpcCount
; i
+= 1)
982 if (engine
->rpcCodes
[i
] == code
)
984 return &engine
->rpcs
[i
];
988 FAudio_assert(0 && "RPC code not found!");
992 float FACT_INTERNAL_CalculateRPC(
1000 if (var
<= rpc
->points
[0].x
)
1002 /* Zero to first defined point */
1003 return rpc
->points
[0].y
;
1005 if (var
>= rpc
->points
[rpc
->pointCount
- 1].x
)
1007 /* Last defined point to infinity */
1008 return rpc
->points
[rpc
->pointCount
- 1].y
;
1011 /* Something between points */
1013 for (i
= 0; i
< rpc
->pointCount
- 1; i
+= 1)
1016 result
= rpc
->points
[i
].y
;
1017 if (var
>= rpc
->points
[i
].x
&& var
<= rpc
->points
[i
+ 1].x
)
1019 const float maxX
= rpc
->points
[i
+ 1].x
- rpc
->points
[i
].x
;
1020 const float maxY
= rpc
->points
[i
+ 1].y
- rpc
->points
[i
].y
;
1021 const float deltaX
= (var
- rpc
->points
[i
].x
);
1022 const float deltaXNormalized
= deltaX
/ maxX
;
1024 if (rpc
->points
[i
].type
== 0) /* Linear */
1026 result
+= maxY
* deltaXNormalized
;
1028 else if (rpc
->points
[i
].type
== 1) /* Fast */
1030 result
+= maxY
* (1.0f
- FAudio_pow(1.0f
- FAudio_pow(deltaXNormalized
, 1.0f
/ 1.5f
), 1.5f
));
1032 else if (rpc
->points
[i
].type
== 2) /* Slow */
1034 result
+= maxY
* (1.0f
- FAudio_pow(1.0f
- FAudio_pow(deltaXNormalized
, 1.5f
), 1.0f
/ 1.5f
));
1036 else if (rpc
->points
[i
].type
== 3) /* SinCos */
1040 result
+= maxY
* (1.0f
- FAudio_pow(1.0f
- FAudio_sqrtf(deltaXNormalized
), 2.0f
));
1044 result
+= maxY
* (1.0f
- FAudio_sqrtf(1.0f
- FAudio_pow(deltaXNormalized
, 2.0f
)));
1049 FAudio_assert(0 && "Unrecognized curve type!");
1058 void FACT_INTERNAL_UpdateRPCs(
1062 FACTInstanceRPCData
*data
,
1064 uint32_t elapsedTrack
1069 float variableValue
;
1070 FACTAudioEngine
*engine
= cue
->parentBank
->parentEngine
;
1074 /* Do NOT overwrite Frequency/QFactor! */
1075 data
->rpcVolume
= 0.0f
;
1076 data
->rpcPitch
= 0.0f
;
1077 data
->rpcReverbSend
= 0.0f
;
1078 for (i
= 0; i
< codeCount
; i
+= 1)
1080 rpc
= FACT_INTERNAL_GetRPC(
1084 if (engine
->variables
[rpc
->variable
].accessibility
& 0x04)
1087 engine
->variableNames
[rpc
->variable
],
1090 variableValue
= (float) elapsedTrack
;
1092 else if (FAudio_strcmp(
1093 engine
->variableNames
[rpc
->variable
],
1096 if (cue
->playingSound
->fadeType
== 3) /* Release RPC */
1098 variableValue
= (float) (timestamp
- cue
->playingSound
->fadeStart
);
1102 variableValue
= 0.0f
;
1107 variableValue
= cue
->variableValues
[rpc
->variable
];
1110 rpcResult
= FACT_INTERNAL_CalculateRPC(
1117 rpcResult
= FACT_INTERNAL_CalculateRPC(
1119 engine
->globalVariableValues
[rpc
->variable
]
1122 if (rpc
->parameter
== RPC_PARAMETER_VOLUME
)
1124 data
->rpcVolume
+= rpcResult
;
1126 else if (rpc
->parameter
== RPC_PARAMETER_PITCH
)
1128 data
->rpcPitch
+= rpcResult
;
1130 else if (rpc
->parameter
== RPC_PARAMETER_REVERBSEND
)
1132 data
->rpcReverbSend
+= rpcResult
;
1134 else if (rpc
->parameter
== RPC_PARAMETER_FILTERFREQUENCY
)
1136 /* Yes, just overwrite... */
1137 data
->rpcFilterFreq
= FACT_INTERNAL_CalculateFilterFrequency(
1139 engine
->audio
->master
->master
.inputSampleRate
1142 else if (rpc
->parameter
== RPC_PARAMETER_FILTERQFACTOR
)
1144 /* Yes, just overwrite... */
1145 data
->rpcFilterQFactor
= 1.0f
/ rpcResult
;
1149 FAudio_assert(0 && "Unhandled RPC parameter type!");
1155 /* Engine Update Function */
1157 void FACT_INTERNAL_UpdateEngine(FACTAudioEngine
*engine
)
1159 FAudioFXReverbParameters rvbPar
;
1162 for (i
= 0; i
< engine
->rpcCount
; i
+= 1)
1164 if (engine
->rpcs
[i
].parameter
>= RPC_PARAMETER_COUNT
)
1166 /* FIXME: Why did I make this global vars only...? */
1167 if (!(engine
->variables
[engine
->rpcs
[i
].variable
].accessibility
& 0x04))
1169 for (j
= 0; j
< engine
->dspPresetCount
; j
+= 1)
1171 /* FIXME: This affects all DSP presets!
1172 * What if there's more than one?
1174 par
= engine
->rpcs
[i
].parameter
- RPC_PARAMETER_COUNT
;
1175 rpcResult
= FACT_INTERNAL_CalculateRPC(
1177 engine
->globalVariableValues
[engine
->rpcs
[i
].variable
]
1179 engine
->dspPresets
[j
].parameters
[par
].value
= FAudio_clamp(
1181 engine
->dspPresets
[j
].parameters
[par
].minVal
,
1182 engine
->dspPresets
[j
].parameters
[par
].maxVal
1189 /* Set Effect parameters from above RPC changes */
1190 if (engine
->reverbVoice
!= NULL
)
1192 rvbPar
.WetDryMix
= engine
->dspPresets
[0].parameters
[21].value
;
1193 rvbPar
.ReflectionsDelay
= (uint32_t) engine
->dspPresets
[0].parameters
[0].value
;
1194 rvbPar
.ReverbDelay
= (uint8_t) engine
->dspPresets
[0].parameters
[1].value
;
1195 rvbPar
.RearDelay
= (uint8_t) engine
->dspPresets
[0].parameters
[12].value
;
1196 rvbPar
.PositionLeft
= (uint8_t) engine
->dspPresets
[0].parameters
[2].value
;
1197 rvbPar
.PositionRight
= (uint8_t) engine
->dspPresets
[0].parameters
[3].value
;
1198 rvbPar
.PositionMatrixLeft
= (uint8_t) engine
->dspPresets
[0].parameters
[4].value
;
1199 rvbPar
.PositionMatrixRight
= (uint8_t) engine
->dspPresets
[0].parameters
[5].value
;
1200 rvbPar
.HighEQGain
= (uint8_t) engine
->dspPresets
[0].parameters
[10].value
;
1201 rvbPar
.LowEQCutoff
= (uint8_t) engine
->dspPresets
[0].parameters
[9].value
;
1202 rvbPar
.LowEQGain
= (uint8_t) engine
->dspPresets
[0].parameters
[8].value
;
1203 rvbPar
.LateDiffusion
= (uint8_t) engine
->dspPresets
[0].parameters
[7].value
;
1204 rvbPar
.EarlyDiffusion
= (uint8_t) engine
->dspPresets
[0].parameters
[6].value
;
1205 rvbPar
.HighEQCutoff
= (uint8_t) engine
->dspPresets
[0].parameters
[11].value
;
1206 rvbPar
.RoomFilterMain
= engine
->dspPresets
[0].parameters
[14].value
;
1207 rvbPar
.RoomFilterFreq
= engine
->dspPresets
[0].parameters
[13].value
;
1208 rvbPar
.RoomFilterHF
= engine
->dspPresets
[0].parameters
[15].value
;
1209 rvbPar
.ReflectionsGain
= engine
->dspPresets
[0].parameters
[16].value
;
1210 rvbPar
.ReverbGain
= engine
->dspPresets
[0].parameters
[17].value
;
1211 rvbPar
.DecayTime
= engine
->dspPresets
[0].parameters
[18].value
;
1212 rvbPar
.Density
= engine
->dspPresets
[0].parameters
[19].value
;
1213 rvbPar
.RoomSize
= engine
->dspPresets
[0].parameters
[20].value
;
1215 FAudioVoice_SetEffectParameters(
1216 engine
->reverbVoice
,
1219 sizeof(FAudioFXReverbParameters
),
1225 /* Cue Update Functions */
1227 static inline void FACT_INTERNAL_StopTrack(
1229 FACTTrackInstance
*trackInst
,
1234 /* Stop the wave (may as-authored or immedate */
1235 if (trackInst
->activeWave
.wave
!= NULL
)
1238 trackInst
->activeWave
.wave
,
1243 /* If there was another sound coming, it ain't now! */
1244 if (trackInst
->upcomingWave
.wave
!= NULL
)
1246 FACTWave_Destroy(trackInst
->upcomingWave
.wave
);
1247 trackInst
->upcomingWave
.wave
= NULL
;
1250 /* Kill the loop count too */
1251 for (i
= 0; i
< track
->eventCount
; i
+= 1)
1253 trackInst
->events
[i
].loopCount
= 0;
1254 trackInst
->events
[i
].finished
= 1;
1258 void FACT_INTERNAL_ActivateEvent(
1259 FACTSoundInstance
*sound
,
1261 FACTTrackInstance
*trackInst
,
1263 FACTEventInstance
*evtInst
,
1268 uint8_t skipLoopCheck
= 0;
1271 if (evt
->type
== FACTEVENT_STOP
)
1274 if (evt
->stop
.flags
& 0x02)
1276 if ( evt
->stop
.flags
& 0x01 ||
1277 ( sound
->parentCue
->parentBank
->cues
[sound
->parentCue
->index
].fadeOutMS
== 0 &&
1278 sound
->parentCue
->maxRpcReleaseTime
== 0 ) )
1280 for (i
= 0; i
< sound
->sound
->trackCount
; i
+= 1)
1282 FACT_INTERNAL_StopTrack(
1283 &sound
->sound
->tracks
[i
],
1291 if (sound
->parentCue
->parentBank
->cues
[sound
->parentCue
->index
].fadeOutMS
> 0)
1293 FACT_INTERNAL_BeginFadeOut(
1295 sound
->parentCue
->parentBank
->cues
[sound
->parentCue
->index
].fadeOutMS
1298 else if (sound
->parentCue
->maxRpcReleaseTime
> 0)
1300 FACT_INTERNAL_BeginReleaseRPC(
1302 sound
->parentCue
->maxRpcReleaseTime
1307 /* Pretty sure this doesn't happen, but just in case? */
1308 sound
->parentCue
->state
|= FACT_STATE_STOPPING
;
1316 FACT_INTERNAL_StopTrack(
1319 evt
->stop
.flags
& 0x01
1325 else if ( evt
->type
== FACTEVENT_PLAYWAVE
||
1326 evt
->type
== FACTEVENT_PLAYWAVETRACKVARIATION
||
1327 evt
->type
== FACTEVENT_PLAYWAVEEFFECTVARIATION
||
1328 evt
->type
== FACTEVENT_PLAYWAVETRACKEFFECTVARIATION
)
1330 FAudio_assert(trackInst
->activeWave
.wave
== NULL
);
1331 FAudio_assert(trackInst
->upcomingWave
.wave
!= NULL
);
1333 &trackInst
->activeWave
,
1334 &trackInst
->upcomingWave
,
1335 sizeof(trackInst
->activeWave
)
1337 trackInst
->upcomingWave
.wave
= NULL
;
1338 FACTWave_Play(trackInst
->activeWave
.wave
);
1342 else if ( evt
->type
== FACTEVENT_PITCH
||
1343 evt
->type
== FACTEVENT_PITCHREPEATING
||
1344 evt
->type
== FACTEVENT_VOLUME
||
1345 evt
->type
== FACTEVENT_VOLUMEREPEATING
)
1348 if (evt
->value
.settings
& 0x01)
1350 /* FIXME: Incorporate 2nd derivative into the interpolated pitch (slopeDelta) */
1351 skipLoopCheck
= elapsed
<= (evtInst
->timestamp
+ evt
->value
.ramp
.duration
);
1353 evt
->value
.ramp
.initialSlope
*
1354 evt
->value
.ramp
.duration
/ 1000 *
1356 ) + evt
->value
.ramp
.initialValue
;
1358 (svResult
- evt
->value
.ramp
.initialValue
)
1360 (float) (elapsed
- evtInst
->timestamp
) / evt
->value
.ramp
.duration
,
1363 ) + evt
->value
.ramp
.initialValue
;
1365 evtInst
->value
= svResult
;
1370 if (evt
->value
.equation
.flags
& 0x04)
1372 svResult
= evt
->value
.equation
.value1
;
1374 else if (evt
->value
.equation
.flags
& 0x08)
1376 svResult
= evt
->value
.equation
.value1
+ FACT_INTERNAL_rng() * (
1377 evt
->value
.equation
.value2
-
1378 evt
->value
.equation
.value1
1384 FAudio_assert(0 && "Equation flags?");
1388 if (evt
->value
.equation
.flags
& 0x01)
1390 if( evt
->type
== FACTEVENT_PITCH
||
1391 evt
->type
== FACTEVENT_PITCHREPEATING
)
1393 evtInst
->value
= trackInst
->evtPitch
+ svResult
;
1397 evtInst
->value
= trackInst
->evtVolume
+ svResult
;
1402 evtInst
->value
= svResult
;
1406 /* Set the result, finally. */
1407 if ( evt
->type
== FACTEVENT_PITCH
||
1408 evt
->type
== FACTEVENT_PITCHREPEATING
)
1410 trackInst
->evtPitch
= evtInst
->value
;
1414 trackInst
->evtVolume
= evtInst
->value
;
1421 if (evtInst
->loopCount
> 0)
1423 if (evtInst
->loopCount
!= 0xFF && evtInst
->loopCount
!= 0xFFFF)
1425 evtInst
->loopCount
-= 1;
1428 evtInst
->timestamp
+= evt
->value
.frequency
;
1434 else if ( evt
->type
== FACTEVENT_MARKER
||
1435 evt
->type
== FACTEVENT_MARKERREPEATING
)
1437 /* TODO: FACT_INTERNAL_Marker(evt->marker*) */
1438 if (evtInst
->loopCount
> 0)
1440 if (evtInst
->loopCount
!= 0xFF)
1442 evtInst
->loopCount
-= 1;
1445 evtInst
->timestamp
+= evt
->marker
.frequency
;
1453 FAudio_assert(0 && "Unknown event type!");
1456 /* If we made it here, we're done! */
1457 evtInst
->finished
= 1;
1460 uint8_t FACT_INTERNAL_UpdateSound(FACTSoundInstance
*sound
, uint32_t timestamp
)
1464 uint32_t elapsedCue
;
1465 FACTEventInstance
*evtInst
;
1466 FAudioFilterParameters filterParams
;
1467 uint8_t finished
= 1;
1469 /* Instance limiting Fade in/out */
1471 if (sound
->fadeType
== 1) /* Fade In */
1473 if ((timestamp
- sound
->fadeStart
) >= sound
->fadeTarget
)
1475 /* We've faded in! */
1477 sound
->fadeStart
= 0;
1478 sound
->fadeTarget
= 0;
1479 sound
->fadeType
= 0;
1484 (float) (timestamp
- sound
->fadeStart
) /
1485 (float) sound
->fadeTarget
1489 else if (sound
->fadeType
== 2) /* Fade Out */
1491 if ((timestamp
- sound
->fadeStart
) >= sound
->fadeTarget
)
1493 /* We've faded out! */
1496 fadeVolume
= 1.0f
- (
1497 (float) (timestamp
- sound
->fadeStart
) /
1498 (float) sound
->fadeTarget
1501 else if (sound
->fadeType
== 3) /* Release RPC */
1503 if ((timestamp
- sound
->fadeStart
) >= sound
->fadeTarget
)
1505 /* We've faded out! */
1515 /* To get the time on a single Cue, subtract from the global time
1516 * the latest start time minus the total time elapsed (minus pause time)
1518 elapsedCue
= timestamp
- (sound
->parentCue
->start
- sound
->parentCue
->elapsed
);
1521 sound
->rpcData
.rpcFilterFreq
= -1.0f
;
1522 sound
->rpcData
.rpcFilterQFactor
= -1.0f
;
1523 FACT_INTERNAL_UpdateRPCs(
1525 sound
->sound
->rpcCodeCount
,
1526 sound
->sound
->rpcCodes
,
1529 elapsedCue
- sound
->tracks
[0].events
[0].timestamp
1531 for (i
= 0; i
< sound
->sound
->trackCount
; i
+= 1)
1533 sound
->tracks
[i
].rpcData
.rpcFilterFreq
= sound
->rpcData
.rpcFilterFreq
;
1534 sound
->tracks
[i
].rpcData
.rpcFilterQFactor
= sound
->rpcData
.rpcFilterQFactor
;
1535 FACT_INTERNAL_UpdateRPCs(
1537 sound
->sound
->tracks
[i
].rpcCodeCount
,
1538 sound
->sound
->tracks
[i
].rpcCodes
,
1539 &sound
->tracks
[i
].rpcData
,
1541 elapsedCue
- sound
->sound
->tracks
[i
].events
[0].timestamp
1545 /* Go through each event for each track */
1546 for (i
= 0; i
< sound
->sound
->trackCount
; i
+= 1)
1549 for (j
= 0; j
< sound
->sound
->tracks
[i
].eventCount
; j
+= 1)
1551 evtInst
= &sound
->tracks
[i
].events
[j
];
1552 if (!evtInst
->finished
)
1554 /* Cue's not done yet...! */
1557 /* Trigger events at the right time */
1558 if (elapsedCue
>= evtInst
->timestamp
)
1560 FACT_INTERNAL_ActivateEvent(
1562 &sound
->sound
->tracks
[i
],
1564 &sound
->sound
->tracks
[i
].events
[j
],
1573 if (sound
->tracks
[i
].activeWave
.wave
== NULL
)
1579 /* Clear out Waves as they finish */
1581 sound
->tracks
[i
].activeWave
.wave
,
1584 if (waveState
& FACT_STATE_STOPPED
)
1586 FACTWave_Destroy(sound
->tracks
[i
].activeWave
.wave
);
1588 &sound
->tracks
[i
].activeWave
,
1589 &sound
->tracks
[i
].upcomingWave
,
1590 sizeof(sound
->tracks
[i
].activeWave
)
1592 sound
->tracks
[i
].upcomingWave
.wave
= NULL
;
1593 if (sound
->tracks
[i
].activeWave
.wave
== NULL
)
1597 FACTWave_Play(sound
->tracks
[i
].activeWave
.wave
);
1601 sound
->tracks
[i
].activeWave
.wave
,
1602 FACT_INTERNAL_CalculateAmplitudeRatio(
1603 sound
->tracks
[i
].activeWave
.baseVolume
+
1604 sound
->rpcData
.rpcVolume
+
1605 sound
->tracks
[i
].rpcData
.rpcVolume
+
1606 sound
->tracks
[i
].evtVolume
1607 ) * sound
->parentCue
->parentBank
->parentEngine
->categories
[
1608 sound
->sound
->category
1613 sound
->tracks
[i
].activeWave
.wave
,
1615 sound
->tracks
[i
].activeWave
.basePitch
+
1616 sound
->rpcData
.rpcPitch
+
1617 sound
->tracks
[i
].rpcData
.rpcPitch
+
1618 sound
->tracks
[i
].evtPitch
1621 if (sound
->sound
->tracks
[i
].filter
!= 0xFF)
1623 /* FIXME: From what I can gather, filter parameters get
1624 * overwritten by the RPC value if a filter RPC exists.
1625 * Priority is Sound < Sound RPC < Track RPC, I think?
1627 filterParams
.Type
= (FAudioFilterType
) sound
->sound
->tracks
[i
].filter
;
1628 if (sound
->tracks
[i
].rpcData
.rpcFilterFreq
>= 0.0f
)
1630 filterParams
.Frequency
= sound
->tracks
[i
].rpcData
.rpcFilterFreq
;
1634 filterParams
.Frequency
= sound
->tracks
[i
].activeWave
.baseFrequency
;
1636 if (sound
->tracks
[i
].rpcData
.rpcFilterQFactor
>= 0.0f
)
1638 filterParams
.OneOverQ
= sound
->tracks
[i
].rpcData
.rpcFilterQFactor
;
1642 filterParams
.OneOverQ
= sound
->tracks
[i
].activeWave
.baseQFactor
;
1644 FAudioVoice_SetFilterParameters(
1645 sound
->tracks
[i
].activeWave
.wave
->voice
,
1650 /* TODO: Wave updates:
1651 * - ReverbSend (SetOutputMatrix on index 1, submix voice)
1658 void FACT_INTERNAL_UpdateCue(FACTCue
*cue
)
1662 FACTSoundInstance
*sound
;
1664 /* Interactive sound selection */
1665 if (!(cue
->data
->flags
& 0x04) && cue
->variation
&& cue
->variation
->flags
== 3)
1668 if (cue
->parentBank
->parentEngine
->variables
[cue
->variation
->variable
].accessibility
& 0x04)
1670 FACTCue_GetVariable(
1672 cue
->variation
->variable
,
1678 FACTAudioEngine_GetGlobalVariable(
1679 cue
->parentBank
->parentEngine
,
1680 cue
->variation
->variable
,
1684 if (next
!= cue
->interactive
)
1686 cue
->interactive
= next
;
1688 /* New sound, time for death! */
1689 if (cue
->playingSound
!= NULL
)
1691 /* Copy of DestroySound but does not set Cue to STOPPED */
1692 sound
= cue
->playingSound
;
1693 sound
->parentCue
->playingSound
= NULL
;
1694 for (i
= 0; i
< sound
->sound
->trackCount
; i
+= 1)
1696 if (sound
->tracks
[i
].activeWave
.wave
!= NULL
)
1699 sound
->tracks
[i
].activeWave
.wave
1702 if (sound
->tracks
[i
].upcomingWave
.wave
!= NULL
)
1705 sound
->tracks
[i
].upcomingWave
.wave
1708 cue
->parentBank
->parentEngine
->pFree(
1709 sound
->tracks
[i
].events
1712 cue
->parentBank
->parentEngine
->pFree(sound
->tracks
);
1714 if (sound
->sound
->category
!= FACTCATEGORY_INVALID
)
1716 sound
->parentCue
->parentBank
->parentEngine
->categories
[
1717 sound
->sound
->category
1718 ].instanceCount
-= 1;
1722 /* TODO: Reset cue times? Transition tables...?
1723 cue->start = elapsed;
1727 FACT_INTERNAL_CreateSound(cue
, 0 /* fadeIn */);
1734 int32_t FACT_INTERNAL_APIThread(void* enginePtr
)
1736 FACTAudioEngine
*engine
= (FACTAudioEngine
*) enginePtr
;
1738 FACTCue
*cue
, *cBackup
;
1739 uint32_t timestamp
, updateTime
;
1741 /* Needs to match the audio thread priority, or else the scheduler will
1742 * let this thread sit around with a lock while the audio thread spins
1745 FAudio_PlatformThreadPriority(FAUDIO_THREAD_PRIORITY_HIGH
);
1748 FAudio_PlatformLockMutex(engine
->apiLock
);
1750 /* We want the timestamp to be uniform across all Cues.
1751 * Oftentimes many Cues are played at once with the expectation
1752 * that they will sync, so give them all the same timestamp
1753 * so all the various actions will go together even if it takes
1754 * an extra millisecond to get through the whole Cue list.
1756 timestamp
= FAudio_timems();
1758 FACT_INTERNAL_UpdateEngine(engine
);
1760 sbList
= engine
->sbList
;
1761 while (sbList
!= NULL
)
1763 cue
= ((FACTSoundBank
*) sbList
->entry
)->cueList
;
1766 FACT_INTERNAL_UpdateCue(cue
);
1768 if (cue
->state
& FACT_STATE_PAUSED
)
1774 if (cue
->playingSound
!= NULL
)
1776 if (FACT_INTERNAL_UpdateSound(cue
->playingSound
, timestamp
))
1778 FACT_INTERNAL_DestroySound(cue
->playingSound
);
1782 /* Destroy if it's done and not user-handled. */
1783 if (cue
->managed
&& (cue
->state
& FACT_STATE_STOPPED
))
1785 cBackup
= cue
->next
;
1786 FACTCue_Destroy(cue
);
1794 sbList
= sbList
->next
;
1797 FAudio_PlatformUnlockMutex(engine
->apiLock
);
1799 if (engine
->initialized
)
1801 /* FIXME: 10ms is based on the XAudio2 update time...? */
1802 updateTime
= FAudio_timems() - timestamp
;
1803 if (updateTime
< 10)
1805 FAudio_sleep(10 - updateTime
);
1813 /* FAudio callbacks */
1815 void FACT_INTERNAL_OnBufferEnd(FAudioVoiceCallback
*callback
, void* pContext
)
1817 FAudioBuffer buffer
;
1818 FAudioBufferWMA bufferWMA
;
1819 FACTWaveCallback
*c
= (FACTWaveCallback
*) callback
;
1820 FACTWaveBankEntry
*entry
;
1821 uint32_t end
, left
, length
;
1823 entry
= &c
->wave
->parentBank
->entries
[c
->wave
->index
];
1825 /* Calculate total bytes left in this wave iteration */
1826 if (c
->wave
->loopCount
> 0 && entry
->LoopRegion
.dwTotalSamples
> 0)
1828 length
= entry
->LoopRegion
.dwStartSample
+ entry
->LoopRegion
.dwTotalSamples
;
1829 if (entry
->Format
.wFormatTag
== 0x0)
1833 entry
->Format
.nChannels
*
1834 (1 << entry
->Format
.wBitsPerSample
)
1837 else if (entry
->Format
.wFormatTag
== 0x2)
1841 /* wSamplesPerBlock */
1842 ((entry
->Format
.wBlockAlign
+ 16) * 2) *
1844 ((entry
->Format
.wBlockAlign
+ 22) * entry
->Format
.nChannels
)
1849 length
= entry
->PlayRegion
.dwLength
;
1854 length
= entry
->PlayRegion
.dwLength
;
1856 end
= entry
->PlayRegion
.dwOffset
+ length
;
1857 left
= length
- (c
->wave
->streamOffset
- entry
->PlayRegion
.dwOffset
);
1859 /* Don't bother if we're EOS or the Wave has stopped */
1860 if ( (c
->wave
->streamOffset
>= end
) ||
1861 (c
->wave
->state
& FACT_STATE_STOPPED
) )
1866 /* Assign buffer memory */
1867 buffer
.pAudioData
= c
->wave
->streamCache
;
1868 buffer
.AudioBytes
= FAudio_min(
1869 c
->wave
->streamSize
,
1874 FACT_INTERNAL_ReadFile(
1875 c
->wave
->parentBank
->parentEngine
->pReadFile
,
1876 c
->wave
->parentBank
->parentEngine
->pGetOverlappedResult
,
1877 c
->wave
->parentBank
->io
,
1878 c
->wave
->streamOffset
,
1879 c
->wave
->parentBank
->packetSize
,
1880 &c
->wave
->parentBank
->packetBuffer
,
1881 &c
->wave
->parentBank
->packetBufferLen
,
1882 c
->wave
->parentBank
->parentEngine
->pRealloc
,
1883 c
->wave
->streamCache
,
1886 c
->wave
->streamOffset
+= buffer
.AudioBytes
;
1888 /* Last buffer in the stream? */
1890 if (c
->wave
->streamOffset
>= end
)
1892 /* Loop if applicable */
1893 if (c
->wave
->loopCount
> 0)
1895 if (c
->wave
->loopCount
!= 255)
1897 c
->wave
->loopCount
-= 1;
1899 c
->wave
->streamOffset
= entry
->PlayRegion
.dwOffset
;
1902 if (entry
->Format
.wFormatTag
== 0x0)
1904 c
->wave
->streamOffset
+= (
1905 entry
->LoopRegion
.dwStartSample
*
1906 entry
->Format
.nChannels
*
1907 (1 << entry
->Format
.wBitsPerSample
)
1910 else if (entry
->Format
.wFormatTag
== 0x2)
1912 c
->wave
->streamOffset
+= (
1913 entry
->LoopRegion
.dwStartSample
/
1914 /* wSamplesPerBlock */
1915 ((entry
->Format
.wBlockAlign
+ 16) * 2) *
1917 ((entry
->Format
.wBlockAlign
+ 22) * entry
->Format
.nChannels
)
1923 buffer
.Flags
= FAUDIO_END_OF_STREAM
;
1927 /* Unused properties */
1928 buffer
.PlayBegin
= 0;
1929 buffer
.PlayLength
= 0;
1930 buffer
.LoopBegin
= 0;
1931 buffer
.LoopLength
= 0;
1932 buffer
.LoopCount
= 0;
1933 buffer
.pContext
= NULL
;
1935 /* Submit, finally. */
1936 if (entry
->Format
.wFormatTag
== 0x3)
1938 bufferWMA
.pDecodedPacketCumulativeBytes
=
1939 c
->wave
->parentBank
->seekTables
[c
->wave
->index
].entries
;
1940 bufferWMA
.PacketCount
=
1941 c
->wave
->parentBank
->seekTables
[c
->wave
->index
].entryCount
;
1942 FAudioSourceVoice_SubmitSourceBuffer(
1950 FAudioSourceVoice_SubmitSourceBuffer(
1958 void FACT_INTERNAL_OnStreamEnd(FAudioVoiceCallback
*callback
)
1960 FACTWaveCallback
*c
= (FACTWaveCallback
*) callback
;
1962 c
->wave
->state
= FACT_STATE_STOPPED
;
1964 if ( c
->wave
->parentCue
!= NULL
&&
1965 c
->wave
->parentCue
->simpleWave
== c
->wave
)
1967 c
->wave
->parentCue
->state
|= FACT_STATE_STOPPED
;
1968 c
->wave
->parentCue
->state
&= ~(
1969 FACT_STATE_PLAYING
|
1972 c
->wave
->parentCue
->data
->instanceCount
-= 1;
1976 /* FAudioIOStream functions */
1978 int32_t FACTCALL
FACT_INTERNAL_DefaultReadFile(
1981 uint32_t nNumberOfBytesToRead
,
1982 uint32_t *lpNumberOfBytesRead
, /* Not referenced! */
1983 FACTOverlapped
*lpOverlapped
1985 FAudioIOStream
*io
= (FAudioIOStream
*) hFile
;
1986 lpOverlapped
->Internal
= (void*) 0x00000103; /* STATUS_PENDING */
1987 FAudio_PlatformLockMutex((FAudioMutex
) io
->lock
);
1988 io
->seek(io
->data
, (size_t) lpOverlapped
->Pointer
, FAUDIO_SEEK_SET
);
1989 lpOverlapped
->InternalHigh
= (void*) (size_t) (io
->read(
1992 nNumberOfBytesToRead
,
1994 ) * nNumberOfBytesToRead
);
1995 FAudio_PlatformUnlockMutex((FAudioMutex
) io
->lock
);
1996 lpOverlapped
->Internal
= 0; /* STATUS_SUCCESS */
2000 int32_t FACTCALL
FACT_INTERNAL_DefaultGetOverlappedResult(
2002 FACTOverlapped
*lpOverlapped
,
2003 uint32_t *lpNumberOfBytesTransferred
,
2006 *lpNumberOfBytesTransferred
= (uint32_t) (size_t) lpOverlapped
->InternalHigh
;
2010 /* Parsing functions */
2012 #define READ_FUNC(type, size, bitsize, suffix) \
2013 static inline type read_##suffix(uint8_t **ptr, const uint8_t swapendian) \
2015 type result = *((type*) *ptr); \
2017 return swapendian ? \
2018 FAudio_swap##bitsize##BE(result) : \
2019 FAudio_swap##bitsize##LE(result); \
2022 static inline uint8_t read_u8(uint8_t **ptr
)
2024 uint8_t result
= *((uint8_t*) *ptr
);
2028 READ_FUNC(uint16_t, 2, 16, u16
)
2029 READ_FUNC(uint32_t, 4, 32, u32
)
2030 READ_FUNC(int16_t, 2, 16, s16
)
2031 READ_FUNC(int32_t, 4, 32, s32
)
2032 static inline float read_f32(uint8_t **ptr
, const uint8_t swapendian
)
2034 float result
= *((float*) *ptr
);
2041 static inline float read_volbyte(uint8_t **ptr
)
2043 /* FIXME: This magnificent beauty came from Mathematica!
2044 * The byte values for all possible input dB values from the .xap are here:
2045 * http://www.flibitijibibo.com/XACTVolume.txt
2046 * Yes, this is actually what the XACT builder really does.
2048 * Thanks to Kenny for plotting all that data.
2051 return (float) ((3969.0 * FAudio_log10(read_u8(ptr
) / 28240.0)) + 8715.0);
2054 uint32_t FACT_INTERNAL_ParseAudioEngine(
2055 FACTAudioEngine
*pEngine
,
2056 const FACTRuntimeParameters
*pParams
2058 uint32_t categoryOffset
,
2061 categoryNameIndexOffset
,
2063 variableNameIndexOffset
,
2069 uint16_t blob1Count
, blob2Count
;
2070 uint8_t version
, tool
;
2076 uint8_t *ptr
= (uint8_t*) pParams
->pGlobalSettingsBuffer
;
2077 uint8_t *start
= ptr
;
2079 magic
= read_u32(&ptr
, 0);
2080 se
= magic
== 0x58475346; /* Swap Endian */
2081 if (magic
!= 0x46534758 && magic
!= 0x58475346) /* 'XGSF' */
2083 return -1; /* TODO: NOT XACT FILE */
2086 if (!FACT_INTERNAL_SupportedContent(read_u16(&ptr
, se
)))
2091 tool
= read_u16(&ptr
, se
); /* Tool version */
2097 ptr
+= 2; /* Unknown value */
2099 /* Last modified, unused */
2102 /* XACT Version (Windows == 3, Xbox == 7) */
2103 version
= read_u8(&ptr
);
2104 if ( version
!= 3 &&
2107 return -4; /* TODO: VERSION TOO OLD */
2111 pEngine
->categoryCount
= read_u16(&ptr
, se
);
2112 pEngine
->variableCount
= read_u16(&ptr
, se
);
2113 blob1Count
= read_u16(&ptr
, se
);
2114 blob2Count
= read_u16(&ptr
, se
);
2115 pEngine
->rpcCount
= read_u16(&ptr
, se
);
2116 pEngine
->dspPresetCount
= read_u16(&ptr
, se
);
2117 pEngine
->dspParameterCount
= read_u16(&ptr
, se
);
2119 /* Object offsets */
2120 categoryOffset
= read_u32(&ptr
, se
);
2121 variableOffset
= read_u32(&ptr
, se
);
2122 blob1Offset
= read_u32(&ptr
, se
);
2123 categoryNameIndexOffset
= read_u32(&ptr
, se
);
2124 blob2Offset
= read_u32(&ptr
, se
);
2125 variableNameIndexOffset
= read_u32(&ptr
, se
);
2126 categoryNameOffset
= read_u32(&ptr
, se
);
2127 variableNameOffset
= read_u32(&ptr
, se
);
2128 rpcOffset
= read_u32(&ptr
, se
);
2129 dspPresetOffset
= read_u32(&ptr
, se
);
2130 dspParameterOffset
= read_u32(&ptr
, se
);
2133 FAudio_assert((ptr
- start
) == categoryOffset
);
2134 pEngine
->categories
= (FACTAudioCategory
*) pEngine
->pMalloc(
2135 sizeof(FACTAudioCategory
) * pEngine
->categoryCount
2137 for (i
= 0; i
< pEngine
->categoryCount
; i
+= 1)
2139 pEngine
->categories
[i
].instanceLimit
= read_u8(&ptr
);
2140 pEngine
->categories
[i
].fadeInMS
= read_u16(&ptr
, se
);
2141 pEngine
->categories
[i
].fadeOutMS
= read_u16(&ptr
, se
);
2142 pEngine
->categories
[i
].maxInstanceBehavior
= read_u8(&ptr
) >> 3;
2143 pEngine
->categories
[i
].parentCategory
= read_u16(&ptr
, se
);
2144 pEngine
->categories
[i
].volume
= FACT_INTERNAL_CalculateAmplitudeRatio(
2147 pEngine
->categories
[i
].visibility
= read_u8(&ptr
);
2148 pEngine
->categories
[i
].instanceCount
= 0;
2149 pEngine
->categories
[i
].currentVolume
= 1.0f
;
2153 FAudio_assert((ptr
- start
) == variableOffset
);
2154 pEngine
->variables
= (FACTVariable
*) pEngine
->pMalloc(
2155 sizeof(FACTVariable
) * pEngine
->variableCount
2157 for (i
= 0; i
< pEngine
->variableCount
; i
+= 1)
2159 pEngine
->variables
[i
].accessibility
= read_u8(&ptr
);
2160 pEngine
->variables
[i
].initialValue
= read_f32(&ptr
, se
);
2161 pEngine
->variables
[i
].minValue
= read_f32(&ptr
, se
);
2162 pEngine
->variables
[i
].maxValue
= read_f32(&ptr
, se
);
2165 /* Global variable storage. Some unused data for non-global vars */
2166 pEngine
->globalVariableValues
= (float*) pEngine
->pMalloc(
2167 sizeof(float) * pEngine
->variableCount
2169 for (i
= 0; i
< pEngine
->variableCount
; i
+= 1)
2171 pEngine
->globalVariableValues
[i
] = pEngine
->variables
[i
].initialValue
;
2175 if (pEngine
->rpcCount
> 0)
2177 FAudio_assert((ptr
- start
) == rpcOffset
);
2178 pEngine
->rpcs
= (FACTRPC
*) pEngine
->pMalloc(
2182 pEngine
->rpcCodes
= (uint32_t*) pEngine
->pMalloc(
2186 for (i
= 0; i
< pEngine
->rpcCount
; i
+= 1)
2188 pEngine
->rpcCodes
[i
] = (uint32_t) (ptr
- start
);
2189 pEngine
->rpcs
[i
].variable
= read_u16(&ptr
, se
);
2190 pEngine
->rpcs
[i
].pointCount
= read_u8(&ptr
);
2191 pEngine
->rpcs
[i
].parameter
= read_u16(&ptr
, se
);
2192 pEngine
->rpcs
[i
].points
= (FACTRPCPoint
*) pEngine
->pMalloc(
2193 sizeof(FACTRPCPoint
) *
2194 pEngine
->rpcs
[i
].pointCount
2196 for (j
= 0; j
< pEngine
->rpcs
[i
].pointCount
; j
+= 1)
2198 pEngine
->rpcs
[i
].points
[j
].x
= read_f32(&ptr
, se
);
2199 pEngine
->rpcs
[i
].points
[j
].y
= read_f32(&ptr
, se
);
2200 pEngine
->rpcs
[i
].points
[j
].type
= read_u8(&ptr
);
2205 /* DSP Preset data */
2206 if (pEngine
->dspPresetCount
> 0)
2208 FAudio_assert((ptr
- start
) == dspPresetOffset
);
2209 pEngine
->dspPresets
= (FACTDSPPreset
*) pEngine
->pMalloc(
2210 sizeof(FACTDSPPreset
) *
2211 pEngine
->dspPresetCount
2213 pEngine
->dspPresetCodes
= (uint32_t*) pEngine
->pMalloc(
2215 pEngine
->dspPresetCount
2217 for (i
= 0; i
< pEngine
->dspPresetCount
; i
+= 1)
2219 pEngine
->dspPresetCodes
[i
] = (uint32_t) (ptr
- start
);
2220 pEngine
->dspPresets
[i
].accessibility
= read_u8(&ptr
);
2221 pEngine
->dspPresets
[i
].parameterCount
= read_u16(&ptr
, se
);
2222 ptr
+= 2; /* Unknown value */
2223 pEngine
->dspPresets
[i
].parameters
= (FACTDSPParameter
*) pEngine
->pMalloc(
2224 sizeof(FACTDSPParameter
) *
2225 pEngine
->dspPresets
[i
].parameterCount
2226 ); /* This will be filled in just a moment... */
2229 /* DSP Parameter data */
2230 FAudio_assert((ptr
- start
) == dspParameterOffset
);
2231 for (i
= 0; i
< pEngine
->dspPresetCount
; i
+= 1)
2233 for (j
= 0; j
< pEngine
->dspPresets
[i
].parameterCount
; j
+= 1)
2235 pEngine
->dspPresets
[i
].parameters
[j
].type
= read_u8(&ptr
);
2236 pEngine
->dspPresets
[i
].parameters
[j
].value
= read_f32(&ptr
, se
);
2237 pEngine
->dspPresets
[i
].parameters
[j
].minVal
= read_f32(&ptr
, se
);
2238 pEngine
->dspPresets
[i
].parameters
[j
].maxVal
= read_f32(&ptr
, se
);
2239 pEngine
->dspPresets
[i
].parameters
[j
].unknown
= read_u16(&ptr
, se
);
2244 /* Blob #1, no idea what this is... */
2245 FAudio_assert((ptr
- start
) == blob1Offset
);
2246 ptr
+= blob1Count
* 2;
2248 /* Category Name Index data */
2249 FAudio_assert((ptr
- start
) == categoryNameIndexOffset
);
2250 ptr
+= pEngine
->categoryCount
* 6; /* FIXME: index as assert value? */
2252 /* Category Name data */
2253 FAudio_assert((ptr
- start
) == categoryNameOffset
);
2254 pEngine
->categoryNames
= (char**) pEngine
->pMalloc(
2256 pEngine
->categoryCount
2258 for (i
= 0; i
< pEngine
->categoryCount
; i
+= 1)
2260 memsize
= FAudio_strlen((char*) ptr
) + 1; /* Dastardly! */
2261 pEngine
->categoryNames
[i
] = (char*) pEngine
->pMalloc(memsize
);
2262 FAudio_memcpy(pEngine
->categoryNames
[i
], ptr
, memsize
);
2266 /* Blob #2, no idea what this is... */
2267 FAudio_assert((ptr
- start
) == blob2Offset
);
2268 ptr
+= blob2Count
* 2;
2270 /* Variable Name Index data */
2271 FAudio_assert((ptr
- start
) == variableNameIndexOffset
);
2272 ptr
+= pEngine
->variableCount
* 6; /* FIXME: index as assert value? */
2274 /* Variable Name data */
2275 FAudio_assert((ptr
- start
) == variableNameOffset
);
2276 pEngine
->variableNames
= (char**) pEngine
->pMalloc(
2278 pEngine
->variableCount
2280 for (i
= 0; i
< pEngine
->variableCount
; i
+= 1)
2282 memsize
= FAudio_strlen((char*) ptr
) + 1; /* Dastardly! */
2283 pEngine
->variableNames
[i
] = (char*) pEngine
->pMalloc(memsize
);
2284 FAudio_memcpy(pEngine
->variableNames
[i
], ptr
, memsize
);
2288 /* Store this pointer in case we're asked to free it */
2289 if (pParams
->globalSettingsFlags
& FACT_FLAG_MANAGEDATA
)
2291 pEngine
->settings
= pParams
->pGlobalSettingsBuffer
;
2295 FAudio_assert((ptr
- start
) == pParams
->globalSettingsBufferSize
);
2299 void FACT_INTERNAL_ParseTrackEvents(
2303 FAudioMallocFunc pMalloc
2306 uint8_t minWeight
, maxWeight
, separator
;
2310 track
->eventCount
= read_u8(ptr
);
2311 track
->events
= (FACTEvent
*) pMalloc(
2315 FAudio_zero(track
->events
, sizeof(FACTEvent
) * track
->eventCount
);
2316 for (i
= 0; i
< track
->eventCount
; i
+= 1)
2318 evtInfo
= read_u32(ptr
, se
);
2319 track
->events
[i
].randomOffset
= read_u16(ptr
, se
);
2321 track
->events
[i
].type
= evtInfo
& 0x001F;
2322 track
->events
[i
].timestamp
= (evtInfo
>> 5) & 0xFFFF;
2324 separator
= read_u8(ptr
);
2325 FAudio_assert(separator
== 0xFF); /* Separator? */
2327 #define EVTTYPE(t) (track->events[i].type == t)
2328 if (EVTTYPE(FACTEVENT_STOP
))
2330 track
->events
[i
].stop
.flags
= read_u8(ptr
);
2332 else if (EVTTYPE(FACTEVENT_PLAYWAVE
))
2335 track
->events
[i
].wave
.isComplex
= 0;
2336 track
->events
[i
].wave
.flags
= read_u8(ptr
);
2337 track
->events
[i
].wave
.simple
.track
= read_u16(ptr
, se
);
2338 track
->events
[i
].wave
.simple
.wavebank
= read_u8(ptr
);
2339 track
->events
[i
].wave
.loopCount
= read_u8(ptr
);
2340 track
->events
[i
].wave
.position
= read_u16(ptr
, se
);
2341 track
->events
[i
].wave
.angle
= read_u16(ptr
, se
);
2343 /* No Effect Variation */
2344 track
->events
[i
].wave
.variationFlags
= 0;
2346 else if (EVTTYPE(FACTEVENT_PLAYWAVETRACKVARIATION
))
2349 track
->events
[i
].wave
.isComplex
= 1;
2350 track
->events
[i
].wave
.flags
= read_u8(ptr
);
2351 track
->events
[i
].wave
.loopCount
= read_u8(ptr
);
2352 track
->events
[i
].wave
.position
= read_u16(ptr
, se
);
2353 track
->events
[i
].wave
.angle
= read_u16(ptr
, se
);
2355 /* Track Variation */
2356 evtInfo
= read_u32(ptr
, se
);
2357 track
->events
[i
].wave
.complex.trackCount
= evtInfo
& 0xFFFF;
2358 track
->events
[i
].wave
.complex.variation
= (evtInfo
>> 16) & 0xFFFF;
2359 *ptr
+= 4; /* Unknown values */
2360 track
->events
[i
].wave
.complex.tracks
= (uint16_t*) pMalloc(
2362 track
->events
[i
].wave
.complex.trackCount
2364 track
->events
[i
].wave
.complex.wavebanks
= (uint8_t*) pMalloc(
2366 track
->events
[i
].wave
.complex.trackCount
2368 track
->events
[i
].wave
.complex.weights
= (uint8_t*) pMalloc(
2370 track
->events
[i
].wave
.complex.trackCount
2372 for (j
= 0; j
< track
->events
[i
].wave
.complex.trackCount
; j
+= 1)
2374 track
->events
[i
].wave
.complex.tracks
[j
] = read_u16(ptr
, se
);
2375 track
->events
[i
].wave
.complex.wavebanks
[j
] = read_u8(ptr
);
2376 minWeight
= read_u8(ptr
);
2377 maxWeight
= read_u8(ptr
);
2378 track
->events
[i
].wave
.complex.weights
[j
] = (
2379 maxWeight
- minWeight
2383 /* No Effect Variation */
2384 track
->events
[i
].wave
.variationFlags
= 0;
2386 else if (EVTTYPE(FACTEVENT_PLAYWAVEEFFECTVARIATION
))
2389 track
->events
[i
].wave
.isComplex
= 0;
2390 track
->events
[i
].wave
.flags
= read_u8(ptr
);
2391 track
->events
[i
].wave
.simple
.track
= read_u16(ptr
, se
);
2392 track
->events
[i
].wave
.simple
.wavebank
= read_u8(ptr
);
2393 track
->events
[i
].wave
.loopCount
= read_u8(ptr
);
2394 track
->events
[i
].wave
.position
= read_u16(ptr
, se
);
2395 track
->events
[i
].wave
.angle
= read_u16(ptr
, se
);
2397 /* Effect Variation */
2398 track
->events
[i
].wave
.minPitch
= read_s16(ptr
, se
);
2399 track
->events
[i
].wave
.maxPitch
= read_s16(ptr
, se
);
2400 track
->events
[i
].wave
.minVolume
= read_volbyte(ptr
);
2401 track
->events
[i
].wave
.maxVolume
= read_volbyte(ptr
);
2402 track
->events
[i
].wave
.minFrequency
= read_f32(ptr
, se
);
2403 track
->events
[i
].wave
.maxFrequency
= read_f32(ptr
, se
);
2404 track
->events
[i
].wave
.minQFactor
= read_f32(ptr
, se
);
2405 track
->events
[i
].wave
.maxQFactor
= read_f32(ptr
, se
);
2406 track
->events
[i
].wave
.variationFlags
= read_u16(ptr
, se
);
2408 else if (EVTTYPE(FACTEVENT_PLAYWAVETRACKEFFECTVARIATION
))
2411 track
->events
[i
].wave
.isComplex
= 1;
2412 track
->events
[i
].wave
.flags
= read_u8(ptr
);
2413 track
->events
[i
].wave
.loopCount
= read_u8(ptr
);
2414 track
->events
[i
].wave
.position
= read_u16(ptr
, se
);
2415 track
->events
[i
].wave
.angle
= read_u16(ptr
, se
);
2417 /* Effect Variation */
2418 track
->events
[i
].wave
.minPitch
= read_s16(ptr
, se
);
2419 track
->events
[i
].wave
.maxPitch
= read_s16(ptr
, se
);
2420 track
->events
[i
].wave
.minVolume
= read_volbyte(ptr
);
2421 track
->events
[i
].wave
.maxVolume
= read_volbyte(ptr
);
2422 track
->events
[i
].wave
.minFrequency
= read_f32(ptr
, se
);
2423 track
->events
[i
].wave
.maxFrequency
= read_f32(ptr
, se
);
2424 track
->events
[i
].wave
.minQFactor
= read_f32(ptr
, se
);
2425 track
->events
[i
].wave
.maxQFactor
= read_f32(ptr
, se
);
2426 track
->events
[i
].wave
.variationFlags
= read_u16(ptr
, se
);
2428 /* Track Variation */
2429 evtInfo
= read_u32(ptr
, se
);
2430 track
->events
[i
].wave
.complex.trackCount
= evtInfo
& 0xFFFF;
2431 track
->events
[i
].wave
.complex.variation
= (evtInfo
>> 16) & 0xFFFF;
2432 *ptr
+= 4; /* Unknown values */
2433 track
->events
[i
].wave
.complex.tracks
= (uint16_t*) pMalloc(
2435 track
->events
[i
].wave
.complex.trackCount
2437 track
->events
[i
].wave
.complex.wavebanks
= (uint8_t*) pMalloc(
2439 track
->events
[i
].wave
.complex.trackCount
2441 track
->events
[i
].wave
.complex.weights
= (uint8_t*) pMalloc(
2443 track
->events
[i
].wave
.complex.trackCount
2445 for (j
= 0; j
< track
->events
[i
].wave
.complex.trackCount
; j
+= 1)
2447 track
->events
[i
].wave
.complex.tracks
[j
] = read_u16(ptr
, se
);
2448 track
->events
[i
].wave
.complex.wavebanks
[j
] = read_u8(ptr
);
2449 minWeight
= read_u8(ptr
);
2450 maxWeight
= read_u8(ptr
);
2451 track
->events
[i
].wave
.complex.weights
[j
] = (
2452 maxWeight
- minWeight
2456 else if ( EVTTYPE(FACTEVENT_PITCH
) ||
2457 EVTTYPE(FACTEVENT_VOLUME
) ||
2458 EVTTYPE(FACTEVENT_PITCHREPEATING
) ||
2459 EVTTYPE(FACTEVENT_VOLUMEREPEATING
) )
2461 track
->events
[i
].value
.settings
= read_u8(ptr
);
2462 if (track
->events
[i
].value
.settings
& 1) /* Ramp */
2464 track
->events
[i
].value
.repeats
= 0;
2465 track
->events
[i
].value
.ramp
.initialValue
= read_f32(ptr
, se
);
2466 track
->events
[i
].value
.ramp
.initialSlope
= read_f32(ptr
, se
) * 100;
2467 track
->events
[i
].value
.ramp
.slopeDelta
= read_f32(ptr
, se
);
2468 track
->events
[i
].value
.ramp
.duration
= read_u16(ptr
, se
);
2472 track
->events
[i
].value
.equation
.flags
= read_u8(ptr
);
2474 /* SetValue, SetRandomValue, anything else? */
2475 FAudio_assert(track
->events
[i
].value
.equation
.flags
& 0x0C);
2477 track
->events
[i
].value
.equation
.value1
= read_f32(ptr
, se
);
2478 track
->events
[i
].value
.equation
.value2
= read_f32(ptr
, se
);
2480 *ptr
+= 5; /* Unknown values */
2482 if ( EVTTYPE(FACTEVENT_PITCHREPEATING
) ||
2483 EVTTYPE(FACTEVENT_VOLUMEREPEATING
) )
2485 track
->events
[i
].value
.repeats
= read_u16(ptr
, se
);
2486 track
->events
[i
].value
.frequency
= read_u16(ptr
, se
);
2490 track
->events
[i
].value
.repeats
= 0;
2494 else if (EVTTYPE(FACTEVENT_MARKER
))
2496 track
->events
[i
].marker
.marker
= read_u32(ptr
, se
);
2497 track
->events
[i
].marker
.repeats
= 0;
2498 track
->events
[i
].marker
.frequency
= 0;
2500 else if (EVTTYPE(FACTEVENT_MARKERREPEATING
))
2502 track
->events
[i
].marker
.marker
= read_u32(ptr
, se
);
2503 track
->events
[i
].marker
.repeats
= read_u16(ptr
, se
);
2504 track
->events
[i
].marker
.frequency
= read_u16(ptr
, se
);
2508 FAudio_assert(0 && "Unknown event type!");
2514 uint32_t FACT_INTERNAL_ParseSoundBank(
2515 FACTAudioEngine
*pEngine
,
2516 const void *pvBuffer
,
2518 FACTSoundBank
**ppSoundBank
2521 uint16_t contentVersion
,
2525 int32_t cueSimpleOffset
,
2534 uint32_t entryCountAndFlags
;
2535 uint16_t filterData
;
2538 uint16_t i
, j
, k
, cur
, tool
;
2539 uint8_t *ptrBookmark
;
2541 uint8_t *ptr
= (uint8_t*) pvBuffer
;
2542 uint8_t *start
= ptr
;
2544 uint32_t magic
= read_u32(&ptr
, 0);
2545 uint8_t se
= magic
== 0x5344424B; /* Swap Endian */
2547 if (magic
!= 0x4B424453 && magic
!= 0x5344424B) /* 'SDBK' */
2549 return -1; /* TODO: NOT XACT FILE */
2552 contentVersion
= read_u16(&ptr
, se
);
2553 if (!FACT_INTERNAL_SupportedContent(contentVersion
))
2558 tool
= read_u16(&ptr
, se
); /* Tool version */
2567 /* Last modified, unused */
2570 /* Windows == 1, Xbox == 3. 0 is unknown, probably old content */
2571 platform
= read_u8(&ptr
);
2572 if ( platform
!= 0 &&
2576 return -4; /* TODO: WRONG PLATFORM */
2579 sb
= (FACTSoundBank
*) pEngine
->pMalloc(sizeof(FACTSoundBank
));
2580 sb
->parentEngine
= pEngine
;
2582 sb
->notifyOnDestroy
= 0;
2583 sb
->usercontext
= NULL
;
2585 cueSimpleCount
= read_u16(&ptr
, se
);
2586 cueComplexCount
= read_u16(&ptr
, se
);
2588 ptr
+= 2; /* Unknown value */
2590 cueTotalAlign
= read_u16(&ptr
, se
); /* FIXME: Why? */
2591 sb
->cueCount
= cueSimpleCount
+ cueComplexCount
;
2592 sb
->wavebankCount
= read_u8(&ptr
);
2593 sb
->soundCount
= read_u16(&ptr
, se
);
2595 /* Cue name length, unused */
2598 ptr
+= 2; /* Unknown value */
2600 cueSimpleOffset
= read_s32(&ptr
, se
);
2601 cueComplexOffset
= read_s32(&ptr
, se
);
2602 cueNameOffset
= read_s32(&ptr
, se
);
2604 ptr
+= 4; /* Unknown value */
2606 variationOffset
= read_s32(&ptr
, se
);
2607 transitionOffset
= read_s32(&ptr
, se
);
2608 wavebankNameOffset
= read_s32(&ptr
, se
);
2609 cueHashOffset
= read_s32(&ptr
, se
);
2610 cueNameIndexOffset
= read_s32(&ptr
, se
);
2611 soundOffset
= read_s32(&ptr
, se
);
2613 /* SoundBank Name */
2614 memsize
= FAudio_strlen((char*) ptr
) + 1; /* Dastardly! */
2615 sb
->name
= (char*) pEngine
->pMalloc(memsize
);
2616 FAudio_memcpy(sb
->name
, ptr
, memsize
);
2619 /* WaveBank Name data */
2620 FAudio_assert((ptr
- start
) == wavebankNameOffset
);
2621 ptr
= start
+ wavebankNameOffset
;
2622 sb
->wavebankNames
= (char**) pEngine
->pMalloc(
2626 for (i
= 0; i
< sb
->wavebankCount
; i
+= 1)
2628 memsize
= FAudio_strlen((char*) ptr
) + 1;
2629 sb
->wavebankNames
[i
] = (char*) pEngine
->pMalloc(memsize
);
2630 FAudio_memcpy(sb
->wavebankNames
[i
], ptr
, memsize
);
2635 FAudio_assert((ptr
- start
) == soundOffset
);
2636 sb
->sounds
= (FACTSound
*) pEngine
->pMalloc(
2640 sb
->soundCodes
= (uint32_t*) pEngine
->pMalloc(
2644 for (i
= 0; i
< sb
->soundCount
; i
+= 1)
2646 sb
->soundCodes
[i
] = (uint32_t) (ptr
- start
);
2647 sb
->sounds
[i
].flags
= read_u8(&ptr
);
2648 sb
->sounds
[i
].category
= read_u16(&ptr
, se
);
2649 sb
->sounds
[i
].volume
= read_volbyte(&ptr
);
2650 sb
->sounds
[i
].pitch
= read_s16(&ptr
, se
);
2651 sb
->sounds
[i
].priority
= read_u8(&ptr
);
2653 /* Length of sound entry, unused */
2656 /* Simple/Complex Track data */
2657 if (sb
->sounds
[i
].flags
& 0x01)
2659 sb
->sounds
[i
].trackCount
= read_u8(&ptr
);
2660 memsize
= sizeof(FACTTrack
) * sb
->sounds
[i
].trackCount
;
2661 sb
->sounds
[i
].tracks
= (FACTTrack
*) pEngine
->pMalloc(memsize
);
2662 FAudio_zero(sb
->sounds
[i
].tracks
, memsize
);
2666 sb
->sounds
[i
].trackCount
= 1;
2667 memsize
= sizeof(FACTTrack
) * sb
->sounds
[i
].trackCount
;
2668 sb
->sounds
[i
].tracks
= (FACTTrack
*) pEngine
->pMalloc(memsize
);
2669 FAudio_zero(sb
->sounds
[i
].tracks
, memsize
);
2670 sb
->sounds
[i
].tracks
[0].volume
= 0.0f
;
2671 sb
->sounds
[i
].tracks
[0].filter
= 0xFF;
2672 sb
->sounds
[i
].tracks
[0].eventCount
= 1;
2673 sb
->sounds
[i
].tracks
[0].events
= (FACTEvent
*) pEngine
->pMalloc(
2677 sb
->sounds
[i
].tracks
[0].events
,
2680 sb
->sounds
[i
].tracks
[0].events
[0].type
= FACTEVENT_PLAYWAVE
;
2681 sb
->sounds
[i
].tracks
[0].events
[0].wave
.position
= 0; /* FIXME */
2682 sb
->sounds
[i
].tracks
[0].events
[0].wave
.angle
= 0; /* FIXME */
2683 sb
->sounds
[i
].tracks
[0].events
[0].wave
.simple
.track
= read_u16(&ptr
, se
);
2684 sb
->sounds
[i
].tracks
[0].events
[0].wave
.simple
.wavebank
= read_u8(&ptr
);
2688 if (sb
->sounds
[i
].flags
& 0x0E)
2690 const uint16_t rpcDataLength
= read_u16(&ptr
, se
);
2691 ptrBookmark
= ptr
- 2;
2693 #define COPYRPCBLOCK(loc) \
2694 loc.rpcCodeCount = read_u8(&ptr); \
2695 memsize = sizeof(uint32_t) * loc.rpcCodeCount; \
2696 loc.rpcCodes = (uint32_t*) pEngine->pMalloc(memsize); \
2697 for (k = 0; k < loc.rpcCodeCount; k += 1) \
2699 loc.rpcCodes[k] = read_u32(&ptr, se); \
2702 /* Sound has attached RPCs */
2703 if (sb
->sounds
[i
].flags
& 0x02)
2705 COPYRPCBLOCK(sb
->sounds
[i
])
2709 sb
->sounds
[i
].rpcCodeCount
= 0;
2710 sb
->sounds
[i
].rpcCodes
= NULL
;
2713 /* Tracks have attached RPCs */
2714 if (sb
->sounds
[i
].flags
& 0x04)
2716 for (j
= 0; j
< sb
->sounds
[i
].trackCount
; j
+= 1)
2718 COPYRPCBLOCK(sb
->sounds
[i
].tracks
[j
])
2723 for (j
= 0; j
< sb
->sounds
[i
].trackCount
; j
+= 1)
2725 sb
->sounds
[i
].tracks
[j
].rpcCodeCount
= 0;
2726 sb
->sounds
[i
].tracks
[j
].rpcCodes
= NULL
;
2732 /* FIXME: Does 0x08 mean something for RPCs...? */
2733 FAudio_assert((ptr
- ptrBookmark
) == rpcDataLength
);
2737 sb
->sounds
[i
].rpcCodeCount
= 0;
2738 sb
->sounds
[i
].rpcCodes
= NULL
;
2739 for (j
= 0; j
< sb
->sounds
[i
].trackCount
; j
+= 1)
2741 sb
->sounds
[i
].tracks
[j
].rpcCodeCount
= 0;
2742 sb
->sounds
[i
].tracks
[j
].rpcCodes
= NULL
;
2746 /* DSP Preset Code data */
2747 if (sb
->sounds
[i
].flags
& 0x10)
2749 /* DSP presets length, unused */
2752 sb
->sounds
[i
].dspCodeCount
= read_u8(&ptr
);
2753 memsize
= sizeof(uint32_t) * sb
->sounds
[i
].dspCodeCount
;
2754 sb
->sounds
[i
].dspCodes
= (uint32_t*) pEngine
->pMalloc(memsize
);
2755 for (j
= 0; j
< sb
->sounds
[i
].dspCodeCount
; j
+= 1)
2757 sb
->sounds
[i
].dspCodes
[j
] = read_u32(&ptr
, se
);
2762 sb
->sounds
[i
].dspCodeCount
= 0;
2763 sb
->sounds
[i
].dspCodes
= NULL
;
2767 if (sb
->sounds
[i
].flags
& 0x01)
2769 for (j
= 0; j
< sb
->sounds
[i
].trackCount
; j
+= 1)
2771 sb
->sounds
[i
].tracks
[j
].volume
= read_volbyte(&ptr
);
2773 sb
->sounds
[i
].tracks
[j
].code
= read_u32(&ptr
, se
);
2775 if (contentVersion
== FACT_CONTENT_VERSION_3_0
)
2777 /* 3.0 doesn't have track filter data */
2778 sb
->sounds
[i
].tracks
[j
].filter
= 0xFF;
2779 sb
->sounds
[i
].tracks
[j
].qfactor
= 0;
2780 sb
->sounds
[i
].tracks
[j
].frequency
= 0;
2784 filterData
= read_u16(&ptr
, se
);
2785 if (filterData
& 0x0001)
2787 sb
->sounds
[i
].tracks
[j
].filter
=
2788 (filterData
>> 1) & 0x02;
2793 sb
->sounds
[i
].tracks
[j
].filter
= 0xFF;
2795 sb
->sounds
[i
].tracks
[j
].qfactor
= (filterData
>> 8) & 0xFF;
2796 sb
->sounds
[i
].tracks
[j
].frequency
= read_u16(&ptr
, se
);
2799 /* All Track events are stored at the end of the block */
2800 for (j
= 0; j
< sb
->sounds
[i
].trackCount
; j
+= 1)
2802 FAudio_assert((ptr
- start
) == sb
->sounds
[i
].tracks
[j
].code
);
2803 FACT_INTERNAL_ParseTrackEvents(
2806 &sb
->sounds
[i
].tracks
[j
],
2814 sb
->variationCount
= 0;
2815 sb
->transitionCount
= 0;
2816 sb
->cues
= (FACTCueData
*) pEngine
->pMalloc(
2817 sizeof(FACTCueData
) *
2822 /* Simple Cue data */
2823 FAudio_assert(cueSimpleCount
== 0 || (ptr
- start
) == cueSimpleOffset
);
2824 if (cueSimpleCount
> 0)
2826 ptr
= start
+ cueSimpleOffset
;
2828 for (i
= 0; i
< cueSimpleCount
; i
+= 1, cur
+= 1)
2830 sb
->cues
[cur
].flags
= read_u8(&ptr
);
2831 sb
->cues
[cur
].sbCode
= read_u32(&ptr
, se
);
2832 sb
->cues
[cur
].transitionOffset
= 0;
2833 sb
->cues
[cur
].instanceLimit
= 0xFF;
2834 sb
->cues
[cur
].fadeInMS
= 0;
2835 sb
->cues
[cur
].fadeOutMS
= 0;
2836 sb
->cues
[cur
].maxInstanceBehavior
= 0;
2837 sb
->cues
[cur
].instanceCount
= 0;
2841 /* Complex Cue data */
2842 FAudio_assert(cueComplexCount
== 0 || (ptr
- start
) == cueComplexOffset
);
2843 if (cueComplexCount
> 0)
2845 ptr
= start
+ cueComplexOffset
;
2847 for (i
= 0; i
< cueComplexCount
; i
+= 1, cur
+= 1)
2849 sb
->cues
[cur
].flags
= read_u8(&ptr
);
2850 sb
->cues
[cur
].sbCode
= read_u32(&ptr
, se
);
2851 sb
->cues
[cur
].transitionOffset
= read_u32(&ptr
, se
);
2852 if (sb
->cues
[cur
].transitionOffset
== 0xFFFFFFFF)
2855 sb
->cues
[cur
].transitionOffset
= 0;
2857 sb
->cues
[cur
].instanceLimit
= read_u8(&ptr
);
2858 sb
->cues
[cur
].fadeInMS
= read_u16(&ptr
, se
);
2859 sb
->cues
[cur
].fadeOutMS
= read_u16(&ptr
, se
);
2860 sb
->cues
[cur
].maxInstanceBehavior
= read_u8(&ptr
) >> 3;
2861 sb
->cues
[cur
].instanceCount
= 0;
2863 if (!(sb
->cues
[cur
].flags
& 0x04))
2865 /* FIXME: Is this the only way to get this...? */
2866 sb
->variationCount
+= 1;
2868 if (sb
->cues
[cur
].transitionOffset
> 0)
2870 /* FIXME: Is this the only way to get this...? */
2871 sb
->transitionCount
+= 1;
2876 /* Variation data */
2877 if (sb
->variationCount
> 0)
2879 FAudio_assert((ptr
- start
) == variationOffset
);
2880 ptr
= start
+ variationOffset
;
2881 sb
->variations
= (FACTVariationTable
*) pEngine
->pMalloc(
2882 sizeof(FACTVariationTable
) *
2885 sb
->variationCodes
= (uint32_t*) pEngine
->pMalloc(
2892 sb
->variations
= NULL
;
2893 sb
->variationCodes
= NULL
;
2895 for (i
= 0; i
< sb
->variationCount
; i
+= 1)
2897 sb
->variationCodes
[i
] = (uint32_t) (ptr
- start
);
2898 entryCountAndFlags
= read_u32(&ptr
, se
);
2899 sb
->variations
[i
].entryCount
= entryCountAndFlags
& 0xFFFF;
2900 sb
->variations
[i
].flags
= (entryCountAndFlags
>> (16 + 3)) & 0x07;
2901 ptr
+= 2; /* Unknown value */
2902 sb
->variations
[i
].variable
= read_s16(&ptr
, se
);
2903 memsize
= sizeof(FACTVariation
) * sb
->variations
[i
].entryCount
;
2904 sb
->variations
[i
].entries
= (FACTVariation
*) pEngine
->pMalloc(
2907 FAudio_zero(sb
->variations
[i
].entries
, memsize
);
2909 if (sb
->variations
[i
].flags
== 0)
2911 /* Wave with byte min/max */
2912 sb
->variations
[i
].isComplex
= 0;
2913 for (j
= 0; j
< sb
->variations
[i
].entryCount
; j
+= 1)
2915 sb
->variations
[i
].entries
[j
].simple
.track
= read_u16(&ptr
, se
);
2916 sb
->variations
[i
].entries
[j
].simple
.wavebank
= read_u8(&ptr
);
2917 sb
->variations
[i
].entries
[j
].minWeight
= read_u8(&ptr
) / 255.0f
;
2918 sb
->variations
[i
].entries
[j
].maxWeight
= read_u8(&ptr
) / 255.0f
;
2921 else if (sb
->variations
[i
].flags
== 1)
2923 /* Complex with byte min/max */
2924 sb
->variations
[i
].isComplex
= 1;
2925 for (j
= 0; j
< sb
->variations
[i
].entryCount
; j
+= 1)
2927 sb
->variations
[i
].entries
[j
].soundCode
= read_u32(&ptr
, se
);
2928 sb
->variations
[i
].entries
[j
].minWeight
= read_u8(&ptr
) / 255.0f
;
2929 sb
->variations
[i
].entries
[j
].maxWeight
= read_u8(&ptr
) / 255.0f
;
2932 else if (sb
->variations
[i
].flags
== 3)
2934 /* Complex Interactive Variation with float min/max */
2935 sb
->variations
[i
].isComplex
= 1;
2936 for (j
= 0; j
< sb
->variations
[i
].entryCount
; j
+= 1)
2938 sb
->variations
[i
].entries
[j
].soundCode
= read_u32(&ptr
, se
);
2939 sb
->variations
[i
].entries
[j
].minWeight
= read_f32(&ptr
, se
);
2940 sb
->variations
[i
].entries
[j
].maxWeight
= read_f32(&ptr
, se
);
2941 sb
->variations
[i
].entries
[j
].linger
= read_u32(&ptr
, se
);
2944 else if (sb
->variations
[i
].flags
== 4)
2947 sb
->variations
[i
].isComplex
= 0;
2948 for (j
= 0; j
< sb
->variations
[i
].entryCount
; j
+= 1)
2950 sb
->variations
[i
].entries
[j
].simple
.track
= read_u16(&ptr
, se
);
2951 sb
->variations
[i
].entries
[j
].simple
.wavebank
= read_u8(&ptr
);
2952 sb
->variations
[i
].entries
[j
].minWeight
= 0.0f
;
2953 sb
->variations
[i
].entries
[j
].maxWeight
= 1.0f
;
2958 FAudio_assert(0 && "Unknown variation type!");
2962 /* Transition data */
2963 if (sb
->transitionCount
> 0)
2965 FAudio_assert((ptr
- start
) == transitionOffset
);
2966 ptr
= start
+ transitionOffset
;
2967 sb
->transitions
= (FACTTransitionTable
*) pEngine
->pMalloc(
2968 sizeof(FACTTransitionTable
) *
2971 sb
->transitionCodes
= (uint32_t*) pEngine
->pMalloc(
2978 sb
->transitions
= NULL
;
2979 sb
->transitionCodes
= NULL
;
2981 for (i
= 0; i
< sb
->transitionCount
; i
+= 1)
2983 sb
->transitionCodes
[i
] = (uint32_t) (ptr
- start
);
2984 sb
->transitions
[i
].entryCount
= read_u32(&ptr
, se
);
2985 memsize
= sizeof(FACTTransition
) * sb
->transitions
[i
].entryCount
;
2986 sb
->transitions
[i
].entries
= (FACTTransition
*) pEngine
->pMalloc(
2989 FAudio_zero(sb
->transitions
[i
].entries
, memsize
);
2990 for (j
= 0; j
< sb
->transitions
[i
].entryCount
; j
+= 1)
2992 sb
->transitions
[i
].entries
[j
].soundCode
= read_s32(&ptr
, se
);
2993 sb
->transitions
[i
].entries
[j
].srcMarkerMin
= read_u32(&ptr
, se
);
2994 sb
->transitions
[i
].entries
[j
].srcMarkerMax
= read_u32(&ptr
, se
);
2995 sb
->transitions
[i
].entries
[j
].dstMarkerMin
= read_u32(&ptr
, se
);
2996 sb
->transitions
[i
].entries
[j
].dstMarkerMax
= read_u32(&ptr
, se
);
2997 sb
->transitions
[i
].entries
[j
].fadeIn
= read_u16(&ptr
, se
);
2998 sb
->transitions
[i
].entries
[j
].fadeOut
= read_u16(&ptr
, se
);
2999 sb
->transitions
[i
].entries
[j
].flags
= read_u16(&ptr
, se
);
3003 /* Cue Hash data? No idea what this is... */
3004 if (cueHashOffset
!= -1)
3006 FAudio_assert((ptr
- start
) == cueHashOffset
);
3007 ptr
+= 2 * cueTotalAlign
;
3010 /* Cue Name Index data */
3011 if (cueNameIndexOffset
!= -1)
3013 FAudio_assert((ptr
- start
) == cueNameIndexOffset
);
3014 ptr
= start
+ cueNameIndexOffset
;
3015 ptr
+= 6 * sb
->cueCount
; /* FIXME: index as assert value? */
3019 if (cueNameOffset
!= -1)
3021 FAudio_assert((ptr
- start
) == cueNameOffset
);
3022 ptr
= start
+ cueNameOffset
;
3023 sb
->cueNames
= (char**) pEngine
->pMalloc(
3027 for (i
= 0; i
< sb
->cueCount
; i
+= 1)
3029 memsize
= FAudio_strlen((char*) ptr
) + 1;
3030 sb
->cueNames
[i
] = (char*) pEngine
->pMalloc(memsize
);
3031 FAudio_memcpy(sb
->cueNames
[i
], ptr
, memsize
);
3037 sb
->cueNames
= NULL
;
3040 /* Add to the Engine SoundBank list */
3041 LinkedList_AddEntry(
3049 FAudio_assert((ptr
- start
) == dwSize
);
3054 /* This parser is based on the unxwb project, written by Luigi Auriemma.
3056 * While the unxwb project was released under the GPL, Luigi has given us
3057 * permission to use the unxwb sources under the zlib license.
3059 * The unxwb website can be found here:
3061 * http://aluigi.altervista.org/papers.htm#xbox
3063 uint32_t FACT_INTERNAL_ParseWaveBank(
3064 FACTAudioEngine
*pEngine
,
3067 uint32_t packetSize
,
3068 FACTReadFileCallback pRead
,
3069 FACTGetOverlappedResultCallback pOverlap
,
3070 uint16_t isStreaming
,
3071 FACTWaveBank
**ppWaveBank
3073 uint8_t se
= 0; /* Swap Endian */
3077 FACTWaveBankHeader header
;
3078 FACTWaveBankData wbinfo
;
3079 uint32_t compactEntry
;
3080 int32_t seekTableOffset
;
3081 uint32_t fileOffset
;
3082 uint8_t *packetBuffer
= NULL
;
3083 uint32_t packetBufferLen
= 0;
3086 #define SEEKSET(loc) \
3087 fileOffset = offset + loc;
3088 #define SEEKCUR(loc) \
3090 #define READ(dst, size) \
3091 FACT_INTERNAL_ReadFile( \
3099 pEngine->pRealloc, \
3105 #define DOSWAP_16(x) x = FAudio_swap16BE(x)
3106 #define DOSWAP_32(x) x = FAudio_swap32BE(x)
3107 #define DOSWAP_64(x) x = FAudio_swap64BE(x)
3109 fileOffset
= offset
;
3111 FAudio_zero(&header
, sizeof(header
));
3112 READ(&header
.dwSignature
, sizeof(header
.dwSignature
));
3113 READ(&header
.dwVersion
, sizeof(header
.dwVersion
));
3114 if (header
.dwVersion
> FACT_CONTENT_VERSION_2_4
)
3116 READ(&header
.dwHeaderVersion
, sizeof(header
.dwHeaderVersion
));
3119 READ(&header
.Segments
, sizeof(header
.Segments
));
3121 se
= header
.dwSignature
== 0x57424E44;
3124 DOSWAP_32(header
.dwSignature
);
3125 DOSWAP_32(header
.dwVersion
);
3126 DOSWAP_32(header
.dwHeaderVersion
);
3127 for (i
= 0; i
< FACT_WAVEBANK_SEGIDX_COUNT
; i
+= 1)
3129 DOSWAP_32(header
.Segments
[i
].dwOffset
);
3130 DOSWAP_32(header
.Segments
[i
].dwLength
);
3133 if (header
.dwSignature
!= 0x444E4257)
3135 return -1; /* TODO: NOT XACT FILE */
3138 /* We support all Wavebank versions - Restore when SoundBank support them also. */
3139 /*if (!FACT_INTERNAL_SupportedContent(header.dwVersion))
3144 if ( header
.dwVersion
< FACT_CONTENT_VERSION_2_4
||
3145 header
.dwVersion
> FACT_CONTENT_VERSION
)
3150 if ( header
.dwVersion
> FACT_CONTENT_VERSION_2_4
&&
3151 !FACT_INTERNAL_SupportedWBContent(header
.dwHeaderVersion
) )
3156 wb
= (FACTWaveBank
*) pEngine
->pMalloc(sizeof(FACTWaveBank
));
3157 wb
->parentEngine
= pEngine
;
3158 wb
->waveList
= NULL
;
3159 wb
->waveLock
= FAudio_PlatformCreateMutex();
3160 wb
->packetSize
= packetSize
;
3162 wb
->notifyOnDestroy
= 0;
3163 wb
->usercontext
= NULL
;
3166 SEEKSET(header
.Segments
[FACT_WAVEBANK_SEGIDX_BANKDATA
].dwOffset
)
3167 READ(&wbinfo
, sizeof(wbinfo
))
3170 DOSWAP_32(wbinfo
.dwFlags
);
3171 DOSWAP_32(wbinfo
.dwEntryCount
);
3172 DOSWAP_32(wbinfo
.dwEntryMetaDataElementSize
);
3173 DOSWAP_32(wbinfo
.dwEntryNameElementSize
);
3174 DOSWAP_32(wbinfo
.dwAlignment
);
3175 DOSWAP_32(wbinfo
.CompactFormat
.dwValue
);
3176 DOSWAP_64(wbinfo
.BuildTime
);
3178 wb
->streaming
= (wbinfo
.dwFlags
& FACT_WAVEBANK_TYPE_STREAMING
);
3179 wb
->entryCount
= wbinfo
.dwEntryCount
;
3180 memsize
= FAudio_strlen(wbinfo
.szBankName
) + 1;
3181 wb
->name
= (char*) pEngine
->pMalloc(memsize
);
3182 FAudio_memcpy(wb
->name
, wbinfo
.szBankName
, memsize
);
3183 memsize
= sizeof(FACTWaveBankEntry
) * wbinfo
.dwEntryCount
;
3184 wb
->entries
= (FACTWaveBankEntry
*) pEngine
->pMalloc(memsize
);
3185 FAudio_zero(wb
->entries
, memsize
);
3186 memsize
= sizeof(uint32_t) * wbinfo
.dwEntryCount
;
3187 wb
->entryRefs
= (uint32_t*) pEngine
->pMalloc(memsize
);
3188 FAudio_zero(wb
->entryRefs
, memsize
);
3190 /* FIXME: How much do we care about this? */
3191 FAudio_assert(wb
->streaming
== isStreaming
);
3192 wb
->streaming
= isStreaming
;
3194 /* WaveBank Entry Metadata */
3195 SEEKSET(header
.Segments
[FACT_WAVEBANK_SEGIDX_ENTRYMETADATA
].dwOffset
)
3196 if (wbinfo
.dwFlags
& FACT_WAVEBANK_FLAGS_COMPACT
)
3198 for (i
= 0; i
< wbinfo
.dwEntryCount
- 1; i
+= 1)
3200 READ(&compactEntry
, sizeof(compactEntry
))
3203 DOSWAP_32(compactEntry
);
3205 wb
->entries
[i
].PlayRegion
.dwOffset
= (
3206 (compactEntry
& ((1 << 21) - 1)) *
3209 wb
->entries
[i
].PlayRegion
.dwLength
= (
3210 (compactEntry
>> 21) & ((1 << 11) - 1)
3213 /* TODO: Deviation table */
3214 SEEKCUR(wbinfo
.dwEntryMetaDataElementSize
)
3215 wb
->entries
[i
].PlayRegion
.dwLength
= (
3216 (compactEntry
& ((1 << 21) - 1)) *
3218 ) - wb
->entries
[i
].PlayRegion
.dwOffset
;
3220 wb
->entries
[i
].PlayRegion
.dwOffset
+=
3221 header
.Segments
[FACT_WAVEBANK_SEGIDX_ENTRYWAVEDATA
].dwOffset
;
3224 READ(&compactEntry
, sizeof(compactEntry
))
3227 DOSWAP_32(compactEntry
);
3229 wb
->entries
[i
].PlayRegion
.dwOffset
= (
3230 (compactEntry
& ((1 << 21) - 1)) *
3234 /* TODO: Deviation table */
3235 SEEKCUR(wbinfo
.dwEntryMetaDataElementSize
)
3236 wb
->entries
[i
].PlayRegion
.dwLength
= (
3237 header
.Segments
[FACT_WAVEBANK_SEGIDX_ENTRYWAVEDATA
].dwLength
-
3238 wb
->entries
[i
].PlayRegion
.dwOffset
3241 wb
->entries
[i
].PlayRegion
.dwOffset
+=
3242 header
.Segments
[FACT_WAVEBANK_SEGIDX_ENTRYWAVEDATA
].dwOffset
;
3246 for (i
= 0; i
< wbinfo
.dwEntryCount
; i
+= 1)
3248 READ(&wb
->entries
[i
], wbinfo
.dwEntryMetaDataElementSize
)
3251 DOSWAP_32(wb
->entries
[i
].dwFlagsAndDuration
);
3252 DOSWAP_32(wb
->entries
[i
].Format
.dwValue
);
3253 DOSWAP_32(wb
->entries
[i
].PlayRegion
.dwOffset
);
3254 DOSWAP_32(wb
->entries
[i
].PlayRegion
.dwLength
);
3255 DOSWAP_32(wb
->entries
[i
].LoopRegion
.dwStartSample
);
3256 DOSWAP_32(wb
->entries
[i
].LoopRegion
.dwTotalSamples
);
3258 wb
->entries
[i
].PlayRegion
.dwOffset
+=
3259 header
.Segments
[FACT_WAVEBANK_SEGIDX_ENTRYWAVEDATA
].dwOffset
;
3261 /* If it's in-memory big-endian PCM, swap! */
3264 wb
->entries
[i
].Format
.wFormatTag
== 0x0 &&
3265 wb
->entries
[i
].Format
.wBitsPerSample
== 1 )
3267 pcm
= (uint16_t*) FAudio_memptr(
3268 (FAudioIOStream
*) wb
->io
,
3269 wb
->entries
[i
].PlayRegion
.dwOffset
3271 for (j
= 0; j
< wb
->entries
[i
].PlayRegion
.dwLength
; j
+= 2, pcm
+= 1)
3278 /* FIXME: This is a bit hacky. */
3279 if (wbinfo
.dwEntryMetaDataElementSize
< 24)
3281 for (i
= 0; i
< wbinfo
.dwEntryCount
; i
+= 1)
3283 wb
->entries
[i
].PlayRegion
.dwLength
=
3284 header
.Segments
[FACT_WAVEBANK_SEGIDX_ENTRYWAVEDATA
].dwLength
;
3289 /* WaveBank Seek Tables */
3290 if ( wbinfo
.dwFlags
& FACT_WAVEBANK_FLAGS_SEEKTABLES
&&
3291 header
.Segments
[FACT_WAVEBANK_SEGIDX_SEEKTABLES
].dwLength
> 0 )
3293 /* The seek table data layout is an absolute disaster! */
3294 wb
->seekTables
= (FACTSeekTable
*) pEngine
->pMalloc(
3295 wbinfo
.dwEntryCount
* sizeof(FACTSeekTable
)
3297 for (i
= 0; i
< wbinfo
.dwEntryCount
; i
+= 1)
3299 /* Get the table offset... */
3301 header
.Segments
[FACT_WAVEBANK_SEGIDX_SEEKTABLES
].dwOffset
+
3302 i
* sizeof(uint32_t)
3304 READ(&seekTableOffset
, sizeof(int32_t))
3307 DOSWAP_32(seekTableOffset
);
3310 /* If the offset is -1, this wave needs no table */
3311 if (seekTableOffset
== -1)
3313 wb
->seekTables
[i
].entryCount
= 0;
3314 wb
->seekTables
[i
].entries
= NULL
;
3318 /* Go to the table offset, after the offset table... */
3320 header
.Segments
[FACT_WAVEBANK_SEGIDX_SEEKTABLES
].dwOffset
+
3321 (wbinfo
.dwEntryCount
* sizeof(uint32_t)) +
3325 /* Read the table, finally. */
3326 READ(&wb
->seekTables
[i
].entryCount
, sizeof(uint32_t))
3329 DOSWAP_32(wb
->seekTables
[i
].entryCount
);
3331 wb
->seekTables
[i
].entries
= (uint32_t*) pEngine
->pMalloc(
3332 wb
->seekTables
[i
].entryCount
* sizeof(uint32_t)
3335 wb
->seekTables
[i
].entries
,
3336 wb
->seekTables
[i
].entryCount
* sizeof(uint32_t)
3340 for (j
= 0; j
< wb
->seekTables
[i
].entryCount
; j
+= 1)
3342 DOSWAP_32(wb
->seekTables
[i
].entries
[j
]);
3349 wb
->seekTables
= NULL
;
3352 /* WaveBank Entry Names */
3353 if (wbinfo
.dwFlags
& FACT_WAVEBANK_FLAGS_ENTRYNAMES
)
3355 SEEKSET(header
.Segments
[FACT_WAVEBANK_SEGIDX_ENTRYNAMES
].dwOffset
)
3356 wb
->waveBankNames
= (char*) pEngine
->pMalloc(64 * wbinfo
.dwEntryCount
);
3357 READ(wb
->waveBankNames
, 64 * wbinfo
.dwEntryCount
);
3361 wb
->waveBankNames
= NULL
;
3364 /* Add to the Engine WaveBank list */
3365 LinkedList_AddEntry(
3373 wb
->packetBuffer
= packetBuffer
;
3374 wb
->packetBufferLen
= packetBufferLen
;
3379 /* vim: set noexpandtab shiftwidth=8 tabstop=8: */