Audio Works (#180)

* initial audio work

* Implements caching and fixes a ton of issues with audio

* Uses correct memory sizes in mixer.c

* Resets mixer values

* Actually correct dmem buff values in mixer.c

* Remove breakpoints

* Fix sequences not playing

* The forbidden type.

* Forbidden TYPES?!

* Thanks Louis

* Thanks Louis Part 2

* Fix garbled audio

* Fixed ADSR bugs

* Fixes ASAN crash in loading samples.

This code is causing the game to attempt to read sample data beyond the actual sample data.

* Comments out the sample clamping since we aren't affecting the rest of the calculations in the function.

* Fixes crashing while loading audio samples.

Additionally, lowers the log level for audio commands.

* Textbox SFX UB Fix

* Decreases priority of more debug messages

* Fixed a couple uintptr_t issues

* Adds context to Jack's hack of shortcutting later loading sequences.

* Audio corruption fix

* Few uintptr_t fixes

* Fix build on linux

* Fix build on mac

* call audio exit

* fix sfx in dialog

* unstub more audio funcs

---------

Co-authored-by: Random06457 <28494085+Random06457@users.noreply.github.com>
Co-authored-by: Nicholas Estelami <NEstelami@users.noreply.github.com>
Co-authored-by: louis <35883445+louist103@users.noreply.github.com>
Co-authored-by: Adam Bird <archez39@me.com>
This commit is contained in:
Kenix3 2024-04-14 16:36:58 -04:00 committed by Garrett Cox
parent 081577ae65
commit 912d46761b
37 changed files with 4715 additions and 719 deletions

View File

@ -48,6 +48,10 @@ RUN git clone https://github.com/libsdl-org/SDL_net.git -b SDL2 && \
cmake --build SDL_net/build --config Release --parallel && \
cmake --install SDL_net/build --config Release
RUN git clone https://github.com/libsdl-org/SDL.git -b SDL2 && \
cmake -B SDL/build -S SDL -DCMAKE_BUILD_TYPE=Release && \
cmake --build SDL/build --config Release --parallel && \
cmake --install SDL/build --config Release
RUN touch /root/.Xauthority && \
xauth add $MY_XAUTH_COOKIE

View File

@ -1,4 +1,4 @@
#include "BenPort.h"
#include "BenPort.h"
#include <iostream>
#include <algorithm>
#include <filesystem>
@ -267,6 +267,84 @@ extern "C" int AudioPlayer_GetDesiredBuffered(void);
extern "C" void ResourceMgr_LoadDirectory(const char* resName);
std::unordered_map<std::string, ExtensionEntry> ExtensionCache;
static struct {
std::thread thread;
std::condition_variable cv_to_thread, cv_from_thread;
std::mutex mutex;
bool running;
bool processing;
} audio;
void OTRAudio_Thread() {
while (audio.running) {
{
std::unique_lock<std::mutex> Lock(audio.mutex);
while (!audio.processing && audio.running) {
audio.cv_to_thread.wait(Lock);
}
if (!audio.running) {
break;
}
}
std::unique_lock<std::mutex> Lock(audio.mutex);
//AudioMgr_ThreadEntry(&gAudioMgr);
// 528 and 544 relate to 60 fps at 32 kHz 32000/60 = 533.333..
// in an ideal world, one third of the calls should use num_samples=544 and two thirds num_samples=528
//#define SAMPLES_HIGH 560
//#define SAMPLES_LOW 528
// PAL values
//#define SAMPLES_HIGH 656
//#define SAMPLES_LOW 624
// 44KHZ values
#define SAMPLES_HIGH 752
#define SAMPLES_LOW 720
#define AUDIO_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1 )
#define NUM_AUDIO_CHANNELS 2
int samples_left = AudioPlayer_Buffered();
u32 num_audio_samples = samples_left < AudioPlayer_GetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW;
// 3 is the maximum authentic frame divisor.
s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3];
for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) {
AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), num_audio_samples);
}
AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE));
audio.processing = false;
audio.cv_from_thread.notify_one();
}
}
// C->C++ Bridge
extern "C" void OTRAudio_Init()
{
// Precache all our samples, sequences, etc...
ResourceMgr_LoadDirectory("audio");
if (!audio.running) {
audio.running = true;
audio.thread = std::thread(OTRAudio_Thread);
}
}
extern "C" void OTRAudio_Exit() {
// Tell the audio thread to stop
{
std::unique_lock<std::mutex> Lock(audio.mutex);
audio.running = false;
}
audio.cv_to_thread.notify_all();
// Wait until the audio thread quit
audio.thread.join();
}
extern "C" void OTRExtScanner() {
auto lst = *LUS::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->ListFiles("*").get();
@ -321,6 +399,7 @@ extern "C" void InitOTR() {
clearMtx = (uintptr_t)&gMtxClear;
//OTRMessage_Init();
OTRAudio_Init();
//OTRExtScanner();
time_t now = time(NULL);
tm* tm_now = localtime(&now);
@ -351,6 +430,7 @@ extern "C" void SaveManager_ThreadPoolWait() {
extern "C" void DeinitOTR() {
SaveManager_ThreadPoolWait();
OTRAudio_Exit();
#ifdef ENABLE_CROWD_CONTROL
CrowdControl::Instance->Disable();
CrowdControl::Instance->Shutdown();
@ -509,57 +589,12 @@ void RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>
// C->C++ Bridge
extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
#if 0
if (!audio.initialized) {
audio.initialized = true;
std::thread([]() {
for (;;) {
{
std::unique_lock<std::mutex> Lock(audio.mutex);
while (!audio.processing) {
audio.cv_to_thread.wait(Lock);
}
}
std::unique_lock<std::mutex> Lock(audio.mutex);
// AudioMgr_ThreadEntry(&gAudioMgr);
// 528 and 544 relate to 60 fps at 32 kHz 32000/60 = 533.333..
// in an ideal world, one third of the calls should use num_samples=544 and two thirds num_samples=528
#define SAMPLES_HIGH 560
#define SAMPLES_LOW 528
// PAL values
//#define SAMPLES_HIGH 656
//#define SAMPLES_LOW 624
#define AUDIO_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1)
#define NUM_AUDIO_CHANNELS 2
int samples_left = AudioPlayer_Buffered();
u32 num_audio_samples = samples_left < AudioPlayer_GetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW;
// printf("Audio samples: %d %u\n", samples_left, num_audio_samples);
// 3 is the maximum authentic frame divisor.
s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3];
for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) {
AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS),
num_audio_samples);
}
// for (uint32_t i = 0; i < 2 * num_audio_samples; i++) {
// audio_buffer[i] = Rand_Next() & 0xFF;
//}
// printf("Audio samples before submitting: %d\n", audio_api->buffered());
AudioPlayer_Play((u8*)audio_buffer,
num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE));
audio.processing = false;
audio.cv_from_thread.notify_one();
}
}).detach();
}
{
std::unique_lock<std::mutex> Lock(audio.mutex);
audio.processing = true;
}
audio.cv_to_thread.notify_one();
#endif
audio.cv_to_thread.notify_one();
std::vector<std::unordered_map<Mtx*, MtxF>> mtx_replacements;
int target_fps = CVarGetInteger("gInterpolationFPS", 20);
static int last_fps;
@ -607,11 +642,17 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
last_fps = fps;
last_update_rate = R_UPDATE_RATE;
//{
// std::unique_lock<std::mutex> Lock(audio.mutex);
// while (audio.processing) {
// audio.cv_from_thread.wait(Lock);
// }
{
std::unique_lock<std::mutex> Lock(audio.mutex);
while (audio.processing) {
audio.cv_from_thread.wait(Lock);
}
}
//
//if (ShouldClearTextureCacheAtEndOfFrame) {
// gfx_texture_cache_clear();
// LUS::SkeletonPatcher::UpdateSkeletons();
// ShouldClearTextureCacheAtEndOfFrame = false;
//}
// OTRTODO: FIGURE OUT END FRAME POINT
@ -1029,6 +1070,10 @@ extern "C" Vtx* ResourceMgr_LoadVtxByName(char* path) {
return (Vtx*)ResourceGetDataByName(path);
}
extern "C" SequenceData ResourceMgr_LoadSeqByName(const char* path) {
SequenceData* sequence = (SequenceData*)ResourceGetDataByName(path);
return *sequence;
}
extern "C" KeyFrameSkeleton* ResourceMgr_LoadKeyFrameSkelByName(const char* path) {
return (KeyFrameSkeleton*)ResourceGetDataByName(path);
}
@ -1036,13 +1081,6 @@ extern "C" KeyFrameSkeleton* ResourceMgr_LoadKeyFrameSkelByName(const char* path
extern "C" KeyFrameAnimation* ResourceMgr_LoadKeyFrameAnimByName(const char* path) {
return (KeyFrameAnimation*)ResourceGetDataByName(path);
}
//extern "C" SequenceData ResourceMgr_LoadSeqByName(const char* path) {
// SequenceData* sequence = (SequenceData*)ResourceGetDataByName(path);
// return *sequence;
//}
//
//std::map<std::string, SoundFontSample*> cachedCustomSFs;
#if 0
extern "C" SoundFontSample* ReadCustomSample(const char* path) {
@ -1104,11 +1142,11 @@ extern "C" SoundFontSample* ReadCustomSample(const char* path) {
extern "C" SoundFontSample* ResourceMgr_LoadAudioSample(const char* path) {
return (SoundFontSample*)ResourceGetDataByName(path);
}
#endif
extern "C" SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path) {
return (SoundFont*)ResourceGetDataByName(path);
}
#endif
extern "C" int ResourceMgr_OTRSigCheck(char* imgData) {
uintptr_t i = (uintptr_t)(imgData);
@ -1570,7 +1608,7 @@ extern "C" void BenSysFlashrom_WriteData(u8* saveBuffer, u32 pageNum, u32 pageCo
std::string fileName = "save_" + std::to_string(flashSlotFile) + ".sav";
if (isBackup) fileName += ".bak";
if (IS_VALID_FILE(save)) {
WriteSaveFile(fileName, save);
} else {

535
mm/2s2h/mixer.c Normal file
View File

@ -0,0 +1,535 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "mixer.h"
#ifndef __clang__
#pragma GCC optimize ("unroll-loops")
#endif
#define ROUND_UP_64(v) (((v) + 63) & ~63)
#define ROUND_UP_32(v) (((v) + 31) & ~31)
#define ROUND_UP_16(v) (((v) + 15) & ~15)
#define ROUND_UP_8(v) (((v) + 7) & ~7)
#define ROUND_DOWN_16(v) ((v) & ~0xf)
//#define DMEM_BUF_SIZE (0x1000 - 0x0330 - 0x10 - 0x40)
#define DMEM_BUF_SIZE 0xC80
#define BUF_U8(a) (rspa.buf.as_u8 + ((a)-0x0330))
#define BUF_S16(a) (rspa.buf.as_s16 + ((a)-0x0330) / sizeof(int16_t))
static struct {
uint16_t in;
uint16_t out;
uint16_t nbytes;
uint16_t vol[2];
uint16_t rate[2];
uint16_t vol_wet;
uint16_t rate_wet;
ADPCM_STATE *adpcm_loop_state;
int16_t adpcm_table[8][2][8];
uint16_t filter_count;
int16_t filter[8];
union {
int16_t as_s16[DMEM_BUF_SIZE / sizeof(int16_t)];
uint8_t as_u8[DMEM_BUF_SIZE];
} buf;
} rspa;
static int16_t resample_table[64][4] = {
{0x0c39, 0x66ad, 0x0d46, 0xffdf}, {0x0b39, 0x6696, 0x0e5f, 0xffd8},
{0x0a44, 0x6669, 0x0f83, 0xffd0}, {0x095a, 0x6626, 0x10b4, 0xffc8},
{0x087d, 0x65cd, 0x11f0, 0xffbf}, {0x07ab, 0x655e, 0x1338, 0xffb6},
{0x06e4, 0x64d9, 0x148c, 0xffac}, {0x0628, 0x643f, 0x15eb, 0xffa1},
{0x0577, 0x638f, 0x1756, 0xff96}, {0x04d1, 0x62cb, 0x18cb, 0xff8a},
{0x0435, 0x61f3, 0x1a4c, 0xff7e}, {0x03a4, 0x6106, 0x1bd7, 0xff71},
{0x031c, 0x6007, 0x1d6c, 0xff64}, {0x029f, 0x5ef5, 0x1f0b, 0xff56},
{0x022a, 0x5dd0, 0x20b3, 0xff48}, {0x01be, 0x5c9a, 0x2264, 0xff3a},
{0x015b, 0x5b53, 0x241e, 0xff2c}, {0x0101, 0x59fc, 0x25e0, 0xff1e},
{0x00ae, 0x5896, 0x27a9, 0xff10}, {0x0063, 0x5720, 0x297a, 0xff02},
{0x001f, 0x559d, 0x2b50, 0xfef4}, {0xffe2, 0x540d, 0x2d2c, 0xfee8},
{0xffac, 0x5270, 0x2f0d, 0xfedb}, {0xff7c, 0x50c7, 0x30f3, 0xfed0},
{0xff53, 0x4f14, 0x32dc, 0xfec6}, {0xff2e, 0x4d57, 0x34c8, 0xfebd},
{0xff0f, 0x4b91, 0x36b6, 0xfeb6}, {0xfef5, 0x49c2, 0x38a5, 0xfeb0},
{0xfedf, 0x47ed, 0x3a95, 0xfeac}, {0xfece, 0x4611, 0x3c85, 0xfeab},
{0xfec0, 0x4430, 0x3e74, 0xfeac}, {0xfeb6, 0x424a, 0x4060, 0xfeaf},
{0xfeaf, 0x4060, 0x424a, 0xfeb6}, {0xfeac, 0x3e74, 0x4430, 0xfec0},
{0xfeab, 0x3c85, 0x4611, 0xfece}, {0xfeac, 0x3a95, 0x47ed, 0xfedf},
{0xfeb0, 0x38a5, 0x49c2, 0xfef5}, {0xfeb6, 0x36b6, 0x4b91, 0xff0f},
{0xfebd, 0x34c8, 0x4d57, 0xff2e}, {0xfec6, 0x32dc, 0x4f14, 0xff53},
{0xfed0, 0x30f3, 0x50c7, 0xff7c}, {0xfedb, 0x2f0d, 0x5270, 0xffac},
{0xfee8, 0x2d2c, 0x540d, 0xffe2}, {0xfef4, 0x2b50, 0x559d, 0x001f},
{0xff02, 0x297a, 0x5720, 0x0063}, {0xff10, 0x27a9, 0x5896, 0x00ae},
{0xff1e, 0x25e0, 0x59fc, 0x0101}, {0xff2c, 0x241e, 0x5b53, 0x015b},
{0xff3a, 0x2264, 0x5c9a, 0x01be}, {0xff48, 0x20b3, 0x5dd0, 0x022a},
{0xff56, 0x1f0b, 0x5ef5, 0x029f}, {0xff64, 0x1d6c, 0x6007, 0x031c},
{0xff71, 0x1bd7, 0x6106, 0x03a4}, {0xff7e, 0x1a4c, 0x61f3, 0x0435},
{0xff8a, 0x18cb, 0x62cb, 0x04d1}, {0xff96, 0x1756, 0x638f, 0x0577},
{0xffa1, 0x15eb, 0x643f, 0x0628}, {0xffac, 0x148c, 0x64d9, 0x06e4},
{0xffb6, 0x1338, 0x655e, 0x07ab}, {0xffbf, 0x11f0, 0x65cd, 0x087d},
{0xffc8, 0x10b4, 0x6626, 0x095a}, {0xffd0, 0x0f83, 0x6669, 0x0a44},
{0xffd8, 0x0e5f, 0x6696, 0x0b39}, {0xffdf, 0x0d46, 0x66ad, 0x0c39}
};
static inline int16_t clamp16(int32_t v) {
if (v < -0x8000) {
return -0x8000;
} else if (v > 0x7fff) {
return 0x7fff;
}
return (int16_t)v;
}
static inline int32_t clamp32(int64_t v) {
if (v < -0x7fffffff - 1) {
return -0x7fffffff - 1;
} else if (v > 0x7fffffff) {
return 0x7fffffff;
}
return (int32_t)v;
}
void aClearBufferImpl(uint16_t addr, int nbytes) {
nbytes = ROUND_UP_16(nbytes);
memset(BUF_U8(addr), 0, nbytes);
}
void aLoadBufferImpl(const void *source_addr, uint16_t dest_addr, uint16_t nbytes) {
#if __SANITIZE_ADDRESS__
for (size_t i = 0; i < ROUND_DOWN_16(nbytes); i++) {
BUF_U8(dest_addr)[i] = ((const unsigned char*)source_addr)[i];
}
#else
memcpy(BUF_U8(dest_addr), source_addr, ROUND_DOWN_16(nbytes));
#endif
}
void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes) {
memcpy(dest_addr, BUF_S16(source_addr), ROUND_DOWN_16(nbytes));
}
void aLoadADPCMImpl(int num_entries_times_16, const int16_t *book_source_addr) {
memcpy(rspa.adpcm_table, book_source_addr, num_entries_times_16);
}
void aSetBufferImpl(uint8_t flags, uint16_t in, uint16_t out, uint16_t nbytes) {
rspa.in = in;
rspa.out = out;
rspa.nbytes = nbytes;
}
void aInterleaveImpl(uint16_t dest, uint16_t left, uint16_t right, uint16_t c) {
int count = ROUND_UP_8(c) / sizeof(int16_t) / 4;
int16_t *l = BUF_S16(left);
int16_t *r = BUF_S16(right);
int16_t *d = BUF_S16(dest);
while (count > 0) {
int16_t l0 = *l++;
int16_t l1 = *l++;
int16_t l2 = *l++;
int16_t l3 = *l++;
int16_t r0 = *r++;
int16_t r1 = *r++;
int16_t r2 = *r++;
int16_t r3 = *r++;
*d++ = l0;
*d++ = r0;
*d++ = l1;
*d++ = r1;
*d++ = l2;
*d++ = r2;
*d++ = l3;
*d++ = r3;
--count;
}
}
void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes) {
nbytes = ROUND_UP_16(nbytes);
memmove(BUF_U8(out_addr), BUF_U8(in_addr), nbytes);
}
void aSetLoopImpl(ADPCM_STATE *adpcm_loop_state) {
rspa.adpcm_loop_state = adpcm_loop_state;
}
void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state) {
uint8_t *in = BUF_U8(rspa.in);
int16_t *out = BUF_S16(rspa.out);
int nbytes = ROUND_UP_32(rspa.nbytes);
if (flags & A_INIT) {
memset(out, 0, 16 * sizeof(int16_t));
} else if (flags & A_LOOP) {
memcpy(out, rspa.adpcm_loop_state, 16 * sizeof(int16_t));
} else {
memcpy(out, state, 16 * sizeof(int16_t));
}
out += 16;
while (nbytes > 0) {
int shift = *in >> 4; // should be in 0..12 or 0..14
int table_index = *in++ & 0xf; // should be in 0..7
int16_t (*tbl)[8] = rspa.adpcm_table[table_index];
int i;
for (i = 0; i < 2; i++) {
int16_t ins[8];
int16_t prev1 = out[-1];
int16_t prev2 = out[-2];
int j, k;
if (flags & 4) {
for (j = 0; j < 2; j++) {
ins[j * 4] = (((*in >> 6) << 30) >> 30) << shift;
ins[j * 4 + 1] = ((((*in >> 4) & 0x3) << 30) >> 30) << shift;
ins[j * 4 + 2] = ((((*in >> 2) & 0x3) << 30) >> 30) << shift;
ins[j * 4 + 3] = (((*in++ & 0x3) << 30) >> 30) << shift;
}
} else {
for (j = 0; j < 4; j++) {
ins[j * 2] = (((*in >> 4) << 28) >> 28) << shift;
ins[j * 2 + 1] = (((*in++ & 0xf) << 28) >> 28) << shift;
}
}
for (j = 0; j < 8; j++) {
int32_t acc = tbl[0][j] * prev2 + tbl[1][j] * prev1 + (ins[j] << 11);
for (k = 0; k < j; k++) {
acc += tbl[1][((j - k) - 1)] * ins[k];
}
acc >>= 11;
*out++ = clamp16(acc);
}
}
nbytes -= 16 * sizeof(int16_t);
}
memcpy(state, out - 16, 16 * sizeof(int16_t));
}
void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state) {
int16_t tmp[16];
int16_t *in_initial = BUF_S16(rspa.in);
int16_t *in = in_initial;
int16_t *out = BUF_S16(rspa.out);
int nbytes = ROUND_UP_16(rspa.nbytes);
uint32_t pitch_accumulator;
int i;
int16_t *tbl;
int32_t sample;
if (flags & A_INIT) {
memset(tmp, 0, 5 * sizeof(int16_t));
} else {
memcpy(tmp, state, 16 * sizeof(int16_t));
}
if (flags & 2) {
memcpy(in - 8, tmp + 8, 8 * sizeof(int16_t));
in -= tmp[5] / sizeof(int16_t);
}
in -= 4;
pitch_accumulator = (uint16_t)tmp[4];
memcpy(in, tmp, 4 * sizeof(int16_t));
do {
for (i = 0; i < 8; i++) {
tbl = resample_table[pitch_accumulator * 64 >> 16];
sample = ((in[0] * tbl[0] + 0x4000) >> 15) +
((in[1] * tbl[1] + 0x4000) >> 15) +
((in[2] * tbl[2] + 0x4000) >> 15) +
((in[3] * tbl[3] + 0x4000) >> 15);
*out++ = clamp16(sample);
pitch_accumulator += (pitch << 1);
in += pitch_accumulator >> 16;
pitch_accumulator %= 0x10000;
}
nbytes -= 8 * sizeof(int16_t);
} while (nbytes > 0);
state[4] = (int16_t)pitch_accumulator;
memcpy(state, in, 4 * sizeof(int16_t));
i = (in - in_initial + 4) & 7;
in -= i;
if (i != 0) {
i = -8 - i;
}
state[5] = i;
memcpy(state + 8, in, 8 * sizeof(int16_t));
}
void aEnvSetup1Impl(uint8_t initial_vol_wet, uint16_t rate_wet, uint16_t rate_left, uint16_t rate_right) {
rspa.vol_wet = (uint16_t)(initial_vol_wet << 8);
rspa.rate_wet = rate_wet;
rspa.rate[0] = rate_left;
rspa.rate[1] = rate_right;
}
void aEnvSetup2Impl(uint16_t initial_vol_left, uint16_t initial_vol_right) {
rspa.vol[0] = initial_vol_left;
rspa.vol[1] = initial_vol_right;
}
void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb,
bool neg_3, bool neg_2,
bool neg_left, bool neg_right,
int32_t wet_dry_addr, u32 unk)
{
int16_t *in = BUF_S16(in_addr);
int16_t *dry[2] = {BUF_S16(((wet_dry_addr >> 24) & 0xFF) << 4), BUF_S16(((wet_dry_addr >> 16) & 0xFF) << 4)};
int16_t *wet[2] = {BUF_S16(((wet_dry_addr >> 8) & 0xFF) << 4), BUF_S16(((wet_dry_addr) & 0xFF) << 4)};
int16_t negs[4] = {neg_left ? -1 : 0, neg_right ? -1 : 0, neg_3 ? -4 : 0, neg_2 ? -2 : 0};
int swapped[2] = {swap_reverb ? 1 : 0, swap_reverb ? 0 : 1};
int n = ROUND_UP_16(n_samples);
uint16_t vols[2] = {rspa.vol[0], rspa.vol[1]};
uint16_t rates[2] = {rspa.rate[0], rspa.rate[1]};
uint16_t vol_wet = rspa.vol_wet;
uint16_t rate_wet = rspa.rate_wet;
do {
for (int i = 0; i < 8; i++) {
int16_t samples[2] = {*in, *in}; in++;
for (int j = 0; j < 2; j++) {
samples[j] = (samples[j] * vols[j] >> 16) ^ negs[j];
}
for (int j = 0; j < 2; j++) {
*dry[j] = clamp16(*dry[j] + samples[j]); dry[j]++;
*wet[j] = clamp16(*wet[j] + ((samples[swapped[j]] * vol_wet >> 16) ^ negs[2 + j])); wet[j]++;
}
}
vols[0] += rates[0];
vols[1] += rates[1];
vol_wet += rate_wet;
n -= 8;
} while (n > 0);
}
void aMixImpl(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
int nbytes = ROUND_UP_32(ROUND_DOWN_16(count << 4));
int16_t *in = BUF_S16(in_addr);
int16_t *out = BUF_S16(out_addr);
int i;
int32_t sample;
if (gain == -0x8000) {
while (nbytes > 0) {
for (i = 0; i < 16; i++) {
sample = *out - *in++;
*out++ = clamp16(sample);
}
nbytes -= 16 * sizeof(int16_t);
}
}
while (nbytes > 0) {
for (i = 0; i < 16; i++) {
sample = ((*out * 0x7fff + *in++ * gain) + 0x4000) >> 15;
*out++ = clamp16(sample);
}
nbytes -= 16 * sizeof(int16_t);
}
}
void aS8DecImpl(uint8_t flags, ADPCM_STATE state) {
uint8_t *in = BUF_U8(rspa.in);
int16_t *out = BUF_S16(rspa.out);
int nbytes = ROUND_UP_32(rspa.nbytes);
if (flags & A_INIT) {
memset(out, 0, 16 * sizeof(int16_t));
} else if (flags & A_LOOP) {
memcpy(out, rspa.adpcm_loop_state, 16 * sizeof(int16_t));
} else {
memcpy(out, state, 16 * sizeof(int16_t));
}
out += 16;
while (nbytes > 0) {
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
*out++ = (int16_t)(*in++ << 8);
nbytes -= 16 * sizeof(int16_t);
}
memcpy(state, out - 16, 16 * sizeof(int16_t));
}
void aAddMixerImpl(uint16_t count, uint16_t in_addr, uint16_t out_addr) {
int16_t *in = BUF_S16(in_addr);
int16_t *out = BUF_S16(out_addr);
int nbytes = ROUND_UP_64(ROUND_DOWN_16(count));
do {
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
*out = clamp16(*out + *in++); out++;
nbytes -= 16 * sizeof(int16_t);
} while (nbytes > 0);
}
void aDuplicateImpl(uint16_t count, uint16_t in_addr, uint16_t out_addr) {
uint8_t* in = BUF_U8(in_addr);
uint8_t *out = BUF_U8(out_addr);
uint8_t tmp[128];
memcpy(tmp, in, 128);
do {
memcpy(out, tmp, 128);
out += 128;
} while (count-- > 0);
}
void aResampleZohImpl(uint16_t pitch, uint16_t start_fract) {
int16_t *in = BUF_S16(rspa.in);
int16_t *out = BUF_S16(rspa.out);
int nbytes = ROUND_UP_8(rspa.nbytes);
uint32_t pos = start_fract;
uint32_t pitch_add = pitch << 2;
do {
*out++ = in[pos >> 17]; pos += pitch_add;
*out++ = in[pos >> 17]; pos += pitch_add;
*out++ = in[pos >> 17]; pos += pitch_add;
*out++ = in[pos >> 17]; pos += pitch_add;
nbytes -= 4 * sizeof(int16_t);
} while (nbytes > 0);
}
void aInterlImpl(uint16_t in_addr, uint16_t out_addr, uint16_t n_samples) {
int16_t *in = BUF_S16(in_addr);
int16_t *out = BUF_S16(out_addr);
int n = ROUND_UP_8(n_samples);
do {
*out++ = *in++; in++;
*out++ = *in++; in++;
*out++ = *in++; in++;
*out++ = *in++; in++;
*out++ = *in++; in++;
*out++ = *in++; in++;
*out++ = *in++; in++;
*out++ = *in++; in++;
n -= 8;
} while (n > 0);
}
void aFilterImpl(uint8_t flags, uint16_t count_or_buf, int16_t *state_or_filter) {
if (flags > A_INIT) {
rspa.filter_count = ROUND_UP_16(count_or_buf);
memcpy(rspa.filter, state_or_filter, sizeof(rspa.filter));
} else {
int16_t tmp[16], tmp2[8];
int count = rspa.filter_count;
int16_t *buf = BUF_S16(count_or_buf);
if (flags == A_INIT) {
#ifndef __clang__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmemset-elt-size"
#endif
memset(tmp, 0, 8 * sizeof(int16_t));
#ifndef __clang__
#pragma GCC diagnostic pop
#endif
memset(tmp2, 0, 8 * sizeof(int16_t));
} else {
memcpy(tmp, state_or_filter, 8 * sizeof(int16_t));
memcpy(tmp2, state_or_filter + 8, 8 * sizeof(int16_t));
}
for (int i = 0; i < 8; i++) {
rspa.filter[i] = (tmp2[i] + rspa.filter[i]) / 2;
}
do {
memcpy(tmp + 8, buf, 8 * sizeof(int16_t));
for (int i = 0; i < 8; i++) {
int64_t sample = 0x4000; // round term
for (int j = 0; j < 8; j++) {
sample += tmp[i + j] * rspa.filter[7 - j];
}
buf[i] = clamp16((int32_t)(sample >> 15));
}
memcpy(tmp, tmp + 8, 8 * sizeof(int16_t));
buf += 8;
count -= 8 * sizeof(int16_t);
} while (count > 0);
memcpy(state_or_filter, tmp, 8 * sizeof(int16_t));
memcpy(state_or_filter + 8, rspa.filter, 8 * sizeof(int16_t));
}
}
void aHiLoGainImpl(uint8_t g, uint16_t count, uint16_t addr) {
int16_t *samples = BUF_S16(addr);
int nbytes = ROUND_UP_32(count);
do {
*samples = clamp16((*samples * g) >> 4); samples++;
*samples = clamp16((*samples * g) >> 4); samples++;
*samples = clamp16((*samples * g) >> 4); samples++;
*samples = clamp16((*samples * g) >> 4); samples++;
*samples = clamp16((*samples * g) >> 4); samples++;
*samples = clamp16((*samples * g) >> 4); samples++;
*samples = clamp16((*samples * g) >> 4); samples++;
*samples = clamp16((*samples * g) >> 4); samples++;
nbytes -= 8;
} while (nbytes > 0);
}
void aUnkCmd3Impl(uint16_t a, uint16_t b, uint16_t c) {
}
void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_addr) {
int nbytes = ROUND_UP_64(count);
int16_t *in = BUF_S16(in_addr + f);
int16_t *out = BUF_S16(out_addr);
int16_t tbl[32];
memcpy(tbl, in, 32 * sizeof(int16_t));
do {
for (int i = 0; i < 32; i++) {
out[i] = clamp16(out[i] * tbl[i]);
}
out += 32;
nbytes -= 32 * sizeof(int16_t);
} while (nbytes > 0);
}

88
mm/2s2h/mixer.h Normal file
View File

@ -0,0 +1,88 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "libultraship/libultra/abi.h"
#undef aSegment
#undef aClearBuffer
#undef aSetBuffer
#undef aLoadBuffer
#undef aSaveBuffer
#undef aDMEMMove
#undef aMix
#undef aEnvMixer
#undef aResample
#undef aInterleave
#undef aSetVolume
#undef aSetVolume32
#undef aSetLoop
#undef aLoadADPCM
#undef aADPCMdec
#undef aS8Dec
#undef aAddMixer
#undef aDuplicate
#undef aDMEMMove2
#undef aResampleZoh
#undef aEnvSetup1
#undef aEnvSetup2
#undef aFilter
#undef aHiLoGain
#undef aInterl
#undef aUnkCmd3
#undef aUnkCmd19
void aClearBufferImpl(uint16_t addr, int nbytes);
void aLoadBufferImpl(const void* source_addr, uint16_t dest_addr, uint16_t nbytes);
void aSaveBufferImpl(uint16_t source_addr, int16_t* dest_addr, uint16_t nbytes);
void aLoadADPCMImpl(int num_entries_times_16, const int16_t* book_source_addr);
void aSetBufferImpl(uint8_t flags, uint16_t in, uint16_t out, uint16_t nbytes);
void aInterleaveImpl(uint16_t dest, uint16_t left, uint16_t right, uint16_t c);
void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes);
void aSetLoopImpl(ADPCM_STATE* adpcm_loop_state);
void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state);
void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state);
void aEnvSetup1Impl(uint8_t initial_vol_wet, uint16_t rate_wet, uint16_t rate_left, uint16_t rate_right);
void aEnvSetup2Impl(uint16_t initial_vol_left, uint16_t initial_vol_right);
void aEnvMixerImpl(uint16_t in_addr, uint16_t n_samples, bool swap_reverb, bool neg_3, bool neg_2, bool neg_left,
bool neg_right, int32_t wet_dry_addr, u32 unk);
void aMixImpl(uint16_t count, int16_t gain, uint16_t in_addr, uint16_t out_addr);
void aS8DecImpl(uint8_t flags, ADPCM_STATE state);
void aAddMixerImpl(uint16_t count, uint16_t in_addr, uint16_t out_addr);
void aDuplicateImpl(uint16_t count, uint16_t in_addr, uint16_t out_addr);
void aResampleZohImpl(uint16_t pitch, uint16_t start_fract);
void aInterlImpl(uint16_t in_addr, uint16_t out_addr, uint16_t n_samples);
void aFilterImpl(uint8_t flags, uint16_t count_or_buf, int16_t* state_or_filter);
void aHiLoGainImpl(uint8_t g, uint16_t count, uint16_t addr);
void aUnkCmd3Impl(uint16_t a, uint16_t b, uint16_t c);
void aUnkCmd19Impl(uint8_t f, uint16_t count, uint16_t out_addr, uint16_t in_addr);
#define aSegment(pkt, s, b) \
do { \
} while (0)
#define aClearBuffer(pkt, d, c) aClearBufferImpl(d, c)
#define aLoadBuffer(pkt, s, d, c) aLoadBufferImpl(s, d, c)
#define aSaveBuffer(pkt, s, d, c) aSaveBufferImpl(s, d, c)
#define aLoadADPCM(pkt, c, d) aLoadADPCMImpl(c, d)
#define aSetBuffer(pkt, f, i, o, c) aSetBufferImpl(f, i, o, c)
#define aInterleave(pkt, o, l, r, c) aInterleaveImpl(o, l, r, c)
#define aDMEMMove(pkt, i, o, c) aDMEMMoveImpl(i, o, c)
#define aSetLoop(pkt, a) aSetLoopImpl(a)
#define aADPCMdec(pkt, f, s) aADPCMdecImpl(f, s)
#define aResample(pkt, f, p, s) aResampleImpl(f, p, s)
#define aEnvSetup1(pkt, initialVolReverb, rampReverb, rampLeft, rampRight) \
aEnvSetup1Impl(initialVolReverb, rampReverb, rampLeft, rampRight)
#define aEnvSetup2(pkt, initialVolLeft, initialVolRight) aEnvSetup2Impl(initialVolLeft, initialVolRight)
#define aEnvMixer(pkt, inBuf, nSamples, swapReverb, negLeft, negRight, dryLeft, dryRight, wetLeft, wetRight) \
aEnvMixerImpl(inBuf, nSamples, swapReverb, negLeft, negRight, dryLeft, dryRight, wetLeft, wetRight)
#define aMix(pkt, c, g, i, o) aMixImpl(c, g, i, o)
#define aS8Dec(pkt, f, s) aS8DecImpl(f, s)
#define aAddMixer(pkt, s, d, c) aAddMixerImpl(s, d, c)
#define aDuplicate(pkt, s, d, c) aDuplicateImpl(s, d, c)
#define aDMEMMove2(pkt, t, i, o, c) aDMEMMove2Impl(t, i, o, c)
#define aResampleZoh(pkt, pitch, startFract) aResampleZohImpl(pitch, startFract)
#define aInterl(pkt, dmemi, dmemo, count) aInterlImpl(dmemi, dmemo, count)
#define aFilter(pkt, f, countOrBuf, addr) aFilterImpl(f, countOrBuf, addr)
#define aHiLoGain(pkt, g, buflen, i, a4) aHiLoGainImpl(g, buflen, i)
#define aUnkCmd3(pkt, a1, a2, a3) aUnkCmd3Impl(a1, a2, a3)
#define aUnkCmd19(pkt, a1, a2, a3, a4) aUnkCmd19Impl(a1, a2, a3, a4)

View File

@ -7,8 +7,8 @@
namespace SOH {
typedef struct {
/* 0x00 */ uintptr_t start;
/* 0x04 */ uintptr_t end;
/* 0x00 */ u32 start;
/* 0x04 */ u32 end;
/* 0x08 */ u32 count;
/* 0x0C */ char unk_0C[0x4];
/* 0x10 */ s16 state[16]; // only exists if count != 0. 8-byte aligned

File diff suppressed because it is too large Load Diff

View File

@ -106,6 +106,6 @@ void* AudioHeap_SearchPermanentCache(s32 tableType, s32 id);
void* AudioHeap_AllocPermanent(s32 tableType, s32 id, size_t size);
void* AudioHeap_AllocSampleCache(size_t size, s32 sampleBankId, void* sampleAddr, s8 medium, s32 cache);
void AudioHeap_ApplySampleBankCache(s32 sampleBankId);
void AudioHeap_SetReverbData(s32 reverbIndex, u32 dataType, s32 data, s32 isFirstInit);
void AudioHeap_SetReverbData(s32 reverbIndex, u32 dataType, uintptr_t data, s32 isFirstInit);
#endif

View File

@ -35,7 +35,7 @@ typedef struct {
/* 0x04 */ uintptr_t romAddr;
/* 0x08 */ char pad[0x8];
/* 0x10 */ AudioTableEntry entries[1]; // (dynamic size)
} AudioTable; // size >= 0x20
} AudioTable; // size >= 0x20
typedef enum {
/* 0 */ LOAD_STATUS_NOT_LOADED,
@ -88,7 +88,8 @@ typedef struct {
/* 0x10 */ u8* ramAddr;
/* 0x14 */ s32 status;
/* 0x18 */ size_t bytesRemaining;
/* 0x1C */ s8* isDone; // TODO: rename in OoT and sync up here. This is an external status while (s32 status) is an internal status
/* 0x1C */ s8* isDone; // TODO: rename in OoT and sync up here. This is an external status while (s32 status) is an
// internal status
/* 0x20 */ struct Sample sample;
/* 0x30 */ OSMesgQueue msgqueue;
/* 0x48 */ OSMesg msg;
@ -103,7 +104,7 @@ typedef struct {
/* 0xC */ u8 unused;
/* 0xD */ u8 reuseIndex; // position in sSampleDmaReuseQueue1/2, if ttl == 0
/* 0xE */ u8 ttl; // Time To Live: duration after which the DMA can be discarded
} SampleDma; // size = 0x10
} SampleDma; // size = 0x10
typedef struct {
/* 0x00 */ u32 endAndMediumKey;
@ -125,7 +126,7 @@ s32 AudioLoad_SyncLoadInstrument(s32 fontId, s32 instId, s32 drumId);
void AudioLoad_AsyncLoadSeq(s32 seqId, s32 arg1, s32 retData, OSMesgQueue* retQueue);
void AudioLoad_AsyncLoadSampleBank(s32 sampleBankId, s32 arg1, s32 retData, OSMesgQueue* retQueue);
void AudioLoad_AsyncLoadFont(s32 fontId, s32 arg1, s32 retData, OSMesgQueue* retQueue);
u8* AudioLoad_GetFontsForSequence(s32 seqId, u32* outNumFonts);
u8* AudioLoad_GetFontsForSequence(s32 seqId, u32* outNumFonts, u8* buff);
void AudioLoad_DiscardSeqFonts(s32 seqId);
void func_8018FA60(u32 tableType, u32 id, s32 type, s32 data);
s32 AudioLoad_SyncInitSeqPlayer(s32 playerIndex, s32 seqId, s32 arg2);

View File

@ -7,7 +7,7 @@ struct EnvelopePoint;
typedef struct AdpcmLoop {
/* 0x00 */ u32 start;
/* 0x04 */ u32 loopEnd; // numSamples position into the sample where the loop ends
/* 0x04 */ u32 loopEnd; // numSamples position into the sample where the loop ends
/* 0x08 */ u32 count; // The number of times the loop is played before the sound completes. Setting count to -1 indicates that the loop should play indefinitely.
/* 0x0C */ u32 sampleEnd; // total number of s16-samples in the sample audio clip
/* 0x10 */ s16 predictorState[16]; // only exists if count != 0. 8-byte aligned
@ -20,7 +20,7 @@ typedef struct AdpcmLoop {
typedef struct AdpcmBook {
/* 0x0 */ s32 order;
/* 0x4 */ s32 numPredictors;
/* 0x8 */ s16 codeBook[1]; // a table of prediction coefficients that the coder selects from to optimize sound quality.
/* 0x8 */ s16* codeBook; // a table of prediction coefficients that the coder selects from to optimize sound quality.
} AdpcmBook; // size >= 0x8
typedef enum SampleCodec {
@ -43,15 +43,22 @@ typedef enum SampleMedium {
} SampleMedium;
typedef struct Sample {
/* 0x0 */ u32 unk_0 : 1;
/* 0x0 */ u32 codec : 3; // The state of compression or decompression, See `SampleCodec`
/* 0x0 */ u32 medium : 2; // Medium where sample is currently stored. See `SampleMedium`
/* 0x0 */ u32 unk_bit26 : 1;
/* 0x0 */ u32 isRelocated : 1; // Has the sample header been relocated (offsets to pointers)
/* 0x1 */ u32 size : 24; // Size of the sample
union {
struct {
///* 0x0 */ u32 unk_0 : 1;
/* 0x0 */ u32 codec : 4; // The state of compression or decompression, See `SampleCodec`
/* 0x0 */ u32 medium : 2; // Medium where sample is currently stored. See `SampleMedium`
/* 0x0 */ u32 unk_bit26 : 1;
/* 0x0 */ u32 isRelocated : 1; // Has the sample header been relocated (offsets to pointers)
/* 0x1 */ u32 size : 24; // Size of the sample
};
u32 asU32;
};
/* 0x4 */ u8* sampleAddr; // Raw sample data. Offset from the start of the sample bank or absolute address to either rom or ram
/* 0x8 */ AdpcmLoop* loop; // Adpcm loop parameters used by the sample. Offset from the start of the sound font / pointer to ram
/* 0xC */ AdpcmBook* book; // Adpcm book parameters used by the sample. Offset from the start of the sound font / pointer to ram
u32 sampleRateMagicValue; // For wav samples only...
s32 sampleRate; // For wav samples only...
} Sample; // size = 0x10
typedef struct TunedSample {
@ -96,6 +103,7 @@ typedef struct SoundFont {
/* 0x08 */ Instrument** instruments;
/* 0x0C */ Drum** drums;
/* 0x10 */ SoundEffect* soundEffects;
s32 fntIndex;
} SoundFont; // size = 0x14
#endif

View File

@ -248,7 +248,7 @@ typedef enum {
* @param sfxState
*/
#define AUDIOCMD_CHANNEL_SET_SFX_STATE(seqPlayerIndex, channelIndex, sfxState) \
AudioThread_QueueCmdS32(AUDIO_MK_CMD(AUDIOCMD_OP_CHANNEL_SET_SFX_STATE, seqPlayerIndex, channelIndex, 0), (s32)sfxState)
AudioThread_QueueCmdPtr(AUDIO_MK_CMD(AUDIOCMD_OP_CHANNEL_SET_SFX_STATE, seqPlayerIndex, channelIndex, 0), (void*)sfxState)
/**
* Set the reverb index.
@ -282,7 +282,7 @@ typedef enum {
* @param filter
*/
#define AUDIOCMD_CHANNEL_SET_FILTER(seqPlayerIndex, channelIndex, filterCutoff, filter) \
AudioThread_QueueCmdS32(AUDIO_MK_CMD(AUDIOCMD_OP_CHANNEL_SET_FILTER, seqPlayerIndex, channelIndex, filterCutoff), \
AudioThread_QueueCmdPtr(AUDIO_MK_CMD(AUDIOCMD_OP_CHANNEL_SET_FILTER, seqPlayerIndex, channelIndex, filterCutoff), \
filter)
/**
@ -456,7 +456,7 @@ typedef enum {
* @param drumPtr (s32) the ptr to the `Drum` struct
*/
#define AUDIOCMD_GLOBAL_SET_DRUM_FONT(fontId, drumId, drumPtr) \
AudioThread_QueueCmdS32(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_DRUM_FONT, 0, fontId, drumId), drumPtr)
AudioThread_QueueCmdPtr(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_DRUM_FONT, 0, fontId, drumId), drumPtr)
/**
* Set a soundeffect ptr within a soundfont
@ -466,7 +466,7 @@ typedef enum {
* @param soundEffectPtr (s32) the ptr to the `SoundEffect` struct
*/
#define AUDIOCMD_GLOBAL_SET_SFX_FONT(fontId, soundEffectId, soundEffectPtr) \
AudioThread_QueueCmdS32(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_SFX_FONT, 0, fontId, soundEffectId), soundEffectPtr)
AudioThread_QueueCmdPtr(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_SFX_FONT, 0, fontId, soundEffectId), soundEffectPtr)
/**
* Set an instrument ptr within a soundfont
@ -476,7 +476,7 @@ typedef enum {
* @param instPtr (s32) the ptr to the `Instrument` struct
*/
#define AUDIOCMD_GLOBAL_SET_INSTRUMENT_FONT(fontId, instId, instPtr) \
AudioThread_QueueCmdS32(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_INSTRUMENT_FONT, 0, fontId, instId), instPtr)
AudioThread_QueueCmdPtr(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_INSTRUMENT_FONT, 0, fontId, instId), instPtr)
/**
* Pop the persistent cache of the specified table
@ -493,7 +493,7 @@ typedef enum {
* @param functionPtr
*/
#define AUDIOCMD_GLOBAL_SET_CUSTOM_FUNCTION(functionType, functionPtr) \
AudioThread_QueueCmdS32(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_CUSTOM_FUNCTION, 0, 0, functionType), (s32)functionPtr)
AudioThread_QueueCmdPtr(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_CUSTOM_FUNCTION, 0, 0, functionType), functionPtr)
/**
* Do something related to the unloaded-type audio data in the heap.
@ -514,7 +514,7 @@ typedef enum {
* @param data
*/
#define AUDIOCMD_GLOBAL_SET_REVERB_DATA(reverbIndex, dataType, data) \
AudioThread_QueueCmdS32(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_REVERB_DATA, dataType, reverbIndex, 0), (s32)data)
AudioThread_QueueCmdPtr(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_REVERB_DATA, dataType, reverbIndex, 0), (uintptr_t)data)
/**
* Change the sound mode of audio
@ -608,7 +608,7 @@ typedef enum {
* @param functionPtr (s32) address of the function to run once every audio frame
*/
#define AUDIOCMD_GLOBAL_SET_CUSTOM_UPDATE_FUNCTION(functionPtr) \
AudioThread_QueueCmdS32(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_CUSTOM_UPDATE_FUNCTION, 0, 0, 0), functionPtr)
AudioThread_QueueCmdPtr(AUDIO_MK_CMD(AUDIOCMD_OP_GLOBAL_SET_CUSTOM_UPDATE_FUNCTION, 0, 0, 0), functionPtr)
/**
* Asynchronously load a sequence

View File

@ -1161,9 +1161,10 @@ void AudioThread_QueueCmdF32(u32 opArgs, f32 data);
void AudioThread_QueueCmdS32(u32 opArgs, s32 data);
void AudioThread_QueueCmdS8(u32 opArgs, s8 data);
void AudioThread_QueueCmdU16(u32 opArgs, u16 data);
void AudioThread_QueueCmdPtr(u32 opArgs, void* data);
s32 AudioThread_ScheduleProcessCmds(void);
u32 AudioThread_GetExternalLoadQueueMsg(u32* retMsg);
u8* AudioThread_GetFontsForSequence(s32 seqId, u32* outNumFonts);
u8* AudioThread_GetFontsForSequence(s32 seqId, u32* outNumFonts, u8* buff);
s32 func_80193C5C(void);
s32 AudioThread_ResetAudioHeap(s32 specId);
void AudioThread_PreNMIInternal(void);

View File

@ -581,12 +581,19 @@ typedef struct {
typedef struct {
union {
/* 0x0 */ u32 opArgs;
u32 opArgs;
struct {
/* 0x0 */ u8 op;
/* 0x1 */ u8 arg0;
/* 0x2 */ u8 arg1;
/* 0x3 */ u8 arg2;
#ifdef IS_BIGENDIAN
u8 op;
u8 arg0;
u8 arg1;
u8 arg2;
#else
u8 arg2;
u8 arg1;
u8 arg0;
u8 op;
#endif
};
};
union {
@ -597,9 +604,9 @@ typedef struct {
/* 0x4 */ s8 asSbyte;
/* 0x4 */ u8 asUbyte;
/* 0x4 */ u32 asUInt;
/* 0x4 */ void* asPtr;
/* 0x4 */ uintptr_t asPtr;
};
} AudioCmd; // size = 0x8
} AudioCmd;
typedef struct {
/* 0x00 */ OSTask task;
@ -706,7 +713,7 @@ typedef struct {
/* 0x435C */ AudioCommonPoolSplit temporaryCommonPoolSplit; // splits temporary common pool into caches for sequences, soundFonts, sample banks
/* 0x4368 */ u8 sampleFontLoadStatus[0x30];
/* 0x4398 */ u8 fontLoadStatus[0x30];
/* 0x43C8 */ u8 seqLoadStatus[0x80];
/* 0x43C8 */ u8* seqLoadStatus;
/* 0x4448 */ volatile u8 resetStatus;
/* 0x4449 */ u8 specId;
/* 0x444C */ s32 audioResetFadeOutFramesLeft;
@ -735,6 +742,8 @@ typedef struct {
/* 0x79E4 */ OSMesg threadCmdProcMsgBuf[4];
/* 0x79F4 */ AudioCmd threadCmdBuf[0x100]; // Audio commands used to transfer audio requests from the graph thread to the audio thread
/* 0x81F4 */ UNK_TYPE1 unk_81F4[4];
u16 seqToPlay[4];
u8 seqReplaced[4];
} AudioContext; // size = 0x81F8
typedef struct {
@ -924,6 +933,8 @@ typedef struct {
// Apply a low-pass filter with a lowPassCutoff of 4
#define SFX_FLAG2_APPLY_LOWPASS_FILTER (1 << 7)
#define MAX_AUTHENTIC_SEQID 128
typedef struct {
/* 0x0 */ u8 importance;
/* 0x1 */ u8 flags;
@ -937,4 +948,14 @@ typedef Acmd* (*AudioCustomSynthFunction)(Acmd*, s32, s32);
extern OSVoiceHandle gVoiceHandle;
typedef struct {
char* seqData;
int32_t seqDataSize;
uint16_t seqNumber;
uint8_t medium;
uint8_t cachePolicy;
int32_t numFonts;
uint8_t fonts[16];
} SequenceData;
#endif

View File

@ -1674,7 +1674,7 @@ u8 sCustomSequenceScript[400] = {
/* 40 */ 0x80, // testlayer 0
// (no end or loop; channel script seems to run into the note layers?)
// .layer layer0
/* 41 */ 0xF3, -4, // rbeqz chan_loop
@ -1683,8 +1683,8 @@ u8 sCustomSequenceScript[400] = {
// .layer layer2?
/* 44 */ 0xC2, -5, // transpose -5
/* 46 */ 0xC0, 0, // ldelay 0
/* 48 */ 0xC1, 87, // shortvel 87
/* 46 */ 0xC0, 0, // ldelay 0
/* 48 */ 0xC1, 87, // shortvel 87
/* 50 */ 0xC9, 0, // shortgate 0
/* 52 */ 0, // empty until the end
};
@ -2744,8 +2744,6 @@ void AudioOcarina_SetOcarinaDisableTimer(u8 unused, u8 timer) {
}
void AudioOcarina_SetInstrument(u8 ocarinaInstrumentId) {
// BENTODO: Crashes on kaleido when moving back and forth between songs
return;
if ((sOcarinaInstrumentId != ocarinaInstrumentId) || (ocarinaInstrumentId == OCARINA_INSTRUMENT_DEFAULT)) {
SEQCMD_SET_CHANNEL_IO(SEQ_PLAYER_SFX, SFX_CHANNEL_OCARINA, 1, ocarinaInstrumentId);
sOcarinaInstrumentId = ocarinaInstrumentId;
@ -4933,10 +4931,11 @@ void Audio_SetSequenceProperties(u8 seqPlayerIndex, Vec3f* projectedPos, s16 fla
if (flags & 8) {
// Uses new filter gBandPassFilterData
AUDIOCMD_CHANNEL_SET_FILTER(seqPlayerIndex, AUDIOCMD_ALL_CHANNELS, 0x54,
((u32)&sSequenceFilter[0] & ~0xF) + 0x10);
((uintptr_t)&sSequenceFilter[0] & ~0xF) + 0x10);
} else {
// Identity Filter
AUDIOCMD_CHANNEL_SET_FILTER(seqPlayerIndex, AUDIOCMD_ALL_CHANNELS, 0, ((u32)&sSequenceFilter[0] & ~0xF) + 0x10);
AUDIOCMD_CHANNEL_SET_FILTER(seqPlayerIndex, AUDIOCMD_ALL_CHANNELS, 0,
((uintptr_t)&sSequenceFilter[0] & ~0xF) + 0x10);
}
if (flags & 0x10) {
@ -5649,15 +5648,17 @@ void Audio_MuteBgmPlayersForFanfare(void) {
* Sets up seqId to play on seqPlayerIndex 1
*/
void Audio_PlayFanfare(u16 seqId) {
u8 prevFontBuff[16];
u8 fontBuff[16];
u16 prevSeqId = AudioSeq_GetActiveSeqId(SEQ_PLAYER_FANFARE);
u32 outNumFonts;
u8* prevFontId = AudioThread_GetFontsForSequence(prevSeqId & 0xFF, &outNumFonts);
u8* fontId = AudioThread_GetFontsForSequence(seqId & 0xFF, &outNumFonts);
u8* prevFontId = AudioThread_GetFontsForSequence(prevSeqId & 0xFF, &outNumFonts, prevFontBuff);
u8* fontId = AudioThread_GetFontsForSequence(seqId & 0xFF, &outNumFonts, fontBuff);
// BENTODO
// #region 2S2H [Audio] TODO: Fixes fanfare crash, should/can be removed after audio is done
// if ((prevSeqId == NA_BGM_DISABLED) || (*prevFontId == *fontId)) {
if ((prevSeqId == NA_BGM_DISABLED) || (prevFontId != NULL && fontId != NULL && *prevFontId == *fontId)) {
// #endregion
// #endregion
sFanfareState = 1;
} else {
sFanfareState = 5;

View File

@ -5,13 +5,13 @@
s32 osAiSetNextBuffer(void* buf, u32 size) {
static u8 D_801D6010 = false;
u32 bufAdjusted = (u32)buf;
uintptr_t bufAdjusted = (uintptr_t)buf;
s32 status;
if (D_801D6010) {
bufAdjusted = (u32)buf - 0x2000;
bufAdjusted = (uintptr_t)buf - 0x2000;
}
if ((((u32)buf + size) & 0x1FFF) == 0) {
if ((((uintptr_t)buf + size) & 0x1FFF) == 0) {
D_801D6010 = true;
} else {
D_801D6010 = false;

View File

@ -1,4 +1,5 @@
#include "global.h"
#include "endianness.h"
s16 gLowPassFilterData[16 * 8] ALIGNED(16) = {
/* 0x0 */ 0, 0, 0, 32767, 0, 0, 0, 0, // Identity filter (delta function)
@ -851,10 +852,10 @@ u8 gDefaultShortNoteGateTimeTable[] = {
};
EnvelopePoint gDefaultEnvelope[] = {
{ 1, 32000 },
{ 1000, 32000 },
{ ADSR_HANG, 0 },
{ ADSR_DISABLE, 0 },
{ BE16SWAP_CONST(1), BE16SWAP_CONST(32000) },
{ BE16SWAP_CONST(1000), BE16SWAP_CONST(32000) },
{ BE16SWAP_CONST(ADSR_HANG), BE16SWAP_CONST(0) },
{ BE16SWAP_CONST(ADSR_DISABLE), BE16SWAP_CONST(0) },
};
NoteSampleState gZeroedSampleState = { 0 };

View File

@ -11,6 +11,7 @@
*/
#include "global.h"
#include "audio/effects.h"
#include "endianness.h"
void AudioScript_SequenceChannelProcessSound(SequenceChannel* channel, s32 recalculateVolume, s32 applyBend) {
f32 channelVolume;
@ -273,7 +274,7 @@ f32 AudioEffects_UpdateAdsr(AdsrState* adsr) {
// fallthrough
retry:
case ADSR_STATUS_LOOP:
adsr->delay = adsr->envelope[adsr->envelopeIndex].delay;
adsr->delay = (s16)BE16SWAP(adsr->envelope[adsr->envelopeIndex].delay);
switch (adsr->delay) {
case ADSR_DISABLE:
adsr->action.s.status = ADSR_STATUS_DISABLED;
@ -284,7 +285,7 @@ f32 AudioEffects_UpdateAdsr(AdsrState* adsr) {
break;
case ADSR_GOTO:
adsr->envelopeIndex = adsr->envelope[adsr->envelopeIndex].arg;
adsr->envelopeIndex = (s16)BE16SWAP(adsr->envelope[adsr->envelopeIndex].arg);
goto retry;
case ADSR_RESTART:
@ -296,7 +297,8 @@ f32 AudioEffects_UpdateAdsr(AdsrState* adsr) {
if (adsr->delay == 0) {
adsr->delay = 1;
}
adsr->target = adsr->envelope[adsr->envelopeIndex].arg / 32767.0f;
adsr->target = (s16)BE16SWAP(adsr->envelope[adsr->envelopeIndex].arg) / 32767.0f;
adsr->target = SQ(adsr->target);
adsr->velocity = (adsr->target - adsr->current) / adsr->delay;
adsr->action.s.status = ADSR_STATUS_FADE;

View File

@ -13,6 +13,8 @@ void AudioHeap_ApplySampleBankCacheInternal(s32 apply, s32 sampleBankId);
void AudioHeap_DiscardSampleBanks(void);
void AudioHeap_InitReverb(s32 reverbIndex, ReverbSettings* settings, s32 isFirstInit);
extern size_t gSequenceToResourceSize;
#define gTatumsPerBeat (gAudioTatumInit[1])
/**
@ -66,7 +68,7 @@ void AudioHeap_ResetLoadStatus(void) {
}
}
for (i = 0; i < ARRAY_COUNT(gAudioCtx.seqLoadStatus); i++) {
for (i = 0; i < gSequenceToResourceSize; i++) {
if (gAudioCtx.seqLoadStatus[i] != LOAD_STATUS_PERMANENT) {
gAudioCtx.seqLoadStatus[i] = LOAD_STATUS_NOT_LOADED;
}
@ -123,6 +125,7 @@ void AudioHeap_DiscardSequence(s32 seqId) {
* Perform a writeback from the L1 data cache to the ram.
*/
void* AudioHeap_WritebackDCache(void* addr, size_t size) {
return addr;
Audio_WritebackDCache(addr, size);
if (addr) {}
@ -1110,9 +1113,9 @@ void* AudioHeap_AllocPermanent(s32 tableType, s32 id, size_t size) {
gAudioCtx.permanentEntries[index].size = size;
//! @bug UB: missing return. "addr" is in v0 at this point, but doing an
// explicit return uses an additional register.
#ifdef AVOID_UB
// #ifdef AVOID_UB
return addr;
#endif
// #endif
}
void* AudioHeap_AllocSampleCache(size_t size, s32 sampleBankId, void* sampleAddr, s8 medium, s32 cache) {
@ -1359,6 +1362,8 @@ void AudioHeap_DiscardSampleCacheForFont(SampleCacheEntry* entry, s32 sampleBank
}
void AudioHeap_DiscardSampleCaches(void) {
return;
s32 numFonts;
s32 sampleBankId1;
s32 sampleBankId2;
@ -1529,7 +1534,7 @@ void AudioHeap_DiscardSampleBanks(void) {
}
}
void AudioHeap_SetReverbData(s32 reverbIndex, u32 dataType, s32 data, s32 isFirstInit) {
void AudioHeap_SetReverbData(s32 reverbIndex, u32 dataType, uintptr_t data, s32 isFirstInit) {
s32 delayNumSamples;
SynthesisReverb* reverb = &gAudioCtx.synthesisReverbs[reverbIndex];

View File

@ -13,6 +13,8 @@
#include "global.h"
#include "buffers.h"
#include <string.h>
#include <stdlib.h>
/**
* SoundFont Notes:
*
@ -57,11 +59,18 @@ void AudioLoad_ProcessAsyncLoad(AudioAsyncLoad* asyncLoad, s32 resetStatus);
void AudioLoad_AsyncDma(AudioAsyncLoad* asyncLoad, size_t size);
void AudioLoad_AsyncDmaRamUnloaded(AudioAsyncLoad* asyncLoad, size_t size);
void AudioLoad_AsyncDmaUnkMedium(uintptr_t devAddr, void* ramAddr, size_t size, s16 arg3);
void AudioLoad_RelocateSample(TunedSample* tunedSample, SoundFontData* fontData, SampleBankRelocInfo* sampleBankReloc);
void AudioLoad_RelocateSample(TunedSample* tunedSample, SoundFontData* fontData, SampleBankRelocInfo* sampleBankReloc,
int fontId);
void AudioLoad_RelocateFontAndPreloadSamples(s32 fontId, SoundFontData* fontData, SampleBankRelocInfo* sampleBankReloc,
s32 isAsync);
s32 AudioLoad_ProcessSamplePreloads(s32 resetStatus);
SequenceData ResourceMgr_LoadSeqByName(const char* path);
SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path);
// TODO: what's that for? it seems to rely on an uninitizalied variable in soh
static uint32_t fontOffsets[8192];
#define MK_ASYNC_MSG(retData, tableType, id, loadStatus) \
(((retData) << 24) | ((tableType) << 16) | ((id) << 8) | (loadStatus))
@ -95,6 +104,11 @@ DmaHandler sDmaHandler; //= osEPiStartDma;
void* sUnusedHandler = NULL;
s32 gAudioCtxInitalized = false;
char** gSequenceToResource;
size_t gSequenceToResourceSize;
u8 seqCachePolicyMap[MAX_AUTHENTIC_SEQID];
char* gFontToResource[256];
void AudioLoad_DecreaseSampleDmaTtls(void) {
u32 i;
@ -487,17 +501,26 @@ void AudioLoad_AsyncLoadFont(s32 fontId, s32 arg1, s32 retData, OSMesgQueue* ret
AudioLoad_AsyncLoad(FONT_TABLE, fontId, 0, retData, retQueue);
}
u8* AudioLoad_GetFontsForSequence(s32 seqId, u32* outNumFonts) {
// BENTODO
*outNumFonts = 0;
return NULL;
s32 index = ((u16*)gAudioCtx.sequenceFontTable)[seqId];
*outNumFonts = gAudioCtx.sequenceFontTable[index++];
if (*outNumFonts == 0) {
u8* AudioLoad_GetFontsForSequence(s32 seqId, u32* outNumFonts, u8* buff) {
if (seqId == NA_BGM_DISABLED || seqId == 0xFF) {
return NULL;
}
return &gAudioCtx.sequenceFontTable[index];
// TODO: Sequence Remplacements
if (seqId > gSequenceToResourceSize || !gSequenceToResource[seqId]) {
return NULL;
}
SequenceData seqData = ResourceMgr_LoadSeqByName(gSequenceToResource[seqId]);
*outNumFonts = seqData.numFonts;
if (seqData.numFonts == 0)
return NULL;
memcpy(buff, seqData.fonts, sizeof(seqData.fonts));
return buff;
}
void AudioLoad_DiscardSeqFonts(s32 seqId) {
@ -559,11 +582,7 @@ s32 AudioLoad_SyncInitSeqPlayer(s32 playerIndex, s32 seqId, s32 arg2) {
}
gAudioCtx.seqPlayers[playerIndex].skipTicks = 0;
AudioLoad_SyncInitSeqPlayerInternal(playerIndex, seqId, arg2);
// Intentionally missing return. Returning the result of the above function
// call matches but is UB because it too is missing a return, and using the
// result of a non-void function that has failed to return a value is UB.
// The callers of this function do not use the return value, so it's fine.
return AudioLoad_SyncInitSeqPlayerInternal(playerIndex, seqId, arg2);
}
s32 AudioLoad_SyncInitSeqPlayerSkipTicks(s32 playerIndex, s32 seqId, s32 skipTicks) {
@ -572,8 +591,7 @@ s32 AudioLoad_SyncInitSeqPlayerSkipTicks(s32 playerIndex, s32 seqId, s32 skipTic
}
gAudioCtx.seqPlayers[playerIndex].skipTicks = skipTicks;
AudioLoad_SyncInitSeqPlayerInternal(playerIndex, seqId, 0);
// Missing return, see above.
return AudioLoad_SyncInitSeqPlayerInternal(playerIndex, seqId, 0);
}
s32 AudioLoad_SyncInitSeqPlayerInternal(s32 playerIndex, s32 seqId, s32 arg2) {
@ -582,22 +600,23 @@ s32 AudioLoad_SyncInitSeqPlayerInternal(s32 playerIndex, s32 seqId, s32 arg2) {
s32 index;
s32 numFonts;
s32 fontId;
if (seqId >= gAudioCtx.numSequences) {
return 0;
}
s8 authCachePolicy = -1; // since 0 is a valid cache policy value
AudioScript_SequencePlayerDisable(seqPlayer);
if (1) {}
fontId = 0xFF;
index = ((u16*)gAudioCtx.sequenceFontTable)[seqId];
numFonts = gAudioCtx.sequenceFontTable[index++];
if (gAudioCtx.seqReplaced[playerIndex]) {
authCachePolicy = seqCachePolicyMap[seqId];
seqId = gAudioCtx.seqToPlay[playerIndex];
}
SequenceData seqData2 = ResourceMgr_LoadSeqByName(gSequenceToResource[seqId]);
if (authCachePolicy != -1) {
seqData2.cachePolicy = authCachePolicy;
}
while (numFonts > 0) {
fontId = gAudioCtx.sequenceFontTable[index++];
for (int i = 0; i < seqData2.numFonts; i++) {
fontId = seqData2.fonts[i];
AudioLoad_SyncLoadFont(fontId);
numFonts--;
}
seqData = AudioLoad_SyncLoadSeq(seqId);
@ -621,6 +640,7 @@ s32 AudioLoad_SyncInitSeqPlayerInternal(s32 playerIndex, s32 seqId, s32 arg2) {
seqPlayer->delay = 0;
seqPlayer->finished = false;
seqPlayer->playerIndex = playerIndex;
return 1;
//! @bug missing return (but the return value is not used so it's not UB)
}
@ -657,9 +677,9 @@ u32 AudioLoad_TrySyncLoadSampleBank(u32 sampleBankId, u32* outMedium, s32 noLoad
return addr;
}
cachePolicy = sampleBankTable->entries[sampleBankId].cachePolicy;
// cachePolicy = sampleBankTable->entries[sampleBankId].cachePolicy;
if ((cachePolicy == CACHE_LOAD_EITHER_NOSYNC) || (noLoad == true)) {
if (/*(cachePolicy == CACHE_LOAD_EITHER_NOSYNC) ||*/ (noLoad == true)) {
*outMedium = sampleBankTable->entries[sampleBankId].medium;
return sampleBankTable->entries[realTableId].romAddr;
}
@ -686,23 +706,24 @@ SoundFontData* AudioLoad_SyncLoadFont(u32 fontId) {
return NULL;
}
sampleBankId1 = gAudioCtx.soundFontList[realFontId].sampleBankId1;
sampleBankId2 = gAudioCtx.soundFontList[realFontId].sampleBankId2;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(gFontToResource[fontId]);
sampleBankId1 = sf->sampleBankId1;
sampleBankId2 = sf->sampleBankId2;
sampleBankReloc.sampleBankId1 = sampleBankId1;
sampleBankReloc.sampleBankId2 = sampleBankId2;
if (sampleBankReloc.sampleBankId1 != 0xFF) {
sampleBankReloc.baseAddr1 =
AudioLoad_TrySyncLoadSampleBank(sampleBankReloc.sampleBankId1, &sampleBankReloc.medium1, false);
} else {
sampleBankReloc.baseAddr1 = 0;
}
// if (sampleBankReloc.sampleBankId1 != 0xFF) {
// sampleBankReloc.baseAddr1 =
// AudioLoad_TrySyncLoadSampleBank(sampleBankReloc.sampleBankId1, &sampleBankReloc.medium1, false);
// } else {
sampleBankReloc.baseAddr1 = 0;
// }
if (sampleBankId2 != 0xFF) {
sampleBankReloc.baseAddr2 = AudioLoad_TrySyncLoadSampleBank(sampleBankId2, &sampleBankReloc.medium2, false);
} else {
sampleBankReloc.baseAddr2 = 0;
}
// if (sampleBankId2 != 0xFF) {
// sampleBankReloc.baseAddr2 = AudioLoad_TrySyncLoadSampleBank(sampleBankId2, &sampleBankReloc.medium2, false);
// } else {
sampleBankReloc.baseAddr2 = 0;
// }
fontData = AudioLoad_SyncLoad(FONT_TABLE, fontId, &didAllocate);
if (fontData == NULL) {
@ -733,12 +754,31 @@ void* AudioLoad_SyncLoad(s32 tableType, u32 id, s32* didAllocate) {
*didAllocate = false;
loadStatus = LOAD_STATUS_COMPLETE;
} else {
table = AudioLoad_GetLoadTable(tableType);
size = table->entries[realId].size;
size = ALIGN16(size);
medium = table->entries[id].medium;
cachePolicy = table->entries[id].cachePolicy;
romAddr = table->entries[realId].romAddr;
// table = AudioLoad_GetLoadTable(tableType);
// size = table->entries[realId].size;
// size = ALIGN16(size);
// medium = table->entries[id].medium;
// cachePolicy = table->entries[id].cachePolicy;
// romAddr = table->entries[realId].romAddr;
char* seqData = 0;
SoundFont* fnt;
if (tableType == SEQUENCE_TABLE) {
SequenceData sData = ResourceMgr_LoadSeqByName(gSequenceToResource[id]);
seqData = sData.seqData;
size = sData.seqDataSize;
medium = sData.medium;
cachePolicy = sData.cachePolicy;
romAddr = 0;
} else if (tableType == FONT_TABLE) {
fnt = ResourceMgr_LoadAudioSoundFont(gFontToResource[id]);
size = sizeof(SoundFont);
medium = 2;
cachePolicy = 0;
romAddr = 0;
}
switch (cachePolicy) {
case CACHE_LOAD_PERMANENT:
//! @bug UB: triggers an UB because this function is missing a return value.
@ -792,7 +832,13 @@ void* AudioLoad_SyncLoad(s32 tableType, u32 id, s32* didAllocate) {
} else if (medium2 == mediumUnk) {
AudioLoad_SyncDmaUnkMedium(romAddr, ramAddr, size, (s16)table->unkMediumParam);
} else {
AudioLoad_SyncDma(romAddr, ramAddr, size, medium);
if (tableType == SEQUENCE_TABLE && seqData != NULL) {
AudioLoad_SyncDma(seqData, ramAddr, size, medium);
} else if (tableType == FONT_TABLE) {
AudioLoad_SyncDma(fnt, ramAddr, size, medium);
} else {
// AudioLoad_SyncDma(romAddr, ret, size, medium);
}
}
loadStatus = (cachePolicy == CACHE_LOAD_PERMANENT) ? LOAD_STATUS_PERMANENT : LOAD_STATUS_COMPLETE;
@ -816,11 +862,11 @@ void* AudioLoad_SyncLoad(s32 tableType, u32 id, s32* didAllocate) {
}
u32 AudioLoad_GetRealTableIndex(s32 tableType, u32 id) {
AudioTable* table = AudioLoad_GetLoadTable(tableType);
// AudioTable* table = AudioLoad_GetLoadTable(tableType);
if (table->entries[id].size == 0) {
id = table->entries[id].romAddr;
}
// if (table->entries[id].size == 0) {
// id = table->entries[id].romAddr;
// }
return id;
}
@ -869,133 +915,81 @@ AudioTable* AudioLoad_GetLoadTable(s32 tableType) {
* @param fontDataStartAddr ram address of raw soundfont binary loaded into cache
* @param sampleBankReloc information on the sampleBank containing raw audio samples
*/
void AudioLoad_RelocateFont(s32 fontId, SoundFontData* fontDataStartAddr, SampleBankRelocInfo* sampleBankReloc) {
uintptr_t soundOffset;
uintptr_t soundListOffset;
void AudioLoad_RelocateFont(s32 fontId, SoundFontData* mem, SampleBankRelocInfo* relocInfo) {
uintptr_t reloc;
uintptr_t reloc2;
Instrument* inst;
Drum* drum;
SoundEffect* soundEffect;
TunedSample* sfx;
s32 i;
s32 numDrums = gAudioCtx.soundFontList[fontId].numDrums;
s32 numInstruments = gAudioCtx.soundFontList[fontId].numInstruments;
s32 numSfx = gAudioCtx.soundFontList[fontId].numSfx;
u32* fontData = (u32*)fontDataStartAddr;
SoundFont* sf = NULL;
s32 numDrums = 0;
s32 numInstruments = 0;
s32 numSfx = 0;
// Relocate an offset (relative to the start of the font data) to a pointer (a ram address)
#define RELOC_TO_RAM(x) (void*)((uintptr_t)(x) + (uintptr_t)(fontDataStartAddr))
sf = ResourceMgr_LoadAudioSoundFont(gFontToResource[fontId]);
numDrums = sf->numDrums;
numInstruments = sf->numInstruments;
numSfx = sf->numSfx;
// Drums relocation
void** ptrs = (void**)mem;
// The first u32 in fontData is an offset to a list of offsets to the drums
soundListOffset = fontData[0];
#define BASE_OFFSET(x) (void*)((uintptr_t)(x) + (uintptr_t)(mem))
// If the soundFont has drums
if ((soundListOffset != 0) && (numDrums != 0)) {
fontData[0] = RELOC_TO_RAM(soundListOffset);
// Loop through the drum offsets
reloc2 = ptrs[0];
if ((numDrums != 0)) {
ptrs[0] = BASE_OFFSET(reloc2);
for (i = 0; i < numDrums; i++) {
// Get the i'th drum offset
soundOffset = ((Drum**)fontData[0])[i];
drum = sf->drums[i];
// Some drum data entries are empty, represented by an offset of 0 in the list of drum offsets
if (soundOffset == 0) {
continue;
if (!drum->isRelocated) {
AudioLoad_RelocateSample(&sf->drums[i]->tunedSample, mem, relocInfo, fontOffsets[fontId]);
drum->isRelocated = 1;
}
soundOffset = RELOC_TO_RAM(soundOffset);
((Drum**)fontData[0])[i] = drum = soundOffset;
// The drum may be in the list multiple times and already relocated
if (drum->isRelocated) {
continue;
}
AudioLoad_RelocateSample(&drum->tunedSample, fontDataStartAddr, sampleBankReloc);
soundOffset = drum->envelope;
drum->envelope = RELOC_TO_RAM(soundOffset);
drum->isRelocated = true;
}
}
// Sound effects relocation
// The second u32 in fontData is an offset to the first sound effect entry
soundListOffset = fontData[1];
// If the soundFont has sound effects
if ((soundListOffset != 0) && (numSfx != 0)) {
fontData[1] = RELOC_TO_RAM(soundListOffset);
// Loop through the sound effects
reloc2 = ptrs[1];
if (numSfx != 0) {
ptrs[1] = BASE_OFFSET(reloc2);
for (i = 0; i < numSfx; i++) {
// Get a pointer to the i'th sound effect
soundOffset = (TunedSample*)fontData[1] + i;
soundEffect = (SoundEffect*)soundOffset;
// Check for NULL (note: the pointer is guaranteed to be in fontData and can never be NULL)
if ((soundEffect == NULL) || (soundEffect->tunedSample.sample == NULL)) {
continue;
}
AudioLoad_RelocateSample(&soundEffect->tunedSample, fontDataStartAddr, sampleBankReloc);
reloc = (TunedSample*)ptrs[1] + i;
AudioLoad_RelocateSample(&sf->soundEffects[i].tunedSample, mem, relocInfo, fontOffsets[fontId]);
}
}
// Instruments relocation
// Instrument Id 126 and above is reserved.
// There can only be 126 instruments, indexed from 0 to 125
if (numInstruments > 126) {
numInstruments = 126;
if (numInstruments > 0x7E) {
numInstruments = 0x7E;
}
// Starting from the 3rd u32 in fontData is the list of offsets to the instruments
// Loop through the instruments
for (i = 2; i <= 2 + numInstruments - 1; i++) {
// Some instrument data entries are empty, represented by an offset of 0 in the list of instrument offsets
if (fontData[i] != 0) {
fontData[i] = RELOC_TO_RAM(fontData[i]);
inst = (Instrument*)fontData[i];
int startI = 0;
int startEC = numInstruments - 1;
for (i = startI; i <= startEC; i++) {
ptrs[i] = BASE_OFFSET(ptrs[i]);
inst = sf->instruments[i];
// The instrument may be in the list multiple times and already relocated
if (!inst->isRelocated) {
// Some instruments have a different sample for low pitches
if (inst->normalRangeLo != 0) {
AudioLoad_RelocateSample(&inst->lowPitchTunedSample, fontDataStartAddr, sampleBankReloc);
}
// Every instrument has a sample for the default range
AudioLoad_RelocateSample(&inst->normalPitchTunedSample, fontDataStartAddr, sampleBankReloc);
// Some instruments have a different sample for high pitches
if (inst->normalRangeHi != 0x7F) {
AudioLoad_RelocateSample(&inst->highPitchTunedSample, fontDataStartAddr, sampleBankReloc);
}
soundOffset = inst->envelope;
inst->envelope = (EnvelopePoint*)RELOC_TO_RAM(soundOffset);
inst->isRelocated = true;
if (inst != NULL && !inst->isRelocated) {
if (inst->normalRangeLo != 0) {
AudioLoad_RelocateSample(&inst->lowPitchTunedSample, mem, relocInfo, fontOffsets[fontId]);
}
AudioLoad_RelocateSample(&inst->normalPitchTunedSample, mem, relocInfo, fontOffsets[fontId]);
if (inst->normalRangeHi != 0x7F) {
AudioLoad_RelocateSample(&inst->highPitchTunedSample, mem, relocInfo, fontOffsets[fontId]);
}
reloc = inst->envelope;
inst->isRelocated = 1;
}
}
#undef RELOC_TO_RAM
// Store the relocated pointers
gAudioCtx.soundFontList[fontId].drums = (Drum**)fontData[0];
gAudioCtx.soundFontList[fontId].soundEffects = (SoundEffect*)fontData[1];
gAudioCtx.soundFontList[fontId].instruments = (Instrument**)(&fontData[2]);
#undef BASE_OFFSET
}
void AudioLoad_SyncDma(uintptr_t devAddr, u8* ramAddr, size_t size, s32 medium) {
OSMesgQueue* msgQueue = &gAudioCtx.syncDmaQueue;
OSIoMesg* ioMesg = &gAudioCtx.syncDmaIoMesg;
size = ALIGN16(size);
//size = ALIGN16(size);
Audio_InvalDCache(ramAddr, size);
@ -1021,38 +1015,12 @@ void AudioLoad_SyncDmaUnkMedium(uintptr_t devAddr, u8* ramAddr, size_t size, s32
s32 AudioLoad_Dma(OSIoMesg* mesg, u32 priority, s32 direction, uintptr_t devAddr, void* ramAddr, size_t size,
OSMesgQueue* reqQueue, s32 medium, const char* dmaFuncType) {
OSPiHandle* handle;
if (gAudioCtx.resetTimer > 16) {
// TODO: what's that for?
if (gAudioCtx.resetTimer > 0x10) {
return -1;
}
switch (medium) {
case MEDIUM_CART:
handle = gAudioCtx.cartHandle;
break;
case MEDIUM_DISK_DRIVE:
// driveHandle is uninitialized and corresponds to stubbed-out disk drive support.
// SM64 Shindou called osDriveRomInit here.
handle = gAudioCtx.driveHandle;
break;
default:
return 0;
}
if ((size % 0x10) != 0) {
size = ALIGN16(size);
}
mesg->hdr.pri = priority;
mesg->hdr.retQueue = reqQueue;
mesg->dramAddr = ramAddr;
mesg->devAddr = devAddr;
mesg->size = size;
handle->transferInfo.cmdType = 2;
sDmaHandler(handle, mesg, direction);
memcpy(ramAddr, devAddr, size);
return 0;
}
@ -1232,11 +1200,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioCtx.resetTimer = 0;
gAudioCtx.unk_29B8 = false;
// Set all of gAudioCtx to 0
audioCtxPtr = (u8*)&gAudioCtx;
for (j = sizeof(gAudioCtx); j >= 0; j--) {
*audioCtxPtr++ = 0;
}
memset(&gAudioCtx, 0, sizeof(gAudioCtx));
switch (osTvType) {
case OS_TV_PAL:
@ -1303,28 +1267,52 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
}
// Connect audio tables to their tables in memory
gAudioCtx.sequenceTable = (AudioTable*)gSequenceTable;
gAudioCtx.soundFontTable = (AudioTable*)gSoundFontTable;
gAudioCtx.sampleBankTable = (AudioTable*)gSampleBankTable;
gAudioCtx.sequenceFontTable = gSequenceFontTable;
gAudioCtx.numSequences = gAudioCtx.sequenceTable->numEntries;
// gAudioCtx.sequenceTable = (AudioTable*)gSequenceTable;
// gAudioCtx.soundFontTable = (AudioTable*)gSoundFontTable;
// gAudioCtx.sampleBankTable = (AudioTable*)gSampleBankTable;
// gAudioCtx.sequenceFontTable = gSequenceFontTable;
// gAudioCtx.numSequences = gAudioCtx.sequenceTable->numEntries;
gAudioCtx.specId = 0;
gAudioCtx.resetStatus = 1; // Set reset to immediately initialize the audio heap
AudioHeap_ResetStep();
// Initialize audio tables
AudioLoad_InitTable(gAudioCtx.sequenceTable, SEGMENT_ROM_START(Audioseq), 0);
AudioLoad_InitTable(gAudioCtx.soundFontTable, SEGMENT_ROM_START(Audiobank), 0);
AudioLoad_InitTable(gAudioCtx.sampleBankTable, SEGMENT_ROM_START(Audiotable), 0);
// AudioLoad_InitTable(gAudioCtx.sequenceTable, SEGMENT_ROM_START(Audioseq), 0);
// AudioLoad_InitTable(gAudioCtx.soundFontTable, SEGMENT_ROM_START(Audiobank), 0);
// AudioLoad_InitTable(gAudioCtx.sampleBankTable, SEGMENT_ROM_START(Audiotable), 0);
numFonts = gAudioCtx.soundFontTable->numEntries;
int seqListSize = 0;
char** seqList = ResourceMgr_ListFiles("audio/sequences*", &seqListSize);
gSequenceToResourceSize = seqListSize;
gSequenceToResource = malloc(gSequenceToResourceSize * sizeof(*gSequenceToResource));
gAudioCtx.seqLoadStatus = malloc(gSequenceToResourceSize * sizeof(*gAudioCtx.seqLoadStatus));
for (size_t i = 0; i < seqListSize; i++) {
SequenceData sDat = ResourceMgr_LoadSeqByName(seqList[i]);
char* seqName = strdup(seqList[i]);
gSequenceToResource[sDat.seqNumber] = seqName;
seqCachePolicyMap[sDat.seqNumber] = sDat.cachePolicy;
}
free(seqList);
int fntListSize = 0;
char** fntList = ResourceMgr_ListFiles("audio/fonts*", &fntListSize);
for (int i = 0; i < fntListSize; i++) {
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fntList[i]);
gFontToResource[sf->fntIndex] = strdup(fntList[i]);
}
free(fntList);
numFonts = fntListSize;
gAudioCtx.soundFontList = AudioHeap_Alloc(&gAudioCtx.initPool, numFonts * sizeof(SoundFont));
for (i = 0; i < numFonts; i++) {
AudioLoad_InitSoundFont(i);
}
// for (i = 0; i < numFonts; i++) {
// AudioLoad_InitSoundFont(i);
// }
if (addr = AudioHeap_Alloc(&gAudioCtx.initPool, gAudioHeapInitSizes.permanentPoolSize), addr == NULL) {
// cast away const from gAudioHeapInitSizes
@ -1518,14 +1506,16 @@ s32 AudioLoad_SlowLoadSeq(s32 seqId, u8* ramAddr, s8* isDone) {
slowLoad->sample.sampleAddr = NULL;
slowLoad->isDone = isDone;
size = seqTable->entries[seqId].size;
size = ALIGN16(size);
SequenceData sData = ResourceMgr_LoadSeqByName(gSequenceToResource[seqId]);
size = sData.seqDataSize;
slowLoad->curDevAddr = sData.seqData;
slowLoad->medium = seqTable->entries[seqId].medium;
slowLoad->curRamAddr = ramAddr;
slowLoad->status = LOAD_STATUS_START;
slowLoad->bytesRemaining = size;
slowLoad->ramAddr = ramAddr;
slowLoad->curDevAddr = seqTable->entries[seqId].romAddr;
slowLoad->medium = seqTable->entries[seqId].medium;
slowLoad->seqOrFontId = seqId;
if (slowLoad->medium == MEDIUM_UNK) {
@ -1763,52 +1753,8 @@ void AudioLoad_AsyncDmaUnkMedium(uintptr_t devAddr, void* ramAddr, size_t size,
* @param fontData ram address of raw soundfont binary loaded into cache
* @param sampleBankReloc information on the sampleBank containing raw audio samples
*/
void AudioLoad_RelocateSample(TunedSample* tunedSample, SoundFontData* fontData, SampleBankRelocInfo* sampleBankReloc) {
Sample* sample;
void* reloc;
// Relocate an offset (relative to data loaded in ram at `base`) to a pointer (a ram address)
#define AUDIO_RELOC(v, base) (reloc = (void*)((uintptr_t)(v) + (uintptr_t)(base)))
if ((uintptr_t)tunedSample->sample <= AUDIO_RELOCATED_ADDRESS_START) {
sample = tunedSample->sample = AUDIO_RELOC(tunedSample->sample, fontData);
// If the sample exists and has not already been relocated
// Note: this is important, as the same sample can be used by different drums, sound effects, instruments
if ((sample->size != 0) && (sample->isRelocated != true)) {
sample->loop = AUDIO_RELOC(sample->loop, fontData);
sample->book = AUDIO_RELOC(sample->book, fontData);
// Resolve the sample medium 2-bit bitfield into a real value based on sampleBankReloc.
// Then relocate the offset sample within the sampleBank (not the fontData) into absolute address.
// sampleAddr can be either rom or ram depending on sampleBank cache policy
// in practice, this is always in rom
switch (sample->medium) {
case 0:
sample->sampleAddr = AUDIO_RELOC(sample->sampleAddr, sampleBankReloc->baseAddr1);
sample->medium = sampleBankReloc->medium1;
break;
case 1:
sample->sampleAddr = AUDIO_RELOC(sample->sampleAddr, sampleBankReloc->baseAddr2);
sample->medium = sampleBankReloc->medium2;
break;
case 2:
case 3:
// Invalid? This leaves sample->medium as MEDIUM_CART and MEDIUM_DISK_DRIVE
// respectively, and the sampleAddr unrelocated.
break;
}
sample->isRelocated = true;
if (sample->unk_bit26 && (sample->medium != MEDIUM_RAM)) {
gAudioCtx.usedSamples[gAudioCtx.numUsedSamples++] = sample;
}
}
}
void AudioLoad_RelocateSample(TunedSample* tunedSample, SoundFontData* fontData, SampleBankRelocInfo* sampleBankReloc,
int fontId) {
}
#undef AUDIO_RELOC
@ -2047,7 +1993,7 @@ s32 AudioLoad_GetSamplesForFont(s32 fontId, Sample** sampleSet) {
void AudioLoad_AddUsedSample(TunedSample* tunedSample) {
Sample* sample = tunedSample->sample;
if ((sample->size != 0) && (sample->unk_bit26) && (sample->medium != MEDIUM_RAM)) {
if (sample && (sample->size != 0) && (sample->unk_bit26) && (sample->medium != MEDIUM_RAM)) {
gAudioCtx.usedSamples[gAudioCtx.numUsedSamples++] = sample;
}
}
@ -2075,9 +2021,10 @@ void AudioLoad_PreloadSamplesForFont(s32 fontId, s32 async, SampleBankRelocInfo*
gAudioCtx.numUsedSamples = 0;
numDrums = gAudioCtx.soundFontList[fontId].numDrums;
numInstruments = gAudioCtx.soundFontList[fontId].numInstruments;
numSfx = gAudioCtx.soundFontList[fontId].numSfx;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(gFontToResource[fontId]);
numDrums = sf->numDrums;
numInstruments = sf->numInstruments;
numSfx = sf->numSfx;
for (i = 0; i < numInstruments; i++) {
instrument = AudioPlayback_GetInstrumentInner(fontId, i);
@ -2194,26 +2141,30 @@ void AudioLoad_LoadPermanentSamples(void) {
s32 pad2;
s32 i;
sampleBankTable = AudioLoad_GetLoadTable(SAMPLE_TABLE);
// sampleBankTable = AudioLoad_GetLoadTable(SAMPLE_TABLE);
for (i = 0; i < gAudioCtx.permanentPool.count; i++) {
SampleBankRelocInfo sampleBankReloc;
if (gAudioCtx.permanentEntries[i].tableType == FONT_TABLE) {
fontId = AudioLoad_GetRealTableIndex(FONT_TABLE, gAudioCtx.permanentEntries[i].id);
sampleBankReloc.sampleBankId1 = gAudioCtx.soundFontList[fontId].sampleBankId1;
sampleBankReloc.sampleBankId2 = gAudioCtx.soundFontList[fontId].sampleBankId2;
if (sampleBankReloc.sampleBankId1 != 0xFF) {
sampleBankReloc.sampleBankId1 =
AudioLoad_GetRealTableIndex(SAMPLE_TABLE, sampleBankReloc.sampleBankId1);
sampleBankReloc.medium1 = sampleBankTable->entries[sampleBankReloc.sampleBankId1].medium;
}
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(gFontToResource[fontId]);
sampleBankReloc.sampleBankId1 = sf->sampleBankId1;
sampleBankReloc.sampleBankId2 = sf->sampleBankId2;
// sampleBankReloc.sampleBankId1 = gAudioCtx.soundFontList[fontId].sampleBankId1;
// sampleBankReloc.sampleBankId2 = gAudioCtx.soundFontList[fontId].sampleBankId2;
if (sampleBankReloc.sampleBankId2 != 0xFF) {
sampleBankReloc.sampleBankId2 =
AudioLoad_GetRealTableIndex(SAMPLE_TABLE, sampleBankReloc.sampleBankId2);
sampleBankReloc.medium2 = sampleBankTable->entries[sampleBankReloc.sampleBankId2].medium;
}
// if (sampleBankReloc.sampleBankId1 != 0xFF) {
// sampleBankReloc.sampleBankId1 =
// AudioLoad_GetRealTableIndex(SAMPLE_TABLE, sampleBankReloc.sampleBankId1);
// sampleBankReloc.medium1 = sampleBankTable->entries[sampleBankReloc.sampleBankId1].medium;
// }
// if (sampleBankReloc.sampleBankId2 != 0xFF) {
// sampleBankReloc.sampleBankId2 =
// AudioLoad_GetRealTableIndex(SAMPLE_TABLE, sampleBankReloc.sampleBankId2);
// sampleBankReloc.medium2 = sampleBankTable->entries[sampleBankReloc.sampleBankId2].medium;
// }
AudioLoad_PreloadSamplesForFont(fontId, false, &sampleBankReloc);
}
}

View File

@ -5,6 +5,10 @@ void AudioPlayback_NoteSetResamplingRate(NoteSampleState* sampleState, f32 resam
void AudioPlayback_AudioListPushFront(AudioListItem* list, AudioListItem* item);
void AudioPlayback_NoteInitForLayer(Note* note, SequenceLayer* layer);
SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path);
extern char* gFontToResource[256];
void AudioPlayback_InitSampleState(Note* note, NoteSampleState* sampleState, NoteSubAttributes* subAttrs) {
f32 volLeft;
f32 volRight;
@ -104,8 +108,9 @@ void AudioPlayback_InitSampleState(Note* note, NoteSampleState* sampleState, Not
vel = 0.0f > vel ? 0.0f : vel;
vel = 1.0f < vel ? 1.0f : vel;
sampleState->targetVolLeft = (s32)((vel * volLeft) * (0x1000 - 0.001f));
sampleState->targetVolRight = (s32)((vel * volRight) * (0x1000 - 0.001f));
float master_vol = CVarGetFloat("gGameMasterVolume", 1.0f);
sampleState->targetVolLeft = (s32)((vel * volLeft) * (0x1000 - 0.001f)) * master_vol;
sampleState->targetVolRight = (s32)((vel * volRight) * (0x1000 - 0.001f)) * master_vol;
sampleState->gain = subAttrs->gain;
sampleState->filter = subAttrs->filter;
@ -179,7 +184,11 @@ void AudioPlayback_ProcessNotes(void) {
sampleState = &gAudioCtx.sampleStateList[gAudioCtx.sampleStateOffset + i];
playbackState = &note->playbackState;
if (playbackState->parentLayer != NO_LAYER) {
if ((u32)playbackState->parentLayer < 0x7FFFFFFF) {
// OTRTODO: This skips playback if the pointer is below where memory on the N64 normally would be.
// This does not translate well to modern platforms and how they map memory.
// Considering that this check is not present in OoT/SoH, we may be able to remove this altogether.
if ((uintptr_t)playbackState->parentLayer < 0x7FFFFFFF) {
continue;
}
@ -355,12 +364,14 @@ Instrument* AudioPlayback_GetInstrumentInner(s32 fontId, s32 instId) {
return NULL;
}
if (instId >= gAudioCtx.soundFontList[fontId].numInstruments) {
gAudioCtx.audioErrorFlags = AUDIO_ERROR(fontId, instId, AUDIO_ERROR_INVALID_INST_ID);
return NULL;
}
int instCnt = 0;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(gFontToResource[fontId]);
if (instId >= sf->numInstruments)
return NULL;
inst = sf->instruments[instId];
inst = gAudioCtx.soundFontList[fontId].instruments[instId];
if (inst == NULL) {
gAudioCtx.audioErrorFlags = AUDIO_ERROR(fontId, instId, AUDIO_ERROR_NO_INST);
return inst;
@ -381,14 +392,10 @@ Drum* AudioPlayback_GetDrum(s32 fontId, s32 drumId) {
return NULL;
}
if (drumId >= gAudioCtx.soundFontList[fontId].numDrums) {
gAudioCtx.audioErrorFlags = AUDIO_ERROR(fontId, drumId, AUDIO_ERROR_INVALID_DRUM_SFX_ID);
return NULL;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(gFontToResource[fontId]);
if (drumId < sf->numDrums) {
drum = sf->drums[drumId];
}
if ((u32)gAudioCtx.soundFontList[fontId].drums < AUDIO_RELOCATED_ADDRESS_START) {
return NULL;
}
drum = gAudioCtx.soundFontList[fontId].drums[drumId];
if (drum == NULL) {
gAudioCtx.audioErrorFlags = AUDIO_ERROR(fontId, drumId, AUDIO_ERROR_NO_DRUM_SFX);
@ -409,22 +416,16 @@ SoundEffect* AudioPlayback_GetSoundEffect(s32 fontId, s32 sfxId) {
return NULL;
}
if (sfxId >= gAudioCtx.soundFontList[fontId].numSfx) {
gAudioCtx.audioErrorFlags = AUDIO_ERROR(fontId, sfxId, AUDIO_ERROR_INVALID_DRUM_SFX_ID);
return NULL;
SoundFont* sf = ResourceMgr_LoadAudioSoundFont(gFontToResource[fontId]);
if (sfxId < sf->numSfx) {
soundEffect = &sf->soundEffects[sfxId];
}
if ((u32)gAudioCtx.soundFontList[fontId].soundEffects < AUDIO_RELOCATED_ADDRESS_START) {
return NULL;
}
soundEffect = &gAudioCtx.soundFontList[fontId].soundEffects[sfxId];
if (soundEffect == NULL) {
gAudioCtx.audioErrorFlags = AUDIO_ERROR(fontId, sfxId, AUDIO_ERROR_NO_DRUM_SFX);
}
if (soundEffect->tunedSample.sample == NULL) {
if (soundEffect != NULL && soundEffect->tunedSample.sample == NULL) {
return NULL;
}

View File

@ -13,6 +13,8 @@
* - All three sets share a common pool of control flow instructions (>= 0xF2).
* Otherwise, each set of instructions has its own command interpreter
*/
#include "endianness.h"
#include "global.h"
#define PROCESS_SCRIPT_END -1
@ -27,6 +29,9 @@ s32 AudioScript_SeqLayerProcessScriptStep4(SequenceLayer* layer, s32 cmd);
s32 AudioScript_SeqLayerProcessScriptStep3(SequenceLayer* layer, s32 cmd);
u8 AudioScript_GetInstrument(SequenceChannel* channel, u8 instId, Instrument** instOut, AdsrSettings* adsr);
SequenceData ResourceMgr_LoadSeqByName(const char* path);
extern char** gSequenceToResource;
/**
* sSeqInstructionArgsTable is a table for each sequence instruction
* that contains both how many arguments an instruction takes, as well
@ -1414,9 +1419,19 @@ void AudioScript_SequenceChannelProcessScript(SequenceChannel* channel) {
cmd = (u8)cmdArgs[0];
if (seqPlayer->defaultFont != 0xFF) {
cmdArgU16 = ((u16*)gAudioCtx.sequenceFontTable)[seqPlayer->seqId];
lowBits = gAudioCtx.sequenceFontTable[cmdArgU16];
cmd = gAudioCtx.sequenceFontTable[cmdArgU16 + lowBits - cmd];
if (gAudioCtx.seqReplaced[seqPlayer->playerIndex]) {
seqPlayer->seqId = gAudioCtx.seqToPlay[seqPlayer->playerIndex];
gAudioCtx.seqReplaced[seqPlayer->playerIndex] = 0;
}
u16 seqId = seqPlayer->seqId; // AudioEditor_GetReplacementSeq(seqPlayer->seqId);
SequenceData sDat = ResourceMgr_LoadSeqByName(gSequenceToResource[seqId]);
// The game apparantely would sometimes do negative array lookups, the result of which would get
// rejected by AudioHeap_SearchCaches, never changing the actual fontid.
if (cmd > sDat.numFonts)
break;
cmd = sDat.fonts[(sDat.numFonts - cmd - 1)];
}
if (AudioHeap_SearchCaches(FONT_TABLE, CACHE_EITHER, cmd)) {
@ -1597,7 +1612,7 @@ void AudioScript_SequenceChannelProcessScript(SequenceChannel* channel) {
case 0xB2: // channel: dynread sequence large
cmdArgU16 = (u16)cmdArgs[0];
channel->unk_22 = *(u16*)(seqPlayer->seqData + (u32)(cmdArgU16 + scriptState->value * 2));
channel->unk_22 = BE16SWAP(*(u16*)(seqPlayer->seqData + (u32)(cmdArgU16 + scriptState->value * 2)));
break;
case 0xB4: // channel: set dyntable large
@ -1605,7 +1620,7 @@ void AudioScript_SequenceChannelProcessScript(SequenceChannel* channel) {
break;
case 0xB5: // channel: read dyntable large
channel->unk_22 = ((u16*)(channel->dynTable))[scriptState->value];
channel->unk_22 = BE16SWAP(((u16*)(channel->dynTable))[scriptState->value]);
break;
case 0xB6: // channel: read dyntable

View File

@ -1,4 +1,6 @@
#include "global.h"
#include "resourcebridge.h"
#include "2s2h/mixer.h"
// DMEM Addresses for the RSP
#define DMEM_TEMP 0x3B0
@ -353,9 +355,9 @@ void AudioSynth_Noop9(void) {
}
void AudioSynth_DMemMove(Acmd* cmd, s32 dmemIn, s32 dmemOut, size_t size) {
// aDMEMMove(cmd, dmemIn, dmemOut, size);
cmd->words.w0 = _SHIFTL(A_DMEMMOVE, 24, 8) | _SHIFTL(dmemIn, 0, 24);
cmd->words.w1 = _SHIFTL(dmemOut, 16, 16) | _SHIFTL(size, 0, 16);
aDMEMMove(cmd, dmemIn, dmemOut, size);
//cmd->words.w0 = _SHIFTL(A_DMEMMOVE, 24, 8) | _SHIFTL(dmemIn, 0, 24);
//cmd->words.w1 = _SHIFTL(dmemOut, 16, 16) | _SHIFTL(size, 0, 16);
}
void AudioSynth_Noop10(void) {
@ -371,9 +373,9 @@ void AudioSynth_Noop13(void) {
}
void AudioSynth_InterL(Acmd* cmd, s32 dmemIn, s32 dmemOut, s32 numSamples) {
// aInterl(cmd, dmemIn, dmemOut, numSamples);
cmd->words.w0 = _SHIFTL(A_INTERL, 24, 8) | _SHIFTL(numSamples, 0, 16);
cmd->words.w1 = _SHIFTL(dmemIn, 16, 16) | _SHIFTL(dmemOut, 0, 16);
aInterl(cmd, dmemIn, dmemOut, numSamples);
// cmd->words.w0 = _SHIFTL(A_INTERL, 24, 8) | _SHIFTL(numSamples, 0, 16);
// cmd->words.w1 = _SHIFTL(dmemIn, 16, 16) | _SHIFTL(dmemOut, 0, 16);
}
void AudioSynth_EnvSetup1(Acmd* cmd, s32 reverbVol, s32 rampReverb, s32 rampLeft, s32 rampRight) {
@ -392,9 +394,9 @@ void AudioSynth_SaveBuffer(Acmd* cmd, s32 dmemSrc, s32 size, void* addrDest) {
}
void AudioSynth_EnvSetup2(Acmd* cmd, s32 volLeft, s32 volRight) {
// aEnvSetup2(cmd, volLeft, volRight);
cmd->words.w0 = _SHIFTL(A_ENVSETUP2, 24, 8);
cmd->words.w1 = _SHIFTL(volLeft, 16, 16) | _SHIFTL(volRight, 0, 16);
aEnvSetup2(cmd, volLeft, volRight);
// cmd->words.w0 = _SHIFTL(A_ENVSETUP2, 24, 8);
// cmd->words.w1 = _SHIFTL(volLeft, 16, 16) | _SHIFTL(volRight, 0, 16);
}
void AudioSynth_Noop15(void) {
@ -411,15 +413,16 @@ void AudioSynth_S8Dec(Acmd* cmd, s32 flags, s16* state) {
}
void AudioSynth_HiLoGain(Acmd* cmd, s32 gain, s32 dmemIn, s32 dmemOut, s32 size) {
// aHiLoGain(cmd, gain, size, dmemIn, dmemOut);
cmd->words.w0 = _SHIFTL(A_HILOGAIN, 24, 8) | _SHIFTL(gain, 16, 8) | _SHIFTL(size, 0, 16);
cmd->words.w1 = _SHIFTL(dmemIn, 16, 16) | _SHIFTL(dmemOut, 0, 16);
aHiLoGain(cmd, gain, size, dmemIn, dmemOut);
// cmd->words.w0 = _SHIFTL(A_HILOGAIN, 24, 8) | _SHIFTL(gain, 16, 8) | _SHIFTL(size, 0, 16);
// cmd->words.w1 = _SHIFTL(dmemIn, 16, 16) | _SHIFTL(dmemOut, 0, 16);
}
// Remnant of OoT
void AudioSynth_UnkCmd19(Acmd* cmd, s32 dmem1, s32 dmem2, s32 size, s32 arg4) {
cmd->words.w0 = _SHIFTL(A_SPNOOP, 24, 8) | _SHIFTL(arg4, 16, 8) | _SHIFTL(size, 0, 16);
cmd->words.w1 = _SHIFTL(dmem1, 16, 16) | _SHIFTL(dmem2, 0, 16);
aUnkCmd19(cmd, dmem1, dmem2, size, arg4);
// cmd->words.w0 = _SHIFTL(A_SPNOOP, 24, 8) | _SHIFTL(arg4, 16, 8) | _SHIFTL(size, 0, 16);
// cmd->words.w1 = _SHIFTL(dmem1, 16, 16) | _SHIFTL(dmem2, 0, 16);
}
void AudioSynth_Noop18(void) {
@ -614,7 +617,7 @@ Acmd* AudioSynth_LoadSubReverbSamples(Acmd* cmd, s32 numSamplesPerUpdate, Synthe
Acmd* AudioSynth_SaveResampledReverbSamplesImpl(Acmd* cmd, u16 dmem, u16 size, uintptr_t startAddr) {
s32 startAddrAlignDropped;
u32 endAddr;
uintptr_t endAddr;
s32 endAddrAlignDropped;
endAddr = startAddr + size;
@ -1028,6 +1031,7 @@ Acmd* AudioSynth_ProcessSample(s32 noteIndex, NoteSampleState* sampleState, Note
}
numEntries = SAMPLES_PER_FRAME * sample->book->order * sample->book->numPredictors;
//ResourceCheckSample(sample->sampleAddr, sample->book->codeBook);
aLoadADPCM(cmd++, numEntries, gAudioCtx.adpcmCodeBook);
}
}
@ -1169,10 +1173,8 @@ Acmd* AudioSynth_ProcessSample(s32 noteIndex, NoteSampleState* sampleState, Note
return cmd;
} else {
// This medium is not in ram, so dma the requested sample into ram
samplesToLoadAddr =
AudioLoad_DmaSampleData((uintptr_t)(sampleAddr + (zeroOffset + sampleAddrOffset)),
ALIGN16((numFramesToDecode * frameSize) + SAMPLES_PER_FRAME), flags,
&synthState->sampleDmaIndex, sample->medium);
// BEN: Assume all samples are in RAM... because they are.
samplesToLoadAddr = sampleAddr + (zeroOffset + sampleAddrOffset);
}
if (samplesToLoadAddr == NULL) {
@ -1182,9 +1184,16 @@ Acmd* AudioSynth_ProcessSample(s32 noteIndex, NoteSampleState* sampleState, Note
// Move the raw sample chunk from ram to the rsp
// DMEM at the addresses before DMEM_COMPRESSED_ADPCM_DATA
sampleDataChunkAlignPad = (u32)samplesToLoadAddr & 0xF;
sampleDataChunkAlignPad = (uintptr_t)samplesToLoadAddr & 0xF;
sampleDataChunkSize = ALIGN16((numFramesToDecode * frameSize) + SAMPLES_PER_FRAME);
sampleDataDmemAddr = DMEM_COMPRESSED_ADPCM_DATA - sampleDataChunkSize;
// BEN: This will crash the asan. We can just ignore alignment since we don't have those strictures.
//if (sampleDataChunkSize + sampleAddrOffset > sample->size) {
// sampleDataChunkSize = sample->size - sampleAddrOffset;
// sampleDataDmemAddr = DMEM_COMPRESSED_ADPCM_DATA - sampleDataChunkSize;
//}
aLoadBuffer(cmd++, samplesToLoadAddr - sampleDataChunkAlignPad, sampleDataDmemAddr,
sampleDataChunkSize);
} else {
@ -1691,7 +1700,8 @@ Acmd* AudioSynth_ApplyHaasEffect(Acmd* cmd, NoteSampleState* sampleState, NoteSy
ALIGN16(haasEffectDelaySize));
}
aAddMixer(cmd++, ALIGN64(size), DMEM_HAAS_TEMP, dmemDest, 0x7FFF);
aAddMixer(cmd++, ALIGN64(size), DMEM_HAAS_TEMP, dmemDest);
// aAddMixer(cmd++, ALIGN64(size), DMEM_HAAS_TEMP, dmemDest, 0x7FFF);
return cmd;
}

View File

@ -5,6 +5,7 @@
*/
#include "global.h"
#include "audio/effects.h"
#include "audio/load.h"
AudioTask* AudioThread_UpdateImpl(void);
void AudioThread_SetFadeOutTimer(s32 seqPlayerIndex, s32 fadeTimer);
@ -14,83 +15,31 @@ void AudioThread_ProcessSeqPlayerCmd(SequencePlayer* seqPlayer, AudioCmd* cmd);
void AudioThread_ProcessChannelCmd(SequenceChannel* channel, AudioCmd* cmd);
s32 AudioThread_GetSamplePos(s32 seqPlayerIndex, s32 channelIndex, s32 layerIndex, s32* loopEnd, s32* samplePosInt);
s32 AudioThread_CountAndReleaseNotes(s32 flags);
s32 AudioThread_ScheduleProcessCmds(void);
AudioTask* AudioThread_Update(void) {
return AudioThread_UpdateImpl();
}
AudioTask* AudioThread_UpdateImpl(void) {
// BENTODO
#if 0
static AudioTask* sWaitingAudioTask = NULL;
u32 numSamplesRemainingInAi;
s32 numAbiCmds;
s32 pad;
s32 j;
s32 dmaCount;
s16* curAiBuffer;
OSTask_t* task;
s32 index;
u32 msg;
s32 validCount;
s32 i;
void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples) {
// static size_t off = 0;
// f32 sample_rate = 44100;
// f32 note_freq = 440; // A4
// size_t note_period_in_samples = sample_rate / note_freq;
// for (size_t i = 0; i < num_samples; i++)
// {
// bool hi = off >= (note_period_in_samples / 2);
// s16 value = hi ? INT16_MAX / 2 : INT16_MIN / 2;
// *samples++ = value; // left
// *samples++ = value; // right
// off = (off + 1) % note_period_in_samples;
// }
// return;
OSMesg sp4C;
gAudioCtx.totalTaskCount++;
if ((gAudioCtx.totalTaskCount % gAudioCtx.audioBufferParameters.specUnk4) != 0) {
if (gAudioCustomUpdateFunction != NULL) {
gAudioCustomUpdateFunction();
}
if (((gAudioCtx.totalTaskCount % gAudioCtx.audioBufferParameters.specUnk4) + 1) ==
gAudioCtx.audioBufferParameters.specUnk4) {
return sWaitingAudioTask;
}
return NULL;
}
osSendMesg(gAudioCtx.taskStartQueueP, OS_MESG_32(gAudioCtx.totalTaskCount), OS_MESG_NOBLOCK);
gAudioCtx.rspTaskIndex ^= 1;
gAudioCtx.curAiBufferIndex++;
gAudioCtx.curAiBufferIndex %= 3;
index = (gAudioCtx.curAiBufferIndex + 1) % 3;
// Division converts size to numSamples: 2 channels (left/right) * 2 bytes per sample
numSamplesRemainingInAi = osAiGetLength() / (2 * SAMPLE_SIZE);
if (gAudioCtx.resetTimer < 16) {
if (gAudioCtx.numSamplesPerFrame[index] != 0) {
osAiSetNextBuffer(gAudioCtx.aiBuffers[index], 2 * gAudioCtx.numSamplesPerFrame[index] * (s32)SAMPLE_SIZE);
if (gAudioCtx.aiBuffers[index]) {}
if (gAudioCtx.numSamplesPerFrame[index]) {}
}
}
if (gAudioCustomUpdateFunction != NULL) {
gAudioCustomUpdateFunction();
}
dmaCount = gAudioCtx.curAudioFrameDmaCount;
for (i = 0; i < gAudioCtx.curAudioFrameDmaCount; i++) {
if (osRecvMesg(&gAudioCtx.curAudioFrameDmaQueue, NULL, OS_MESG_NOBLOCK) == 0) {
dmaCount--;
}
}
if (dmaCount != 0) {
for (i = 0; i < dmaCount; i++) {
osRecvMesg(&gAudioCtx.curAudioFrameDmaQueue, NULL, OS_MESG_BLOCK);
}
}
validCount = gAudioCtx.curAudioFrameDmaQueue.validCount;
if (validCount != 0) {
for (i = 0; i < validCount; i++) {
osRecvMesg(&gAudioCtx.curAudioFrameDmaQueue, NULL, OS_MESG_NOBLOCK);
}
}
gAudioCtx.curAudioFrameDmaCount = 0;
AudioLoad_DecreaseSampleDmaTtls();
AudioLoad_ProcessLoads(gAudioCtx.resetStatus);
AudioLoad_ProcessScriptLoads();
@ -98,105 +47,29 @@ AudioTask* AudioThread_UpdateImpl(void) {
if (gAudioCtx.resetStatus != 0) {
if (AudioHeap_ResetStep() == 0) {
if (gAudioCtx.resetStatus == 0) {
osSendMesg(gAudioCtx.audioResetQueueP, OS_MESG_8(gAudioCtx.specId), OS_MESG_NOBLOCK);
osSendMesg8(gAudioCtx.audioResetQueueP, gAudioCtx.specId, OS_MESG_NOBLOCK);
}
sWaitingAudioTask = NULL;
return NULL;
}
}
if (gAudioCtx.resetTimer > 16) {
return NULL;
}
if (gAudioCtx.resetTimer != 0) {
gAudioCtx.resetTimer++;
}
gAudioCtx.curTask = &gAudioCtx.rspTask[gAudioCtx.rspTaskIndex];
gAudioCtx.curAbiCmdBuf = gAudioCtx.abiCmdBufs[gAudioCtx.rspTaskIndex];
index = gAudioCtx.curAiBufferIndex;
curAiBuffer = gAudioCtx.aiBuffers[index];
gAudioCtx.numSamplesPerFrame[index] =
(s16)((((gAudioCtx.audioBufferParameters.numSamplesPerFrameTarget - numSamplesRemainingInAi) +
(8 * SAMPLES_PER_FRAME)) &
~0xF) +
(1 * SAMPLES_PER_FRAME));
// Clamp numSamplesPerFrame between numSamplesPerFrameMin and numSamplesPerFrameMax
if (gAudioCtx.numSamplesPerFrame[index] < gAudioCtx.audioBufferParameters.numSamplesPerFrameMin) {
gAudioCtx.numSamplesPerFrame[index] = gAudioCtx.audioBufferParameters.numSamplesPerFrameMin;
}
if (gAudioCtx.numSamplesPerFrame[index] > gAudioCtx.audioBufferParameters.numSamplesPerFrameMax) {
gAudioCtx.numSamplesPerFrame[index] = gAudioCtx.audioBufferParameters.numSamplesPerFrameMax;
}
j = 0;
int j = 0;
if (gAudioCtx.resetStatus == 0) {
// msg = 0000RREE R = read pos, E = End Pos
while (osRecvMesg(gAudioCtx.threadCmdProcQueueP, (OSMesg*)&msg, OS_MESG_NOBLOCK) != -1) {
//! FAKE:
if (1) {}
AudioThread_ProcessCmds(msg);
while (osRecvMesg(gAudioCtx.threadCmdProcQueueP, &sp4C, OS_MESG_NOBLOCK) != -1) {
AudioThread_ProcessCmds(sp4C.data32);
j++;
}
if ((j == 0) && gAudioCtx.threadCmdQueueFinished) {
if ((j == 0) && (gAudioCtx.threadCmdQueueFinished)) {
AudioThread_ScheduleProcessCmds();
}
}
if (gAudioSPDataPtr == (u64*)gAudioCtx.curAbiCmdBuf) {
return (void*)-1;
}
gAudioCtx.curAbiCmdBuf =
AudioSynth_Update(gAudioCtx.curAbiCmdBuf, &numAbiCmds, curAiBuffer, gAudioCtx.numSamplesPerFrame[index]);
// Update audioRandom to the next random number
s32 writtenCmds;
AudioSynth_Update(gAudioCtx.curAbiCmdBuf, &writtenCmds, samples, num_samples);
gAudioCtx.audioRandom = (gAudioCtx.audioRandom + gAudioCtx.totalTaskCount) * osGetCount();
gAudioCtx.audioRandom = gAudioCtx.audioRandom + gAudioCtx.aiBuffers[index][gAudioCtx.totalTaskCount & 0xFF];
}
// gWaveSamples[8] interprets compiled assembly code as s16 samples as a way to generate sound with noise.
// Start with the address of AudioThread_Update(), and offset it by a random number between 0 - 0xFFF0
// Use the resulting address as the starting address to interpret an array of samples i.e. `s16 samples[]`
gWaveSamples[8] = (s16*)((u8*)AudioThread_Update + (gAudioCtx.audioRandom & 0xFFF0));
index = gAudioCtx.rspTaskIndex;
gAudioCtx.curTask->taskQueue = NULL;
gAudioCtx.curTask->unk_44 = NULL;
task = &gAudioCtx.curTask->task.t;
task->type = M_AUDTASK;
task->flags = 0;
task->ucode_boot = aspMainTextStart;
task->ucode_boot_size = SP_UCODE_SIZE;
task->ucode_data_size = ((aspMainDataEnd - aspMainDataStart) * sizeof(u64)) - 1;
task->ucode = aspMainTextStart;
task->ucode_data = aspMainDataStart;
task->ucode_size = SP_UCODE_SIZE;
task->dram_stack = (u64*)D_801D6200;
task->dram_stack_size = 0;
task->output_buff = NULL;
task->output_buff_size = NULL;
if (1) {}
task->data_ptr = (u64*)gAudioCtx.abiCmdBufs[index];
task->data_size = numAbiCmds * sizeof(Acmd);
task->yield_data_ptr = NULL;
task->yield_data_size = 0;
if (gAudioCtx.numAbiCmdsMax < numAbiCmds) {
gAudioCtx.numAbiCmdsMax = numAbiCmds;
}
if (gAudioCtx.audioBufferParameters.specUnk4 == 1) {
return gAudioCtx.curTask;
} else {
sWaitingAudioTask = gAudioCtx.curTask;
return NULL;
}
#endif
AudioTask* AudioThread_UpdateImpl(void) {
return NULL;
}
void AudioThread_ProcessGlobalCmd(AudioCmd* cmd) {
@ -343,7 +216,7 @@ void AudioThread_ProcessGlobalCmd(AudioCmd* cmd) {
break;
case AUDIOCMD_OP_GLOBAL_SET_REVERB_DATA:
AudioHeap_SetReverbData(cmd->arg1, cmd->arg0, cmd->asInt, false);
AudioHeap_SetReverbData(cmd->arg1, cmd->arg0, cmd->asPtr, false);
break;
default:
@ -391,11 +264,13 @@ void AudioThread_InitMesgQueuesInternal(void) {
osCreateMesgQueue(gAudioCtx.audioResetQueueP, gAudioCtx.audioResetMesgs, ARRAY_COUNT(gAudioCtx.audioResetMesgs));
}
void AudioThread_QueueCmd(u32 opArgs, void** data) {
AudioCmd* cmd = &gAudioCtx.threadCmdBuf[gAudioCtx.threadCmdWritePos & 0xFF];
const char* cmd_op_to_str(u8 op);
cmd->opArgs = opArgs;
cmd->data = *data;
void AudioThread_QueueCmd(AudioCmd cmdData) {
AudioCmd* cmd = &gAudioCtx.threadCmdBuf[gAudioCtx.threadCmdWritePos & 0xFF];
*cmd = cmdData;
LUSLOG_TRACE("Queueing Command: %s", cmd_op_to_str(cmd->op));
gAudioCtx.threadCmdWritePos++;
@ -404,24 +279,44 @@ void AudioThread_QueueCmd(u32 opArgs, void** data) {
}
}
void AudioThread_QueueCmdPtr(u32 opArgs, void* data) {
AudioCmd cmd = {
.opArgs = opArgs,
.asPtr = data,
};
AudioThread_QueueCmd(cmd);
}
void AudioThread_QueueCmdF32(u32 opArgs, f32 data) {
AudioThread_QueueCmd(opArgs, (void**)&data);
AudioCmd cmd = {
.opArgs = opArgs,
.asFloat = data,
};
AudioThread_QueueCmd(cmd);
}
void AudioThread_QueueCmdS32(u32 opArgs, s32 data) {
AudioThread_QueueCmd(opArgs, (void**)&data);
AudioCmd cmd = {
.opArgs = opArgs,
.asInt = data,
};
AudioThread_QueueCmd(cmd);
}
void AudioThread_QueueCmdS8(u32 opArgs, s8 data) {
u32 uData = data << 0x18;
AudioThread_QueueCmd(opArgs, (void**)&uData);
AudioCmd cmd = {
.opArgs = opArgs,
.asSbyte = data,
};
AudioThread_QueueCmd(cmd);
}
void AudioThread_QueueCmdU16(u32 opArgs, u16 data) {
u32 uData = data << 0x10;
AudioThread_QueueCmd(opArgs, (void**)&uData);
AudioCmd cmd = {
.opArgs = opArgs,
.asUShort = data,
};
AudioThread_QueueCmd(cmd);
}
s32 AudioThread_ScheduleProcessCmds(void) {
@ -489,6 +384,72 @@ void AudioThread_ProcessCmd(AudioCmd* cmd) {
}
}
const char* cmd_op_to_str(u8 op) {
#define CASE(x) \
case x: \
return #x
switch (op) {
CASE(AUDIOCMD_OP_NOOP);
CASE(AUDIOCMD_OP_CHANNEL_SET_VOL_SCALE);
CASE(AUDIOCMD_OP_CHANNEL_SET_VOL);
CASE(AUDIOCMD_OP_CHANNEL_SET_PAN);
CASE(AUDIOCMD_OP_CHANNEL_SET_FREQ_SCALE);
CASE(AUDIOCMD_OP_CHANNEL_SET_REVERB_VOLUME);
CASE(AUDIOCMD_OP_CHANNEL_SET_IO);
CASE(AUDIOCMD_OP_CHANNEL_SET_PAN_WEIGHT);
CASE(AUDIOCMD_OP_CHANNEL_SET_MUTE);
CASE(AUDIOCMD_OP_CHANNEL_SET_MUTE_FLAGS);
CASE(AUDIOCMD_OP_CHANNEL_SET_VIBRATO_DEPTH);
CASE(AUDIOCMD_OP_CHANNEL_SET_VIBRATO_RATE);
CASE(AUDIOCMD_OP_CHANNEL_SET_COMB_FILTER_SIZE);
CASE(AUDIOCMD_OP_CHANNEL_SET_COMB_FILTER_GAIN);
CASE(AUDIOCMD_OP_CHANNEL_SET_STEREO);
CASE(AUDIOCMD_OP_CHANNEL_SET_SET_START_POS);
CASE(AUDIOCMD_OP_CHANNEL_SET_SFX_STATE);
CASE(AUDIOCMD_OP_CHANNEL_SET_REVERB_INDEX);
CASE(AUDIOCMD_OP_CHANNEL_SET_SURROUND_EFFECT_INDEX);
CASE(AUDIOCMD_OP_CHANNEL_SET_FILTER);
CASE(AUDIOCMD_OP_CHANNEL_SET_GAIN);
CASE(AUDIOCMD_OP_SEQPLAYER_FADE_VOLUME_SCALE);
CASE(AUDIOCMD_OP_SEQPLAYER_SET_IO);
CASE(AUDIOCMD_OP_SEQPLAYER_SET_TEMPO);
CASE(AUDIOCMD_OP_SEQPLAYER_SET_TRANSPOSITION);
CASE(AUDIOCMD_OP_SEQPLAYER_CHANGE_TEMPO);
CASE(AUDIOCMD_OP_SEQPLAYER_FADE_TO_SET_VOLUME);
CASE(AUDIOCMD_OP_SEQPLAYER_FADE_TO_SCALED_VOLUME);
CASE(AUDIOCMD_OP_SEQPLAYER_RESET_VOLUME);
CASE(AUDIOCMD_OP_SEQPLAYER_SET_BEND);
CASE(AUDIOCMD_OP_SEQPLAYER_CHANGE_TEMPO_TICKS);
CASE(AUDIOCMD_OP_GLOBAL_SYNC_LOAD_SEQ_PARTS);
CASE(AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER);
CASE(AUDIOCMD_OP_GLOBAL_DISABLE_SEQPLAYER);
CASE(AUDIOCMD_OP_GLOBAL_INIT_SEQPLAYER_SKIP_TICKS);
CASE(AUDIOCMD_OP_GLOBAL_SET_CHANNEL_MASK);
CASE(AUDIOCMD_OP_GLOBAL_SET_DRUM_FONT);
CASE(AUDIOCMD_OP_GLOBAL_SET_SFX_FONT);
CASE(AUDIOCMD_OP_GLOBAL_SET_INSTRUMENT_FONT);
CASE(AUDIOCMD_OP_GLOBAL_POP_PERSISTENT_CACHE);
CASE(AUDIOCMD_OP_GLOBAL_SET_CUSTOM_FUNCTION);
CASE(AUDIOCMD_OP_GLOBAL_E5);
CASE(AUDIOCMD_OP_GLOBAL_SET_REVERB_DATA);
CASE(AUDIOCMD_OP_GLOBAL_SET_SOUND_MODE);
CASE(AUDIOCMD_OP_GLOBAL_MUTE);
CASE(AUDIOCMD_OP_GLOBAL_UNMUTE);
CASE(AUDIOCMD_OP_GLOBAL_SYNC_LOAD_INSTRUMENT);
CASE(AUDIOCMD_OP_GLOBAL_ASYNC_LOAD_SAMPLE_BANK);
CASE(AUDIOCMD_OP_GLOBAL_ASYNC_LOAD_FONT);
CASE(AUDIOCMD_OP_GLOBAL_DISCARD_SEQ_FONTS);
CASE(AUDIOCMD_OP_GLOBAL_STOP_AUDIOCMDS);
CASE(AUDIOCMD_OP_GLOBAL_RESET_AUDIO_HEAP);
CASE(AUDIOCMD_OP_GLOBAL_NOOP_1);
CASE(AUDIOCMD_OP_GLOBAL_SET_CUSTOM_UPDATE_FUNCTION);
CASE(AUDIOCMD_OP_GLOBAL_ASYNC_LOAD_SEQ);
CASE(AUDIOCMD_OP_GLOBAL_NOOP_2);
CASE(AUDIOCMD_OP_GLOBAL_DISABLE_ALL_SEQPLAYERS);
}
#undef CASE
}
void AudioThread_ProcessCmds(u32 msg) {
static u8 sCurCmdRdPos = 0;
AudioCmd* cmd;
@ -506,6 +467,7 @@ void AudioThread_ProcessCmds(u32 msg) {
}
cmd = &gAudioCtx.threadCmdBuf[sCurCmdRdPos++ & 0xFF];
LUSLOG_TRACE("Process Command: %s", cmd_op_to_str(cmd->op));
if (cmd->op == AUDIOCMD_OP_GLOBAL_STOP_AUDIOCMDS) {
gAudioCtx.threadCmdQueueFinished = true;
break;
@ -528,8 +490,8 @@ u32 AudioThread_GetExternalLoadQueueMsg(u32* retMsg) {
return msg >> 0x18;
}
u8* AudioThread_GetFontsForSequence(s32 seqId, u32* outNumFonts) {
return AudioLoad_GetFontsForSequence(seqId, outNumFonts);
u8* AudioThread_GetFontsForSequence(s32 seqId, u32* outNumFonts, u8* buff) {
return AudioLoad_GetFontsForSequence(seqId, outNumFonts, buff);
}
void AudioThread_GetSampleBankIdsOfFont(s32 fontId, u32* sampleBankId1, u32* sampleBankId2) {
@ -539,11 +501,11 @@ void AudioThread_GetSampleBankIdsOfFont(s32 fontId, u32* sampleBankId1, u32* sam
s32 func_80193C5C(void) {
s32 pad;
s32 specId;
OSMesg specId;
if (osRecvMesg(gAudioCtx.audioResetQueueP, (OSMesg*)&specId, OS_MESG_NOBLOCK) == -1) {
if (osRecvMesg(gAudioCtx.audioResetQueueP, &specId, OS_MESG_NOBLOCK) == -1) {
return 0;
} else if (gAudioCtx.specId != specId) {
} else if (gAudioCtx.specId != specId.data8) {
return -1;
} else {
return 1;

View File

@ -115,7 +115,11 @@ void AudioSeq_ProcessSeqCmd(u32 cmd) {
// `fadeTimer` continues to be scaled in `AudioSeq_StartSequence`
fadeTimer = (cmd & 0xFF0000) >> 13;
if (!gActiveSeqs[seqPlayerIndex].isWaitingForFonts && !sStartSeqDisabled) {
if (seqArgs < 0x80) {
// BEN: The code block to later load a sequence doesn't exist in OOT.
// BEN: The thing preventing this code block from running is actually the fact that we killed the audio tables.
// BEN: This delayed loading method actually utilizes some functions that OOT is no longer utilizing.
// BEN: The short of it ends up being the short circuit here is fine since it works and the stuff is loaded anyway.
if (seqArgs < 0x80 || 1) {
AudioSeq_StartSequence(seqPlayerIndex, seqId, seqArgs, fadeTimer);
} else {
// Store the cmd to be called again once the fonts are loaded
@ -123,19 +127,22 @@ void AudioSeq_ProcessSeqCmd(u32 cmd) {
gActiveSeqs[seqPlayerIndex].startAsyncSeqCmd =
(cmd & ~(SEQ_FLAG_ASYNC | SEQCMD_ASYNC_ACTIVE)) + SEQCMD_ASYNC_ACTIVE;
gActiveSeqs[seqPlayerIndex].isWaitingForFonts = true;
gActiveSeqs[seqPlayerIndex].fontId = *AudioThread_GetFontsForSequence(seqId, &outNumFonts);
u8* fontBuff[16];
u8* prevFontBuff[16];
u8* font = AudioThread_GetFontsForSequence(seqId, &outNumFonts, fontBuff);
gActiveSeqs[seqPlayerIndex].fontId = *font;
AudioSeq_StopSequence(seqPlayerIndex, 1);
if (gActiveSeqs[seqPlayerIndex].prevSeqId != NA_BGM_DISABLED) {
if (*AudioThread_GetFontsForSequence(seqId, &outNumFonts) !=
*AudioThread_GetFontsForSequence(gActiveSeqs[seqPlayerIndex].prevSeqId & 0xFF,
&outNumFonts)) {
if (*AudioThread_GetFontsForSequence(seqId, &outNumFonts, fontBuff) !=
*AudioThread_GetFontsForSequence(gActiveSeqs[seqPlayerIndex].prevSeqId & 0xFF, &outNumFonts,
prevFontBuff)) {
// Discard Seq Fonts
AUDIOCMD_GLOBAL_DISCARD_SEQ_FONTS((s32)seqId);
}
}
AUDIOCMD_GLOBAL_ASYNC_LOAD_FONT(*AudioThread_GetFontsForSequence(seqId, &outNumFonts),
AUDIOCMD_GLOBAL_ASYNC_LOAD_FONT(*AudioThread_GetFontsForSequence(seqId, &outNumFonts, fontBuff),
(u8)((seqPlayerIndex + 1) & 0xFF));
}
}
@ -861,7 +868,7 @@ u8 AudioSeq_ResetReverb(void) {
if (fadeReverb & 1) {
AUDIOCMD_GLOBAL_SET_REVERB_DATA(
reverbIndex, REVERB_DATA_TYPE_SETTINGS,
(s32)(gReverbSettingsTable[(u8)(sResetAudioHeapSeqCmd & 0xFF)] + reverbIndex));
(uintptr_t)(gReverbSettingsTable[(u8)(sResetAudioHeapSeqCmd & 0xFF)] + reverbIndex));
AudioThread_ScheduleProcessCmds();
}
reverbIndex++;

View File

@ -22,11 +22,13 @@ const s16 gAudioTatumInit[] = {
#define PERMANENT_POOL_SIZE \
(SFX_SEQ_SIZE + AMBIENCE_SEQ_SIZE + SOUNDFONT_0_SIZE + SOUNDFONT_1_SIZE + SOUNDFONT_2_SIZE + 0x430)
const AudioHeapInitSizes gAudioHeapInitSizes = {
ALIGN16(sizeof(gAudioHeap) - 0x100), // audio heap size
ALIGN16(PERMANENT_POOL_SIZE + AI_BUFFERS_SIZE + SOUNDFONT_LIST_SIZE + 0x40), // init pool size
ALIGN16(PERMANENT_POOL_SIZE), // permanent pool size
};
// const AudioHeapInitSizes gAudioHeapInitSizes = {
// ALIGN16(sizeof(gAudioHeap) - 0x100), // audio heap size
// ALIGN16(PERMANENT_POOL_SIZE + AI_BUFFERS_SIZE + SOUNDFONT_LIST_SIZE + 0x40), // init pool size
// ALIGN16(PERMANENT_POOL_SIZE), // permanent pool size
// };
const AudioHeapInitSizes gAudioHeapInitSizes = { 0x37F000, 0xE0E00, 0xBCE00 };
#define REVERB_INDEX_0_SETTINGS \
{ 1, 0x30, 0x3000, 0, 0, 0x7FFF, 0x0000, 0x0000, REVERB_INDEX_NONE, 0x3000, 0, 0 }
@ -120,66 +122,66 @@ ReverbSettings* gReverbSettingsTable[] = {
AudioSpec gAudioSpecs[21] = {
/* 0x0 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x1 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x2 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x3 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x4 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x5 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x6 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x7 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x8 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x9 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0xA */
{ 32000, 1, 28, 3, 0, 0, 2, reverbSettingsA, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x2800, 0x2D00, 0, 0,
{ 44100, 1, 28, 3, 0, 0, 2, reverbSettingsA, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x2800, 0x2D00, 0, 0,
0xDC800 },
/* 0xB */
{ 32000, 1, 28, 3, 0, 0, 2, reverbSettingsA, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 28, 3, 0, 0, 2, reverbSettingsA, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0xC */
{ 32000, 1, 28, 5, 0, 0, 2, reverbSettingsA, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 28, 5, 0, 0, 2, reverbSettingsA, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xCC800 },
/* 0xD */
{ 32000, 1, 24, 5, 0, 0, 3, reverbSettingsD, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 3, reverbSettingsD, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0xE */
{ 32000, 1, 24, 5, 0, 0, 3, reverbSettingsE, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 3, reverbSettingsE, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0xF */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4000, 0x2D00, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettingsF, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4000, 0x2D00, 0, 0,
0xDC800 },
/* 0x10 */
{ 32000, 1, 22, 5, 0, 0, 2, reverbSettings0, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 22, 5, 0, 0, 2, reverbSettings0, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x11 */
{ 32000, 1, 22, 5, 0, 0, 2, reverbSettings8, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 22, 5, 0, 0, 2, reverbSettings8, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x12 */
{ 32000, 1, 16, 5, 0, 0, 2, reverbSettings0, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
{ 44100, 1, 16, 5, 0, 0, 2, reverbSettings0, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x13 */
{ 22050, 1, 24, 5, 0, 0, 2, reverbSettings0, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x4100, 0x2D00, 0, 0,
0xDC800 },
/* 0x14 */
{ 32000, 1, 24, 5, 0, 0, 2, reverbSettings2, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x3600, 0x2600, 0, 0,
{ 44100, 1, 24, 5, 0, 0, 2, reverbSettings2, 0x500, 0x200, 0x7FFF, 0xAF0, 0x2D80, 0, 0x3600, 0x2600, 0, 0,
0xDC800 },
};

View File

@ -741,8 +741,6 @@ void AudioSfx_StopByPosAndBank(u8 bankId, Vec3f* pos) {
}
void AudioSfx_StopByPos(Vec3f* pos) {
// BENTODO: infinite loop
#if 0
u8 bankId;
SfxBankEntry entryToRemove;
@ -752,7 +750,6 @@ void AudioSfx_StopByPos(Vec3f* pos) {
entryToRemove.posX = &pos->x;
AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_POS, &entryToRemove);
#endif
}
void AudioSfx_StopByPosAndId(Vec3f* pos, u16 sfxId) {
@ -817,8 +814,6 @@ void AudioSfx_StopByTokenAndId(u8 token, u16 sfxId) {
}
void AudioSfx_StopById(u32 sfxId) {
// BENTODO: infinite loop
#if 0
SfxBankEntry* entry;
u8 entryIndex = gSfxBanks[SFX_BANK(sfxId)][0].next;
u8 prevEntryIndex = 0;
@ -842,7 +837,6 @@ void AudioSfx_StopById(u32 sfxId) {
entryToRemove.sfxId = sfxId;
AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_ID, &entryToRemove);
#endif
}
void AudioSfx_ProcessRequests(void) {

View File

@ -9,9 +9,9 @@ void AudioMgr_NotifyTaskDone(AudioMgr* audioMgr) {
osSendMesg(task->taskQueue, OS_MESG_PTR(NULL), OS_MESG_BLOCK);
}
}
// BENTODO
void AudioMgr_HandleRetrace(AudioMgr* audioMgr) {
#if 0
return;
static s32 sRetryCount = 10;
AudioTask* rspTask;
s32 timerMsgVal = 666;
@ -45,31 +45,9 @@ void AudioMgr_HandleRetrace(AudioMgr* audioMgr) {
rspTask = AudioThread_Update();
}
if (audioMgr->rspTask != NULL) {
while (true) {
osSetTimer(&timer, OS_USEC_TO_CYCLES(32000), 0, &audioMgr->cmdQueue, OS_MESG_32(timerMsgVal));
osRecvMesg(&audioMgr->cmdQueue, (OSMesg*)&msg, OS_MESG_BLOCK);
osStopTimer(&timer);
if (msg == timerMsgVal) {
osSyncPrintf("AUDIO SP TIMEOUT %08x %08x\n", audioMgr->rspTask, audioMgr->rspTask->task);
if (sRetryCount >= 0) {
sRetryCount--;
Sched_SendAudioCancelMsg(audioMgr->sched);
} else {
osSyncPrintf("audioMgr.c:もうダメ!死ぬ!\n");
osDestroyThread(NULL);
break;
}
} else {
break;
}
}
AudioMgr_NotifyTaskDone(audioMgr);
}
AudioMgr_NotifyTaskDone(audioMgr);
audioMgr->rspTask = rspTask;
#endif
}
void AudioMgr_HandlePreNMI(AudioMgr* audioMgr) {
@ -139,6 +117,16 @@ void AudioMgr_Init(AudioMgr* audioMgr, void* stack, OSPri pri, OSId id, SchedCon
osCreateMesgQueue(&audioMgr->interruptQueue, audioMgr->interruptMsgBuf, ARRAY_COUNT(audioMgr->interruptMsgBuf));
osCreateMesgQueue(&audioMgr->lockQueue, audioMgr->lockMsgBuf, ARRAY_COUNT(audioMgr->lockMsgBuf));
osCreateThread(&audioMgr->thread, id, AudioMgr_ThreadEntry, audioMgr, stack, pri);
osStartThread(&audioMgr->thread);
Audio_Init();
AudioLoad_SetDmaHandler(DmaMgr_DmaHandler);
Audio_InitSound();
osSendMesg(&audioMgr->lockQueue, OS_MESG_PTR(NULL), OS_MESG_BLOCK);
// Audio_SetGameVolume(SEQ_PLAYER_BGM_MAIN, CVarGetFloat("gMainMusicVolume", 1.0f));
// Audio_SetGameVolume(SEQ_PLAYER_BGM_SUB, CVarGetFloat("gSubMusicVolume", 1.0f));
// Audio_SetGameVolume(SEQ_PLAYER_FANFARE, CVarGetFloat("gFanfareVolume", 1.0f));
// Audio_SetGameVolume(SEQ_PLAYER_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f));
// osCreateThread(&audioMgr->thread, id, AudioMgr_ThreadEntry, audioMgr, stack, pri);
// osStartThread(&audioMgr->thread);
}

View File

@ -240,8 +240,8 @@ void GameState_Init(GameState* gameState, GameStateFunc init, GraphicsContext* g
void GameState_Destroy(GameState* gameState) {
// BENTODO
//AudioMgr_StopAllSfxExceptSystem();
//Audio_Update();
AudioMgr_StopAllSfxExceptSystem();
Audio_Update();
osRecvMesg(&gameState->gfxCtx->queue, NULL, OS_MESG_BLOCK);
if (gameState->destroy != NULL) {

View File

@ -242,9 +242,9 @@ void Graph_UpdateGame(GameState* gameState) {
GameState_GetInput(gameState);
GameState_IncrementFrameCount(gameState);
// BENTODO
// if (SREG(20) < 3) {
// Audio_Update();
//}
if (SREG(20) < 3) {
Audio_Update();
}
}
/**
@ -277,10 +277,10 @@ void Graph_ExecuteAndDraw(GraphicsContext* gfxCtx, GameState* gameState) {
Gfx* gfx = gGfxMasterDL->taskStart;
gSPSegment(gfx++, 0x0E, gGfxMasterDL);
gSPDisplayList(gfx++, D_0E000000_TO_SEGMENTED(disps[3])); // Work buffer
gSPDisplayList(gfx++, D_0E000000_TO_SEGMENTED(disps[0])); // OPA buffer
gSPDisplayList(gfx++, D_0E000000_TO_SEGMENTED(disps[1])); // XLU buffer
gSPDisplayList(gfx++, D_0E000000_TO_SEGMENTED(disps[2])); // Overlay buffer
gSPDisplayList(gfx++, D_0E000000_TO_SEGMENTED(disps[3])); // Work buffer
gSPDisplayList(gfx++, D_0E000000_TO_SEGMENTED(disps[0])); // OPA buffer
gSPDisplayList(gfx++, D_0E000000_TO_SEGMENTED(disps[1])); // XLU buffer
gSPDisplayList(gfx++, D_0E000000_TO_SEGMENTED(disps[2])); // Overlay buffer
gSPDisplayList(gfx++, D_0E000000_TO_SEGMENTED(debugDisp[0])); // Debug buffer
gDPPipeSync(gfx++);

View File

@ -75,6 +75,8 @@ void SDL_main(int argc, char** argv /* void* arg*/) {
osCreateMesgQueue(&sIrqMgrMsgQueue, sIrqMgrMsgBuf, ARRAY_COUNT(sIrqMgrMsgBuf));
PadMgr_Init(&sSerialEventQueue, &gIrqMgr, Z_THREAD_ID_PADMGR, Z_PRIORITY_PADMGR, STACK_TOP(sPadMgrStack));
AudioMgr_Init(&sAudioMgr, STACK_TOP(sAudioStack), Z_PRIORITY_AUDIOMGR, Z_THREAD_ID_AUDIOMGR, &gSchedContext,
&gIrqMgr);
#if 0
StackCheck_Init(&sSchedStackInfo, sSchedStack, STACK_TOP(sSchedStack), 0, 0x100, "sched");
Sched_Init(&gSchedContext, STACK_TOP(sSchedStack), Z_PRIORITY_SCHED, gViConfigModeType, 1, &gIrqMgr);

View File

@ -40,10 +40,10 @@ ActiveSequence gActiveSeqs[5];
AudioContext gAudioCtx;
s32 D_801FD120;
u8 gSoundFontTable[5];
u8 gSequenceFontTable[5];
u8 gSequenceTable[5];
u8 gSampleBankTable[5];
// u8 gSoundFontTable[5];
// u8 gSequenceFontTable[5];
// u8 gSequenceTable[5];
// u8 gSampleBankTable[5];
AudioCustomUpdateFunction gAudioCustomUpdateFunction;
AudioCustomSeqFunction gAudioCustomSeqFunction;
@ -170,9 +170,9 @@ char* ResourceMgr_LoadTexOrDListByName(const char* data);
void gSPSegment(void* value, int segNum, uintptr_t target) {
char* imgData = (char*)target;
int res = ResourceMgr_OTRSigCheck(imgData);
// OTRTODO: Disabled for now to fix an issue with HD Textures.
// With HD textures, we need to pass the path to F3D, not the raw texture data.
// Otherwise the needed metadata is not available for proper rendering...
@ -181,23 +181,23 @@ void gSPSegment(void* value, int segNum, uintptr_t target) {
// That should not affect HD textures.
if (res) {
uintptr_t desiredTarget = (uintptr_t)ResourceMgr_LoadIfDListByName(imgData);
if (desiredTarget != NULL)
target = desiredTarget;
}
__gSPSegment(value, segNum, target);
}
void gSPSegmentLoadRes(void* value, int segNum, uintptr_t target) {
char* imgData = (char*)target;
int res = ResourceMgr_OTRSigCheck(imgData);
if (res) {
target = (uintptr_t)ResourceMgr_LoadTexOrDListByName(imgData);
}
__gSPSegment(value, segNum, target);
}
@ -211,42 +211,42 @@ void gDPSetTextureImageFB(Gfx* pkt, u32 format, u32 size, u32 width, int fb) {
void gSPDisplayList(Gfx* pkt, Gfx* dl) {
char* imgData = (char*)dl;
if (ResourceMgr_OTRSigCheck(imgData) == 1) {
// ResourceMgr_PushCurrentDirectory(imgData);
// gsSPPushCD(pkt++, imgData);
dl = ResourceMgr_LoadGfxByName(imgData);
}
__gSPDisplayList(pkt, dl);
}
void gSPDisplayListOffset(Gfx* pkt, Gfx* dl, int offset) {
char* imgData = (char*)dl;
if (ResourceMgr_OTRSigCheck(imgData) == 1)
dl = ResourceMgr_LoadGfxByName(imgData);
__gSPDisplayList(pkt, dl + offset);
}
void gSPVertex(Gfx* pkt, uintptr_t v, int n, int v0) {
if (ResourceMgr_OTRSigCheck((char*)v) == 1)
v = (uintptr_t)ResourceMgr_LoadVtxByName((char*)v);
__gSPVertex(pkt, v, n, v0);
}
void gSPInvalidateTexCache(Gfx* pkt, uintptr_t texAddr) {
char* imgData = (char*)texAddr;
if (texAddr != 0 && ResourceMgr_OTRSigCheck(imgData)) {
// Temporary solution to the mq/nonmq issue, this will be
// handled better with LUS 1.0
texAddr = (uintptr_t)ResourceMgr_LoadTexOrDListByName(imgData);
}
__gSPInvalidateTexCache(pkt, texAddr);
}
void func_801A1290(void) {
@ -758,7 +758,7 @@ void guPerspectiveF(f32 mf[4][4], u16* perspNorm, f32 fovy, f32 aspect, f32 near
void guPerspective(Mtx* m, u16* perspNorm, float fovy, float aspect, float near, float far, float scale) {
float mf[4][4];
guPerspectiveF(mf, perspNorm, fovy, aspect, near, far, scale);
Matrix_MtxFToMtx((MtxF*)mf, m);
//guPerspectiveF(mf, perspNorm, fovy, aspect, near, far, scale);

View File

@ -3507,8 +3507,8 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) {
if (actor == actorCtx->targetCtx.bgmEnemy) {
actorCtx->targetCtx.bgmEnemy = NULL;
}
// BENTODO
// AudioSfx_StopByPos(&actor->projectedPos);
AudioSfx_StopByPos(&actor->projectedPos);
Actor_Destroy(actor, play);
newHead = Actor_RemoveFromCategory(play, actorCtx, actor);

View File

@ -62,7 +62,7 @@ void ActorOverlayTable_FaultClient(void* arg0, void* arg1) {
overlaySize = (uintptr_t)overlayEntry->vramEnd - (uintptr_t)overlayEntry->vramStart;
if (overlayEntry->loadedRamAddr != NULL) {
FaultDrawer_Printf("%3d %08x-%08x %3d %s\n", actorId, overlayEntry->loadedRamAddr,
(u32)overlayEntry->loadedRamAddr + overlaySize, overlayEntry->numLoaded, "");
(uintptr_t)overlayEntry->loadedRamAddr + overlaySize, overlayEntry->numLoaded, "");
}
}
}

View File

@ -579,7 +579,7 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) {
case 0x1B: // MESSAGE_BOX_BREAK_DELAYED
if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING) {
stateTimerHi = msgCtx->decodedBuffer.schar[++i] << 8;
stateTimerHi |= msgCtx->decodedBuffer.schar[++i];
stateTimerHi += msgCtx->decodedBuffer.schar[++i];
msgCtx->stateTimer = stateTimerHi;
msgCtx->msgMode = MSGMODE_TEXT_DELAYED_BREAK;
}
@ -595,7 +595,7 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) {
msgCtx->textboxEndType = 0x50;
}
stateTimerHi = msgCtx->decodedBuffer.schar[++i] << 8;
stateTimerHi |= msgCtx->decodedBuffer.schar[++i];
stateTimerHi += msgCtx->decodedBuffer.schar[++i];
msgCtx->stateTimer = stateTimerHi;
Font_LoadMessageBoxEndIcon(font, 1);
if (play->csCtx.state == CS_STATE_IDLE) {
@ -610,7 +610,7 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) {
msgCtx->msgMode = MSGMODE_TEXT_DONE;
msgCtx->textboxEndType = 0x52;
stateTimerHi = msgCtx->decodedBuffer.schar[++i] << 8;
stateTimerHi |= msgCtx->decodedBuffer.schar[++i];
stateTimerHi += msgCtx->decodedBuffer.schar[++i];
msgCtx->stateTimer = stateTimerHi;
Font_LoadMessageBoxEndIcon(font, 1);
if (play->csCtx.state == CS_STATE_IDLE) {
@ -623,7 +623,7 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) {
case 0x1E: // MESSAGE_SFX
if (((i + 1) == msgCtx->textDrawPos) && (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING)) {
stateTimerHi = msgCtx->decodedBuffer.schar[i + 1] << 8;
stateTimerHi |= msgCtx->decodedBuffer.schar[i + 2];
stateTimerHi += (uint8_t)msgCtx->decodedBuffer.schar[i + 2];
Audio_PlaySfx(stateTimerHi);
}
if ((i + 1) == msgCtx->textDrawPos) {
@ -636,7 +636,7 @@ void Message_DrawTextNES(PlayState* play, Gfx** gfxP, u16 textDrawPos) {
if (((i + 1) == msgCtx->textDrawPos) && (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING)) {
msgCtx->msgMode = MSGMODE_9;
stateTimerHi = msgCtx->decodedBuffer.schar[i + 1] << 8;
stateTimerHi |= msgCtx->decodedBuffer.schar[i + 2];
stateTimerHi += msgCtx->decodedBuffer.schar[i + 2];
msgCtx->textDelayTimer = stateTimerHi;
}
i += 2;
@ -1878,7 +1878,7 @@ void Message_DecodeNES(PlayState* play) {
(msgCtx->textBoxType == TEXTBOX_TYPE_8) || (msgCtx->textBoxType == TEXTBOX_TYPE_9) ||
(msgCtx->textBoxType == TEXTBOX_TYPE_B) || (msgCtx->unk11F0C == 3)) {
sfxHi = msgCtx->decodedBuffer.schar[decodedBufPos - 1] << 8;
sfxHi |= msgCtx->decodedBuffer.schar[decodedBufPos];
sfxHi += (uint8_t)msgCtx->decodedBuffer.schar[decodedBufPos];
Audio_PlaySfx(sfxHi);
}
} else if (curChar == 0x1F) {

View File

@ -62,7 +62,7 @@ void Object_InitContext(GameState* gameState, ObjectContext* objectCtx) {
// clang-format on
objectCtx->spaceStart = objectCtx->slots[0].segment = THA_AllocTailAlign16(&gameState->tha, spaceSize);
objectCtx->spaceEnd = (void*)((u32)objectCtx->spaceStart + spaceSize);
objectCtx->spaceEnd = (void*)((uintptr_t)objectCtx->spaceStart + spaceSize);
objectCtx->mainKeepSlot = Object_SpawnPersistent(objectCtx, GAMEPLAY_KEEP);
gSegments[4] = OS_K0_TO_PHYSICAL(objectCtx->slots[objectCtx->mainKeepSlot].segment);

View File

@ -48,8 +48,6 @@ void ObjSound_Destroy(Actor* thisx, PlayState* play) {
}
void ObjSound_Update(Actor* thisx, PlayState* play) {
// BENTODO: stub audio code that crashes
#if 0
ObjSound* this = THIS;
if (this->soundType == OBJ_SOUND_TYPE_SFX) {
@ -67,7 +65,6 @@ void ObjSound_Update(Actor* thisx, PlayState* play) {
} else {
this->unk_144 = true;
}
#endif
}
void ObjSound_Draw(Actor* thisx, PlayState* play) {

View File

@ -5,6 +5,7 @@
*/
#include "z_oceff_wipe5.h"
#include "assets/overlays/ovl_Oceff_Wipe5/ovl_Oceff_Wipe5.h"
#include "BenPort.h"
#define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_2000000)
@ -29,20 +30,21 @@ ActorInit Oceff_Wipe5_InitVars = {
};
UNK_TYPE4 D_80BC9260;
static Vtx* gOceff5VtxData;
void OceffWipe5_Init(Actor* thisx, PlayState* play) {
OceffWipe5* this = THIS;
gOceff5VtxData = ResourceMgr_LoadArrayByName(gOceff5Vtx);
Actor_SetScale(&this->actor, 1.0f);
this->counter = 0;
this->actor.world.pos = play->cameraPtrs[play->activeCamId]->eye;
}
static Vtx* gOceff5VtxData;
void OceffWipe5_Destroy(Actor* thisx, PlayState* play) {
OceffWipe5* this = THIS;
gOceff5VtxData = ResourceMgr_LoadArrayByName(gOceff5VtxData);
gOceff5VtxData = ResourceMgr_LoadArrayByName(gOceff5Vtx);
Magic_Reset(play);
play->msgCtx.ocarinaSongEffectActive = false;
@ -59,7 +61,6 @@ void OceffWipe5_Update(Actor* thisx, PlayState* play) {
}
}
#include "assets/overlays/ovl_Oceff_Wipe5/ovl_Oceff_Wipe5.h"
static u8 sPrimColors[] = {
255, 255, 200, 255, 255, 200, 200, 255, 255, 255, 255, 200, 255, 200, 255,

View File

@ -1781,8 +1781,6 @@ u16 D_8085C3EC[] = {
};
void func_8082E00C(Player* this) {
return;
// BENTODO
s32 i;
u16* sfxIdPtr = D_8085C3EC;