Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Rubberduckycooly
GitHub Repository: Rubberduckycooly/RSDKv5-Decompilation
Path: blob/master/RSDKv5/RSDK/Audio/Audio.cpp
1163 views
1
#include "RSDK/Core/RetroEngine.hpp"
2
3
using namespace RSDK;
4
5
#if RETRO_REV0U
6
#include "Legacy/AudioLegacy.cpp"
7
#endif
8
9
#define STB_VORBIS_NO_PUSHDATA_API
10
#define STB_VORBIS_NO_STDIO
11
#define STB_VORBIS_NO_INTEGER_CONVERSION
12
#include "stb_vorbis/stb_vorbis.c"
13
14
stb_vorbis *vorbisInfo = NULL;
15
stb_vorbis_alloc vorbisAlloc;
16
17
SFXInfo RSDK::sfxList[SFX_COUNT];
18
ChannelInfo RSDK::channels[CHANNEL_COUNT];
19
20
char streamFilePath[0x40];
21
uint8 *streamBuffer = NULL;
22
int32 streamBufferSize = 0;
23
uint32 streamStartPos = 0;
24
int32 streamLoopPoint = 0;
25
26
#define LINEAR_INTERPOLATION_LOOKUP_DIVISOR 0x40 // Determines the 'resolution' of the lookup table.
27
#define LINEAR_INTERPOLATION_LOOKUP_LENGTH (TO_FIXED(1) / LINEAR_INTERPOLATION_LOOKUP_DIVISOR)
28
29
float linearInterpolationLookup[LINEAR_INTERPOLATION_LOOKUP_LENGTH];
30
31
#if RETRO_AUDIODEVICE_XAUDIO
32
#include "XAudio/XAudioDevice.cpp"
33
#elif RETRO_AUDIODEVICE_SDL2
34
#include "SDL2/SDL2AudioDevice.cpp"
35
#elif RETRO_AUDIODEVICE_PORT
36
#include "PortAudio/PortAudioDevice.cpp"
37
#elif RETRO_AUDIODEVICE_MINI
38
#include "MiniAudio/MiniAudioDevice.cpp"
39
#elif RETRO_AUDIODEVICE_OBOE
40
#include "Oboe/OboeAudioDevice.cpp"
41
#endif
42
43
uint8 AudioDeviceBase::initializedAudioChannels = false;
44
uint8 AudioDeviceBase::audioState = 0;
45
uint8 AudioDeviceBase::audioFocus = 0;
46
47
void AudioDeviceBase::Release()
48
{
49
// This is missing, meaning that the garbage collector will never reclaim stb_vorbis's buffer.
50
#if !RETRO_USE_ORIGINAL_CODE
51
stb_vorbis_close(vorbisInfo);
52
vorbisInfo = NULL;
53
#endif
54
}
55
56
void AudioDeviceBase::ProcessAudioMixing(void *stream, int32 length)
57
{
58
SAMPLE_FORMAT *streamF = (SAMPLE_FORMAT *)stream;
59
SAMPLE_FORMAT *streamEndF = ((SAMPLE_FORMAT *)stream) + length;
60
61
memset(stream, 0, length * sizeof(SAMPLE_FORMAT));
62
63
for (int32 c = 0; c < CHANNEL_COUNT; ++c) {
64
ChannelInfo *channel = &channels[c];
65
66
switch (channel->state) {
67
default:
68
case CHANNEL_IDLE: break;
69
70
case CHANNEL_SFX: {
71
SAMPLE_FORMAT *sfxBuffer = &channel->samplePtr[channel->bufferPos];
72
73
float volL = channel->volume, volR = channel->volume;
74
if (channel->pan < 0.0f)
75
volR = (1.0f + channel->pan) * channel->volume;
76
else
77
volL = (1.0f - channel->pan) * channel->volume;
78
79
float panL = volL * engine.soundFXVolume;
80
float panR = volR * engine.soundFXVolume;
81
82
uint32 speedPercent = 0;
83
SAMPLE_FORMAT *curStreamF = streamF;
84
while (curStreamF < streamEndF && streamF < streamEndF) {
85
// Perform linear interpolation.
86
SAMPLE_FORMAT sample;
87
#if !RETRO_USE_ORIGINAL_CODE
88
if (!sfxBuffer) // PROTECTION FOR v5U (and other mysterious crashes 👻)
89
sample = 0;
90
else
91
#endif
92
sample = (sfxBuffer[1] - sfxBuffer[0]) * linearInterpolationLookup[speedPercent / LINEAR_INTERPOLATION_LOOKUP_DIVISOR]
93
+ sfxBuffer[0];
94
95
speedPercent += channel->speed;
96
sfxBuffer += FROM_FIXED(speedPercent);
97
channel->bufferPos += FROM_FIXED(speedPercent);
98
speedPercent %= TO_FIXED(1);
99
100
curStreamF[0] += sample * panL;
101
curStreamF[1] += sample * panR;
102
curStreamF += 2;
103
104
if (channel->bufferPos >= channel->sampleLength) {
105
if (channel->loop == (uint32)-1) {
106
channel->state = CHANNEL_IDLE;
107
channel->soundID = -1;
108
break;
109
}
110
else {
111
channel->bufferPos -= (uint32)channel->sampleLength;
112
channel->bufferPos += channel->loop;
113
114
sfxBuffer = &channel->samplePtr[channel->bufferPos];
115
}
116
}
117
}
118
119
break;
120
}
121
122
case CHANNEL_STREAM: {
123
SAMPLE_FORMAT *streamBuffer = &channel->samplePtr[channel->bufferPos];
124
125
float volL = channel->volume, volR = channel->volume;
126
if (channel->pan < 0.0f)
127
volR = (1.0f + channel->pan) * channel->volume;
128
else
129
volL = (1.0f - channel->pan) * channel->volume;
130
131
float panL = volL * engine.streamVolume;
132
float panR = volR * engine.streamVolume;
133
134
uint32 speedPercent = 0;
135
SAMPLE_FORMAT *curStreamF = streamF;
136
while (curStreamF < streamEndF && streamF < streamEndF) {
137
speedPercent += channel->speed;
138
int32 next = FROM_FIXED(speedPercent);
139
speedPercent %= TO_FIXED(1);
140
141
curStreamF[0] += streamBuffer[0] * panL;
142
curStreamF[1] += streamBuffer[1] * panR;
143
curStreamF += 2;
144
145
streamBuffer += next * 2;
146
channel->bufferPos += next * 2;
147
148
if (channel->bufferPos >= channel->sampleLength) {
149
channel->bufferPos -= (uint32)channel->sampleLength;
150
151
streamBuffer = &channel->samplePtr[channel->bufferPos];
152
153
UpdateStreamBuffer(channel);
154
}
155
}
156
break;
157
}
158
159
case CHANNEL_LOADING_STREAM: break;
160
}
161
}
162
}
163
164
void AudioDeviceBase::InitAudioChannels()
165
{
166
for (int32 i = 0; i < CHANNEL_COUNT; ++i) {
167
channels[i].soundID = -1;
168
channels[i].state = CHANNEL_IDLE;
169
}
170
171
// Compute a lookup table of floating-point linear interpolation delta scales,
172
// to speed-up the process of converting from fixed-point to floating-point.
173
for (int32 i = 0; i < LINEAR_INTERPOLATION_LOOKUP_LENGTH; ++i) linearInterpolationLookup[i] = i / (float)LINEAR_INTERPOLATION_LOOKUP_LENGTH;
174
175
GEN_HASH_MD5("Stream Channel 0", sfxList[SFX_COUNT - 1].hash);
176
sfxList[SFX_COUNT - 1].scope = SCOPE_GLOBAL;
177
sfxList[SFX_COUNT - 1].maxConcurrentPlays = 1;
178
sfxList[SFX_COUNT - 1].length = MIX_BUFFER_SIZE;
179
AllocateStorage((void **)&sfxList[SFX_COUNT - 1].buffer, MIX_BUFFER_SIZE * sizeof(SAMPLE_FORMAT), DATASET_MUS, false);
180
181
initializedAudioChannels = true;
182
}
183
184
void RSDK::UpdateStreamBuffer(ChannelInfo *channel)
185
{
186
int32 bufferRemaining = MIX_BUFFER_SIZE;
187
float *buffer = channel->samplePtr;
188
189
for (int32 s = 0; s < MIX_BUFFER_SIZE;) {
190
int32 samples = stb_vorbis_get_samples_float_interleaved(vorbisInfo, 2, buffer, bufferRemaining) * 2;
191
if (!samples) {
192
if (channel->loop == 1 && stb_vorbis_seek_frame(vorbisInfo, streamLoopPoint)) {
193
// we're looping & the seek was successful, get more samples
194
}
195
else {
196
channel->state = CHANNEL_IDLE;
197
channel->soundID = -1;
198
memset(buffer, 0, sizeof(float) * bufferRemaining);
199
200
break;
201
}
202
}
203
204
s += samples;
205
buffer += samples;
206
bufferRemaining = MIX_BUFFER_SIZE - s;
207
}
208
209
for (int32 i = 0; i < MIX_BUFFER_SIZE; ++i) channel->samplePtr[i] *= 0.5f;
210
}
211
212
void RSDK::LoadStream(ChannelInfo *channel)
213
{
214
if (channel->state != CHANNEL_LOADING_STREAM)
215
return;
216
217
stb_vorbis_close(vorbisInfo);
218
219
FileInfo info;
220
InitFileInfo(&info);
221
222
if (LoadFile(&info, streamFilePath, FMODE_RB)) {
223
streamBufferSize = info.fileSize;
224
streamBuffer = NULL;
225
AllocateStorage((void **)&streamBuffer, info.fileSize, DATASET_MUS, false);
226
ReadBytes(&info, streamBuffer, streamBufferSize);
227
CloseFile(&info);
228
229
if (streamBufferSize > 0) {
230
vorbisAlloc.alloc_buffer_length_in_bytes = 512 * 1024; // 512KiB
231
AllocateStorage((void **)&vorbisAlloc.alloc_buffer, 512 * 1024, DATASET_MUS, false);
232
233
vorbisInfo = stb_vorbis_open_memory(streamBuffer, streamBufferSize, NULL, &vorbisAlloc);
234
if (vorbisInfo) {
235
if (streamStartPos)
236
stb_vorbis_seek(vorbisInfo, streamStartPos);
237
UpdateStreamBuffer(channel);
238
239
channel->state = CHANNEL_STREAM;
240
}
241
}
242
}
243
244
if (channel->state == CHANNEL_LOADING_STREAM)
245
channel->state = CHANNEL_IDLE;
246
}
247
248
int32 RSDK::PlayStream(const char *filename, uint32 slot, uint32 startPos, uint32 loopPoint, bool32 loadASync)
249
{
250
if (!engine.streamsEnabled)
251
return -1;
252
253
if (slot >= CHANNEL_COUNT) {
254
for (int32 c = 0; c < CHANNEL_COUNT && slot >= CHANNEL_COUNT; ++c) {
255
if (channels[c].soundID == -1 && channels[c].state != CHANNEL_LOADING_STREAM) {
256
slot = c;
257
}
258
}
259
260
// as a last resort, run through all channels
261
// pick the channel closest to being finished
262
if (slot >= CHANNEL_COUNT) {
263
uint32 len = 0xFFFFFFFF;
264
for (int32 c = 0; c < CHANNEL_COUNT; ++c) {
265
if (channels[c].sampleLength < len && channels[c].state != CHANNEL_LOADING_STREAM) {
266
slot = c;
267
len = (uint32)channels[c].sampleLength;
268
}
269
}
270
}
271
}
272
273
if (slot >= CHANNEL_COUNT)
274
return -1;
275
276
ChannelInfo *channel = &channels[slot];
277
278
LockAudioDevice();
279
280
channel->soundID = 0xFF;
281
channel->loop = loopPoint != 0;
282
channel->priority = 0xFF;
283
channel->state = CHANNEL_LOADING_STREAM;
284
channel->pan = 0.0f;
285
channel->volume = 1.0f;
286
channel->sampleLength = sfxList[SFX_COUNT - 1].length;
287
channel->samplePtr = sfxList[SFX_COUNT - 1].buffer;
288
channel->bufferPos = 0;
289
channel->speed = TO_FIXED(1);
290
291
sprintf_s(streamFilePath, sizeof(streamFilePath), "Data/Music/%s", filename);
292
streamStartPos = startPos;
293
streamLoopPoint = loopPoint;
294
295
AudioDevice::HandleStreamLoad(channel, loadASync);
296
297
UnlockAudioDevice();
298
299
return slot;
300
}
301
302
#define WAV_SIG_HEADER (0x46464952) // RIFF
303
#define WAV_SIG_DATA (0x61746164) // data
304
305
void RSDK::LoadSfxToSlot(char *filename, uint8 slot, uint8 plays, uint8 scope)
306
{
307
FileInfo info;
308
InitFileInfo(&info);
309
310
char fullFilePath[0x80];
311
sprintf_s(fullFilePath, sizeof(fullFilePath), "Data/SoundFX/%s", filename);
312
313
RETRO_HASH_MD5(hash);
314
GEN_HASH_MD5(filename, hash);
315
316
if (LoadFile(&info, fullFilePath, FMODE_RB)) {
317
HASH_COPY_MD5(sfxList[slot].hash, hash);
318
sfxList[slot].scope = scope;
319
sfxList[slot].maxConcurrentPlays = plays;
320
321
uint8 type = fullFilePath[strlen(fullFilePath) - 1];
322
if (type == 'v' || type == 'V') { // A very loose way of checking that we're trying to load a '.wav' file.
323
uint32 signature = ReadInt32(&info, false);
324
325
if (signature == WAV_SIG_HEADER) {
326
ReadInt32(&info, false); // chunk size
327
ReadInt32(&info, false); // WAVE
328
ReadInt32(&info, false); // FMT
329
#if !RETRO_USE_ORIGINAL_CODE
330
int32 chunkSize = ReadInt32(&info, false); // chunk size
331
#else
332
ReadInt32(&info, false); // chunk size
333
#endif
334
ReadInt16(&info); // audio format
335
ReadInt16(&info); // channels
336
ReadInt32(&info, false); // sample rate
337
ReadInt32(&info, false); // bytes per sec
338
ReadInt16(&info); // block align
339
ReadInt16(&info); // format
340
341
Seek_Set(&info, 34);
342
uint16 sampleBits = ReadInt16(&info);
343
344
#if !RETRO_USE_ORIGINAL_CODE
345
// Original code added to help fix some issues
346
Seek_Set(&info, 20 + chunkSize);
347
#endif
348
349
// Find the data header
350
int32 loop = 0;
351
while (true) {
352
signature = ReadInt32(&info, false);
353
if (signature == WAV_SIG_DATA)
354
break;
355
356
loop += 4;
357
if (loop >= 0x40) {
358
if (loop != 0x100) {
359
CloseFile(&info);
360
// There's a bug here: `sfxList[id].scope` is not reset to `SCOPE_NONE`,
361
// meaning that the game will consider the SFX valid and allow it to be played.
362
// This can cause a crash because the SFX is incomplete.
363
#if !RETRO_USE_ORIGINAL_CODE
364
PrintLog(PRINT_ERROR, "Unable to read sfx: %s", filename);
365
#endif
366
return;
367
}
368
else {
369
break;
370
}
371
}
372
}
373
374
uint32 length = ReadInt32(&info, false);
375
if (sampleBits == 16)
376
length /= 2;
377
378
AllocateStorage((void **)&sfxList[slot].buffer, sizeof(float) * length, DATASET_SFX, false);
379
sfxList[slot].length = length;
380
381
// Convert the sample data to F32 format
382
float *buffer = (float *)sfxList[slot].buffer;
383
if (sampleBits == 8) {
384
// 8-bit sample. Convert from U8 to S8, and then from S8 to F32.
385
for (int32 s = 0; s < length; ++s) {
386
int32 sample = ReadInt8(&info);
387
*buffer++ = (sample - 0x80) / (float)0x80;
388
}
389
}
390
else {
391
// 16-bit sample. Convert from S16 to F32.
392
for (int32 s = 0; s < length; ++s) {
393
// For some reason, the game performs sign-extension manually here.
394
// Note that this is different from the 8-bit format's unsigned-to-signed conversion.
395
int32 sample = (uint16)ReadInt16(&info);
396
397
if (sample > 0x7FFF)
398
sample = (sample & 0x7FFF) - 0x8000;
399
400
*buffer++ = (sample / (float)0x8000) * 0.75f;
401
}
402
}
403
}
404
#if !RETRO_USE_ORIGINAL_CODE
405
else {
406
PrintLog(PRINT_ERROR, "Invalid header in sfx: %s", filename);
407
}
408
#endif
409
}
410
#if !RETRO_USE_ORIGINAL_CODE
411
else {
412
// what the
413
PrintLog(PRINT_ERROR, "Could not find header in sfx: %s", filename);
414
}
415
#endif
416
}
417
#if !RETRO_USE_ORIGINAL_CODE
418
else {
419
PrintLog(PRINT_ERROR, "Unable to open sfx: %s", filename);
420
}
421
#endif
422
423
CloseFile(&info);
424
}
425
426
void RSDK::LoadSfx(char *filename, uint8 plays, uint8 scope)
427
{
428
// Find an empty sound slot.
429
uint16 id = -1;
430
for (uint32 i = 0; i < SFX_COUNT; ++i) {
431
if (sfxList[i].scope == SCOPE_NONE) {
432
id = i;
433
break;
434
}
435
}
436
437
if (id != (uint16)-1)
438
LoadSfxToSlot(filename, id, plays, scope);
439
}
440
441
int32 RSDK::PlaySfx(uint16 sfx, uint32 loopPoint, uint32 priority)
442
{
443
if (sfx >= SFX_COUNT || !sfxList[sfx].scope)
444
return -1;
445
446
uint8 count = 0;
447
for (int32 c = 0; c < CHANNEL_COUNT; ++c) {
448
if (channels[c].soundID == sfx)
449
++count;
450
}
451
452
int8 slot = -1;
453
// if we've hit the max, replace the oldest one
454
if (count >= sfxList[sfx].maxConcurrentPlays) {
455
int32 highestStackID = 0;
456
for (int32 c = 0; c < CHANNEL_COUNT; ++c) {
457
int32 stackID = sfxList[sfx].playCount - channels[c].playIndex;
458
if (stackID > highestStackID && channels[c].soundID == sfx) {
459
slot = c;
460
highestStackID = stackID;
461
}
462
}
463
}
464
465
// if we don't have a slot yet, try to pick any channel that's not currently playing
466
for (int32 c = 0; c < CHANNEL_COUNT && slot < 0; ++c) {
467
if (channels[c].soundID == -1 && channels[c].state != CHANNEL_LOADING_STREAM) {
468
slot = c;
469
}
470
}
471
472
// as a last resort, run through all channels
473
// pick the channel closest to being finished AND with lower priority
474
if (slot < 0) {
475
uint32 len = 0xFFFFFFFF;
476
for (int32 c = 0; c < CHANNEL_COUNT; ++c) {
477
if (channels[c].sampleLength < len && priority > channels[c].priority && channels[c].state != CHANNEL_LOADING_STREAM) {
478
slot = c;
479
len = (uint32)channels[c].sampleLength;
480
}
481
}
482
}
483
484
if (slot == -1)
485
return -1;
486
487
LockAudioDevice();
488
489
channels[slot].state = CHANNEL_SFX;
490
channels[slot].bufferPos = 0;
491
channels[slot].samplePtr = sfxList[sfx].buffer;
492
channels[slot].sampleLength = sfxList[sfx].length;
493
channels[slot].volume = 1.0f;
494
channels[slot].pan = 0.0f;
495
channels[slot].speed = TO_FIXED(1);
496
channels[slot].soundID = sfx;
497
if (loopPoint >= 2)
498
channels[slot].loop = loopPoint;
499
else
500
channels[slot].loop = loopPoint - 1;
501
channels[slot].priority = priority;
502
channels[slot].playIndex = sfxList[sfx].playCount++;
503
504
UnlockAudioDevice();
505
506
return slot;
507
}
508
509
void RSDK::SetChannelAttributes(uint8 channel, float volume, float panning, float speed)
510
{
511
if (channel < CHANNEL_COUNT) {
512
volume = fminf(4.0f, volume);
513
volume = fmaxf(0.0f, volume);
514
channels[channel].volume = volume;
515
516
panning = fminf(1.0f, panning);
517
panning = fmaxf(-1.0f, panning);
518
channels[channel].pan = panning;
519
520
if (speed > 0.0f)
521
channels[channel].speed = (int32)(speed * TO_FIXED(1));
522
else if (speed == 1.0f)
523
channels[channel].speed = TO_FIXED(1);
524
}
525
}
526
527
uint32 RSDK::GetChannelPos(uint32 channel)
528
{
529
if (channel >= CHANNEL_COUNT)
530
return 0;
531
532
if (channels[channel].state == CHANNEL_SFX)
533
return channels[channel].bufferPos;
534
535
if (channels[channel].state == CHANNEL_STREAM) {
536
if (!vorbisInfo->current_loc_valid || vorbisInfo->current_loc < 0)
537
return 0;
538
539
return vorbisInfo->current_loc;
540
}
541
542
return 0;
543
}
544
545
double RSDK::GetVideoStreamPos()
546
{
547
if (channels[0].state == CHANNEL_STREAM && AudioDevice::audioState && AudioDevice::initializedAudioChannels && vorbisInfo->current_loc_valid) {
548
return vorbisInfo->current_loc / (double)AUDIO_FREQUENCY;
549
}
550
551
return -1.0;
552
}
553
554
void RSDK::ClearStageSfx()
555
{
556
LockAudioDevice();
557
558
for (int32 c = 0; c < CHANNEL_COUNT; ++c) {
559
if (channels[c].state == CHANNEL_SFX || channels[c].state == (CHANNEL_SFX | CHANNEL_PAUSED)) {
560
channels[c].soundID = -1;
561
channels[c].state = CHANNEL_IDLE;
562
}
563
}
564
565
// Unload stage SFX
566
for (int32 s = 0; s < SFX_COUNT; ++s) {
567
if (sfxList[s].scope >= SCOPE_STAGE) {
568
MEM_ZERO(sfxList[s]);
569
sfxList[s].scope = SCOPE_NONE;
570
}
571
}
572
573
UnlockAudioDevice();
574
}
575
576
#if RETRO_USE_MOD_LOADER
577
void RSDK::ClearGlobalSfx()
578
{
579
LockAudioDevice();
580
581
for (int32 c = 0; c < CHANNEL_COUNT; ++c) {
582
if (channels[c].state == CHANNEL_SFX || channels[c].state == (CHANNEL_SFX | CHANNEL_PAUSED)) {
583
channels[c].soundID = -1;
584
channels[c].state = CHANNEL_IDLE;
585
}
586
}
587
588
// Unload global SFX
589
for (int32 s = 0; s < SFX_COUNT; ++s) {
590
// clear global sfx (do NOT clear the stream channel 0 slot)
591
if (sfxList[s].scope == SCOPE_GLOBAL && s != SFX_COUNT - 1) {
592
MEM_ZERO(sfxList[s]);
593
sfxList[s].scope = SCOPE_NONE;
594
}
595
}
596
597
UnlockAudioDevice();
598
}
599
#endif
600
601