Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/faudio/src/FACT_internal.c
4389 views
1
/* FAudio - XAudio Reimplementation for FNA
2
*
3
* Copyright (c) 2011-2024 Ethan Lee, Luigi Auriemma, and the MonoGame Team
4
*
5
* This software is provided 'as-is', without any express or implied warranty.
6
* In no event will the authors be held liable for any damages arising from
7
* the use of this software.
8
*
9
* Permission is granted to anyone to use this software for any purpose,
10
* including commercial applications, and to alter it and redistribute it
11
* freely, subject to the following restrictions:
12
*
13
* 1. The origin of this software must not be misrepresented; you must not
14
* claim that you wrote the original software. If you use this software in a
15
* product, an acknowledgment in the product documentation would be
16
* appreciated but is not required.
17
*
18
* 2. Altered source versions must be plainly marked as such, and must not be
19
* misrepresented as being the original software.
20
*
21
* 3. This notice may not be removed or altered from any source distribution.
22
*
23
* Ethan "flibitijibibo" Lee <[email protected]>
24
*
25
*/
26
27
#include "FACT_internal.h"
28
#include "FAudioFX.h"
29
30
/* RNG */
31
32
#define STB_EXTERN
33
#define STB_DEFINE
34
#include "stb.h"
35
#define FACT_INTERNAL_rng() ((float) stb_frand())
36
37
/* XACT Versions */
38
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
44
45
static inline int FACT_INTERNAL_SupportedContent(uint16_t version)
46
{
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 );
51
}
52
53
#define WAVEBANK_HEADER_VERSION 44
54
#define WAVEBANK_HEADER_VERSION_3_4 43
55
#define WAVEBANK_HEADER_VERSION_3_1 42
56
57
static inline int FACT_INTERNAL_SupportedWBContent(uint16_t version)
58
{
59
return ( version == WAVEBANK_HEADER_VERSION ||
60
version == WAVEBANK_HEADER_VERSION_3_4 ||
61
version == WAVEBANK_HEADER_VERSION_3_1 );
62
}
63
64
/* Helper Functions */
65
66
static inline float FACT_INTERNAL_CalculateAmplitudeRatio(float decibel)
67
{
68
return (float) FAudio_pow(10.0, decibel / 2000.0);
69
}
70
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.
78
*
79
* The formula is...
80
*
81
* (2 * sin(pi * (desired filter cutoff frequency) / sampleRate))
82
*
83
* ... but it behaves badly as the filter frequency gets too high as a
84
* fraction of the sample rate, hence the mins.
85
*
86
* -@Woflox
87
*/
88
float freq = 2.0f * FAudio_sinf(
89
F3DAUDIO_PI *
90
FAudio_min(desiredFrequency / sampleRate, 0.5f)
91
);
92
return FAudio_min(freq, 1.0f);
93
}
94
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
106
) {
107
FACTOverlapped ovlp;
108
uint32_t realOffset, realLen, offPacket, lenPacket, result;
109
uint8_t usePacketBuffer;
110
void *buf;
111
112
ovlp.Internal = NULL;
113
ovlp.InternalHigh = NULL;
114
ovlp.OffsetHigh = 0; /* I sure hope so... */
115
ovlp.hEvent = NULL;
116
117
/* We have to read data in multiples of the sector size, or else
118
* Win32 ReadFile returns ERROR_INVALID_PARAMETER
119
*/
120
realOffset = offset;
121
realLen = len;
122
usePacketBuffer = 0;
123
if (packetSize > 0)
124
{
125
offPacket = realOffset % packetSize;
126
if (offPacket > 0)
127
{
128
usePacketBuffer = 1;
129
realOffset -= offPacket;
130
realLen += offPacket;
131
}
132
lenPacket = realLen % packetSize;
133
if (lenPacket > 0)
134
{
135
usePacketBuffer = 1;
136
realLen += (packetSize - lenPacket);
137
}
138
}
139
140
/* If we're compensating for sector alignment, use a temp buffer and copy to
141
* the real destination after we're finished.
142
*/
143
if (usePacketBuffer)
144
{
145
if (*packetBufferLen < realLen)
146
{
147
*packetBufferLen = realLen;
148
*packetBuffer = pRealloc(*packetBuffer, realLen);
149
}
150
buf = *packetBuffer;
151
}
152
else
153
{
154
buf = dst;
155
}
156
157
/* Read, finally. */
158
ovlp.Offset = realOffset;
159
if (!pReadFile(io, buf, realLen, NULL, &ovlp))
160
{
161
while (ovlp.Internal == (void*) 0x103) /* STATUS_PENDING */
162
{
163
/* Don't actually sleep, just yield the thread */
164
FAudio_sleep(0);
165
}
166
}
167
pGetOverlappedResult(io, &ovlp, &result, 1);
168
169
/* Copy the subregion that we actually care about, if applicable */
170
if (usePacketBuffer)
171
{
172
FAudio_memcpy(dst, *packetBuffer + offPacket, len);
173
}
174
}
175
176
/* Internal Functions */
177
178
void FACT_INTERNAL_GetNextWave(
179
FACTCue *cue,
180
FACTSound *sound,
181
FACTTrack *track,
182
FACTTrackInstance *trackInst,
183
FACTEvent *evt,
184
FACTEventInstance *evtInst
185
) {
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;
197
198
/* Track Variation */
199
if (evt->wave.isComplex)
200
{
201
if ( trackInst->activeWave.wave == NULL ||
202
!(evt->wave.complex.variation & 0x00F0) )
203
{
204
/* No-op, no variation on loop */
205
}
206
/* Ordered, Ordered From Random */
207
else if ( (evt->wave.complex.variation & 0xF) == 0 ||
208
(evt->wave.complex.variation & 0xF) == 1 )
209
{
210
evtInst->valuei += 1;
211
if (evtInst->valuei >= evt->wave.complex.trackCount)
212
{
213
evtInst->valuei = 0;
214
}
215
}
216
/* Random */
217
else if ((evt->wave.complex.variation & 0xF) == 2)
218
{
219
max = 0.0f;
220
for (i = 0; i < evt->wave.complex.trackCount; i += 1)
221
{
222
max += evt->wave.complex.weights[i];
223
}
224
next = FACT_INTERNAL_rng() * max;
225
for (i = evt->wave.complex.trackCount; i > 0; i -= 1)
226
{
227
if (next > (max - evt->wave.complex.weights[i - 1]))
228
{
229
evtInst->valuei = i - 1;
230
break;
231
}
232
max -= evt->wave.complex.weights[i - 1];
233
}
234
}
235
/* Random (No Immediate Repeats), Shuffle */
236
else if ( (evt->wave.complex.variation & 0xF) == 3 ||
237
(evt->wave.complex.variation & 0xF) == 4 )
238
{
239
max = 0.0f;
240
for (i = 0; i < evt->wave.complex.trackCount; i += 1)
241
{
242
if (i == evtInst->valuei)
243
{
244
continue;
245
}
246
max += evt->wave.complex.weights[i];
247
}
248
next = FACT_INTERNAL_rng() * max;
249
for (i = evt->wave.complex.trackCount; i > 0; i -= 1)
250
{
251
if (i - 1 == evtInst->valuei)
252
{
253
continue;
254
}
255
if (next > (max - evt->wave.complex.weights[i - 1]))
256
{
257
evtInst->valuei = i - 1;
258
break;
259
}
260
max -= evt->wave.complex.weights[i - 1];
261
}
262
}
263
264
if (evt->wave.complex.variation & 0x00F0)
265
{
266
noTrackVariation = 0;
267
}
268
269
wbIndex = evt->wave.complex.wavebanks[evtInst->valuei];
270
wbTrack = evt->wave.complex.tracks[evtInst->valuei];
271
}
272
else
273
{
274
wbIndex = evt->wave.simple.wavebank;
275
wbTrack = evt->wave.simple.track;
276
}
277
wbName = cue->parentBank->wavebankNames[wbIndex];
278
list = cue->parentBank->parentEngine->wbList;
279
while (list != NULL)
280
{
281
wb = (FACTWaveBank*) list->entry;
282
if (FAudio_strcmp(wbName, wb->name) == 0)
283
{
284
break;
285
}
286
list = list->next;
287
}
288
FAudio_assert(wb != NULL);
289
290
/* Generate the Wave */
291
if ( evtInst->loopCount == 255 &&
292
noTrackVariation &&
293
!(evt->wave.variationFlags & 0x0F00) )
294
{
295
/* For infinite loops with no variation, let Wave do the work */
296
loopCount = 255;
297
}
298
FACTWaveBank_Prepare(
299
wb,
300
wbTrack,
301
evt->wave.flags,
302
0,
303
loopCount,
304
&trackInst->upcomingWave.wave
305
);
306
trackInst->upcomingWave.wave->parentCue = cue;
307
if (sound->dspCodeCount > 0) /* Never more than 1...? */
308
{
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
318
);
319
}
320
321
/* 3D Audio */
322
if (cue->active3D)
323
{
324
FACTWave_SetMatrixCoefficients(
325
trackInst->upcomingWave.wave,
326
cue->srcChannels,
327
cue->dstChannels,
328
cue->matrixCoefficients
329
);
330
}
331
else
332
{
333
/* TODO: Position/Angle/UseCenterSpeaker */
334
}
335
336
/* Pitch Variation */
337
if (evt->wave.variationFlags & 0x1000)
338
{
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)
344
{
345
/* Variation on Loop */
346
if (evt->wave.variationFlags & 0x0100)
347
{
348
/* Add/Replace */
349
if (evt->wave.variationFlags & 0x0004)
350
{
351
trackInst->upcomingWave.basePitch =
352
trackInst->activeWave.basePitch + rngPitch;
353
}
354
else
355
{
356
trackInst->upcomingWave.basePitch = rngPitch + sound->pitch;
357
}
358
}
359
}
360
else
361
{
362
/* Initial Pitch Variation */
363
trackInst->upcomingWave.basePitch = rngPitch + sound->pitch;
364
}
365
}
366
else
367
{
368
trackInst->upcomingWave.basePitch = sound->pitch;
369
}
370
371
/* Volume Variation */
372
if (evt->wave.variationFlags & 0x2000)
373
{
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)
379
{
380
/* Variation on Loop */
381
if (evt->wave.variationFlags & 0x0200)
382
{
383
/* Add/Replace */
384
if (evt->wave.variationFlags & 0x0001)
385
{
386
trackInst->upcomingWave.baseVolume =
387
trackInst->activeWave.baseVolume + rngVolume;
388
}
389
else
390
{
391
trackInst->upcomingWave.baseVolume = (
392
rngVolume +
393
sound->volume +
394
track->volume
395
);
396
}
397
}
398
}
399
else
400
{
401
/* Initial Volume Variation */
402
trackInst->upcomingWave.baseVolume = (
403
rngVolume +
404
sound->volume +
405
track->volume
406
);
407
}
408
}
409
else
410
{
411
trackInst->upcomingWave.baseVolume = sound->volume + track->volume;
412
}
413
414
/* Filter Variation, QFactor/Freq are always together */
415
if (evt->wave.variationFlags & 0xC000)
416
{
417
const float rngQFactor = 1.0f / (
418
FACT_INTERNAL_rng() *
419
(evt->wave.maxQFactor - evt->wave.minQFactor) +
420
evt->wave.minQFactor
421
);
422
const float rngFrequency = FACT_INTERNAL_CalculateFilterFrequency(
423
(
424
FACT_INTERNAL_rng() *
425
(evt->wave.maxFrequency - evt->wave.minFrequency) +
426
evt->wave.minFrequency
427
),
428
cue->parentBank->parentEngine->audio->master->master.inputSampleRate
429
);
430
if (trackInst->activeWave.wave != NULL)
431
{
432
/* Variation on Loop */
433
if (evt->wave.variationFlags & 0x0C00)
434
{
435
/* TODO: Add/Replace */
436
/* FIXME: Which is QFactor/Freq?
437
if (evt->wave.variationFlags & 0x0010)
438
{
439
}
440
else
441
{
442
}
443
if (evt->wave.variationFlags & 0x0040)
444
{
445
}
446
else
447
{
448
}
449
*/
450
trackInst->upcomingWave.baseQFactor = rngQFactor;
451
trackInst->upcomingWave.baseFrequency = rngFrequency;
452
}
453
}
454
else
455
{
456
/* Initial Filter Variation */
457
trackInst->upcomingWave.baseQFactor = rngQFactor;
458
trackInst->upcomingWave.baseFrequency = rngFrequency;
459
}
460
}
461
else
462
{
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
467
);
468
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.
471
*/
472
trackInst->upcomingWave.baseQFactor = FAudio_min(
473
trackInst->upcomingWave.baseQFactor,
474
1.0f
475
);
476
}
477
478
/* Try to change loop counter at the very end */
479
if (loopCount == 255)
480
{
481
/* For infinite loops with no variation, Wave does the work */
482
evtInst->loopCount = 0;
483
}
484
else if (evtInst->loopCount > 0)
485
{
486
evtInst->loopCount -= 1;
487
}
488
}
489
490
uint8_t FACT_INTERNAL_CreateSound(FACTCue *cue, uint16_t fadeInMS)
491
{
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;
503
504
union
505
{
506
float maxf;
507
uint8_t maxi;
508
} limitmax;
509
FACTCue *tmp, *wnr;
510
uint16_t categoryIndex;
511
FACTAudioCategory *category;
512
513
if (cue->data->flags & 0x04)
514
{
515
/* Sound */
516
baseSound = cue->sound;
517
}
518
else if (cue->variation)
519
{
520
/* Variation */
521
if (cue->variation->flags == 3)
522
{
523
/* Interactive */
524
if (cue->parentBank->parentEngine->variables[cue->variation->variable].accessibility & 0x04)
525
{
526
FACTCue_GetVariable(
527
cue,
528
cue->variation->variable,
529
&next
530
);
531
}
532
else
533
{
534
FACTAudioEngine_GetGlobalVariable(
535
cue->parentBank->parentEngine,
536
cue->variation->variable,
537
&next
538
);
539
}
540
for (i = 0; i < cue->variation->entryCount; i += 1)
541
{
542
if ( next <= cue->variation->entries[i].maxWeight &&
543
next >= cue->variation->entries[i].minWeight )
544
{
545
break;
546
}
547
}
548
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.
553
*/
554
if (i == cue->variation->entryCount)
555
{
556
return 1;
557
}
558
}
559
else
560
{
561
/* Random */
562
max = 0.0f;
563
for (i = 0; i < cue->variation->entryCount; i += 1)
564
{
565
max += (
566
cue->variation->entries[i].maxWeight -
567
cue->variation->entries[i].minWeight
568
);
569
}
570
next = FACT_INTERNAL_rng() * max;
571
572
/* Use > 0, not >= 0. If we hit 0, that's it! */
573
for (i = cue->variation->entryCount - 1; i > 0; i -= 1)
574
{
575
weight = (
576
cue->variation->entries[i].maxWeight -
577
cue->variation->entries[i].minWeight
578
);
579
if (next > (max - weight))
580
{
581
break;
582
}
583
max -= weight;
584
}
585
}
586
587
if (cue->variation->isComplex)
588
{
589
/* Grab the Sound via the code. FIXME: Do this at load time? */
590
for (j = 0; j < cue->parentBank->soundCount; j += 1)
591
{
592
if (cue->variation->entries[i].soundCode == cue->parentBank->soundCodes[j])
593
{
594
baseSound = &cue->parentBank->sounds[j];
595
break;
596
}
597
}
598
}
599
else
600
{
601
/* Pull in the WaveBank... */
602
wbName = cue->parentBank->wavebankNames[
603
cue->variation->entries[i].simple.wavebank
604
];
605
list = cue->parentBank->parentEngine->wbList;
606
while (list != NULL)
607
{
608
wb = (FACTWaveBank*) list->entry;
609
if (FAudio_strcmp(wbName, wb->name) == 0)
610
{
611
break;
612
}
613
list = list->next;
614
}
615
FAudio_assert(wb != NULL);
616
617
/* Generate the wave... */
618
FACTWaveBank_Prepare(
619
wb,
620
cue->variation->entries[i].simple.track,
621
0,
622
0,
623
0,
624
&cue->simpleWave
625
);
626
cue->simpleWave->parentCue = cue;
627
}
628
}
629
630
/* Alloc SoundInstance variables */
631
if (baseSound != NULL)
632
{
633
/* Category Instance Limits */
634
categoryIndex = baseSound->category;
635
if (categoryIndex != FACTCATEGORY_INVALID)
636
{
637
category = &cue->parentBank->parentEngine->categories[categoryIndex];
638
if (category->instanceCount >= category->instanceLimit)
639
{
640
wnr = NULL;
641
tmp = cue->parentBank->cueList;
642
if (category->maxInstanceBehavior == 0) /* Fail */
643
{
644
cue->state |= FACT_STATE_STOPPED;
645
cue->state &= ~(
646
FACT_STATE_PLAYING |
647
FACT_STATE_STOPPING |
648
FACT_STATE_PAUSED
649
);
650
return 0;
651
}
652
else if (category->maxInstanceBehavior == 1) /* Queue */
653
{
654
/* FIXME: How is this different from Replace Oldest? */
655
while (tmp != NULL)
656
{
657
if ( tmp != cue &&
658
tmp->playingSound != NULL &&
659
tmp->playingSound->sound->category == categoryIndex &&
660
!(tmp->state & (FACT_STATE_STOPPING | FACT_STATE_STOPPED)) )
661
{
662
wnr = tmp;
663
break;
664
}
665
tmp = tmp->next;
666
}
667
}
668
else if (category->maxInstanceBehavior == 2) /* Replace Oldest */
669
{
670
while (tmp != NULL)
671
{
672
if ( tmp != cue &&
673
tmp->playingSound != NULL &&
674
tmp->playingSound->sound->category == categoryIndex &&
675
!(tmp->state & (FACT_STATE_STOPPING | FACT_STATE_STOPPED)) )
676
{
677
wnr = tmp;
678
break;
679
}
680
tmp = tmp->next;
681
}
682
}
683
else if (category->maxInstanceBehavior == 3) /* Replace Quietest */
684
{
685
limitmax.maxf = FACTVOLUME_MAX;
686
while (tmp != NULL)
687
{
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)) )
693
{
694
wnr = tmp;
695
/* limitmax.maxf = tmp->playingSound->volume; */
696
}
697
tmp = tmp->next;
698
}
699
}
700
else if (category->maxInstanceBehavior == 4) /* Replace Lowest Priority */
701
{
702
limitmax.maxi = 0xFF;
703
while (tmp != NULL)
704
{
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)) )
710
{
711
wnr = tmp;
712
limitmax.maxi = tmp->playingSound->sound->priority;
713
}
714
tmp = tmp->next;
715
}
716
}
717
if (wnr != NULL)
718
{
719
fadeInMS = category->fadeInMS;
720
if (wnr->playingSound != NULL)
721
{
722
FACT_INTERNAL_BeginFadeOut(wnr->playingSound, category->fadeOutMS);
723
}
724
else
725
{
726
FACTCue_Stop(wnr, 0);
727
}
728
}
729
}
730
category->instanceCount += 1;
731
}
732
733
newSound = (FACTSoundInstance*) cue->parentBank->parentEngine->pMalloc(
734
sizeof(FACTSoundInstance)
735
);
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)
745
{
746
newSound->fadeStart = FAudio_timems();
747
newSound->fadeTarget = fadeInMS;
748
}
749
else
750
{
751
newSound->fadeStart = 0;
752
newSound->fadeTarget = 0;
753
}
754
newSound->tracks = (FACTTrackInstance*) cue->parentBank->parentEngine->pMalloc(
755
sizeof(FACTTrackInstance) * newSound->sound->trackCount
756
);
757
for (i = 0; i < newSound->sound->trackCount; i += 1)
758
{
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;
764
765
newSound->tracks[i].evtVolume = 0.0f;
766
newSound->tracks[i].evtPitch = 0.0f;
767
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;
778
779
newSound->tracks[i].events = (FACTEventInstance*) cue->parentBank->parentEngine->pMalloc(
780
sizeof(FACTEventInstance) * newSound->sound->tracks[i].eventCount
781
);
782
for (j = 0; j < newSound->sound->tracks[i].eventCount; j += 1)
783
{
784
evt = &newSound->sound->tracks[i].events[j];
785
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;
791
792
if ( evt->type == FACTEVENT_PLAYWAVE ||
793
evt->type == FACTEVENT_PLAYWAVETRACKVARIATION ||
794
evt->type == FACTEVENT_PLAYWAVEEFFECTVARIATION ||
795
evt->type == FACTEVENT_PLAYWAVETRACKEFFECTVARIATION )
796
{
797
newSound->tracks[i].events[j].loopCount =
798
newSound->sound->tracks[i].events[j].wave.loopCount;
799
800
evtInst = &newSound->tracks[i].events[j];
801
if ( !evt->wave.isComplex ||
802
(evt->wave.complex.variation & 0xF) == 0 )
803
{
804
evtInst->valuei = 0;
805
}
806
else
807
{
808
max = 0.0f;
809
for (k = 0; k < evt->wave.complex.trackCount; k += 1)
810
{
811
max += evt->wave.complex.weights[k];
812
}
813
next = FACT_INTERNAL_rng() * max;
814
for (k = evt->wave.complex.trackCount - 1; k >= 0; k -= 1)
815
{
816
if (next > (max - evt->wave.complex.weights[k]))
817
{
818
evtInst->valuei = k;
819
break;
820
}
821
max -= evt->wave.complex.weights[k];
822
}
823
}
824
FACT_INTERNAL_GetNextWave(
825
cue,
826
newSound->sound,
827
&newSound->sound->tracks[i],
828
&newSound->tracks[i],
829
evt,
830
evtInst
831
);
832
newSound->tracks[i].waveEvt = evt;
833
newSound->tracks[i].waveEvtInst = evtInst;
834
}
835
else if ( evt->type == FACTEVENT_PITCHREPEATING ||
836
evt->type == FACTEVENT_VOLUMEREPEATING )
837
{
838
newSound->tracks[i].events[j].loopCount =
839
newSound->sound->tracks[i].events[j].value.repeats;
840
}
841
else if (evt->type == FACTEVENT_MARKERREPEATING)
842
{
843
newSound->tracks[i].events[j].loopCount =
844
newSound->sound->tracks[i].events[j].marker.repeats;
845
}
846
}
847
}
848
849
/* Calculate Max RPC Release Time */
850
cue->maxRpcReleaseTime = 0;
851
for (i = 0; i < newSound->sound->trackCount; i += 1)
852
{
853
for (j = 0; j < newSound->sound->tracks[i].rpcCodeCount; j += 1)
854
{
855
rpc = FACT_INTERNAL_GetRPC(
856
newSound->parentCue->parentBank->parentEngine,
857
newSound->sound->tracks[i].rpcCodes[j]
858
);
859
if ( rpc->parameter == RPC_PARAMETER_VOLUME &&
860
cue->parentBank->parentEngine->variables[rpc->variable].accessibility & 0x04 )
861
{
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)
868
{
869
cue->maxRpcReleaseTime = (uint32_t) lastX /* bleh */;
870
}
871
}
872
}
873
}
874
}
875
876
cue->playingSound = newSound;
877
}
878
879
return 1;
880
}
881
882
void FACT_INTERNAL_SendCueNotification(FACTCue *cue, FACTNoticationsFlags flag, uint8_t type)
883
{
884
if (cue->parentBank->parentEngine->notifications & flag)
885
{
886
FACTNotification note;
887
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;
893
894
cue->parentBank->parentEngine->notificationCallback(&note);
895
}
896
}
897
898
void FACT_INTERNAL_DestroySound(FACTSoundInstance *sound)
899
{
900
uint8_t i;
901
902
sound->parentCue->playingSound = NULL;
903
for (i = 0; i < sound->sound->trackCount; i += 1)
904
{
905
if (sound->tracks[i].activeWave.wave != NULL)
906
{
907
FACTWave_Destroy(
908
sound->tracks[i].activeWave.wave
909
);
910
}
911
if (sound->tracks[i].upcomingWave.wave != NULL)
912
{
913
FACTWave_Destroy(
914
sound->tracks[i].upcomingWave.wave
915
);
916
}
917
sound->parentCue->parentBank->parentEngine->pFree(
918
sound->tracks[i].events
919
);
920
}
921
sound->parentCue->parentBank->parentEngine->pFree(sound->tracks);
922
923
if (sound->sound->category != FACTCATEGORY_INVALID)
924
{
925
sound->parentCue->parentBank->parentEngine->categories[
926
sound->sound->category
927
].instanceCount -= 1;
928
}
929
930
/* TODO: if (sound->parentCue->playingSounds == NULL) */
931
{
932
sound->parentCue->state |= FACT_STATE_STOPPED;
933
sound->parentCue->state &= ~(FACT_STATE_PLAYING | FACT_STATE_PAUSED | FACT_STATE_STOPPING);
934
sound->parentCue->data->instanceCount -= 1;
935
936
FACT_INTERNAL_SendCueNotification(sound->parentCue, NOTIFY_CUESTOP, FACTNOTIFICATIONTYPE_CUESTOP);
937
}
938
sound->parentCue->parentBank->parentEngine->pFree(sound);
939
}
940
941
void FACT_INTERNAL_BeginFadeOut(FACTSoundInstance *sound, uint16_t fadeOutMS)
942
{
943
/* FIXME: Even for 0ms it seems to want to be in STOPPING for one frame.
944
* Should we still destroy but defer state changes to the next frame?
945
* -flibit
946
*/
947
#if 0
948
if (fadeOutMS == 0)
949
{
950
/* No fade? Screw it, just delete us */
951
FACT_INTERNAL_DestroySound(sound);
952
return;
953
}
954
#endif
955
956
sound->fadeType = 2; /* Out */
957
sound->fadeStart = FAudio_timems();
958
sound->fadeTarget = fadeOutMS;
959
960
sound->parentCue->state |= FACT_STATE_STOPPING;
961
}
962
963
void FACT_INTERNAL_BeginReleaseRPC(FACTSoundInstance *sound, uint16_t releaseMS)
964
{
965
if (releaseMS == 0)
966
{
967
/* No release RPC? Screw it, just delete us */
968
FACT_INTERNAL_DestroySound(sound);
969
return;
970
}
971
972
sound->fadeType = 3; /* Release RPC */
973
sound->fadeStart = FAudio_timems();
974
sound->fadeTarget = releaseMS;
975
976
sound->parentCue->state |= FACT_STATE_STOPPING;
977
}
978
979
/* RPC Helper Functions */
980
981
FACTRPC* FACT_INTERNAL_GetRPC(
982
FACTAudioEngine *engine,
983
uint32_t code
984
) {
985
uint16_t i;
986
for (i = 0; i < engine->rpcCount; i += 1)
987
{
988
if (engine->rpcCodes[i] == code)
989
{
990
return &engine->rpcs[i];
991
}
992
}
993
994
FAudio_assert(0 && "RPC code not found!");
995
return NULL;
996
}
997
998
float FACT_INTERNAL_CalculateRPC(
999
FACTRPC *rpc,
1000
float var
1001
) {
1002
float result;
1003
uint8_t i;
1004
1005
/* Min/Max */
1006
if (var <= rpc->points[0].x)
1007
{
1008
/* Zero to first defined point */
1009
return rpc->points[0].y;
1010
}
1011
if (var >= rpc->points[rpc->pointCount - 1].x)
1012
{
1013
/* Last defined point to infinity */
1014
return rpc->points[rpc->pointCount - 1].y;
1015
}
1016
1017
/* Something between points */
1018
result = 0.0f;
1019
for (i = 0; i < rpc->pointCount - 1; i += 1)
1020
{
1021
/* y = b */
1022
result = rpc->points[i].y;
1023
if (var >= rpc->points[i].x && var <= rpc->points[i + 1].x)
1024
{
1025
const float maxX = rpc->points[i + 1].x - rpc->points[i].x;
1026
const float maxY = rpc->points[i + 1].y - rpc->points[i].y;
1027
const float deltaX = (var - rpc->points[i].x);
1028
const float deltaXNormalized = deltaX / maxX;
1029
1030
if (rpc->points[i].type == 0) /* Linear */
1031
{
1032
result += maxY * deltaXNormalized;
1033
}
1034
else if (rpc->points[i].type == 1) /* Fast */
1035
{
1036
result += maxY * (1.0f - FAudio_powf(1.0f - FAudio_powf(deltaXNormalized, 1.0f / 1.5f), 1.5f));
1037
}
1038
else if (rpc->points[i].type == 2) /* Slow */
1039
{
1040
result += maxY * (1.0f - FAudio_powf(1.0f - FAudio_powf(deltaXNormalized, 1.5f), 1.0f / 1.5f));
1041
}
1042
else if (rpc->points[i].type == 3) /* SinCos */
1043
{
1044
if (maxY > 0.0f)
1045
{
1046
result += maxY * (1.0f - FAudio_powf(1.0f - FAudio_sqrtf(deltaXNormalized), 2.0f));
1047
}
1048
else
1049
{
1050
result += maxY * (1.0f - FAudio_sqrtf(1.0f - FAudio_powf(deltaXNormalized, 2.0f)));
1051
}
1052
}
1053
else
1054
{
1055
FAudio_assert(0 && "Unrecognized curve type!");
1056
}
1057
1058
break;
1059
}
1060
}
1061
return result;
1062
}
1063
1064
void FACT_INTERNAL_UpdateRPCs(
1065
FACTCue *cue,
1066
uint8_t codeCount,
1067
uint32_t *codes,
1068
FACTInstanceRPCData *data,
1069
uint32_t timestamp,
1070
uint32_t elapsedTrack
1071
) {
1072
uint8_t i;
1073
FACTRPC *rpc;
1074
float rpcResult;
1075
float variableValue;
1076
FACTAudioEngine *engine = cue->parentBank->parentEngine;
1077
1078
if (codeCount > 0)
1079
{
1080
/* Do NOT overwrite Frequency/QFactor! */
1081
data->rpcVolume = 0.0f;
1082
data->rpcPitch = 0.0f;
1083
data->rpcReverbSend = 0.0f;
1084
for (i = 0; i < codeCount; i += 1)
1085
{
1086
rpc = FACT_INTERNAL_GetRPC(
1087
engine,
1088
codes[i]
1089
);
1090
if (engine->variables[rpc->variable].accessibility & 0x04)
1091
{
1092
if (FAudio_strcmp(
1093
engine->variableNames[rpc->variable],
1094
"AttackTime"
1095
) == 0) {
1096
variableValue = (float) elapsedTrack;
1097
}
1098
else if (FAudio_strcmp(
1099
engine->variableNames[rpc->variable],
1100
"ReleaseTime"
1101
) == 0) {
1102
if (cue->playingSound->fadeType == 3) /* Release RPC */
1103
{
1104
variableValue = (float) (timestamp - cue->playingSound->fadeStart);
1105
}
1106
else
1107
{
1108
variableValue = 0.0f;
1109
}
1110
}
1111
else
1112
{
1113
variableValue = cue->variableValues[rpc->variable];
1114
}
1115
1116
rpcResult = FACT_INTERNAL_CalculateRPC(
1117
rpc,
1118
variableValue
1119
);
1120
}
1121
else
1122
{
1123
rpcResult = FACT_INTERNAL_CalculateRPC(
1124
rpc,
1125
engine->globalVariableValues[rpc->variable]
1126
);
1127
}
1128
if (rpc->parameter == RPC_PARAMETER_VOLUME)
1129
{
1130
data->rpcVolume += rpcResult;
1131
}
1132
else if (rpc->parameter == RPC_PARAMETER_PITCH)
1133
{
1134
data->rpcPitch += rpcResult;
1135
}
1136
else if (rpc->parameter == RPC_PARAMETER_REVERBSEND)
1137
{
1138
data->rpcReverbSend += rpcResult;
1139
}
1140
else if (rpc->parameter == RPC_PARAMETER_FILTERFREQUENCY)
1141
{
1142
/* Yes, just overwrite... */
1143
data->rpcFilterFreq = FACT_INTERNAL_CalculateFilterFrequency(
1144
rpcResult,
1145
engine->audio->master->master.inputSampleRate
1146
);
1147
}
1148
else if (rpc->parameter == RPC_PARAMETER_FILTERQFACTOR)
1149
{
1150
/* Yes, just overwrite... */
1151
data->rpcFilterQFactor = 1.0f / rpcResult;
1152
}
1153
else
1154
{
1155
FAudio_assert(0 && "Unhandled RPC parameter type!");
1156
}
1157
}
1158
}
1159
}
1160
1161
/* Engine Update Function */
1162
1163
void FACT_INTERNAL_UpdateEngine(FACTAudioEngine *engine)
1164
{
1165
FAudioFXReverbParameters rvbPar;
1166
uint16_t i, j, par;
1167
float rpcResult;
1168
for (i = 0; i < engine->rpcCount; i += 1)
1169
{
1170
if (engine->rpcs[i].parameter >= RPC_PARAMETER_COUNT)
1171
{
1172
/* FIXME: Why did I make this global vars only...? */
1173
if (!(engine->variables[engine->rpcs[i].variable].accessibility & 0x04))
1174
{
1175
for (j = 0; j < engine->dspPresetCount; j += 1)
1176
{
1177
/* FIXME: This affects all DSP presets!
1178
* What if there's more than one?
1179
*/
1180
par = engine->rpcs[i].parameter - RPC_PARAMETER_COUNT;
1181
rpcResult = FACT_INTERNAL_CalculateRPC(
1182
&engine->rpcs[i],
1183
engine->globalVariableValues[engine->rpcs[i].variable]
1184
);
1185
engine->dspPresets[j].parameters[par].value = FAudio_clamp(
1186
rpcResult,
1187
engine->dspPresets[j].parameters[par].minVal,
1188
engine->dspPresets[j].parameters[par].maxVal
1189
);
1190
}
1191
}
1192
}
1193
}
1194
1195
/* Set Effect parameters from above RPC changes */
1196
if (engine->reverbVoice != NULL)
1197
{
1198
rvbPar.WetDryMix = engine->dspPresets[0].parameters[21].value;
1199
rvbPar.ReflectionsDelay = (uint32_t) engine->dspPresets[0].parameters[0].value;
1200
rvbPar.ReverbDelay = (uint8_t) engine->dspPresets[0].parameters[1].value;
1201
rvbPar.RearDelay = (uint8_t) engine->dspPresets[0].parameters[12].value;
1202
rvbPar.PositionLeft = (uint8_t) engine->dspPresets[0].parameters[2].value;
1203
rvbPar.PositionRight = (uint8_t) engine->dspPresets[0].parameters[3].value;
1204
rvbPar.PositionMatrixLeft = (uint8_t) engine->dspPresets[0].parameters[4].value;
1205
rvbPar.PositionMatrixRight = (uint8_t) engine->dspPresets[0].parameters[5].value;
1206
rvbPar.HighEQGain = (uint8_t) engine->dspPresets[0].parameters[10].value;
1207
rvbPar.LowEQCutoff = (uint8_t) engine->dspPresets[0].parameters[9].value;
1208
rvbPar.LowEQGain = (uint8_t) engine->dspPresets[0].parameters[8].value;
1209
rvbPar.LateDiffusion = (uint8_t) engine->dspPresets[0].parameters[7].value;
1210
rvbPar.EarlyDiffusion = (uint8_t) engine->dspPresets[0].parameters[6].value;
1211
rvbPar.HighEQCutoff = (uint8_t) engine->dspPresets[0].parameters[11].value;
1212
rvbPar.RoomFilterMain = engine->dspPresets[0].parameters[14].value;
1213
rvbPar.RoomFilterFreq = engine->dspPresets[0].parameters[13].value;
1214
rvbPar.RoomFilterHF = engine->dspPresets[0].parameters[15].value;
1215
rvbPar.ReflectionsGain = engine->dspPresets[0].parameters[16].value;
1216
rvbPar.ReverbGain = engine->dspPresets[0].parameters[17].value;
1217
rvbPar.DecayTime = engine->dspPresets[0].parameters[18].value;
1218
rvbPar.Density = engine->dspPresets[0].parameters[19].value;
1219
rvbPar.RoomSize = engine->dspPresets[0].parameters[20].value;
1220
1221
FAudioVoice_SetEffectParameters(
1222
engine->reverbVoice,
1223
0,
1224
&rvbPar,
1225
sizeof(FAudioFXReverbParameters),
1226
0
1227
);
1228
}
1229
}
1230
1231
/* Cue Update Functions */
1232
1233
static inline void FACT_INTERNAL_StopTrack(
1234
FACTTrack *track,
1235
FACTTrackInstance *trackInst,
1236
uint8_t immediate
1237
) {
1238
uint8_t i;
1239
1240
/* Stop the wave (may as-authored or immedate */
1241
if (trackInst->activeWave.wave != NULL)
1242
{
1243
FACTWave_Stop(
1244
trackInst->activeWave.wave,
1245
immediate
1246
);
1247
}
1248
1249
/* If there was another sound coming, it ain't now! */
1250
if (trackInst->upcomingWave.wave != NULL)
1251
{
1252
FACTWave_Destroy(trackInst->upcomingWave.wave);
1253
trackInst->upcomingWave.wave = NULL;
1254
}
1255
1256
/* Kill the loop count too */
1257
for (i = 0; i < track->eventCount; i += 1)
1258
{
1259
trackInst->events[i].loopCount = 0;
1260
trackInst->events[i].finished = 1;
1261
}
1262
}
1263
1264
void FACT_INTERNAL_ActivateEvent(
1265
FACTSoundInstance *sound,
1266
FACTTrack *track,
1267
FACTTrackInstance *trackInst,
1268
FACTEvent *evt,
1269
FACTEventInstance *evtInst,
1270
uint32_t elapsed
1271
) {
1272
uint8_t i;
1273
float svResult;
1274
uint8_t skipLoopCheck = 0;
1275
1276
/* STOP */
1277
if (evt->type == FACTEVENT_STOP)
1278
{
1279
/* Stop Cue */
1280
if (evt->stop.flags & 0x02)
1281
{
1282
if ( evt->stop.flags & 0x01 ||
1283
( sound->parentCue->parentBank->cues[sound->parentCue->index].fadeOutMS == 0 &&
1284
sound->parentCue->maxRpcReleaseTime == 0 ) )
1285
{
1286
for (i = 0; i < sound->sound->trackCount; i += 1)
1287
{
1288
FACT_INTERNAL_StopTrack(
1289
&sound->sound->tracks[i],
1290
&sound->tracks[i],
1291
1
1292
);
1293
}
1294
}
1295
else
1296
{
1297
if (sound->parentCue->parentBank->cues[sound->parentCue->index].fadeOutMS > 0)
1298
{
1299
FACT_INTERNAL_BeginFadeOut(
1300
sound,
1301
sound->parentCue->parentBank->cues[sound->parentCue->index].fadeOutMS
1302
);
1303
}
1304
else if (sound->parentCue->maxRpcReleaseTime > 0)
1305
{
1306
FACT_INTERNAL_BeginReleaseRPC(
1307
sound,
1308
sound->parentCue->maxRpcReleaseTime
1309
);
1310
}
1311
else
1312
{
1313
/* Pretty sure this doesn't happen, but just in case? */
1314
sound->parentCue->state |= FACT_STATE_STOPPING;
1315
}
1316
}
1317
}
1318
1319
/* Stop track */
1320
else
1321
{
1322
FACT_INTERNAL_StopTrack(
1323
track,
1324
trackInst,
1325
evt->stop.flags & 0x01
1326
);
1327
}
1328
}
1329
1330
/* PLAYWAVE */
1331
else if ( evt->type == FACTEVENT_PLAYWAVE ||
1332
evt->type == FACTEVENT_PLAYWAVETRACKVARIATION ||
1333
evt->type == FACTEVENT_PLAYWAVEEFFECTVARIATION ||
1334
evt->type == FACTEVENT_PLAYWAVETRACKEFFECTVARIATION )
1335
{
1336
FAudio_assert(trackInst->activeWave.wave == NULL);
1337
FAudio_assert(trackInst->upcomingWave.wave != NULL);
1338
FAudio_memcpy(
1339
&trackInst->activeWave,
1340
&trackInst->upcomingWave,
1341
sizeof(trackInst->activeWave)
1342
);
1343
trackInst->upcomingWave.wave = NULL;
1344
FACTWave_Play(trackInst->activeWave.wave);
1345
}
1346
1347
/* SETVALUE */
1348
else if ( evt->type == FACTEVENT_PITCH ||
1349
evt->type == FACTEVENT_PITCHREPEATING ||
1350
evt->type == FACTEVENT_VOLUME ||
1351
evt->type == FACTEVENT_VOLUMEREPEATING )
1352
{
1353
/* Ramp/Equation */
1354
if (evt->value.settings & 0x01)
1355
{
1356
/* FIXME: Incorporate 2nd derivative into the interpolated pitch (slopeDelta) */
1357
skipLoopCheck = elapsed <= (evtInst->timestamp + evt->value.ramp.duration);
1358
svResult = (
1359
evt->value.ramp.initialSlope *
1360
evt->value.ramp.duration / 1000 *
1361
10 /* "Slices" */
1362
) + evt->value.ramp.initialValue;
1363
svResult = (
1364
(svResult - evt->value.ramp.initialValue)
1365
) * FAudio_clamp(
1366
(float) (elapsed - evtInst->timestamp) / evt->value.ramp.duration,
1367
0.0f,
1368
1.0f
1369
) + evt->value.ramp.initialValue;
1370
1371
evtInst->value = svResult;
1372
}
1373
else
1374
{
1375
/* Value/Random */
1376
if (evt->value.equation.flags & 0x04)
1377
{
1378
svResult = evt->value.equation.value1;
1379
}
1380
else if (evt->value.equation.flags & 0x08)
1381
{
1382
svResult = evt->value.equation.value1 + FACT_INTERNAL_rng() * (
1383
evt->value.equation.value2 -
1384
evt->value.equation.value1
1385
);
1386
}
1387
else
1388
{
1389
svResult = 0.0f;
1390
FAudio_assert(0 && "Equation flags?");
1391
}
1392
1393
/* Add/Replace */
1394
if (evt->value.equation.flags & 0x01)
1395
{
1396
if( evt->type == FACTEVENT_PITCH ||
1397
evt->type == FACTEVENT_PITCHREPEATING )
1398
{
1399
evtInst->value = trackInst->evtPitch + svResult;
1400
}
1401
else
1402
{
1403
evtInst->value = trackInst->evtVolume + svResult;
1404
}
1405
}
1406
else
1407
{
1408
evtInst->value = svResult;
1409
}
1410
}
1411
1412
/* Set the result, finally. */
1413
if ( evt->type == FACTEVENT_PITCH ||
1414
evt->type == FACTEVENT_PITCHREPEATING )
1415
{
1416
trackInst->evtPitch = evtInst->value;
1417
}
1418
else
1419
{
1420
trackInst->evtVolume = evtInst->value;
1421
}
1422
1423
if (skipLoopCheck)
1424
{
1425
return;
1426
}
1427
if (evtInst->loopCount > 0)
1428
{
1429
if (evtInst->loopCount != 0xFF && evtInst->loopCount != 0xFFFF)
1430
{
1431
evtInst->loopCount -= 1;
1432
}
1433
1434
evtInst->timestamp += evt->value.frequency;
1435
return;
1436
}
1437
}
1438
1439
/* MARKER */
1440
else if ( evt->type == FACTEVENT_MARKER ||
1441
evt->type == FACTEVENT_MARKERREPEATING )
1442
{
1443
/* TODO: FACT_INTERNAL_Marker(evt->marker*) */
1444
if (evtInst->loopCount > 0)
1445
{
1446
if (evtInst->loopCount != 0xFF)
1447
{
1448
evtInst->loopCount -= 1;
1449
}
1450
1451
evtInst->timestamp += evt->marker.frequency;
1452
return;
1453
}
1454
}
1455
1456
/* ??? */
1457
else
1458
{
1459
FAudio_assert(0 && "Unknown event type!");
1460
}
1461
1462
/* If we made it here, we're done! */
1463
evtInst->finished = 1;
1464
}
1465
1466
uint8_t FACT_INTERNAL_UpdateSound(FACTSoundInstance *sound, uint32_t timestamp)
1467
{
1468
uint8_t i, j;
1469
uint32_t waveState;
1470
uint32_t elapsedCue;
1471
FACTEventInstance *evtInst;
1472
FAudioFilterParameters filterParams;
1473
uint8_t finished = 1;
1474
1475
/* Instance limiting Fade in/out */
1476
float fadeVolume;
1477
if (sound->fadeType == 1) /* Fade In */
1478
{
1479
if ((timestamp - sound->fadeStart) >= sound->fadeTarget)
1480
{
1481
/* We've faded in! */
1482
fadeVolume = 1.0f;
1483
sound->fadeStart = 0;
1484
sound->fadeTarget = 0;
1485
sound->fadeType = 0;
1486
}
1487
else
1488
{
1489
fadeVolume = (
1490
(float) (timestamp - sound->fadeStart) /
1491
(float) sound->fadeTarget
1492
);
1493
}
1494
}
1495
else if (sound->fadeType == 2) /* Fade Out */
1496
{
1497
if ((timestamp - sound->fadeStart) >= sound->fadeTarget)
1498
{
1499
/* We've faded out! */
1500
return 1;
1501
}
1502
fadeVolume = 1.0f - (
1503
(float) (timestamp - sound->fadeStart) /
1504
(float) sound->fadeTarget
1505
);
1506
}
1507
else if (sound->fadeType == 3) /* Release RPC */
1508
{
1509
if ((timestamp - sound->fadeStart) >= sound->fadeTarget)
1510
{
1511
/* We've faded out! */
1512
return 1;
1513
}
1514
fadeVolume = 1.0f;
1515
}
1516
else
1517
{
1518
fadeVolume = 1.0f;
1519
}
1520
1521
/* To get the time on a single Cue, subtract from the global time
1522
* the latest start time minus the total time elapsed (minus pause time)
1523
*/
1524
elapsedCue = timestamp - (sound->parentCue->start - sound->parentCue->elapsed);
1525
1526
/* RPC updates */
1527
sound->rpcData.rpcFilterFreq = -1.0f;
1528
sound->rpcData.rpcFilterQFactor = -1.0f;
1529
FACT_INTERNAL_UpdateRPCs(
1530
sound->parentCue,
1531
sound->sound->rpcCodeCount,
1532
sound->sound->rpcCodes,
1533
&sound->rpcData,
1534
timestamp,
1535
elapsedCue - sound->tracks[0].events[0].timestamp
1536
);
1537
for (i = 0; i < sound->sound->trackCount; i += 1)
1538
{
1539
sound->tracks[i].rpcData.rpcFilterFreq = sound->rpcData.rpcFilterFreq;
1540
sound->tracks[i].rpcData.rpcFilterQFactor = sound->rpcData.rpcFilterQFactor;
1541
FACT_INTERNAL_UpdateRPCs(
1542
sound->parentCue,
1543
sound->sound->tracks[i].rpcCodeCount,
1544
sound->sound->tracks[i].rpcCodes,
1545
&sound->tracks[i].rpcData,
1546
timestamp,
1547
elapsedCue - sound->sound->tracks[i].events[0].timestamp
1548
);
1549
}
1550
1551
/* Go through each event for each track */
1552
for (i = 0; i < sound->sound->trackCount; i += 1)
1553
{
1554
/* Event updates */
1555
for (j = 0; j < sound->sound->tracks[i].eventCount; j += 1)
1556
{
1557
evtInst = &sound->tracks[i].events[j];
1558
if (!evtInst->finished)
1559
{
1560
/* Cue's not done yet...! */
1561
finished = 0;
1562
1563
/* Trigger events at the right time */
1564
if (elapsedCue >= evtInst->timestamp)
1565
{
1566
FACT_INTERNAL_ActivateEvent(
1567
sound,
1568
&sound->sound->tracks[i],
1569
&sound->tracks[i],
1570
&sound->sound->tracks[i].events[j],
1571
evtInst,
1572
elapsedCue
1573
);
1574
}
1575
}
1576
}
1577
1578
/* Wave updates */
1579
if (sound->tracks[i].activeWave.wave == NULL)
1580
{
1581
continue;
1582
}
1583
finished = 0;
1584
1585
/* Clear out Waves as they finish */
1586
FACTWave_GetState(
1587
sound->tracks[i].activeWave.wave,
1588
&waveState
1589
);
1590
if (waveState & FACT_STATE_STOPPED)
1591
{
1592
FACTWave_Destroy(sound->tracks[i].activeWave.wave);
1593
FAudio_memcpy(
1594
&sound->tracks[i].activeWave,
1595
&sound->tracks[i].upcomingWave,
1596
sizeof(sound->tracks[i].activeWave)
1597
);
1598
sound->tracks[i].upcomingWave.wave = NULL;
1599
if (sound->tracks[i].activeWave.wave == NULL)
1600
{
1601
continue;
1602
}
1603
FACTWave_Play(sound->tracks[i].activeWave.wave);
1604
}
1605
1606
FACTWave_SetVolume(
1607
sound->tracks[i].activeWave.wave,
1608
FACT_INTERNAL_CalculateAmplitudeRatio(
1609
sound->tracks[i].activeWave.baseVolume +
1610
sound->rpcData.rpcVolume +
1611
sound->tracks[i].rpcData.rpcVolume +
1612
sound->tracks[i].evtVolume
1613
) * sound->parentCue->parentBank->parentEngine->categories[
1614
sound->sound->category
1615
].currentVolume *
1616
fadeVolume
1617
);
1618
FACTWave_SetPitch(
1619
sound->tracks[i].activeWave.wave,
1620
(int16_t) (
1621
sound->tracks[i].activeWave.basePitch +
1622
sound->rpcData.rpcPitch +
1623
sound->tracks[i].rpcData.rpcPitch +
1624
sound->tracks[i].evtPitch
1625
)
1626
);
1627
if (sound->sound->tracks[i].filter != 0xFF)
1628
{
1629
/* FIXME: From what I can gather, filter parameters get
1630
* overwritten by the RPC value if a filter RPC exists.
1631
* Priority is Sound < Sound RPC < Track RPC, I think?
1632
*/
1633
filterParams.Type = (FAudioFilterType) sound->sound->tracks[i].filter;
1634
if (sound->tracks[i].rpcData.rpcFilterFreq >= 0.0f)
1635
{
1636
filterParams.Frequency = sound->tracks[i].rpcData.rpcFilterFreq;
1637
}
1638
else
1639
{
1640
filterParams.Frequency = sound->tracks[i].activeWave.baseFrequency;
1641
}
1642
if (sound->tracks[i].rpcData.rpcFilterQFactor >= 0.0f)
1643
{
1644
filterParams.OneOverQ = sound->tracks[i].rpcData.rpcFilterQFactor;
1645
}
1646
else
1647
{
1648
filterParams.OneOverQ = sound->tracks[i].activeWave.baseQFactor;
1649
}
1650
FAudioVoice_SetFilterParameters(
1651
sound->tracks[i].activeWave.wave->voice,
1652
&filterParams,
1653
0
1654
);
1655
}
1656
/* TODO: Wave updates:
1657
* - ReverbSend (SetOutputMatrix on index 1, submix voice)
1658
*/
1659
}
1660
1661
return finished;
1662
}
1663
1664
void FACT_INTERNAL_UpdateCue(FACTCue *cue)
1665
{
1666
uint32_t i;
1667
float next;
1668
FACTSoundInstance *sound;
1669
1670
/* Interactive sound selection */
1671
if (!(cue->data->flags & 0x04) && cue->variation && cue->variation->flags == 3)
1672
{
1673
/* Interactive */
1674
if (cue->parentBank->parentEngine->variables[cue->variation->variable].accessibility & 0x04)
1675
{
1676
FACTCue_GetVariable(
1677
cue,
1678
cue->variation->variable,
1679
&next
1680
);
1681
}
1682
else
1683
{
1684
FACTAudioEngine_GetGlobalVariable(
1685
cue->parentBank->parentEngine,
1686
cue->variation->variable,
1687
&next
1688
);
1689
}
1690
if (next != cue->interactive)
1691
{
1692
cue->interactive = next;
1693
1694
/* New sound, time for death! */
1695
if (cue->playingSound != NULL)
1696
{
1697
/* Copy of DestroySound but does not set Cue to STOPPED */
1698
sound = cue->playingSound;
1699
sound->parentCue->playingSound = NULL;
1700
for (i = 0; i < sound->sound->trackCount; i += 1)
1701
{
1702
if (sound->tracks[i].activeWave.wave != NULL)
1703
{
1704
FACTWave_Destroy(
1705
sound->tracks[i].activeWave.wave
1706
);
1707
}
1708
if (sound->tracks[i].upcomingWave.wave != NULL)
1709
{
1710
FACTWave_Destroy(
1711
sound->tracks[i].upcomingWave.wave
1712
);
1713
}
1714
cue->parentBank->parentEngine->pFree(
1715
sound->tracks[i].events
1716
);
1717
}
1718
cue->parentBank->parentEngine->pFree(sound->tracks);
1719
1720
if (sound->sound->category != FACTCATEGORY_INVALID)
1721
{
1722
sound->parentCue->parentBank->parentEngine->categories[
1723
sound->sound->category
1724
].instanceCount -= 1;
1725
}
1726
}
1727
1728
/* TODO: Reset cue times? Transition tables...?
1729
cue->start = elapsed;
1730
cue->elapsed = 0;
1731
*/
1732
1733
FACT_INTERNAL_CreateSound(cue, 0 /* fadeIn */);
1734
}
1735
}
1736
}
1737
1738
/* FACT Thread */
1739
1740
int32_t FACT_INTERNAL_APIThread(void* enginePtr)
1741
{
1742
FACTAudioEngine *engine = (FACTAudioEngine*) enginePtr;
1743
LinkedList *sbList;
1744
FACTCue *cue, *cBackup;
1745
uint32_t timestamp, updateTime;
1746
1747
/* Needs to match the audio thread priority, or else the scheduler will
1748
* let this thread sit around with a lock while the audio thread spins
1749
* infinitely!
1750
*/
1751
FAudio_PlatformThreadPriority(FAUDIO_THREAD_PRIORITY_HIGH);
1752
1753
threadstart:
1754
FAudio_PlatformLockMutex(engine->apiLock);
1755
1756
/* We want the timestamp to be uniform across all Cues.
1757
* Oftentimes many Cues are played at once with the expectation
1758
* that they will sync, so give them all the same timestamp
1759
* so all the various actions will go together even if it takes
1760
* an extra millisecond to get through the whole Cue list.
1761
*/
1762
timestamp = FAudio_timems();
1763
1764
FACT_INTERNAL_UpdateEngine(engine);
1765
1766
sbList = engine->sbList;
1767
while (sbList != NULL)
1768
{
1769
cue = ((FACTSoundBank*) sbList->entry)->cueList;
1770
while (cue != NULL)
1771
{
1772
FACT_INTERNAL_UpdateCue(cue);
1773
1774
if (cue->state & FACT_STATE_PAUSED)
1775
{
1776
/* Funky edge case where we need to keep updating even when paused */
1777
if (!(cue->state & FACT_STATE_STOPPING))
1778
{
1779
cue = cue->next;
1780
continue;
1781
}
1782
}
1783
1784
if (cue->playingSound != NULL)
1785
{
1786
if (FACT_INTERNAL_UpdateSound(cue->playingSound, timestamp))
1787
{
1788
FACT_INTERNAL_DestroySound(cue->playingSound);
1789
}
1790
}
1791
1792
/* Destroy if it's done and not user-handled. */
1793
if (cue->managed && (cue->state & FACT_STATE_STOPPED))
1794
{
1795
cBackup = cue->next;
1796
FACTCue_Destroy(cue);
1797
cue = cBackup;
1798
}
1799
else
1800
{
1801
cue = cue->next;
1802
}
1803
}
1804
sbList = sbList->next;
1805
}
1806
1807
FAudio_PlatformUnlockMutex(engine->apiLock);
1808
1809
if (engine->initialized)
1810
{
1811
/* FIXME: 10ms is based on the XAudio2 update time...? */
1812
updateTime = FAudio_timems() - timestamp;
1813
if (updateTime < 10)
1814
{
1815
FAudio_sleep(10 - updateTime);
1816
}
1817
goto threadstart;
1818
}
1819
1820
return 0;
1821
}
1822
1823
/* FAudio callbacks */
1824
1825
void FACT_INTERNAL_OnBufferEnd(FAudioVoiceCallback *callback, void* pContext)
1826
{
1827
FAudioBuffer buffer;
1828
FAudioBufferWMA bufferWMA;
1829
FACTWaveCallback *c = (FACTWaveCallback*) callback;
1830
FACTWaveBankEntry *entry;
1831
uint32_t end, left, length;
1832
1833
entry = &c->wave->parentBank->entries[c->wave->index];
1834
1835
/* Calculate total bytes left in this wave iteration */
1836
if (c->wave->loopCount > 0 && entry->LoopRegion.dwTotalSamples > 0)
1837
{
1838
length = entry->LoopRegion.dwStartSample + entry->LoopRegion.dwTotalSamples;
1839
if (entry->Format.wFormatTag == 0x0)
1840
{
1841
length = (
1842
length *
1843
entry->Format.nChannels *
1844
(1 << entry->Format.wBitsPerSample)
1845
);
1846
}
1847
else if (entry->Format.wFormatTag == 0x2)
1848
{
1849
length = (
1850
length /
1851
/* wSamplesPerBlock */
1852
((entry->Format.wBlockAlign + 16) * 2) *
1853
/* nBlockAlign */
1854
((entry->Format.wBlockAlign + 22) * entry->Format.nChannels)
1855
);
1856
}
1857
else
1858
{
1859
length = entry->PlayRegion.dwLength;
1860
}
1861
}
1862
else
1863
{
1864
length = entry->PlayRegion.dwLength;
1865
}
1866
end = entry->PlayRegion.dwOffset + length;
1867
left = length - (c->wave->streamOffset - entry->PlayRegion.dwOffset);
1868
1869
/* Don't bother if we're EOS or the Wave has stopped */
1870
if ( (c->wave->streamOffset >= end) ||
1871
(c->wave->state & FACT_STATE_STOPPED) )
1872
{
1873
return;
1874
}
1875
1876
/* Assign buffer memory */
1877
buffer.pAudioData = c->wave->streamCache;
1878
buffer.AudioBytes = FAudio_min(
1879
c->wave->streamSize,
1880
left
1881
);
1882
1883
/* Read! */
1884
FACT_INTERNAL_ReadFile(
1885
c->wave->parentBank->parentEngine->pReadFile,
1886
c->wave->parentBank->parentEngine->pGetOverlappedResult,
1887
c->wave->parentBank->io,
1888
c->wave->streamOffset,
1889
c->wave->parentBank->packetSize,
1890
&c->wave->parentBank->packetBuffer,
1891
&c->wave->parentBank->packetBufferLen,
1892
c->wave->parentBank->parentEngine->pRealloc,
1893
c->wave->streamCache,
1894
buffer.AudioBytes
1895
);
1896
c->wave->streamOffset += buffer.AudioBytes;
1897
1898
/* Last buffer in the stream? */
1899
buffer.Flags = 0;
1900
if (c->wave->streamOffset >= end)
1901
{
1902
/* Loop if applicable */
1903
if (c->wave->loopCount > 0)
1904
{
1905
if (c->wave->loopCount != 255)
1906
{
1907
c->wave->loopCount -= 1;
1908
}
1909
c->wave->streamOffset = entry->PlayRegion.dwOffset;
1910
1911
/* Loop start */
1912
if (entry->Format.wFormatTag == 0x0)
1913
{
1914
c->wave->streamOffset += (
1915
entry->LoopRegion.dwStartSample *
1916
entry->Format.nChannels *
1917
(1 << entry->Format.wBitsPerSample)
1918
);
1919
}
1920
else if (entry->Format.wFormatTag == 0x2)
1921
{
1922
c->wave->streamOffset += (
1923
entry->LoopRegion.dwStartSample /
1924
/* wSamplesPerBlock */
1925
((entry->Format.wBlockAlign + 16) * 2) *
1926
/* nBlockAlign */
1927
((entry->Format.wBlockAlign + 22) * entry->Format.nChannels)
1928
);
1929
}
1930
}
1931
else
1932
{
1933
buffer.Flags = FAUDIO_END_OF_STREAM;
1934
}
1935
}
1936
1937
/* Unused properties */
1938
buffer.PlayBegin = 0;
1939
buffer.PlayLength = 0;
1940
buffer.LoopBegin = 0;
1941
buffer.LoopLength = 0;
1942
buffer.LoopCount = 0;
1943
buffer.pContext = NULL;
1944
1945
/* Submit, finally. */
1946
if (entry->Format.wFormatTag == 0x3)
1947
{
1948
bufferWMA.pDecodedPacketCumulativeBytes =
1949
c->wave->parentBank->seekTables[c->wave->index].entries;
1950
bufferWMA.PacketCount =
1951
c->wave->parentBank->seekTables[c->wave->index].entryCount;
1952
FAudioSourceVoice_SubmitSourceBuffer(
1953
c->wave->voice,
1954
&buffer,
1955
&bufferWMA
1956
);
1957
}
1958
else
1959
{
1960
FAudioSourceVoice_SubmitSourceBuffer(
1961
c->wave->voice,
1962
&buffer,
1963
NULL
1964
);
1965
}
1966
}
1967
1968
void FACT_INTERNAL_OnStreamEnd(FAudioVoiceCallback *callback)
1969
{
1970
FACTWaveCallback *c = (FACTWaveCallback*) callback;
1971
1972
c->wave->state = FACT_STATE_STOPPED;
1973
1974
if ( c->wave->parentCue != NULL &&
1975
c->wave->parentCue->simpleWave == c->wave )
1976
{
1977
c->wave->parentCue->state |= FACT_STATE_STOPPED;
1978
c->wave->parentCue->state &= ~(
1979
FACT_STATE_PLAYING |
1980
FACT_STATE_STOPPING
1981
);
1982
c->wave->parentCue->data->instanceCount -= 1;
1983
}
1984
}
1985
1986
/* FAudioIOStream functions */
1987
1988
int32_t FACTCALL FACT_INTERNAL_DefaultReadFile(
1989
void *hFile,
1990
void *buffer,
1991
uint32_t nNumberOfBytesToRead,
1992
uint32_t *lpNumberOfBytesRead, /* Not referenced! */
1993
FACTOverlapped *lpOverlapped
1994
) {
1995
FAudioIOStream *io = (FAudioIOStream*) hFile;
1996
lpOverlapped->Internal = (void*) 0x00000103; /* STATUS_PENDING */
1997
FAudio_PlatformLockMutex((FAudioMutex) io->lock);
1998
io->seek(io->data, (size_t) lpOverlapped->Pointer, FAUDIO_SEEK_SET);
1999
lpOverlapped->InternalHigh = (void*) (size_t) (io->read(
2000
io->data,
2001
buffer,
2002
nNumberOfBytesToRead,
2003
1
2004
) * nNumberOfBytesToRead);
2005
FAudio_PlatformUnlockMutex((FAudioMutex) io->lock);
2006
lpOverlapped->Internal = 0; /* STATUS_SUCCESS */
2007
return 1;
2008
}
2009
2010
int32_t FACTCALL FACT_INTERNAL_DefaultGetOverlappedResult(
2011
void *hFile,
2012
FACTOverlapped *lpOverlapped,
2013
uint32_t *lpNumberOfBytesTransferred,
2014
int32_t bWait
2015
) {
2016
*lpNumberOfBytesTransferred = (uint32_t) (size_t) lpOverlapped->InternalHigh;
2017
return 1;
2018
}
2019
2020
/* Parsing functions */
2021
2022
#define READ_FUNC(type, size, bitsize, suffix) \
2023
static inline type read_##suffix(uint8_t **ptr, const uint8_t swapendian) \
2024
{ \
2025
type result = *((type*) *ptr); \
2026
*ptr += size; \
2027
return swapendian ? \
2028
FAudio_swap##bitsize##BE(result) : \
2029
FAudio_swap##bitsize##LE(result); \
2030
}
2031
2032
static inline uint8_t read_u8(uint8_t **ptr)
2033
{
2034
uint8_t result = *((uint8_t*) *ptr);
2035
*ptr += 1;
2036
return result;
2037
}
2038
READ_FUNC(uint16_t, 2, 16, u16)
2039
READ_FUNC(uint32_t, 4, 32, u32)
2040
READ_FUNC(int16_t, 2, 16, s16)
2041
READ_FUNC(int32_t, 4, 32, s32)
2042
static inline float read_f32(uint8_t **ptr, const uint8_t swapendian)
2043
{
2044
float result = *((float*) *ptr);
2045
*ptr += 4;
2046
return result;
2047
}
2048
2049
#undef READ_FUNC
2050
2051
static inline float read_volbyte(uint8_t **ptr)
2052
{
2053
/* FIXME: This magnificent beauty came from Mathematica!
2054
* The byte values for all possible input dB values from the .xap are here:
2055
* http://www.flibitijibibo.com/XACTVolume.txt
2056
* Yes, this is actually what the XACT builder really does.
2057
*
2058
* Thanks to Kenny for plotting all that data.
2059
* -flibit
2060
*/
2061
return (float) ((3969.0 * FAudio_log10(read_u8(ptr) / 28240.0)) + 8715.0);
2062
}
2063
2064
uint32_t FACT_INTERNAL_ParseAudioEngine(
2065
FACTAudioEngine *pEngine,
2066
const FACTRuntimeParameters *pParams
2067
) {
2068
uint32_t categoryOffset,
2069
variableOffset,
2070
blob1Offset,
2071
categoryNameIndexOffset,
2072
blob2Offset,
2073
variableNameIndexOffset,
2074
categoryNameOffset,
2075
variableNameOffset,
2076
rpcOffset,
2077
dspPresetOffset,
2078
dspParameterOffset;
2079
uint16_t blob1Count, blob2Count, tool;
2080
uint8_t version;
2081
uint8_t se;
2082
uint32_t magic;
2083
size_t memsize;
2084
uint16_t i, j;
2085
2086
uint8_t *ptr = (uint8_t*) pParams->pGlobalSettingsBuffer;
2087
uint8_t *start = ptr;
2088
2089
magic = read_u32(&ptr, 0);
2090
se = magic == 0x58475346; /* Swap Endian */
2091
if (magic != 0x46534758 && magic != 0x58475346) /* 'XGSF' */
2092
{
2093
return -1; /* TODO: NOT XACT FILE */
2094
}
2095
2096
if (!FACT_INTERNAL_SupportedContent(read_u16(&ptr, se)))
2097
{
2098
return -2;
2099
}
2100
2101
tool = read_u16(&ptr, se); /* Tool version */
2102
if (tool != 42)
2103
{
2104
return -3;
2105
}
2106
2107
ptr += 2; /* Unknown value */
2108
2109
/* Last modified, unused */
2110
ptr += 8;
2111
2112
/* XACT Version (Windows == 3, Xbox == 7) */
2113
version = read_u8(&ptr);
2114
if ( version != 3 &&
2115
version != 7 )
2116
{
2117
return -4; /* TODO: VERSION TOO OLD */
2118
}
2119
2120
/* Object counts */
2121
pEngine->categoryCount = read_u16(&ptr, se);
2122
pEngine->variableCount = read_u16(&ptr, se);
2123
blob1Count = read_u16(&ptr, se);
2124
blob2Count = read_u16(&ptr, se);
2125
pEngine->rpcCount = read_u16(&ptr, se);
2126
pEngine->dspPresetCount = read_u16(&ptr, se);
2127
pEngine->dspParameterCount = read_u16(&ptr, se);
2128
2129
/* Object offsets */
2130
categoryOffset = read_u32(&ptr, se);
2131
variableOffset = read_u32(&ptr, se);
2132
blob1Offset = read_u32(&ptr, se);
2133
categoryNameIndexOffset = read_u32(&ptr, se);
2134
blob2Offset = read_u32(&ptr, se);
2135
variableNameIndexOffset = read_u32(&ptr, se);
2136
categoryNameOffset = read_u32(&ptr, se);
2137
variableNameOffset = read_u32(&ptr, se);
2138
rpcOffset = read_u32(&ptr, se);
2139
dspPresetOffset = read_u32(&ptr, se);
2140
dspParameterOffset = read_u32(&ptr, se);
2141
2142
/* Category data */
2143
FAudio_assert((ptr - start) == categoryOffset);
2144
pEngine->categories = (FACTAudioCategory*) pEngine->pMalloc(
2145
sizeof(FACTAudioCategory) * pEngine->categoryCount
2146
);
2147
for (i = 0; i < pEngine->categoryCount; i += 1)
2148
{
2149
pEngine->categories[i].instanceLimit = read_u8(&ptr);
2150
pEngine->categories[i].fadeInMS = read_u16(&ptr, se);
2151
pEngine->categories[i].fadeOutMS = read_u16(&ptr, se);
2152
pEngine->categories[i].maxInstanceBehavior = read_u8(&ptr) >> 3;
2153
pEngine->categories[i].parentCategory = read_u16(&ptr, se);
2154
pEngine->categories[i].volume = FACT_INTERNAL_CalculateAmplitudeRatio(
2155
read_volbyte(&ptr)
2156
);
2157
pEngine->categories[i].visibility = read_u8(&ptr);
2158
pEngine->categories[i].instanceCount = 0;
2159
pEngine->categories[i].currentVolume = 1.0f;
2160
}
2161
2162
/* Variable data */
2163
FAudio_assert((ptr - start) == variableOffset);
2164
pEngine->variables = (FACTVariable*) pEngine->pMalloc(
2165
sizeof(FACTVariable) * pEngine->variableCount
2166
);
2167
for (i = 0; i < pEngine->variableCount; i += 1)
2168
{
2169
pEngine->variables[i].accessibility = read_u8(&ptr);
2170
pEngine->variables[i].initialValue = read_f32(&ptr, se);
2171
pEngine->variables[i].minValue = read_f32(&ptr, se);
2172
pEngine->variables[i].maxValue = read_f32(&ptr, se);
2173
}
2174
2175
/* Global variable storage. Some unused data for non-global vars */
2176
pEngine->globalVariableValues = (float*) pEngine->pMalloc(
2177
sizeof(float) * pEngine->variableCount
2178
);
2179
for (i = 0; i < pEngine->variableCount; i += 1)
2180
{
2181
pEngine->globalVariableValues[i] = pEngine->variables[i].initialValue;
2182
}
2183
2184
/* RPC data */
2185
if (pEngine->rpcCount > 0)
2186
{
2187
FAudio_assert((ptr - start) == rpcOffset);
2188
pEngine->rpcs = (FACTRPC*) pEngine->pMalloc(
2189
sizeof(FACTRPC) *
2190
pEngine->rpcCount
2191
);
2192
pEngine->rpcCodes = (uint32_t*) pEngine->pMalloc(
2193
sizeof(uint32_t) *
2194
pEngine->rpcCount
2195
);
2196
for (i = 0; i < pEngine->rpcCount; i += 1)
2197
{
2198
pEngine->rpcCodes[i] = (uint32_t) (ptr - start);
2199
pEngine->rpcs[i].variable = read_u16(&ptr, se);
2200
pEngine->rpcs[i].pointCount = read_u8(&ptr);
2201
pEngine->rpcs[i].parameter = read_u16(&ptr, se);
2202
pEngine->rpcs[i].points = (FACTRPCPoint*) pEngine->pMalloc(
2203
sizeof(FACTRPCPoint) *
2204
pEngine->rpcs[i].pointCount
2205
);
2206
for (j = 0; j < pEngine->rpcs[i].pointCount; j += 1)
2207
{
2208
pEngine->rpcs[i].points[j].x = read_f32(&ptr, se);
2209
pEngine->rpcs[i].points[j].y = read_f32(&ptr, se);
2210
pEngine->rpcs[i].points[j].type = read_u8(&ptr);
2211
}
2212
}
2213
}
2214
2215
/* DSP Preset data */
2216
if (pEngine->dspPresetCount > 0)
2217
{
2218
FAudio_assert((ptr - start) == dspPresetOffset);
2219
pEngine->dspPresets = (FACTDSPPreset*) pEngine->pMalloc(
2220
sizeof(FACTDSPPreset) *
2221
pEngine->dspPresetCount
2222
);
2223
pEngine->dspPresetCodes = (uint32_t*) pEngine->pMalloc(
2224
sizeof(uint32_t) *
2225
pEngine->dspPresetCount
2226
);
2227
for (i = 0; i < pEngine->dspPresetCount; i += 1)
2228
{
2229
pEngine->dspPresetCodes[i] = (uint32_t) (ptr - start);
2230
pEngine->dspPresets[i].accessibility = read_u8(&ptr);
2231
pEngine->dspPresets[i].parameterCount = read_u16(&ptr, se);
2232
ptr += 2; /* Unknown value */
2233
pEngine->dspPresets[i].parameters = (FACTDSPParameter*) pEngine->pMalloc(
2234
sizeof(FACTDSPParameter) *
2235
pEngine->dspPresets[i].parameterCount
2236
); /* This will be filled in just a moment... */
2237
}
2238
2239
/* DSP Parameter data */
2240
FAudio_assert((ptr - start) == dspParameterOffset);
2241
for (i = 0; i < pEngine->dspPresetCount; i += 1)
2242
{
2243
for (j = 0; j < pEngine->dspPresets[i].parameterCount; j += 1)
2244
{
2245
pEngine->dspPresets[i].parameters[j].type = read_u8(&ptr);
2246
pEngine->dspPresets[i].parameters[j].value = read_f32(&ptr, se);
2247
pEngine->dspPresets[i].parameters[j].minVal = read_f32(&ptr, se);
2248
pEngine->dspPresets[i].parameters[j].maxVal = read_f32(&ptr, se);
2249
pEngine->dspPresets[i].parameters[j].unknown = read_u16(&ptr, se);
2250
}
2251
}
2252
}
2253
2254
/* Blob #1, no idea what this is... */
2255
FAudio_assert((ptr - start) == blob1Offset);
2256
ptr += blob1Count * 2;
2257
2258
/* Category Name Index data */
2259
FAudio_assert((ptr - start) == categoryNameIndexOffset);
2260
ptr += pEngine->categoryCount * 6; /* FIXME: index as assert value? */
2261
2262
/* Category Name data */
2263
FAudio_assert((ptr - start) == categoryNameOffset);
2264
pEngine->categoryNames = (char**) pEngine->pMalloc(
2265
sizeof(char*) *
2266
pEngine->categoryCount
2267
);
2268
for (i = 0; i < pEngine->categoryCount; i += 1)
2269
{
2270
memsize = FAudio_strlen((char*) ptr) + 1; /* Dastardly! */
2271
pEngine->categoryNames[i] = (char*) pEngine->pMalloc(memsize);
2272
FAudio_memcpy(pEngine->categoryNames[i], ptr, memsize);
2273
ptr += memsize;
2274
}
2275
2276
/* Blob #2, no idea what this is... */
2277
FAudio_assert((ptr - start) == blob2Offset);
2278
ptr += blob2Count * 2;
2279
2280
/* Variable Name Index data */
2281
FAudio_assert((ptr - start) == variableNameIndexOffset);
2282
ptr += pEngine->variableCount * 6; /* FIXME: index as assert value? */
2283
2284
/* Variable Name data */
2285
FAudio_assert((ptr - start) == variableNameOffset);
2286
pEngine->variableNames = (char**) pEngine->pMalloc(
2287
sizeof(char*) *
2288
pEngine->variableCount
2289
);
2290
for (i = 0; i < pEngine->variableCount; i += 1)
2291
{
2292
memsize = FAudio_strlen((char*) ptr) + 1; /* Dastardly! */
2293
pEngine->variableNames[i] = (char*) pEngine->pMalloc(memsize);
2294
FAudio_memcpy(pEngine->variableNames[i], ptr, memsize);
2295
ptr += memsize;
2296
}
2297
2298
/* Store this pointer in case we're asked to free it */
2299
if (pParams->globalSettingsFlags & FACT_FLAG_MANAGEDATA)
2300
{
2301
pEngine->settings = pParams->pGlobalSettingsBuffer;
2302
}
2303
2304
/* Finally. */
2305
FAudio_assert((ptr - start) == pParams->globalSettingsBufferSize);
2306
return 0;
2307
}
2308
2309
void FACT_INTERNAL_ParseTrackEvents(
2310
uint8_t **ptr,
2311
uint8_t se,
2312
FACTTrack *track,
2313
FAudioMallocFunc pMalloc
2314
) {
2315
uint32_t evtInfo;
2316
uint8_t minWeight, maxWeight, separator;
2317
uint8_t i;
2318
uint16_t j;
2319
2320
track->eventCount = read_u8(ptr);
2321
track->events = (FACTEvent*) pMalloc(
2322
sizeof(FACTEvent) *
2323
track->eventCount
2324
);
2325
FAudio_zero(track->events, sizeof(FACTEvent) * track->eventCount);
2326
for (i = 0; i < track->eventCount; i += 1)
2327
{
2328
evtInfo = read_u32(ptr, se);
2329
track->events[i].randomOffset = read_u16(ptr, se);
2330
2331
track->events[i].type = evtInfo & 0x001F;
2332
track->events[i].timestamp = (evtInfo >> 5) & 0xFFFF;
2333
2334
separator = read_u8(ptr);
2335
FAudio_assert(separator == 0xFF); /* Separator? */
2336
2337
#define EVTTYPE(t) (track->events[i].type == t)
2338
if (EVTTYPE(FACTEVENT_STOP))
2339
{
2340
track->events[i].stop.flags = read_u8(ptr);
2341
}
2342
else if (EVTTYPE(FACTEVENT_PLAYWAVE))
2343
{
2344
/* Basic Wave */
2345
track->events[i].wave.isComplex = 0;
2346
track->events[i].wave.flags = read_u8(ptr);
2347
track->events[i].wave.simple.track = read_u16(ptr, se);
2348
track->events[i].wave.simple.wavebank = read_u8(ptr);
2349
track->events[i].wave.loopCount = read_u8(ptr);
2350
track->events[i].wave.position = read_u16(ptr, se);
2351
track->events[i].wave.angle = read_u16(ptr, se);
2352
2353
/* No Effect Variation */
2354
track->events[i].wave.variationFlags = 0;
2355
}
2356
else if (EVTTYPE(FACTEVENT_PLAYWAVETRACKVARIATION))
2357
{
2358
/* Complex Wave */
2359
track->events[i].wave.isComplex = 1;
2360
track->events[i].wave.flags = read_u8(ptr);
2361
track->events[i].wave.loopCount = read_u8(ptr);
2362
track->events[i].wave.position = read_u16(ptr, se);
2363
track->events[i].wave.angle = read_u16(ptr, se);
2364
2365
/* Track Variation */
2366
evtInfo = read_u32(ptr, se);
2367
track->events[i].wave.complex.trackCount = evtInfo & 0xFFFF;
2368
track->events[i].wave.complex.variation = (evtInfo >> 16) & 0xFFFF;
2369
*ptr += 4; /* Unknown values */
2370
track->events[i].wave.complex.tracks = (uint16_t*) pMalloc(
2371
sizeof(uint16_t) *
2372
track->events[i].wave.complex.trackCount
2373
);
2374
track->events[i].wave.complex.wavebanks = (uint8_t*) pMalloc(
2375
sizeof(uint8_t) *
2376
track->events[i].wave.complex.trackCount
2377
);
2378
track->events[i].wave.complex.weights = (uint8_t*) pMalloc(
2379
sizeof(uint8_t) *
2380
track->events[i].wave.complex.trackCount
2381
);
2382
for (j = 0; j < track->events[i].wave.complex.trackCount; j += 1)
2383
{
2384
track->events[i].wave.complex.tracks[j] = read_u16(ptr, se);
2385
track->events[i].wave.complex.wavebanks[j] = read_u8(ptr);
2386
minWeight = read_u8(ptr);
2387
maxWeight = read_u8(ptr);
2388
track->events[i].wave.complex.weights[j] = (
2389
maxWeight - minWeight
2390
);
2391
}
2392
2393
/* No Effect Variation */
2394
track->events[i].wave.variationFlags = 0;
2395
}
2396
else if (EVTTYPE(FACTEVENT_PLAYWAVEEFFECTVARIATION))
2397
{
2398
/* Basic Wave */
2399
track->events[i].wave.isComplex = 0;
2400
track->events[i].wave.flags = read_u8(ptr);
2401
track->events[i].wave.simple.track = read_u16(ptr, se);
2402
track->events[i].wave.simple.wavebank = read_u8(ptr);
2403
track->events[i].wave.loopCount = read_u8(ptr);
2404
track->events[i].wave.position = read_u16(ptr, se);
2405
track->events[i].wave.angle = read_u16(ptr, se);
2406
2407
/* Effect Variation */
2408
track->events[i].wave.minPitch = read_s16(ptr, se);
2409
track->events[i].wave.maxPitch = read_s16(ptr, se);
2410
track->events[i].wave.minVolume = read_volbyte(ptr);
2411
track->events[i].wave.maxVolume = read_volbyte(ptr);
2412
track->events[i].wave.minFrequency = read_f32(ptr, se);
2413
track->events[i].wave.maxFrequency = read_f32(ptr, se);
2414
track->events[i].wave.minQFactor = read_f32(ptr, se);
2415
track->events[i].wave.maxQFactor = read_f32(ptr, se);
2416
track->events[i].wave.variationFlags = read_u16(ptr, se);
2417
}
2418
else if (EVTTYPE(FACTEVENT_PLAYWAVETRACKEFFECTVARIATION))
2419
{
2420
/* Complex Wave */
2421
track->events[i].wave.isComplex = 1;
2422
track->events[i].wave.flags = read_u8(ptr);
2423
track->events[i].wave.loopCount = read_u8(ptr);
2424
track->events[i].wave.position = read_u16(ptr, se);
2425
track->events[i].wave.angle = read_u16(ptr, se);
2426
2427
/* Effect Variation */
2428
track->events[i].wave.minPitch = read_s16(ptr, se);
2429
track->events[i].wave.maxPitch = read_s16(ptr, se);
2430
track->events[i].wave.minVolume = read_volbyte(ptr);
2431
track->events[i].wave.maxVolume = read_volbyte(ptr);
2432
track->events[i].wave.minFrequency = read_f32(ptr, se);
2433
track->events[i].wave.maxFrequency = read_f32(ptr, se);
2434
track->events[i].wave.minQFactor = read_f32(ptr, se);
2435
track->events[i].wave.maxQFactor = read_f32(ptr, se);
2436
track->events[i].wave.variationFlags = read_u16(ptr, se);
2437
2438
/* Track Variation */
2439
evtInfo = read_u32(ptr, se);
2440
track->events[i].wave.complex.trackCount = evtInfo & 0xFFFF;
2441
track->events[i].wave.complex.variation = (evtInfo >> 16) & 0xFFFF;
2442
*ptr += 4; /* Unknown values */
2443
track->events[i].wave.complex.tracks = (uint16_t*) pMalloc(
2444
sizeof(uint16_t) *
2445
track->events[i].wave.complex.trackCount
2446
);
2447
track->events[i].wave.complex.wavebanks = (uint8_t*) pMalloc(
2448
sizeof(uint8_t) *
2449
track->events[i].wave.complex.trackCount
2450
);
2451
track->events[i].wave.complex.weights = (uint8_t*) pMalloc(
2452
sizeof(uint8_t) *
2453
track->events[i].wave.complex.trackCount
2454
);
2455
for (j = 0; j < track->events[i].wave.complex.trackCount; j += 1)
2456
{
2457
track->events[i].wave.complex.tracks[j] = read_u16(ptr, se);
2458
track->events[i].wave.complex.wavebanks[j] = read_u8(ptr);
2459
minWeight = read_u8(ptr);
2460
maxWeight = read_u8(ptr);
2461
track->events[i].wave.complex.weights[j] = (
2462
maxWeight - minWeight
2463
);
2464
}
2465
}
2466
else if ( EVTTYPE(FACTEVENT_PITCH) ||
2467
EVTTYPE(FACTEVENT_VOLUME) ||
2468
EVTTYPE(FACTEVENT_PITCHREPEATING) ||
2469
EVTTYPE(FACTEVENT_VOLUMEREPEATING) )
2470
{
2471
track->events[i].value.settings = read_u8(ptr);
2472
if (track->events[i].value.settings & 1) /* Ramp */
2473
{
2474
track->events[i].value.repeats = 0;
2475
track->events[i].value.ramp.initialValue = read_f32(ptr, se);
2476
track->events[i].value.ramp.initialSlope = read_f32(ptr, se) * 100;
2477
track->events[i].value.ramp.slopeDelta = read_f32(ptr, se);
2478
track->events[i].value.ramp.duration = read_u16(ptr, se);
2479
}
2480
else /* Equation */
2481
{
2482
track->events[i].value.equation.flags = read_u8(ptr);
2483
2484
/* SetValue, SetRandomValue, anything else? */
2485
FAudio_assert(track->events[i].value.equation.flags & 0x0C);
2486
2487
track->events[i].value.equation.value1 = read_f32(ptr, se);
2488
track->events[i].value.equation.value2 = read_f32(ptr, se);
2489
2490
*ptr += 5; /* Unknown values */
2491
2492
if ( EVTTYPE(FACTEVENT_PITCHREPEATING) ||
2493
EVTTYPE(FACTEVENT_VOLUMEREPEATING) )
2494
{
2495
track->events[i].value.repeats = read_u16(ptr, se);
2496
track->events[i].value.frequency = read_u16(ptr, se);
2497
}
2498
else
2499
{
2500
track->events[i].value.repeats = 0;
2501
}
2502
}
2503
}
2504
else if (EVTTYPE(FACTEVENT_MARKER))
2505
{
2506
track->events[i].marker.marker = read_u32(ptr, se);
2507
track->events[i].marker.repeats = 0;
2508
track->events[i].marker.frequency = 0;
2509
}
2510
else if (EVTTYPE(FACTEVENT_MARKERREPEATING))
2511
{
2512
track->events[i].marker.marker = read_u32(ptr, se);
2513
track->events[i].marker.repeats = read_u16(ptr, se);
2514
track->events[i].marker.frequency = read_u16(ptr, se);
2515
}
2516
else
2517
{
2518
FAudio_assert(0 && "Unknown event type!");
2519
}
2520
#undef EVTTYPE
2521
}
2522
}
2523
2524
uint32_t FACT_INTERNAL_ParseSoundBank(
2525
FACTAudioEngine *pEngine,
2526
const void *pvBuffer,
2527
uint32_t dwSize,
2528
FACTSoundBank **ppSoundBank
2529
) {
2530
FACTSoundBank *sb;
2531
uint16_t contentVersion,
2532
cueSimpleCount,
2533
cueComplexCount,
2534
cueTotalAlign;
2535
int32_t cueSimpleOffset,
2536
cueComplexOffset,
2537
cueNameOffset,
2538
variationOffset,
2539
transitionOffset,
2540
wavebankNameOffset,
2541
cueHashOffset,
2542
cueNameIndexOffset,
2543
soundOffset;
2544
uint32_t entryCountAndFlags;
2545
uint16_t filterData;
2546
uint8_t platform;
2547
size_t memsize;
2548
uint16_t i, j, k, cur, tool;
2549
uint8_t *ptrBookmark;
2550
2551
uint8_t *ptr = (uint8_t*) pvBuffer;
2552
uint8_t *start = ptr;
2553
2554
uint32_t magic = read_u32(&ptr, 0);
2555
uint8_t se = magic == 0x5344424B; /* Swap Endian */
2556
2557
if (magic != 0x4B424453 && magic != 0x5344424B) /* 'SDBK' */
2558
{
2559
return -1; /* TODO: NOT XACT FILE */
2560
}
2561
2562
contentVersion = read_u16(&ptr, se);
2563
if (!FACT_INTERNAL_SupportedContent(contentVersion))
2564
{
2565
return -2;
2566
}
2567
2568
tool = read_u16(&ptr, se); /* Tool version */
2569
if (tool != 43)
2570
{
2571
return -3;
2572
}
2573
2574
/* CRC, unused */
2575
ptr += 2;
2576
2577
/* Last modified, unused */
2578
ptr += 8;
2579
2580
/* Windows == 1, Xbox == 3. 0 is unknown, probably old content */
2581
platform = read_u8(&ptr);
2582
if ( platform != 0 &&
2583
platform != 1 &&
2584
platform != 3 )
2585
{
2586
return -4; /* TODO: WRONG PLATFORM */
2587
}
2588
2589
sb = (FACTSoundBank*) pEngine->pMalloc(sizeof(FACTSoundBank));
2590
sb->parentEngine = pEngine;
2591
sb->cueList = NULL;
2592
sb->notifyOnDestroy = 0;
2593
sb->usercontext = NULL;
2594
2595
cueSimpleCount = read_u16(&ptr, se);
2596
cueComplexCount = read_u16(&ptr, se);
2597
2598
ptr += 2; /* Unknown value */
2599
2600
cueTotalAlign = read_u16(&ptr, se); /* FIXME: Why? */
2601
sb->cueCount = cueSimpleCount + cueComplexCount;
2602
sb->wavebankCount = read_u8(&ptr);
2603
sb->soundCount = read_u16(&ptr, se);
2604
2605
/* Cue name length, unused */
2606
ptr += 2;
2607
2608
ptr += 2; /* Unknown value */
2609
2610
cueSimpleOffset = read_s32(&ptr, se);
2611
cueComplexOffset = read_s32(&ptr, se);
2612
cueNameOffset = read_s32(&ptr, se);
2613
2614
ptr += 4; /* Unknown value */
2615
2616
variationOffset = read_s32(&ptr, se);
2617
transitionOffset = read_s32(&ptr, se);
2618
wavebankNameOffset = read_s32(&ptr, se);
2619
cueHashOffset = read_s32(&ptr, se);
2620
cueNameIndexOffset = read_s32(&ptr, se);
2621
soundOffset = read_s32(&ptr, se);
2622
2623
/* SoundBank Name */
2624
memsize = FAudio_strlen((char*) ptr) + 1; /* Dastardly! */
2625
sb->name = (char*) pEngine->pMalloc(memsize);
2626
FAudio_memcpy(sb->name, ptr, memsize);
2627
ptr += 64;
2628
2629
/* WaveBank Name data */
2630
FAudio_assert((ptr - start) == wavebankNameOffset);
2631
ptr = start + wavebankNameOffset;
2632
sb->wavebankNames = (char**) pEngine->pMalloc(
2633
sizeof(char*) *
2634
sb->wavebankCount
2635
);
2636
for (i = 0; i < sb->wavebankCount; i += 1)
2637
{
2638
memsize = FAudio_strlen((char*) ptr) + 1;
2639
sb->wavebankNames[i] = (char*) pEngine->pMalloc(memsize);
2640
FAudio_memcpy(sb->wavebankNames[i], ptr, memsize);
2641
ptr += 64;
2642
}
2643
2644
/* Sound data */
2645
FAudio_assert((ptr - start) == soundOffset);
2646
sb->sounds = (FACTSound*) pEngine->pMalloc(
2647
sizeof(FACTSound) *
2648
sb->soundCount
2649
);
2650
sb->soundCodes = (uint32_t*) pEngine->pMalloc(
2651
sizeof(uint32_t) *
2652
sb->soundCount
2653
);
2654
for (i = 0; i < sb->soundCount; i += 1)
2655
{
2656
sb->soundCodes[i] = (uint32_t) (ptr - start);
2657
sb->sounds[i].flags = read_u8(&ptr);
2658
sb->sounds[i].category = read_u16(&ptr, se);
2659
sb->sounds[i].volume = read_volbyte(&ptr);
2660
sb->sounds[i].pitch = read_s16(&ptr, se);
2661
sb->sounds[i].priority = read_u8(&ptr);
2662
2663
/* Length of sound entry, unused */
2664
ptr += 2;
2665
2666
/* Simple/Complex Track data */
2667
if (sb->sounds[i].flags & 0x01)
2668
{
2669
sb->sounds[i].trackCount = read_u8(&ptr);
2670
memsize = sizeof(FACTTrack) * sb->sounds[i].trackCount;
2671
sb->sounds[i].tracks = (FACTTrack*) pEngine->pMalloc(memsize);
2672
FAudio_zero(sb->sounds[i].tracks, memsize);
2673
}
2674
else
2675
{
2676
sb->sounds[i].trackCount = 1;
2677
memsize = sizeof(FACTTrack) * sb->sounds[i].trackCount;
2678
sb->sounds[i].tracks = (FACTTrack*) pEngine->pMalloc(memsize);
2679
FAudio_zero(sb->sounds[i].tracks, memsize);
2680
sb->sounds[i].tracks[0].volume = 0.0f;
2681
sb->sounds[i].tracks[0].filter = 0xFF;
2682
sb->sounds[i].tracks[0].eventCount = 1;
2683
sb->sounds[i].tracks[0].events = (FACTEvent*) pEngine->pMalloc(
2684
sizeof(FACTEvent)
2685
);
2686
FAudio_zero(
2687
sb->sounds[i].tracks[0].events,
2688
sizeof(FACTEvent)
2689
);
2690
sb->sounds[i].tracks[0].events[0].type = FACTEVENT_PLAYWAVE;
2691
sb->sounds[i].tracks[0].events[0].wave.position = 0; /* FIXME */
2692
sb->sounds[i].tracks[0].events[0].wave.angle = 0; /* FIXME */
2693
sb->sounds[i].tracks[0].events[0].wave.simple.track = read_u16(&ptr, se);
2694
sb->sounds[i].tracks[0].events[0].wave.simple.wavebank = read_u8(&ptr);
2695
}
2696
2697
/* RPC Code data */
2698
if (sb->sounds[i].flags & 0x0E)
2699
{
2700
const uint16_t rpcDataLength = read_u16(&ptr, se);
2701
ptrBookmark = ptr - 2;
2702
2703
#define COPYRPCBLOCK(loc) \
2704
loc.rpcCodeCount = read_u8(&ptr); \
2705
memsize = sizeof(uint32_t) * loc.rpcCodeCount; \
2706
loc.rpcCodes = (uint32_t*) pEngine->pMalloc(memsize); \
2707
for (k = 0; k < loc.rpcCodeCount; k += 1) \
2708
{ \
2709
loc.rpcCodes[k] = read_u32(&ptr, se); \
2710
} \
2711
2712
/* Sound has attached RPCs */
2713
if (sb->sounds[i].flags & 0x02)
2714
{
2715
COPYRPCBLOCK(sb->sounds[i])
2716
}
2717
else
2718
{
2719
sb->sounds[i].rpcCodeCount = 0;
2720
sb->sounds[i].rpcCodes = NULL;
2721
}
2722
2723
/* Tracks have attached RPCs */
2724
if (sb->sounds[i].flags & 0x04)
2725
{
2726
for (j = 0; j < sb->sounds[i].trackCount; j += 1)
2727
{
2728
COPYRPCBLOCK(sb->sounds[i].tracks[j])
2729
}
2730
}
2731
else
2732
{
2733
for (j = 0; j < sb->sounds[i].trackCount; j += 1)
2734
{
2735
sb->sounds[i].tracks[j].rpcCodeCount = 0;
2736
sb->sounds[i].tracks[j].rpcCodes = NULL;
2737
}
2738
}
2739
2740
#undef COPYRPCBLOCK
2741
2742
/* FIXME: Does 0x08 mean something for RPCs...? */
2743
FAudio_assert((ptr - ptrBookmark) == rpcDataLength);
2744
}
2745
else
2746
{
2747
sb->sounds[i].rpcCodeCount = 0;
2748
sb->sounds[i].rpcCodes = NULL;
2749
for (j = 0; j < sb->sounds[i].trackCount; j += 1)
2750
{
2751
sb->sounds[i].tracks[j].rpcCodeCount = 0;
2752
sb->sounds[i].tracks[j].rpcCodes = NULL;
2753
}
2754
}
2755
2756
/* DSP Preset Code data */
2757
if (sb->sounds[i].flags & 0x10)
2758
{
2759
/* DSP presets length, unused */
2760
ptr += 2;
2761
2762
sb->sounds[i].dspCodeCount = read_u8(&ptr);
2763
memsize = sizeof(uint32_t) * sb->sounds[i].dspCodeCount;
2764
sb->sounds[i].dspCodes = (uint32_t*) pEngine->pMalloc(memsize);
2765
for (j = 0; j < sb->sounds[i].dspCodeCount; j += 1)
2766
{
2767
sb->sounds[i].dspCodes[j] = read_u32(&ptr, se);
2768
}
2769
}
2770
else
2771
{
2772
sb->sounds[i].dspCodeCount = 0;
2773
sb->sounds[i].dspCodes = NULL;
2774
}
2775
2776
/* Track data */
2777
if (sb->sounds[i].flags & 0x01)
2778
{
2779
for (j = 0; j < sb->sounds[i].trackCount; j += 1)
2780
{
2781
sb->sounds[i].tracks[j].volume = read_volbyte(&ptr);
2782
2783
sb->sounds[i].tracks[j].code = read_u32(&ptr, se);
2784
2785
if (contentVersion == FACT_CONTENT_VERSION_3_0)
2786
{
2787
/* 3.0 doesn't have track filter data */
2788
sb->sounds[i].tracks[j].filter = 0xFF;
2789
sb->sounds[i].tracks[j].qfactor = 0;
2790
sb->sounds[i].tracks[j].frequency = 0;
2791
continue;
2792
}
2793
2794
filterData = read_u16(&ptr, se);
2795
if (filterData & 0x0001)
2796
{
2797
sb->sounds[i].tracks[j].filter =
2798
(filterData >> 1) & 0x02;
2799
}
2800
else
2801
{
2802
/* Huh...? */
2803
sb->sounds[i].tracks[j].filter = 0xFF;
2804
}
2805
sb->sounds[i].tracks[j].qfactor = (filterData >> 8) & 0xFF;
2806
sb->sounds[i].tracks[j].frequency = read_u16(&ptr, se);
2807
}
2808
2809
/* All Track events are stored at the end of the block */
2810
for (j = 0; j < sb->sounds[i].trackCount; j += 1)
2811
{
2812
FAudio_assert((ptr - start) == sb->sounds[i].tracks[j].code);
2813
FACT_INTERNAL_ParseTrackEvents(
2814
&ptr,
2815
se,
2816
&sb->sounds[i].tracks[j],
2817
pEngine->pMalloc
2818
);
2819
}
2820
}
2821
}
2822
2823
/* All Cue data */
2824
sb->variationCount = 0;
2825
sb->transitionCount = 0;
2826
sb->cues = (FACTCueData*) pEngine->pMalloc(
2827
sizeof(FACTCueData) *
2828
sb->cueCount
2829
);
2830
cur = 0;
2831
2832
/* Simple Cue data */
2833
FAudio_assert(cueSimpleCount == 0 || (ptr - start) == cueSimpleOffset);
2834
if (cueSimpleCount > 0)
2835
{
2836
ptr = start + cueSimpleOffset;
2837
2838
for (i = 0; i < cueSimpleCount; i += 1, cur += 1)
2839
{
2840
sb->cues[cur].flags = read_u8(&ptr);
2841
sb->cues[cur].sbCode = read_u32(&ptr, se);
2842
sb->cues[cur].transitionOffset = 0;
2843
sb->cues[cur].instanceLimit = 0xFF;
2844
sb->cues[cur].fadeInMS = 0;
2845
sb->cues[cur].fadeOutMS = 0;
2846
sb->cues[cur].maxInstanceBehavior = 0;
2847
sb->cues[cur].instanceCount = 0;
2848
}
2849
}
2850
2851
/* Complex Cue data */
2852
FAudio_assert(cueComplexCount == 0 || (ptr - start) == cueComplexOffset);
2853
if (cueComplexCount > 0)
2854
{
2855
ptr = start + cueComplexOffset;
2856
2857
for (i = 0; i < cueComplexCount; i += 1, cur += 1)
2858
{
2859
sb->cues[cur].flags = read_u8(&ptr);
2860
sb->cues[cur].sbCode = read_u32(&ptr, se);
2861
sb->cues[cur].transitionOffset = read_u32(&ptr, se);
2862
if (sb->cues[cur].transitionOffset == 0xFFFFFFFF)
2863
{
2864
/* FIXME: Why */
2865
sb->cues[cur].transitionOffset = 0;
2866
}
2867
sb->cues[cur].instanceLimit = read_u8(&ptr);
2868
sb->cues[cur].fadeInMS = read_u16(&ptr, se);
2869
sb->cues[cur].fadeOutMS = read_u16(&ptr, se);
2870
sb->cues[cur].maxInstanceBehavior = read_u8(&ptr) >> 3;
2871
sb->cues[cur].instanceCount = 0;
2872
2873
if (!(sb->cues[cur].flags & 0x04))
2874
{
2875
/* FIXME: Is this the only way to get this...? */
2876
sb->variationCount += 1;
2877
}
2878
if (sb->cues[cur].transitionOffset > 0)
2879
{
2880
/* FIXME: Is this the only way to get this...? */
2881
sb->transitionCount += 1;
2882
}
2883
}
2884
}
2885
2886
/* Variation data */
2887
if (sb->variationCount > 0)
2888
{
2889
FAudio_assert((ptr - start) == variationOffset);
2890
ptr = start + variationOffset;
2891
sb->variations = (FACTVariationTable*) pEngine->pMalloc(
2892
sizeof(FACTVariationTable) *
2893
sb->variationCount
2894
);
2895
sb->variationCodes = (uint32_t*) pEngine->pMalloc(
2896
sizeof(uint32_t) *
2897
sb->variationCount
2898
);
2899
}
2900
else
2901
{
2902
sb->variations = NULL;
2903
sb->variationCodes = NULL;
2904
}
2905
for (i = 0; i < sb->variationCount; i += 1)
2906
{
2907
sb->variationCodes[i] = (uint32_t) (ptr - start);
2908
entryCountAndFlags = read_u32(&ptr, se);
2909
sb->variations[i].entryCount = entryCountAndFlags & 0xFFFF;
2910
sb->variations[i].flags = (entryCountAndFlags >> (16 + 3)) & 0x07;
2911
ptr += 2; /* Unknown value */
2912
sb->variations[i].variable = read_s16(&ptr, se);
2913
memsize = sizeof(FACTVariation) * sb->variations[i].entryCount;
2914
sb->variations[i].entries = (FACTVariation*) pEngine->pMalloc(
2915
memsize
2916
);
2917
FAudio_zero(sb->variations[i].entries, memsize);
2918
2919
if (sb->variations[i].flags == 0)
2920
{
2921
/* Wave with byte min/max */
2922
sb->variations[i].isComplex = 0;
2923
for (j = 0; j < sb->variations[i].entryCount; j += 1)
2924
{
2925
sb->variations[i].entries[j].simple.track = read_u16(&ptr, se);
2926
sb->variations[i].entries[j].simple.wavebank = read_u8(&ptr);
2927
sb->variations[i].entries[j].minWeight = read_u8(&ptr) / 255.0f;
2928
sb->variations[i].entries[j].maxWeight = read_u8(&ptr) / 255.0f;
2929
}
2930
}
2931
else if (sb->variations[i].flags == 1)
2932
{
2933
/* Complex with byte min/max */
2934
sb->variations[i].isComplex = 1;
2935
for (j = 0; j < sb->variations[i].entryCount; j += 1)
2936
{
2937
sb->variations[i].entries[j].soundCode = read_u32(&ptr, se);
2938
sb->variations[i].entries[j].minWeight = read_u8(&ptr) / 255.0f;
2939
sb->variations[i].entries[j].maxWeight = read_u8(&ptr) / 255.0f;
2940
}
2941
}
2942
else if (sb->variations[i].flags == 3)
2943
{
2944
/* Complex Interactive Variation with float min/max */
2945
sb->variations[i].isComplex = 1;
2946
for (j = 0; j < sb->variations[i].entryCount; j += 1)
2947
{
2948
sb->variations[i].entries[j].soundCode = read_u32(&ptr, se);
2949
sb->variations[i].entries[j].minWeight = read_f32(&ptr, se);
2950
sb->variations[i].entries[j].maxWeight = read_f32(&ptr, se);
2951
sb->variations[i].entries[j].linger = read_u32(&ptr, se);
2952
}
2953
}
2954
else if (sb->variations[i].flags == 4)
2955
{
2956
/* Compact Wave */
2957
sb->variations[i].isComplex = 0;
2958
for (j = 0; j < sb->variations[i].entryCount; j += 1)
2959
{
2960
sb->variations[i].entries[j].simple.track = read_u16(&ptr, se);
2961
sb->variations[i].entries[j].simple.wavebank = read_u8(&ptr);
2962
sb->variations[i].entries[j].minWeight = 0.0f;
2963
sb->variations[i].entries[j].maxWeight = 1.0f;
2964
}
2965
}
2966
else
2967
{
2968
FAudio_assert(0 && "Unknown variation type!");
2969
}
2970
}
2971
2972
/* Transition data */
2973
if (sb->transitionCount > 0)
2974
{
2975
FAudio_assert((ptr - start) == transitionOffset);
2976
ptr = start + transitionOffset;
2977
sb->transitions = (FACTTransitionTable*) pEngine->pMalloc(
2978
sizeof(FACTTransitionTable) *
2979
sb->transitionCount
2980
);
2981
sb->transitionCodes = (uint32_t*) pEngine->pMalloc(
2982
sizeof(uint32_t) *
2983
sb->transitionCount
2984
);
2985
}
2986
else
2987
{
2988
sb->transitions = NULL;
2989
sb->transitionCodes = NULL;
2990
}
2991
for (i = 0; i < sb->transitionCount; i += 1)
2992
{
2993
sb->transitionCodes[i] = (uint32_t) (ptr - start);
2994
sb->transitions[i].entryCount = read_u32(&ptr, se);
2995
memsize = sizeof(FACTTransition) * sb->transitions[i].entryCount;
2996
sb->transitions[i].entries = (FACTTransition*) pEngine->pMalloc(
2997
memsize
2998
);
2999
FAudio_zero(sb->transitions[i].entries, memsize);
3000
for (j = 0; j < sb->transitions[i].entryCount; j += 1)
3001
{
3002
sb->transitions[i].entries[j].soundCode = read_s32(&ptr, se);
3003
sb->transitions[i].entries[j].srcMarkerMin = read_u32(&ptr, se);
3004
sb->transitions[i].entries[j].srcMarkerMax = read_u32(&ptr, se);
3005
sb->transitions[i].entries[j].dstMarkerMin = read_u32(&ptr, se);
3006
sb->transitions[i].entries[j].dstMarkerMax = read_u32(&ptr, se);
3007
sb->transitions[i].entries[j].fadeIn = read_u16(&ptr, se);
3008
sb->transitions[i].entries[j].fadeOut = read_u16(&ptr, se);
3009
sb->transitions[i].entries[j].flags = read_u16(&ptr, se);
3010
}
3011
}
3012
3013
/* Cue Hash data? No idea what this is... */
3014
if (cueHashOffset != -1)
3015
{
3016
FAudio_assert((ptr - start) == cueHashOffset);
3017
ptr += 2 * cueTotalAlign;
3018
}
3019
3020
/* Cue Name Index data */
3021
if (cueNameIndexOffset != -1)
3022
{
3023
FAudio_assert((ptr - start) == cueNameIndexOffset);
3024
ptr = start + cueNameIndexOffset;
3025
ptr += 6 * sb->cueCount; /* FIXME: index as assert value? */
3026
}
3027
3028
/* Cue Name data */
3029
if (cueNameOffset != -1)
3030
{
3031
FAudio_assert((ptr - start) == cueNameOffset);
3032
ptr = start + cueNameOffset;
3033
sb->cueNames = (char**) pEngine->pMalloc(
3034
sizeof(char*) *
3035
sb->cueCount
3036
);
3037
for (i = 0; i < sb->cueCount; i += 1)
3038
{
3039
memsize = FAudio_strlen((char*) ptr) + 1;
3040
sb->cueNames[i] = (char*) pEngine->pMalloc(memsize);
3041
FAudio_memcpy(sb->cueNames[i], ptr, memsize);
3042
ptr += memsize;
3043
}
3044
}
3045
else
3046
{
3047
sb->cueNames = NULL;
3048
}
3049
3050
/* Add to the Engine SoundBank list */
3051
LinkedList_AddEntry(
3052
&pEngine->sbList,
3053
sb,
3054
pEngine->sbLock,
3055
pEngine->pMalloc
3056
);
3057
3058
/* Finally. */
3059
FAudio_assert((ptr - start) == dwSize);
3060
*ppSoundBank = sb;
3061
return 0;
3062
}
3063
3064
/* This parser is based on the unxwb project, written by Luigi Auriemma.
3065
*
3066
* While the unxwb project was released under the GPL, Luigi has given us
3067
* permission to use the unxwb sources under the zlib license.
3068
*
3069
* The unxwb website can be found here:
3070
*
3071
* http://aluigi.altervista.org/papers.htm#xbox
3072
*/
3073
uint32_t FACT_INTERNAL_ParseWaveBank(
3074
FACTAudioEngine *pEngine,
3075
void* io,
3076
uint32_t offset,
3077
uint32_t packetSize,
3078
FACTReadFileCallback pRead,
3079
FACTGetOverlappedResultCallback pOverlap,
3080
uint16_t isStreaming,
3081
FACTWaveBank **ppWaveBank
3082
) {
3083
uint8_t se = 0; /* Swap Endian */
3084
FACTWaveBank *wb;
3085
size_t memsize;
3086
uint32_t i, j;
3087
FACTWaveBankHeader header;
3088
FACTWaveBankData wbinfo;
3089
uint32_t compactEntry;
3090
int32_t seekTableOffset;
3091
uint32_t fileOffset;
3092
uint8_t *packetBuffer = NULL;
3093
uint32_t packetBufferLen = 0;
3094
uint16_t *pcm;
3095
3096
#define SEEKSET(loc) \
3097
fileOffset = offset + loc;
3098
#define SEEKCUR(loc) \
3099
fileOffset += loc;
3100
#define READ(dst, size) \
3101
FACT_INTERNAL_ReadFile( \
3102
pRead, \
3103
pOverlap, \
3104
io, \
3105
fileOffset, \
3106
packetSize, \
3107
&packetBuffer, \
3108
&packetBufferLen, \
3109
pEngine->pRealloc, \
3110
dst, \
3111
size \
3112
); \
3113
SEEKCUR(size)
3114
3115
#define DOSWAP_16(x) x = FAudio_swap16BE(x)
3116
#define DOSWAP_32(x) x = FAudio_swap32BE(x)
3117
#define DOSWAP_64(x) x = FAudio_swap64BE(x)
3118
3119
fileOffset = offset;
3120
3121
FAudio_zero(&header, sizeof(header));
3122
READ(&header.dwSignature, sizeof(header.dwSignature));
3123
READ(&header.dwVersion, sizeof(header.dwVersion));
3124
if (header.dwVersion > FACT_CONTENT_VERSION_2_4)
3125
{
3126
READ(&header.dwHeaderVersion, sizeof(header.dwHeaderVersion));
3127
}
3128
3129
READ(&header.Segments, sizeof(header.Segments));
3130
3131
se = header.dwSignature == 0x57424E44;
3132
if (se)
3133
{
3134
DOSWAP_32(header.dwSignature);
3135
DOSWAP_32(header.dwVersion);
3136
DOSWAP_32(header.dwHeaderVersion);
3137
for (i = 0; i < FACT_WAVEBANK_SEGIDX_COUNT; i += 1)
3138
{
3139
DOSWAP_32(header.Segments[i].dwOffset);
3140
DOSWAP_32(header.Segments[i].dwLength);
3141
}
3142
}
3143
if (header.dwSignature != 0x444E4257)
3144
{
3145
return -1; /* TODO: NOT XACT FILE */
3146
}
3147
3148
/* We support all Wavebank versions - Restore when SoundBank support them also. */
3149
/*if (!FACT_INTERNAL_SupportedContent(header.dwVersion))
3150
{
3151
return -2;
3152
}
3153
*/
3154
if ( header.dwVersion < FACT_CONTENT_VERSION_2_4 ||
3155
header.dwVersion > FACT_CONTENT_VERSION )
3156
{
3157
return -2;
3158
}
3159
3160
if ( header.dwVersion > FACT_CONTENT_VERSION_2_4 &&
3161
!FACT_INTERNAL_SupportedWBContent(header.dwHeaderVersion) )
3162
{
3163
return -3;
3164
}
3165
3166
wb = (FACTWaveBank*) pEngine->pMalloc(sizeof(FACTWaveBank));
3167
wb->parentEngine = pEngine;
3168
wb->waveList = NULL;
3169
wb->waveLock = FAudio_PlatformCreateMutex();
3170
wb->packetSize = packetSize;
3171
wb->io = io;
3172
wb->notifyOnDestroy = 0;
3173
wb->usercontext = NULL;
3174
3175
/* WaveBank Data */
3176
SEEKSET(header.Segments[FACT_WAVEBANK_SEGIDX_BANKDATA].dwOffset)
3177
READ(&wbinfo, sizeof(wbinfo))
3178
if (se)
3179
{
3180
DOSWAP_32(wbinfo.dwFlags);
3181
DOSWAP_32(wbinfo.dwEntryCount);
3182
DOSWAP_32(wbinfo.dwEntryMetaDataElementSize);
3183
DOSWAP_32(wbinfo.dwEntryNameElementSize);
3184
DOSWAP_32(wbinfo.dwAlignment);
3185
DOSWAP_32(wbinfo.CompactFormat.dwValue);
3186
DOSWAP_64(wbinfo.BuildTime);
3187
}
3188
wb->streaming = (wbinfo.dwFlags & FACT_WAVEBANK_TYPE_STREAMING);
3189
wb->entryCount = wbinfo.dwEntryCount;
3190
memsize = FAudio_strlen(wbinfo.szBankName) + 1;
3191
wb->name = (char*) pEngine->pMalloc(memsize);
3192
FAudio_memcpy(wb->name, wbinfo.szBankName, memsize);
3193
memsize = sizeof(FACTWaveBankEntry) * wbinfo.dwEntryCount;
3194
wb->entries = (FACTWaveBankEntry*) pEngine->pMalloc(memsize);
3195
FAudio_zero(wb->entries, memsize);
3196
memsize = sizeof(uint32_t) * wbinfo.dwEntryCount;
3197
wb->entryRefs = (uint32_t*) pEngine->pMalloc(memsize);
3198
FAudio_zero(wb->entryRefs, memsize);
3199
3200
/* FIXME: How much do we care about this? */
3201
FAudio_assert(wb->streaming == isStreaming);
3202
wb->streaming = isStreaming;
3203
3204
/* WaveBank Entry Metadata */
3205
SEEKSET(header.Segments[FACT_WAVEBANK_SEGIDX_ENTRYMETADATA].dwOffset)
3206
if (wbinfo.dwFlags & FACT_WAVEBANK_FLAGS_COMPACT)
3207
{
3208
for (i = 0; i < wbinfo.dwEntryCount - 1; i += 1)
3209
{
3210
READ(&compactEntry, sizeof(compactEntry))
3211
if (se)
3212
{
3213
DOSWAP_32(compactEntry);
3214
}
3215
wb->entries[i].PlayRegion.dwOffset = (
3216
(compactEntry & ((1 << 21) - 1)) *
3217
wbinfo.dwAlignment
3218
);
3219
wb->entries[i].PlayRegion.dwLength = (
3220
(compactEntry >> 21) & ((1 << 11) - 1)
3221
);
3222
3223
/* TODO: Deviation table */
3224
SEEKCUR(wbinfo.dwEntryMetaDataElementSize)
3225
wb->entries[i].PlayRegion.dwLength = (
3226
(compactEntry & ((1 << 21) - 1)) *
3227
wbinfo.dwAlignment
3228
) - wb->entries[i].PlayRegion.dwOffset;
3229
3230
wb->entries[i].PlayRegion.dwOffset +=
3231
header.Segments[FACT_WAVEBANK_SEGIDX_ENTRYWAVEDATA].dwOffset;
3232
}
3233
3234
READ(&compactEntry, sizeof(compactEntry))
3235
if (se)
3236
{
3237
DOSWAP_32(compactEntry);
3238
}
3239
wb->entries[i].PlayRegion.dwOffset = (
3240
(compactEntry & ((1 << 21) - 1)) *
3241
wbinfo.dwAlignment
3242
);
3243
3244
/* TODO: Deviation table */
3245
SEEKCUR(wbinfo.dwEntryMetaDataElementSize)
3246
wb->entries[i].PlayRegion.dwLength = (
3247
header.Segments[FACT_WAVEBANK_SEGIDX_ENTRYWAVEDATA].dwLength -
3248
wb->entries[i].PlayRegion.dwOffset
3249
);
3250
3251
wb->entries[i].PlayRegion.dwOffset +=
3252
header.Segments[FACT_WAVEBANK_SEGIDX_ENTRYWAVEDATA].dwOffset;
3253
}
3254
else
3255
{
3256
for (i = 0; i < wbinfo.dwEntryCount; i += 1)
3257
{
3258
READ(&wb->entries[i], wbinfo.dwEntryMetaDataElementSize)
3259
if (se)
3260
{
3261
DOSWAP_32(wb->entries[i].dwFlagsAndDuration);
3262
DOSWAP_32(wb->entries[i].Format.dwValue);
3263
DOSWAP_32(wb->entries[i].PlayRegion.dwOffset);
3264
DOSWAP_32(wb->entries[i].PlayRegion.dwLength);
3265
DOSWAP_32(wb->entries[i].LoopRegion.dwStartSample);
3266
DOSWAP_32(wb->entries[i].LoopRegion.dwTotalSamples);
3267
}
3268
wb->entries[i].PlayRegion.dwOffset +=
3269
header.Segments[FACT_WAVEBANK_SEGIDX_ENTRYWAVEDATA].dwOffset;
3270
3271
/* If it's in-memory big-endian PCM, swap! */
3272
if ( se &&
3273
!wb->streaming &&
3274
wb->entries[i].Format.wFormatTag == 0x0 &&
3275
wb->entries[i].Format.wBitsPerSample == 1 )
3276
{
3277
pcm = (uint16_t*) FAudio_memptr(
3278
(FAudioIOStream*) wb->io,
3279
wb->entries[i].PlayRegion.dwOffset
3280
);
3281
for (j = 0; j < wb->entries[i].PlayRegion.dwLength; j += 2, pcm += 1)
3282
{
3283
DOSWAP_16(*pcm);
3284
}
3285
}
3286
}
3287
3288
/* FIXME: This is a bit hacky. */
3289
if (wbinfo.dwEntryMetaDataElementSize < 24)
3290
{
3291
for (i = 0; i < wbinfo.dwEntryCount; i += 1)
3292
{
3293
wb->entries[i].PlayRegion.dwLength =
3294
header.Segments[FACT_WAVEBANK_SEGIDX_ENTRYWAVEDATA].dwLength;
3295
}
3296
}
3297
}
3298
3299
/* WaveBank Seek Tables */
3300
if ( wbinfo.dwFlags & FACT_WAVEBANK_FLAGS_SEEKTABLES &&
3301
header.Segments[FACT_WAVEBANK_SEGIDX_SEEKTABLES].dwLength > 0 )
3302
{
3303
/* The seek table data layout is an absolute disaster! */
3304
wb->seekTables = (FACTSeekTable*) pEngine->pMalloc(
3305
wbinfo.dwEntryCount * sizeof(FACTSeekTable)
3306
);
3307
for (i = 0; i < wbinfo.dwEntryCount; i += 1)
3308
{
3309
/* Get the table offset... */
3310
SEEKSET(
3311
header.Segments[FACT_WAVEBANK_SEGIDX_SEEKTABLES].dwOffset +
3312
i * sizeof(uint32_t)
3313
)
3314
READ(&seekTableOffset, sizeof(int32_t))
3315
if (se)
3316
{
3317
DOSWAP_32(seekTableOffset);
3318
}
3319
3320
/* If the offset is -1, this wave needs no table */
3321
if (seekTableOffset == -1)
3322
{
3323
wb->seekTables[i].entryCount = 0;
3324
wb->seekTables[i].entries = NULL;
3325
continue;
3326
}
3327
3328
/* Go to the table offset, after the offset table... */
3329
SEEKSET(
3330
header.Segments[FACT_WAVEBANK_SEGIDX_SEEKTABLES].dwOffset +
3331
(wbinfo.dwEntryCount * sizeof(uint32_t)) +
3332
seekTableOffset
3333
)
3334
3335
/* Read the table, finally. */
3336
READ(&wb->seekTables[i].entryCount, sizeof(uint32_t))
3337
if (se)
3338
{
3339
DOSWAP_32(wb->seekTables[i].entryCount);
3340
}
3341
wb->seekTables[i].entries = (uint32_t*) pEngine->pMalloc(
3342
wb->seekTables[i].entryCount * sizeof(uint32_t)
3343
);
3344
READ(
3345
wb->seekTables[i].entries,
3346
wb->seekTables[i].entryCount * sizeof(uint32_t)
3347
)
3348
if (se)
3349
{
3350
for (j = 0; j < wb->seekTables[i].entryCount; j += 1)
3351
{
3352
DOSWAP_32(wb->seekTables[i].entries[j]);
3353
}
3354
}
3355
}
3356
}
3357
else
3358
{
3359
wb->seekTables = NULL;
3360
}
3361
3362
/* WaveBank Entry Names */
3363
if (wbinfo.dwFlags & FACT_WAVEBANK_FLAGS_ENTRYNAMES)
3364
{
3365
SEEKSET(header.Segments[FACT_WAVEBANK_SEGIDX_ENTRYNAMES].dwOffset)
3366
wb->waveBankNames = (char*) pEngine->pMalloc(64 * wbinfo.dwEntryCount);
3367
READ(wb->waveBankNames, 64 * wbinfo.dwEntryCount);
3368
}
3369
else
3370
{
3371
wb->waveBankNames = NULL;
3372
}
3373
3374
/* Add to the Engine WaveBank list */
3375
LinkedList_AddEntry(
3376
&pEngine->wbList,
3377
wb,
3378
pEngine->wbLock,
3379
pEngine->pMalloc
3380
);
3381
3382
/* Finally. */
3383
wb->packetBuffer = packetBuffer;
3384
wb->packetBufferLen = packetBufferLen;
3385
*ppWaveBank = wb;
3386
return 0;
3387
}
3388
3389
/* vim: set noexpandtab shiftwidth=8 tabstop=8: */
3390
3391