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