faudio: Import upstream release 24.05.
[wine.git] / libs / faudio / src / FACT_internal.c
blob0f0e4f968d96c7b649be210fc06855da64a2cf1e
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"
28 #include "FAudioFX.h"
30 /* RNG */
32 #define STB_EXTERN
33 #define STB_DEFINE
34 #include "stb.h"
35 #define FACT_INTERNAL_rng() ((float) stb_frand())
37 /* XACT Versions */
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,
73 uint32_t sampleRate
74 ) {
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.
79 * The formula is...
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.
86 * -@Woflox
88 float freq = 2 * FAudio_sin(
89 F3DAUDIO_PI *
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,
98 void* io,
99 uint32_t offset,
100 uint32_t packetSize,
101 uint8_t **packetBuffer,
102 uint32_t *packetBufferLen,
103 FAudioReallocFunc pRealloc,
104 void* dst,
105 uint32_t len
107 FACTOverlapped ovlp;
108 uint32_t realOffset, realLen, offPacket, lenPacket, result;
109 uint8_t usePacketBuffer;
110 void *buf;
112 ovlp.Internal = NULL;
113 ovlp.InternalHigh = NULL;
114 ovlp.OffsetHigh = 0; /* I sure hope so... */
115 ovlp.hEvent = NULL;
117 /* We have to read data in multiples of the sector size, or else
118 * Win32 ReadFile returns ERROR_INVALID_PARAMETER
120 realOffset = offset;
121 realLen = len;
122 usePacketBuffer = 0;
123 if (packetSize > 0)
125 offPacket = realOffset % packetSize;
126 if (offPacket > 0)
128 usePacketBuffer = 1;
129 realOffset -= offPacket;
130 realLen += offPacket;
132 lenPacket = realLen % packetSize;
133 if (lenPacket > 0)
135 usePacketBuffer = 1;
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.
143 if (usePacketBuffer)
145 if (*packetBufferLen < realLen)
147 *packetBufferLen = realLen;
148 *packetBuffer = pRealloc(*packetBuffer, realLen);
150 buf = *packetBuffer;
152 else
154 buf = dst;
157 /* Read, finally. */
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 */
164 FAudio_sleep(0);
167 pGetOverlappedResult(io, &ovlp, &result, 1);
169 /* Copy the subregion that we actually care about, if applicable */
170 if (usePacketBuffer)
172 FAudio_memcpy(dst, *packetBuffer + offPacket, len);
176 /* Internal Functions */
178 void FACT_INTERNAL_GetNextWave(
179 FACTCue *cue,
180 FACTSound *sound,
181 FACTTrack *track,
182 FACTTrackInstance *trackInst,
183 FACTEvent *evt,
184 FACTEventInstance *evtInst
186 FAudioSendDescriptor reverbDesc[2];
187 FAudioVoiceSends reverbSends;
188 const char *wbName;
189 FACTWaveBank *wb = NULL;
190 LinkedList *list;
191 uint16_t wbTrack;
192 uint8_t wbIndex;
193 uint8_t loopCount = 0;
194 float max, next;
195 uint8_t noTrackVariation = 1;
196 uint32_t i;
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)
213 evtInst->valuei = 0;
216 /* Random */
217 else if ((evt->wave.complex.variation & 0xF) == 2)
219 max = 0.0f;
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;
230 break;
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 )
239 max = 0.0f;
240 for (i = 0; i < evt->wave.complex.trackCount; i += 1)
242 if (i == evtInst->valuei)
244 continue;
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)
253 continue;
255 if (next > (max - evt->wave.complex.weights[i - 1]))
257 evtInst->valuei = i - 1;
258 break;
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];
272 else
274 wbIndex = evt->wave.simple.wavebank;
275 wbTrack = evt->wave.simple.track;
277 wbName = cue->parentBank->wavebankNames[wbIndex];
278 list = cue->parentBank->parentEngine->wbList;
279 while (list != NULL)
281 wb = (FACTWaveBank*) list->entry;
282 if (FAudio_strcmp(wbName, wb->name) == 0)
284 break;
286 list = list->next;
288 FAudio_assert(wb != NULL);
290 /* Generate the Wave */
291 if ( evtInst->loopCount == 255 &&
292 noTrackVariation &&
293 !(evt->wave.variationFlags & 0x0F00) )
295 /* For infinite loops with no variation, let Wave do the work */
296 loopCount = 255;
298 FACTWaveBank_Prepare(
300 wbTrack,
301 evt->wave.flags,
303 loopCount,
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,
317 &reverbSends
321 /* 3D Audio */
322 if (cue->active3D)
324 FACTWave_SetMatrixCoefficients(
325 trackInst->upcomingWave.wave,
326 cue->srcChannels,
327 cue->dstChannels,
328 cue->matrixCoefficients
331 else
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)
348 /* Add/Replace */
349 if (evt->wave.variationFlags & 0x0004)
351 trackInst->upcomingWave.basePitch =
352 trackInst->activeWave.basePitch + rngPitch;
354 else
356 trackInst->upcomingWave.basePitch = rngPitch + sound->pitch;
360 else
362 /* Initial Pitch Variation */
363 trackInst->upcomingWave.basePitch = rngPitch + sound->pitch;
366 else
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)
383 /* Add/Replace */
384 if (evt->wave.variationFlags & 0x0001)
386 trackInst->upcomingWave.baseVolume =
387 trackInst->activeWave.baseVolume + rngVolume;
389 else
391 trackInst->upcomingWave.baseVolume = (
392 rngVolume +
393 sound->volume +
394 track->volume
399 else
401 /* Initial Volume Variation */
402 trackInst->upcomingWave.baseVolume = (
403 rngVolume +
404 sound->volume +
405 track->volume
409 else
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) +
420 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)
440 else
443 if (evt->wave.variationFlags & 0x0040)
446 else
450 trackInst->upcomingWave.baseQFactor = rngQFactor;
451 trackInst->upcomingWave.baseFrequency = rngFrequency;
454 else
456 /* Initial Filter Variation */
457 trackInst->upcomingWave.baseQFactor = rngQFactor;
458 trackInst->upcomingWave.baseFrequency = rngFrequency;
461 else
463 trackInst->upcomingWave.baseQFactor = 1.0f / (track->qfactor / 3.0f);
464 trackInst->upcomingWave.baseFrequency = FACT_INTERNAL_CalculateFilterFrequency(
465 track->frequency,
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,
474 1.0f
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)
492 int32_t i, j, k;
493 float max, next, weight;
494 const char *wbName;
495 FACTWaveBank *wb = NULL;
496 LinkedList *list;
497 FACTEvent *evt;
498 FACTEventInstance *evtInst;
499 FACTSound *baseSound = NULL;
500 FACTSoundInstance *newSound;
501 FACTRPC *rpc;
502 float lastX;
504 union
506 float maxf;
507 uint8_t maxi;
508 } limitmax;
509 FACTCue *tmp, *wnr;
510 uint16_t categoryIndex;
511 FACTAudioCategory *category;
513 if (cue->data->flags & 0x04)
515 /* Sound */
516 baseSound = cue->sound;
518 else if (cue->variation)
520 /* Variation */
521 if (cue->variation->flags == 3)
523 /* Interactive */
524 if (cue->parentBank->parentEngine->variables[cue->variation->variable].accessibility & 0x04)
526 FACTCue_GetVariable(
527 cue,
528 cue->variation->variable,
529 &next
532 else
534 FACTAudioEngine_GetGlobalVariable(
535 cue->parentBank->parentEngine,
536 cue->variation->variable,
537 &next
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 )
545 break;
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)
556 return 1;
559 else
561 /* Random */
562 max = 0.0f;
563 for (i = 0; i < cue->variation->entryCount; i += 1)
565 max += (
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)
575 weight = (
576 cue->variation->entries[i].maxWeight -
577 cue->variation->entries[i].minWeight
579 if (next > (max - weight))
581 break;
583 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];
595 break;
599 else
601 /* Pull in the WaveBank... */
602 wbName = cue->parentBank->wavebankNames[
603 cue->variation->entries[i].simple.wavebank
605 list = cue->parentBank->parentEngine->wbList;
606 while (list != NULL)
608 wb = (FACTWaveBank*) list->entry;
609 if (FAudio_strcmp(wbName, wb->name) == 0)
611 break;
613 list = list->next;
615 FAudio_assert(wb != NULL);
617 /* Generate the wave... */
618 FACTWaveBank_Prepare(
620 cue->variation->entries[i].simple.track,
624 &cue->simpleWave
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)
640 wnr = NULL;
641 tmp = cue->parentBank->cueList;
642 if (category->maxInstanceBehavior == 0) /* Fail */
644 cue->state |= FACT_STATE_STOPPED;
645 cue->state &= ~(
646 FACT_STATE_PLAYING |
647 FACT_STATE_STOPPING |
648 FACT_STATE_PAUSED
650 return 0;
652 else if (category->maxInstanceBehavior == 1) /* Queue */
654 /* FIXME: How is this different from Replace Oldest? */
655 while (tmp != NULL)
657 if ( tmp != cue &&
658 tmp->playingSound != NULL &&
659 tmp->playingSound->sound->category == categoryIndex &&
660 !(tmp->state & (FACT_STATE_STOPPING | FACT_STATE_STOPPED)) )
662 wnr = tmp;
663 break;
665 tmp = tmp->next;
668 else if (category->maxInstanceBehavior == 2) /* Replace Oldest */
670 while (tmp != NULL)
672 if ( tmp != cue &&
673 tmp->playingSound != NULL &&
674 tmp->playingSound->sound->category == categoryIndex &&
675 !(tmp->state & (FACT_STATE_STOPPING | FACT_STATE_STOPPED)) )
677 wnr = tmp;
678 break;
680 tmp = tmp->next;
683 else if (category->maxInstanceBehavior == 3) /* Replace Quietest */
685 limitmax.maxf = FACTVOLUME_MAX;
686 while (tmp != NULL)
688 if ( tmp != cue &&
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)) )
694 wnr = tmp;
695 /* limitmax.maxf = tmp->playingSound->volume; */
697 tmp = tmp->next;
700 else if (category->maxInstanceBehavior == 4) /* Replace Lowest Priority */
702 limitmax.maxi = 0xFF;
703 while (tmp != NULL)
705 if ( tmp != cue &&
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)) )
711 wnr = tmp;
712 limitmax.maxi = tmp->playingSound->sound->priority;
714 tmp = tmp->next;
717 if (wnr != NULL)
719 fadeInMS = category->fadeInMS;
720 if (wnr->playingSound != NULL)
722 FACT_INTERNAL_BeginFadeOut(wnr->playingSound, category->fadeOutMS);
724 else
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;
749 else
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 )
804 evtInst->valuei = 0;
806 else
808 max = 0.0f;
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]))
818 evtInst->valuei = k;
819 break;
821 max -= evt->wave.complex.weights[k];
824 FACT_INTERNAL_GetNextWave(
825 cue,
826 newSound->sound,
827 &newSound->sound->tracks[i],
828 &newSound->tracks[i],
829 evt,
830 evtInst
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 )
862 if (FAudio_strcmp(
863 newSound->parentCue->parentBank->parentEngine->variableNames[rpc->variable],
864 "ReleaseTime"
865 ) == 0) {
866 lastX = rpc->points[rpc->pointCount - 1].x;
867 if (lastX > cue->maxRpcReleaseTime)
869 cue->maxRpcReleaseTime = (uint32_t) lastX /* bleh */;
876 cue->playingSound = newSound;
879 return 1;
882 void FACT_INTERNAL_SendCueNotification(FACTCue *cue, FACTNoticationsFlags flag, uint8_t type)
884 if (cue->parentBank->parentEngine->notifications & flag)
886 FACTNotification note;
888 note.type = type;
889 note.pvContext = cue->parentBank->parentEngine->cue_context;
890 note.cue.cueIndex = cue->index;
891 note.cue.pSoundBank = cue->parentBank;
892 note.cue.pCue = cue;
894 cue->parentBank->parentEngine->notificationCallback(&note);
898 void FACT_INTERNAL_DestroySound(FACTSoundInstance *sound)
900 uint8_t i;
902 sound->parentCue->playingSound = NULL;
903 for (i = 0; i < sound->sound->trackCount; i += 1)
905 if (sound->tracks[i].activeWave.wave != NULL)
907 FACTWave_Destroy(
908 sound->tracks[i].activeWave.wave
911 if (sound->tracks[i].upcomingWave.wave != NULL)
913 FACTWave_Destroy(
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)
943 if (fadeOutMS == 0)
945 /* No fade? Screw it, just delete us */
946 FACT_INTERNAL_DestroySound(sound);
947 return;
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)
959 if (releaseMS == 0)
961 /* No release RPC? Screw it, just delete us */
962 FACT_INTERNAL_DestroySound(sound);
963 return;
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,
977 uint32_t code
979 uint16_t i;
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!");
989 return NULL;
992 float FACT_INTERNAL_CalculateRPC(
993 FACTRPC *rpc,
994 float var
996 float result;
997 uint8_t i;
999 /* Min/Max */
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 */
1012 result = 0.0f;
1013 for (i = 0; i < rpc->pointCount - 1; i += 1)
1015 /* y = b */
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 */
1038 if (maxY > 0.0f)
1040 result += maxY * (1.0f - FAudio_pow(1.0f - FAudio_sqrtf(deltaXNormalized), 2.0f));
1042 else
1044 result += maxY * (1.0f - FAudio_sqrtf(1.0f - FAudio_pow(deltaXNormalized, 2.0f)));
1047 else
1049 FAudio_assert(0 && "Unrecognized curve type!");
1052 break;
1055 return result;
1058 void FACT_INTERNAL_UpdateRPCs(
1059 FACTCue *cue,
1060 uint8_t codeCount,
1061 uint32_t *codes,
1062 FACTInstanceRPCData *data,
1063 uint32_t timestamp,
1064 uint32_t elapsedTrack
1066 uint8_t i;
1067 FACTRPC *rpc;
1068 float rpcResult;
1069 float variableValue;
1070 FACTAudioEngine *engine = cue->parentBank->parentEngine;
1072 if (codeCount > 0)
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(
1081 engine,
1082 codes[i]
1084 if (engine->variables[rpc->variable].accessibility & 0x04)
1086 if (FAudio_strcmp(
1087 engine->variableNames[rpc->variable],
1088 "AttackTime"
1089 ) == 0) {
1090 variableValue = (float) elapsedTrack;
1092 else if (FAudio_strcmp(
1093 engine->variableNames[rpc->variable],
1094 "ReleaseTime"
1095 ) == 0) {
1096 if (cue->playingSound->fadeType == 3) /* Release RPC */
1098 variableValue = (float) (timestamp - cue->playingSound->fadeStart);
1100 else
1102 variableValue = 0.0f;
1105 else
1107 variableValue = cue->variableValues[rpc->variable];
1110 rpcResult = FACT_INTERNAL_CalculateRPC(
1111 rpc,
1112 variableValue
1115 else
1117 rpcResult = FACT_INTERNAL_CalculateRPC(
1118 rpc,
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(
1138 rpcResult,
1139 engine->audio->master->master.inputSampleRate
1142 else if (rpc->parameter == RPC_PARAMETER_FILTERQFACTOR)
1144 /* Yes, just overwrite... */
1145 data->rpcFilterQFactor = 1.0f / rpcResult;
1147 else
1149 FAudio_assert(0 && "Unhandled RPC parameter type!");
1155 /* Engine Update Function */
1157 void FACT_INTERNAL_UpdateEngine(FACTAudioEngine *engine)
1159 FAudioFXReverbParameters rvbPar;
1160 uint16_t i, j, par;
1161 float rpcResult;
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(
1176 &engine->rpcs[i],
1177 engine->globalVariableValues[engine->rpcs[i].variable]
1179 engine->dspPresets[j].parameters[par].value = FAudio_clamp(
1180 rpcResult,
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,
1218 &rvbPar,
1219 sizeof(FAudioFXReverbParameters),
1225 /* Cue Update Functions */
1227 static inline void FACT_INTERNAL_StopTrack(
1228 FACTTrack *track,
1229 FACTTrackInstance *trackInst,
1230 uint8_t immediate
1232 uint8_t i;
1234 /* Stop the wave (may as-authored or immedate */
1235 if (trackInst->activeWave.wave != NULL)
1237 FACTWave_Stop(
1238 trackInst->activeWave.wave,
1239 immediate
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,
1260 FACTTrack *track,
1261 FACTTrackInstance *trackInst,
1262 FACTEvent *evt,
1263 FACTEventInstance *evtInst,
1264 uint32_t elapsed
1266 uint8_t i;
1267 float svResult;
1268 uint8_t skipLoopCheck = 0;
1270 /* STOP */
1271 if (evt->type == FACTEVENT_STOP)
1273 /* Stop Cue */
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],
1284 &sound->tracks[i],
1289 else
1291 if (sound->parentCue->parentBank->cues[sound->parentCue->index].fadeOutMS > 0)
1293 FACT_INTERNAL_BeginFadeOut(
1294 sound,
1295 sound->parentCue->parentBank->cues[sound->parentCue->index].fadeOutMS
1298 else if (sound->parentCue->maxRpcReleaseTime > 0)
1300 FACT_INTERNAL_BeginReleaseRPC(
1301 sound,
1302 sound->parentCue->maxRpcReleaseTime
1305 else
1307 /* Pretty sure this doesn't happen, but just in case? */
1308 sound->parentCue->state |= FACT_STATE_STOPPING;
1313 /* Stop track */
1314 else
1316 FACT_INTERNAL_StopTrack(
1317 track,
1318 trackInst,
1319 evt->stop.flags & 0x01
1324 /* PLAYWAVE */
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);
1332 FAudio_memcpy(
1333 &trackInst->activeWave,
1334 &trackInst->upcomingWave,
1335 sizeof(trackInst->activeWave)
1337 trackInst->upcomingWave.wave = NULL;
1338 FACTWave_Play(trackInst->activeWave.wave);
1341 /* SETVALUE */
1342 else if ( evt->type == FACTEVENT_PITCH ||
1343 evt->type == FACTEVENT_PITCHREPEATING ||
1344 evt->type == FACTEVENT_VOLUME ||
1345 evt->type == FACTEVENT_VOLUMEREPEATING )
1347 /* Ramp/Equation */
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);
1352 svResult = (
1353 evt->value.ramp.initialSlope *
1354 evt->value.ramp.duration / 1000 *
1355 10 /* "Slices" */
1356 ) + evt->value.ramp.initialValue;
1357 svResult = (
1358 (svResult - evt->value.ramp.initialValue)
1359 ) * FAudio_clamp(
1360 (float) (elapsed - evtInst->timestamp) / evt->value.ramp.duration,
1361 0.0f,
1362 1.0f
1363 ) + evt->value.ramp.initialValue;
1365 evtInst->value = svResult;
1367 else
1369 /* Value/Random */
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
1381 else
1383 svResult = 0.0f;
1384 FAudio_assert(0 && "Equation flags?");
1387 /* Add/Replace */
1388 if (evt->value.equation.flags & 0x01)
1390 if( evt->type == FACTEVENT_PITCH ||
1391 evt->type == FACTEVENT_PITCHREPEATING )
1393 evtInst->value = trackInst->evtPitch + svResult;
1395 else
1397 evtInst->value = trackInst->evtVolume + svResult;
1400 else
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;
1412 else
1414 trackInst->evtVolume = evtInst->value;
1417 if (skipLoopCheck)
1419 return;
1421 if (evtInst->loopCount > 0)
1423 if (evtInst->loopCount != 0xFF && evtInst->loopCount != 0xFFFF)
1425 evtInst->loopCount -= 1;
1428 evtInst->timestamp += evt->value.frequency;
1429 return;
1433 /* MARKER */
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;
1446 return;
1450 /* ??? */
1451 else
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)
1462 uint8_t i, j;
1463 uint32_t waveState;
1464 uint32_t elapsedCue;
1465 FACTEventInstance *evtInst;
1466 FAudioFilterParameters filterParams;
1467 uint8_t finished = 1;
1469 /* Instance limiting Fade in/out */
1470 float fadeVolume;
1471 if (sound->fadeType == 1) /* Fade In */
1473 if ((timestamp - sound->fadeStart) >= sound->fadeTarget)
1475 /* We've faded in! */
1476 fadeVolume = 1.0f;
1477 sound->fadeStart = 0;
1478 sound->fadeTarget = 0;
1479 sound->fadeType = 0;
1481 else
1483 fadeVolume = (
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! */
1494 return 1;
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! */
1506 return 1;
1508 fadeVolume = 1.0f;
1510 else
1512 fadeVolume = 1.0f;
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);
1520 /* RPC updates */
1521 sound->rpcData.rpcFilterFreq = -1.0f;
1522 sound->rpcData.rpcFilterQFactor = -1.0f;
1523 FACT_INTERNAL_UpdateRPCs(
1524 sound->parentCue,
1525 sound->sound->rpcCodeCount,
1526 sound->sound->rpcCodes,
1527 &sound->rpcData,
1528 timestamp,
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(
1536 sound->parentCue,
1537 sound->sound->tracks[i].rpcCodeCount,
1538 sound->sound->tracks[i].rpcCodes,
1539 &sound->tracks[i].rpcData,
1540 timestamp,
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)
1548 /* Event updates */
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...! */
1555 finished = 0;
1557 /* Trigger events at the right time */
1558 if (elapsedCue >= evtInst->timestamp)
1560 FACT_INTERNAL_ActivateEvent(
1561 sound,
1562 &sound->sound->tracks[i],
1563 &sound->tracks[i],
1564 &sound->sound->tracks[i].events[j],
1565 evtInst,
1566 elapsedCue
1572 /* Wave updates */
1573 if (sound->tracks[i].activeWave.wave == NULL)
1575 continue;
1577 finished = 0;
1579 /* Clear out Waves as they finish */
1580 FACTWave_GetState(
1581 sound->tracks[i].activeWave.wave,
1582 &waveState
1584 if (waveState & FACT_STATE_STOPPED)
1586 FACTWave_Destroy(sound->tracks[i].activeWave.wave);
1587 FAudio_memcpy(
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)
1595 continue;
1597 FACTWave_Play(sound->tracks[i].activeWave.wave);
1600 FACTWave_SetVolume(
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
1609 ].currentVolume *
1610 fadeVolume
1612 FACTWave_SetPitch(
1613 sound->tracks[i].activeWave.wave,
1614 (int16_t) (
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;
1632 else
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;
1640 else
1642 filterParams.OneOverQ = sound->tracks[i].activeWave.baseQFactor;
1644 FAudioVoice_SetFilterParameters(
1645 sound->tracks[i].activeWave.wave->voice,
1646 &filterParams,
1650 /* TODO: Wave updates:
1651 * - ReverbSend (SetOutputMatrix on index 1, submix voice)
1655 return finished;
1658 void FACT_INTERNAL_UpdateCue(FACTCue *cue)
1660 uint32_t i;
1661 float next;
1662 FACTSoundInstance *sound;
1664 /* Interactive sound selection */
1665 if (!(cue->data->flags & 0x04) && cue->variation && cue->variation->flags == 3)
1667 /* Interactive */
1668 if (cue->parentBank->parentEngine->variables[cue->variation->variable].accessibility & 0x04)
1670 FACTCue_GetVariable(
1671 cue,
1672 cue->variation->variable,
1673 &next
1676 else
1678 FACTAudioEngine_GetGlobalVariable(
1679 cue->parentBank->parentEngine,
1680 cue->variation->variable,
1681 &next
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)
1698 FACTWave_Destroy(
1699 sound->tracks[i].activeWave.wave
1702 if (sound->tracks[i].upcomingWave.wave != NULL)
1704 FACTWave_Destroy(
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;
1724 cue->elapsed = 0;
1727 FACT_INTERNAL_CreateSound(cue, 0 /* fadeIn */);
1732 /* FACT Thread */
1734 int32_t FACT_INTERNAL_APIThread(void* enginePtr)
1736 FACTAudioEngine *engine = (FACTAudioEngine*) enginePtr;
1737 LinkedList *sbList;
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
1743 * infinitely!
1745 FAudio_PlatformThreadPriority(FAUDIO_THREAD_PRIORITY_HIGH);
1747 threadstart:
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;
1764 while (cue != NULL)
1766 FACT_INTERNAL_UpdateCue(cue);
1768 if (cue->state & FACT_STATE_PAUSED)
1770 cue = cue->next;
1771 continue;
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);
1787 cue = cBackup;
1789 else
1791 cue = cue->next;
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);
1807 goto threadstart;
1810 return 0;
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)
1831 length = (
1832 length *
1833 entry->Format.nChannels *
1834 (1 << entry->Format.wBitsPerSample)
1837 else if (entry->Format.wFormatTag == 0x2)
1839 length = (
1840 length /
1841 /* wSamplesPerBlock */
1842 ((entry->Format.wBlockAlign + 16) * 2) *
1843 /* nBlockAlign */
1844 ((entry->Format.wBlockAlign + 22) * entry->Format.nChannels)
1847 else
1849 length = entry->PlayRegion.dwLength;
1852 else
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) )
1863 return;
1866 /* Assign buffer memory */
1867 buffer.pAudioData = c->wave->streamCache;
1868 buffer.AudioBytes = FAudio_min(
1869 c->wave->streamSize,
1870 left
1873 /* Read! */
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,
1884 buffer.AudioBytes
1886 c->wave->streamOffset += buffer.AudioBytes;
1888 /* Last buffer in the stream? */
1889 buffer.Flags = 0;
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;
1901 /* Loop start */
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) *
1916 /* nBlockAlign */
1917 ((entry->Format.wBlockAlign + 22) * entry->Format.nChannels)
1921 else
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(
1943 c->wave->voice,
1944 &buffer,
1945 &bufferWMA
1948 else
1950 FAudioSourceVoice_SubmitSourceBuffer(
1951 c->wave->voice,
1952 &buffer,
1953 NULL
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 |
1970 FACT_STATE_STOPPING
1972 c->wave->parentCue->data->instanceCount -= 1;
1976 /* FAudioIOStream functions */
1978 int32_t FACTCALL FACT_INTERNAL_DefaultReadFile(
1979 void *hFile,
1980 void *buffer,
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(
1990 io->data,
1991 buffer,
1992 nNumberOfBytesToRead,
1994 ) * nNumberOfBytesToRead);
1995 FAudio_PlatformUnlockMutex((FAudioMutex) io->lock);
1996 lpOverlapped->Internal = 0; /* STATUS_SUCCESS */
1997 return 1;
2000 int32_t FACTCALL FACT_INTERNAL_DefaultGetOverlappedResult(
2001 void *hFile,
2002 FACTOverlapped *lpOverlapped,
2003 uint32_t *lpNumberOfBytesTransferred,
2004 int32_t bWait
2006 *lpNumberOfBytesTransferred = (uint32_t) (size_t) lpOverlapped->InternalHigh;
2007 return 1;
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); \
2016 *ptr += size; \
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);
2025 *ptr += 1;
2026 return result;
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);
2035 *ptr += 4;
2036 return result;
2039 #undef READ_FUNC
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.
2049 * -flibit
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,
2059 variableOffset,
2060 blob1Offset,
2061 categoryNameIndexOffset,
2062 blob2Offset,
2063 variableNameIndexOffset,
2064 categoryNameOffset,
2065 variableNameOffset,
2066 rpcOffset,
2067 dspPresetOffset,
2068 dspParameterOffset;
2069 uint16_t blob1Count, blob2Count;
2070 uint8_t version, tool;
2071 uint8_t se;
2072 uint32_t magic;
2073 size_t memsize;
2074 uint16_t i, j;
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)))
2088 return -2;
2091 tool = read_u16(&ptr, se); /* Tool version */
2092 if (tool != 42)
2094 return -3;
2097 ptr += 2; /* Unknown value */
2099 /* Last modified, unused */
2100 ptr += 8;
2102 /* XACT Version (Windows == 3, Xbox == 7) */
2103 version = read_u8(&ptr);
2104 if ( version != 3 &&
2105 version != 7 )
2107 return -4; /* TODO: VERSION TOO OLD */
2110 /* Object counts */
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);
2132 /* Category data */
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(
2145 read_volbyte(&ptr)
2147 pEngine->categories[i].visibility = read_u8(&ptr);
2148 pEngine->categories[i].instanceCount = 0;
2149 pEngine->categories[i].currentVolume = 1.0f;
2152 /* Variable data */
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;
2174 /* RPC data */
2175 if (pEngine->rpcCount > 0)
2177 FAudio_assert((ptr - start) == rpcOffset);
2178 pEngine->rpcs = (FACTRPC*) pEngine->pMalloc(
2179 sizeof(FACTRPC) *
2180 pEngine->rpcCount
2182 pEngine->rpcCodes = (uint32_t*) pEngine->pMalloc(
2183 sizeof(uint32_t) *
2184 pEngine->rpcCount
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(
2214 sizeof(uint32_t) *
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(
2255 sizeof(char*) *
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);
2263 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(
2277 sizeof(char*) *
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);
2285 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;
2294 /* Finally. */
2295 FAudio_assert((ptr - start) == pParams->globalSettingsBufferSize);
2296 return 0;
2299 void FACT_INTERNAL_ParseTrackEvents(
2300 uint8_t **ptr,
2301 uint8_t se,
2302 FACTTrack *track,
2303 FAudioMallocFunc pMalloc
2305 uint32_t evtInfo;
2306 uint8_t minWeight, maxWeight, separator;
2307 uint8_t i;
2308 uint16_t j;
2310 track->eventCount = read_u8(ptr);
2311 track->events = (FACTEvent*) pMalloc(
2312 sizeof(FACTEvent) *
2313 track->eventCount
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))
2334 /* Basic Wave */
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))
2348 /* Complex Wave */
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(
2361 sizeof(uint16_t) *
2362 track->events[i].wave.complex.trackCount
2364 track->events[i].wave.complex.wavebanks = (uint8_t*) pMalloc(
2365 sizeof(uint8_t) *
2366 track->events[i].wave.complex.trackCount
2368 track->events[i].wave.complex.weights = (uint8_t*) pMalloc(
2369 sizeof(uint8_t) *
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))
2388 /* Basic Wave */
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))
2410 /* Complex Wave */
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(
2434 sizeof(uint16_t) *
2435 track->events[i].wave.complex.trackCount
2437 track->events[i].wave.complex.wavebanks = (uint8_t*) pMalloc(
2438 sizeof(uint8_t) *
2439 track->events[i].wave.complex.trackCount
2441 track->events[i].wave.complex.weights = (uint8_t*) pMalloc(
2442 sizeof(uint8_t) *
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);
2470 else /* Equation */
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);
2488 else
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);
2506 else
2508 FAudio_assert(0 && "Unknown event type!");
2510 #undef EVTTYPE
2514 uint32_t FACT_INTERNAL_ParseSoundBank(
2515 FACTAudioEngine *pEngine,
2516 const void *pvBuffer,
2517 uint32_t dwSize,
2518 FACTSoundBank **ppSoundBank
2520 FACTSoundBank *sb;
2521 uint16_t contentVersion,
2522 cueSimpleCount,
2523 cueComplexCount,
2524 cueTotalAlign;
2525 int32_t cueSimpleOffset,
2526 cueComplexOffset,
2527 cueNameOffset,
2528 variationOffset,
2529 transitionOffset,
2530 wavebankNameOffset,
2531 cueHashOffset,
2532 cueNameIndexOffset,
2533 soundOffset;
2534 uint32_t entryCountAndFlags;
2535 uint16_t filterData;
2536 uint8_t platform;
2537 size_t memsize;
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))
2555 return -2;
2558 tool = read_u16(&ptr, se); /* Tool version */
2559 if (tool != 43)
2561 return -3;
2564 /* CRC, unused */
2565 ptr += 2;
2567 /* Last modified, unused */
2568 ptr += 8;
2570 /* Windows == 1, Xbox == 3. 0 is unknown, probably old content */
2571 platform = read_u8(&ptr);
2572 if ( platform != 0 &&
2573 platform != 1 &&
2574 platform != 3 )
2576 return -4; /* TODO: WRONG PLATFORM */
2579 sb = (FACTSoundBank*) pEngine->pMalloc(sizeof(FACTSoundBank));
2580 sb->parentEngine = pEngine;
2581 sb->cueList = NULL;
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 */
2596 ptr += 2;
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);
2617 ptr += 64;
2619 /* WaveBank Name data */
2620 FAudio_assert((ptr - start) == wavebankNameOffset);
2621 ptr = start + wavebankNameOffset;
2622 sb->wavebankNames = (char**) pEngine->pMalloc(
2623 sizeof(char*) *
2624 sb->wavebankCount
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);
2631 ptr += 64;
2634 /* Sound data */
2635 FAudio_assert((ptr - start) == soundOffset);
2636 sb->sounds = (FACTSound*) pEngine->pMalloc(
2637 sizeof(FACTSound) *
2638 sb->soundCount
2640 sb->soundCodes = (uint32_t*) pEngine->pMalloc(
2641 sizeof(uint32_t) *
2642 sb->soundCount
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 */
2654 ptr += 2;
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);
2664 else
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(
2674 sizeof(FACTEvent)
2676 FAudio_zero(
2677 sb->sounds[i].tracks[0].events,
2678 sizeof(FACTEvent)
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);
2687 /* RPC Code data */
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])
2707 else
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])
2721 else
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;
2730 #undef COPYRPCBLOCK
2732 /* FIXME: Does 0x08 mean something for RPCs...? */
2733 FAudio_assert((ptr - ptrBookmark) == rpcDataLength);
2735 else
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 */
2750 ptr += 2;
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);
2760 else
2762 sb->sounds[i].dspCodeCount = 0;
2763 sb->sounds[i].dspCodes = NULL;
2766 /* Track data */
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;
2781 continue;
2784 filterData = read_u16(&ptr, se);
2785 if (filterData & 0x0001)
2787 sb->sounds[i].tracks[j].filter =
2788 (filterData >> 1) & 0x02;
2790 else
2792 /* Huh...? */
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(
2804 &ptr,
2806 &sb->sounds[i].tracks[j],
2807 pEngine->pMalloc
2813 /* All Cue data */
2814 sb->variationCount = 0;
2815 sb->transitionCount = 0;
2816 sb->cues = (FACTCueData*) pEngine->pMalloc(
2817 sizeof(FACTCueData) *
2818 sb->cueCount
2820 cur = 0;
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)
2854 /* FIXME: Why */
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) *
2883 sb->variationCount
2885 sb->variationCodes = (uint32_t*) pEngine->pMalloc(
2886 sizeof(uint32_t) *
2887 sb->variationCount
2890 else
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(
2905 memsize
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)
2946 /* Compact Wave */
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;
2956 else
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) *
2969 sb->transitionCount
2971 sb->transitionCodes = (uint32_t*) pEngine->pMalloc(
2972 sizeof(uint32_t) *
2973 sb->transitionCount
2976 else
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(
2987 memsize
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? */
3018 /* Cue Name data */
3019 if (cueNameOffset != -1)
3021 FAudio_assert((ptr - start) == cueNameOffset);
3022 ptr = start + cueNameOffset;
3023 sb->cueNames = (char**) pEngine->pMalloc(
3024 sizeof(char*) *
3025 sb->cueCount
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);
3032 ptr += memsize;
3035 else
3037 sb->cueNames = NULL;
3040 /* Add to the Engine SoundBank list */
3041 LinkedList_AddEntry(
3042 &pEngine->sbList,
3044 pEngine->sbLock,
3045 pEngine->pMalloc
3048 /* Finally. */
3049 FAudio_assert((ptr - start) == dwSize);
3050 *ppSoundBank = sb;
3051 return 0;
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,
3065 void* io,
3066 uint32_t offset,
3067 uint32_t packetSize,
3068 FACTReadFileCallback pRead,
3069 FACTGetOverlappedResultCallback pOverlap,
3070 uint16_t isStreaming,
3071 FACTWaveBank **ppWaveBank
3073 uint8_t se = 0; /* Swap Endian */
3074 FACTWaveBank *wb;
3075 size_t memsize;
3076 uint32_t i, j;
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;
3084 uint16_t *pcm;
3086 #define SEEKSET(loc) \
3087 fileOffset = offset + loc;
3088 #define SEEKCUR(loc) \
3089 fileOffset += loc;
3090 #define READ(dst, size) \
3091 FACT_INTERNAL_ReadFile( \
3092 pRead, \
3093 pOverlap, \
3094 io, \
3095 fileOffset, \
3096 packetSize, \
3097 &packetBuffer, \
3098 &packetBufferLen, \
3099 pEngine->pRealloc, \
3100 dst, \
3101 size \
3102 ); \
3103 SEEKCUR(size)
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;
3122 if (se)
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))
3141 return -2;
3144 if ( header.dwVersion < FACT_CONTENT_VERSION_2_4 ||
3145 header.dwVersion > FACT_CONTENT_VERSION )
3147 return -2;
3150 if ( header.dwVersion > FACT_CONTENT_VERSION_2_4 &&
3151 !FACT_INTERNAL_SupportedWBContent(header.dwHeaderVersion) )
3153 return -3;
3156 wb = (FACTWaveBank*) pEngine->pMalloc(sizeof(FACTWaveBank));
3157 wb->parentEngine = pEngine;
3158 wb->waveList = NULL;
3159 wb->waveLock = FAudio_PlatformCreateMutex();
3160 wb->packetSize = packetSize;
3161 wb->io = io;
3162 wb->notifyOnDestroy = 0;
3163 wb->usercontext = NULL;
3165 /* WaveBank Data */
3166 SEEKSET(header.Segments[FACT_WAVEBANK_SEGIDX_BANKDATA].dwOffset)
3167 READ(&wbinfo, sizeof(wbinfo))
3168 if (se)
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))
3201 if (se)
3203 DOSWAP_32(compactEntry);
3205 wb->entries[i].PlayRegion.dwOffset = (
3206 (compactEntry & ((1 << 21) - 1)) *
3207 wbinfo.dwAlignment
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)) *
3217 wbinfo.dwAlignment
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))
3225 if (se)
3227 DOSWAP_32(compactEntry);
3229 wb->entries[i].PlayRegion.dwOffset = (
3230 (compactEntry & ((1 << 21) - 1)) *
3231 wbinfo.dwAlignment
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;
3244 else
3246 for (i = 0; i < wbinfo.dwEntryCount; i += 1)
3248 READ(&wb->entries[i], wbinfo.dwEntryMetaDataElementSize)
3249 if (se)
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! */
3262 if ( se &&
3263 !wb->streaming &&
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)
3273 DOSWAP_16(*pcm);
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... */
3300 SEEKSET(
3301 header.Segments[FACT_WAVEBANK_SEGIDX_SEEKTABLES].dwOffset +
3302 i * sizeof(uint32_t)
3304 READ(&seekTableOffset, sizeof(int32_t))
3305 if (se)
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;
3315 continue;
3318 /* Go to the table offset, after the offset table... */
3319 SEEKSET(
3320 header.Segments[FACT_WAVEBANK_SEGIDX_SEEKTABLES].dwOffset +
3321 (wbinfo.dwEntryCount * sizeof(uint32_t)) +
3322 seekTableOffset
3325 /* Read the table, finally. */
3326 READ(&wb->seekTables[i].entryCount, sizeof(uint32_t))
3327 if (se)
3329 DOSWAP_32(wb->seekTables[i].entryCount);
3331 wb->seekTables[i].entries = (uint32_t*) pEngine->pMalloc(
3332 wb->seekTables[i].entryCount * sizeof(uint32_t)
3334 READ(
3335 wb->seekTables[i].entries,
3336 wb->seekTables[i].entryCount * sizeof(uint32_t)
3338 if (se)
3340 for (j = 0; j < wb->seekTables[i].entryCount; j += 1)
3342 DOSWAP_32(wb->seekTables[i].entries[j]);
3347 else
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);
3359 else
3361 wb->waveBankNames = NULL;
3364 /* Add to the Engine WaveBank list */
3365 LinkedList_AddEntry(
3366 &pEngine->wbList,
3368 pEngine->wbLock,
3369 pEngine->pMalloc
3372 /* Finally. */
3373 wb->packetBuffer = packetBuffer;
3374 wb->packetBufferLen = packetBufferLen;
3375 *ppWaveBank = wb;
3376 return 0;
3379 /* vim: set noexpandtab shiftwidth=8 tabstop=8: */