a bunch of fixes (#216)

Nice job targeting the main branch Isaac

Co-Authored-By: Isaac0-dev <62234577+Isaac0-dev@users.noreply.github.com>
This commit is contained in:
Agent X 2024-07-17 08:37:42 -04:00
parent 2b6a173f8b
commit 594ff262bc
15 changed files with 122 additions and 85 deletions

View file

@ -86,6 +86,7 @@ override_field_invisible = {
"NetworkPlayer": [ "gag", "moderator", "discordId" ], "NetworkPlayer": [ "gag", "moderator", "discordId" ],
"GraphNode": [ "_guard1", "_guard2" ], "GraphNode": [ "_guard1", "_guard2" ],
"Object": [ "firstSurface" ], "Object": [ "firstSurface" ],
"ModAudio": [ "sound", "decoder", "buffer", "bufferSize", "sampleCopiesTail" ],
} }
override_field_deprecated = { override_field_deprecated = {
@ -116,6 +117,7 @@ override_field_immutable = {
"AnimationTable": [ "count" ], "AnimationTable": [ "count" ],
"Controller": [ "controllerData", "statusData" ], "Controller": [ "controllerData", "statusData" ],
"FirstPersonCamera": [ "enabled" ], "FirstPersonCamera": [ "enabled" ],
"ModAudio": [ "isStream", "loaded" ],
} }
override_field_version_excludes = { override_field_version_excludes = {

View file

@ -1075,7 +1075,6 @@
--- @field public file ModFile --- @field public file ModFile
--- @field public isStream boolean --- @field public isStream boolean
--- @field public loaded boolean --- @field public loaded boolean
--- @field public sampleCopiesTail ModAudioSampleCopies
--- @class ModAudioSampleCopies --- @class ModAudioSampleCopies
--- @field public next ModAudioSampleCopies --- @field public next ModAudioSampleCopies

View file

@ -1456,9 +1456,8 @@
| ----- | ---- | ------ | | ----- | ---- | ------ |
| baseVolume | `number` | | | baseVolume | `number` | |
| file | [ModFile](structs.md#ModFile) | | | file | [ModFile](structs.md#ModFile) | |
| isStream | `boolean` | | | isStream | `boolean` | read-only |
| loaded | `boolean` | | | loaded | `boolean` | read-only |
| sampleCopiesTail | [ModAudioSampleCopies](structs.md#ModAudioSampleCopies) | |
[:arrow_up_small:](#) [:arrow_up_small:](#)

View file

@ -196,6 +196,8 @@ void bhv_normal_cap_init(void) {
} }
void normal_cap_set_save_flags(void) { void normal_cap_set_save_flags(void) {
if (o->oBehParams - 1 != 0) { return; }
save_file_clear_flags(SAVE_FLAG_CAP_ON_GROUND); save_file_clear_flags(SAVE_FLAG_CAP_ON_GROUND);
switch (gCurrCourseNum) { switch (gCurrCourseNum) {

View file

@ -3349,11 +3349,13 @@ void update_camera(struct Camera *c) {
// Make sure the palette editor cutscene is properly reset // Make sure the palette editor cutscene is properly reset
struct MarioState *m = gMarioState; struct MarioState *m = gMarioState;
if (c->paletteEditorCap && c->cutscene != CUTSCENE_PALETTE_EDITOR && m->action != ACT_PUTTING_ON_CAP) { if (c->paletteEditorCap) {
if (!(m->flags & MARIO_CAP_ON_HEAD)) { if (m->flags & MARIO_CAP_ON_HEAD) {
c->paletteEditorCap = false;
} else if (c->cutscene != CUTSCENE_PALETTE_EDITOR && m->action != ACT_PUTTING_ON_CAP) {
cutscene_put_cap_on(m); cutscene_put_cap_on(m);
c->paletteEditorCap = false;
} }
c->paletteEditorCap = false;
} }
} }
@ -10856,6 +10858,7 @@ BAD_RETURN(s32) cutscene_door_mode(struct Camera *c) {
} }
// coop specific // coop specific
extern struct DjuiText* gDjuiPaletteToggle;
void cutscene_palette_editor(struct Camera *c) { void cutscene_palette_editor(struct Camera *c) {
if (!c) { return; } if (!c) { return; }
struct MarioState* m = gMarioState; struct MarioState* m = gMarioState;
@ -10879,23 +10882,14 @@ void cutscene_palette_editor(struct Camera *c) {
return; return;
} }
// Press the Z bind to toggle cap
static bool pressed = false; static bool pressed = false;
if (gInteractablePad.button & PAD_BUTTON_Z) { if (gInteractablePad.button & PAD_BUTTON_Z) {
if (!pressed && m->action != ACT_TAKING_OFF_CAP && m->action != ACT_PUTTING_ON_CAP) { if (!pressed && m->action == ACT_IDLE) {
if (m->flags & MARIO_CAP_ON_HEAD) { if (m->flags & MARIO_CAP_ON_HEAD) {
if (m->action == ACT_IDLE) { set_mario_action(m, ACT_TAKING_OFF_CAP, 1); // Add palette editor action arg
set_mario_action(m, ACT_TAKING_OFF_CAP, 1); // Add palette editor action arg
} else {
cutscene_take_cap_off(m);
gCamera->paletteEditorCap = true;
}
} else { } else {
if (m->action == ACT_IDLE) { set_mario_action(m, ACT_PUTTING_ON_CAP, 0);
set_mario_action(m, ACT_PUTTING_ON_CAP, 0);
} else {
cutscene_put_cap_on(m);
gCamera->paletteEditorCap = false;
}
} }
} }
pressed = true; pressed = true;
@ -10903,6 +10897,16 @@ void cutscene_palette_editor(struct Camera *c) {
pressed = false; pressed = false;
} }
// Hide text if it is not possible to toggle cap
if (gDjuiPaletteToggle) {
djui_base_set_visible(
&gDjuiPaletteToggle->base,
m->action == ACT_IDLE ||
m->action == ACT_TAKING_OFF_CAP ||
m->action == ACT_PUTTING_ON_CAP
);
}
c->pos[0] = m->pos[0] + (0x200 * sins(m->faceAngle[1])); c->pos[0] = m->pos[0] + (0x200 * sins(m->faceAngle[1]));
c->pos[1] = m->pos[1] + 0x80; c->pos[1] = m->pos[1] + 0x80;
c->pos[2] = m->pos[2] + (0x200 * coss(m->faceAngle[1])); c->pos[2] = m->pos[2] + (0x200 * coss(m->faceAngle[1]));

View file

@ -1895,12 +1895,10 @@ s32 act_taking_off_cap(struct MarioState *m) {
cutscene_take_cap_off(m); cutscene_take_cap_off(m);
if (m->actionArg == 1) { gCamera->paletteEditorCap = true; } if (m->actionArg == 1) { gCamera->paletteEditorCap = true; }
break; break;
default: }
if (animFrame >= 30 || gCamera->cutscene != CUTSCENE_PALETTE_EDITOR) { if (animFrame >= 30 || gCamera->cutscene != CUTSCENE_PALETTE_EDITOR) {
set_mario_action(m, ACT_IDLE, 0); set_mario_action(m, ACT_IDLE, 0);
disable_time_stop(); disable_time_stop();
}
break;
} }
stationary_ground_step(m); stationary_ground_step(m);

View file

@ -613,5 +613,7 @@ bool djui_hud_is_pause_menu_created(void) {
} }
void djui_open_pause_menu(void) { void djui_open_pause_menu(void) {
djui_panel_pause_create(NULL); if (!gDjuiPanelPauseCreated) {
djui_panel_pause_create(NULL);
}
} }

View file

@ -406,10 +406,14 @@ void djui_interactable_update(void) {
u16 mainButtons = PAD_BUTTON_A | PAD_BUTTON_B; u16 mainButtons = PAD_BUTTON_A | PAD_BUTTON_B;
if ((mouseButtons & MOUSE_BUTTON_1) && !(sLastMouseButtons && MOUSE_BUTTON_1) && !djui_cursor_inside_base(gInteractableFocus)) { if ((mouseButtons & MOUSE_BUTTON_1) && !(sLastMouseButtons && MOUSE_BUTTON_1) && !djui_cursor_inside_base(gInteractableFocus)) {
// clicked outside of focused // clicked outside of focused
djui_interactable_set_input_focus(NULL); if (!gDjuiChatBoxFocus && gInteractableFocus != &gDjuiChatBox->chatInput->base) {
djui_interactable_set_input_focus(NULL);
}
} else if ((padButtons & mainButtons) && !(sLastInteractablePad.button & mainButtons)) { } else if ((padButtons & mainButtons) && !(sLastInteractablePad.button & mainButtons)) {
// pressed main face button // pressed main face button
djui_interactable_set_input_focus(NULL); if (!gDjuiChatBoxFocus && gInteractableFocus != &gDjuiChatBox->chatInput->base) {
djui_interactable_set_input_focus(NULL);
}
} else { } else {
djui_interactable_on_focus(gInteractableFocus); djui_interactable_on_focus(gInteractableFocus);
} }

View file

@ -52,6 +52,7 @@ static void djui_panel_pause_quit(struct DjuiBase* caller) {
} }
void djui_panel_pause_create(struct DjuiBase* caller) { void djui_panel_pause_create(struct DjuiBase* caller) {
if (gDjuiPanelPauseCreated) { return; }
if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); } if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); }
struct DjuiBase* defaultBase = NULL; struct DjuiBase* defaultBase = NULL;

View file

@ -25,6 +25,8 @@ static struct DjuiInputbox* sPalettePresetNameTextBox = NULL;
static struct DjuiRect *sColorRect = NULL; static struct DjuiRect *sColorRect = NULL;
struct DjuiText* gDjuiPaletteToggle = NULL;
void djui_panel_player_create(struct DjuiBase* caller); void djui_panel_player_create(struct DjuiBase* caller);
//////////////////////// ////////////////////////
@ -307,6 +309,14 @@ static void djui_panel_player_edit_palette_create(struct DjuiBase* caller) {
} }
djui_button_create(body, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back); djui_button_create(body, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back);
{
struct DjuiText *text = djui_text_create(body, DLANG(PLAYER, CAP_TOGGLE));
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP);
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&text->base, 1.0f, 64);
gDjuiPaletteToggle = text;
}
} }
djui_panel_add(caller, panel, NULL); djui_panel_add(caller, panel, NULL);
@ -458,6 +468,7 @@ void djui_panel_player_create(struct DjuiBase* caller) {
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP); djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_TOP);
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&text->base, 1.0f, 64); djui_base_set_size(&text->base, 1.0f, 64);
gDjuiPaletteToggle = text;
} }
} }

View file

@ -28,6 +28,7 @@
#define LUA_STACK_CHECK_BEGIN() int __LUA_STACK_TOP = lua_gettop(gLuaState) #define LUA_STACK_CHECK_BEGIN() int __LUA_STACK_TOP = lua_gettop(gLuaState)
#define LUA_STACK_CHECK_END() if ((__LUA_STACK_TOP) != lua_gettop(gLuaState)) { smlua_dump_stack(); fflush(stdout); } assert((__LUA_STACK_TOP) == lua_gettop(gLuaState)) #define LUA_STACK_CHECK_END() if ((__LUA_STACK_TOP) != lua_gettop(gLuaState)) { smlua_dump_stack(); fflush(stdout); } assert((__LUA_STACK_TOP) == lua_gettop(gLuaState))
#else #else
#define LOG_LUA_LINE_WARNING(...) { snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__), sys_swap_backslashes(gDjuiConsoleTmpBuffer), djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_WARNING); }
#define LUA_STACK_CHECK_BEGIN() #define LUA_STACK_CHECK_BEGIN()
#define LUA_STACK_CHECK_END() #define LUA_STACK_CHECK_END()
#endif #endif

View file

@ -1203,22 +1203,21 @@ static struct LuaObjectField sModFields[LUA_MOD_FIELD_COUNT] = {
// { "size", LVT_???, offsetof(struct Mod, size), true, LOT_??? }, <--- UNIMPLEMENTED // { "size", LVT_???, offsetof(struct Mod, size), true, LOT_??? }, <--- UNIMPLEMENTED
}; };
#define LUA_MOD_AUDIO_FIELD_COUNT 5 #define LUA_MOD_AUDIO_FIELD_COUNT 4
static struct LuaObjectField sModAudioFields[LUA_MOD_AUDIO_FIELD_COUNT] = { static struct LuaObjectField sModAudioFields[LUA_MOD_AUDIO_FIELD_COUNT] = {
{ "baseVolume", LVT_F32, offsetof(struct ModAudio, baseVolume), false, LOT_NONE }, { "baseVolume", LVT_F32, offsetof(struct ModAudio, baseVolume), false, LOT_NONE },
{ "file", LVT_COBJECT_P, offsetof(struct ModAudio, file), false, LOT_MODFILE }, { "file", LVT_COBJECT_P, offsetof(struct ModAudio, file), false, LOT_MODFILE },
{ "isStream", LVT_BOOL, offsetof(struct ModAudio, isStream), false, LOT_NONE }, { "isStream", LVT_BOOL, offsetof(struct ModAudio, isStream), true, LOT_NONE },
{ "loaded", LVT_BOOL, offsetof(struct ModAudio, loaded), false, LOT_NONE }, { "loaded", LVT_BOOL, offsetof(struct ModAudio, loaded), true, LOT_NONE },
{ "sampleCopiesTail", LVT_COBJECT_P, offsetof(struct ModAudio, sampleCopiesTail), false, LOT_MODAUDIOSAMPLECOPIES },
// { "sound", LVT_???, offsetof(struct ModAudio, sound), false, LOT_??? }, <--- UNIMPLEMENTED
}; };
#define LUA_MOD_AUDIO_SAMPLE_COPIES_FIELD_COUNT 3 #define LUA_MOD_AUDIO_SAMPLE_COPIES_FIELD_COUNT 3
static struct LuaObjectField sModAudioSampleCopiesFields[LUA_MOD_AUDIO_SAMPLE_COPIES_FIELD_COUNT] = { static struct LuaObjectField sModAudioSampleCopiesFields[LUA_MOD_AUDIO_SAMPLE_COPIES_FIELD_COUNT] = {
{ "next", LVT_COBJECT_P, offsetof(struct ModAudioSampleCopies, next), false, LOT_MODAUDIOSAMPLECOPIES }, // { "decoder", LVT_???, offsetof(struct ModAudioSampleCopies, decoder), false, LOT_??? }, <--- UNIMPLEMENTED
{ "parent", LVT_COBJECT_P, offsetof(struct ModAudioSampleCopies, parent), false, LOT_MODAUDIO }, { "next", LVT_COBJECT_P, offsetof(struct ModAudioSampleCopies, next), false, LOT_MODAUDIOSAMPLECOPIES },
{ "prev", LVT_COBJECT_P, offsetof(struct ModAudioSampleCopies, prev), false, LOT_MODAUDIOSAMPLECOPIES }, { "parent", LVT_COBJECT_P, offsetof(struct ModAudioSampleCopies, parent), false, LOT_MODAUDIO },
// { "sound", LVT_???, offsetof(struct ModAudioSampleCopies, sound), false, LOT_??? }, <--- UNIMPLEMENTED { "prev", LVT_COBJECT_P, offsetof(struct ModAudioSampleCopies, prev), false, LOT_MODAUDIOSAMPLECOPIES },
// { "sound", LVT_???, offsetof(struct ModAudioSampleCopies, sound), false, LOT_??? }, <--- UNIMPLEMENTED
}; };
#define LUA_MOD_FILE_FIELD_COUNT 3 #define LUA_MOD_FILE_FIELD_COUNT 3

View file

@ -178,8 +178,8 @@ static struct ModAudio* find_mod_audio(struct ModFile* file) {
} }
static bool audio_sanity_check(struct ModAudio* audio, bool isStream, const char* action) { static bool audio_sanity_check(struct ModAudio* audio, bool isStream, const char* action) {
if (audio == NULL) { if (audio == NULL || !audio->loaded) {
LOG_LUA_LINE("Tried to %s unloaded audio stream", action); LOG_LUA_LINE("Tried to %s unloaded audio %s", action, audio->isStream ? "stream" : "sample");
return false; return false;
} }
if (isStream && !audio->isStream) { if (isStream && !audio->isStream) {
@ -283,28 +283,26 @@ struct ModAudio* audio_load_internal(const char* filename, bool isStream) {
f_delete(f); f_delete(f);
// decode the audio buffer // decode the audio buffer
// note: buffer and decoder are not freed after a successful call, because ma_decoder_init_memory() does not make copies of them ma_result result = ma_decoder_init_memory(buffer, size, NULL, &audio->decoder);
ma_decoder *decoder = calloc(1, sizeof(ma_decoder));
ma_result result = ma_decoder_init_memory(buffer, size, NULL, decoder);
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
free(decoder);
free(buffer); free(buffer);
LOG_ERROR("failed to load audio file '%s': failed to decode raw audio: %d", filename, result); LOG_ERROR("failed to load audio file '%s': failed to decode raw audio: %d", filename, result);
return NULL; return NULL;
} }
result = ma_sound_init_from_data_source( result = ma_sound_init_from_data_source(
&sModAudioEngine, decoder, &sModAudioEngine, &audio->decoder,
isStream ? MA_SOUND_STREAM_FLAGS : MA_SOUND_SAMPLE_FLAGS, isStream ? MA_SOUND_STREAM_FLAGS : MA_SOUND_SAMPLE_FLAGS,
NULL, &audio->sound NULL, &audio->sound
); );
if (result != MA_SUCCESS) { if (result != MA_SUCCESS) {
free(decoder);
free(buffer); free(buffer);
LOG_ERROR("failed to load audio file '%s': %d", filename, result); LOG_ERROR("failed to load audio file '%s': %d", filename, result);
return NULL; return NULL;
} }
audio->buffer = buffer;
audio->bufferSize = size;
audio->isStream = isStream; audio->isStream = isStream;
audio->loaded = true; audio->loaded = true;
return audio; return audio;
@ -320,7 +318,7 @@ void audio_stream_destroy(struct ModAudio* audio) {
} }
ma_sound_uninit(&audio->sound); ma_sound_uninit(&audio->sound);
dynamic_pool_free(sModAudioPool, audio); audio->loaded = false;
} }
void audio_stream_play(struct ModAudio* audio, bool restart, f32 volume) { void audio_stream_play(struct ModAudio* audio, bool restart, f32 volume) {
@ -437,7 +435,7 @@ void audio_stream_set_volume(struct ModAudio* audio, f32 volume) {
// Use mutexes to be sure we don't try to delete the same memory at the same time // Use mutexes to be sure we don't try to delete the same memory at the same time
#include <pthread.h> #include <pthread.h>
static pthread_mutex_t sSampleCopyMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t sSampleCopyMutex = PTHREAD_MUTEX_INITIALIZER;
static struct ModAudioSampleCopies *sSampleCopiesPendingUninitTail = NULL; static struct ModAudioSampleCopies *sSampleCopyFreeTail = NULL;
// Called whenever a sample copy finishes playback (called from the miniaudio thread) // Called whenever a sample copy finishes playback (called from the miniaudio thread)
// removes the copy from it's linked list, and adds it to the pending list // removes the copy from it's linked list, and adds it to the pending list
@ -448,48 +446,45 @@ static void audio_sample_copy_end_callback(void* userData, UNUSED ma_sound* soun
if (copy->next) { copy->next->prev = copy->prev; } if (copy->next) { copy->next->prev = copy->prev; }
if (copy->prev) { copy->prev->next = copy->next; } if (copy->prev) { copy->prev->next = copy->next; }
if (!copy->next && !copy->prev) { if (!copy->next && !copy->prev) {
copy->parent->sampleCopiesTail = NULL; // Clear the pointer to this copy // This is the last copy of this sample, clear the pointer to it
copy->parent->sampleCopiesTail = NULL;
} }
copy->next = NULL; copy->next = NULL;
copy->prev = NULL; copy->prev = NULL;
// add copy to list // add copy to list
if (!sSampleCopiesPendingUninitTail) { if (sSampleCopyFreeTail) {
sSampleCopiesPendingUninitTail = copy; copy->prev = sSampleCopyFreeTail;
} else { sSampleCopyFreeTail->next = copy;
copy->prev = sSampleCopiesPendingUninitTail;
sSampleCopiesPendingUninitTail->next = copy;
sSampleCopiesPendingUninitTail = copy;
} }
sSampleCopyFreeTail = copy;
pthread_mutex_unlock(&sSampleCopyMutex); pthread_mutex_unlock(&sSampleCopyMutex);
} }
void audio_destroy_copies(struct ModAudioSampleCopies* node) {
while (node) {
struct ModAudioSampleCopies* prev = node->prev;
ma_sound_uninit(&node->sound);
free(node);
node = prev;
}
}
// Called every frame in the main thread from smlua_update() // Called every frame in the main thread from smlua_update()
// Frees all audio sample copies that are in the pending list // Frees all audio sample copies that are in the pending list
void audio_sample_destroy_pending_copies(void) { void audio_sample_destroy_pending_copies(void) {
if (sSampleCopiesPendingUninitTail) { if (sSampleCopyFreeTail) {
pthread_mutex_lock(&sSampleCopyMutex); pthread_mutex_lock(&sSampleCopyMutex);
for (struct ModAudioSampleCopies *node = sSampleCopiesPendingUninitTail; node;) { audio_destroy_copies(sSampleCopyFreeTail);
struct ModAudioSampleCopies *prev = node->prev; sSampleCopyFreeTail = NULL;
ma_sound_stop(&node->sound);
ma_sound_uninit(&node->sound);
free(node);
node = prev;
}
sSampleCopiesPendingUninitTail = NULL;
pthread_mutex_unlock(&sSampleCopyMutex); pthread_mutex_unlock(&sSampleCopyMutex);
} }
} }
static void audio_sample_destroy_copies(struct ModAudio* audio) { static void audio_sample_destroy_copies(struct ModAudio* audio) {
pthread_mutex_lock(&sSampleCopyMutex); pthread_mutex_lock(&sSampleCopyMutex);
for (struct ModAudioSampleCopies* node = audio->sampleCopiesTail; node;) { audio_destroy_copies(audio->sampleCopiesTail);
struct ModAudioSampleCopies* prev = node->prev;
ma_sound_stop(&node->sound);
ma_sound_uninit(&node->sound);
free(node);
node = prev;
}
audio->sampleCopiesTail = NULL; audio->sampleCopiesTail = NULL;
pthread_mutex_unlock(&sSampleCopyMutex); pthread_mutex_unlock(&sSampleCopyMutex);
} }
@ -508,7 +503,7 @@ void audio_sample_destroy(struct ModAudio* audio) {
} }
ma_sound_stop(&audio->sound); ma_sound_stop(&audio->sound);
ma_sound_uninit(&audio->sound); ma_sound_uninit(&audio->sound);
dynamic_pool_free(sModAudioPool, audio); audio->loaded = false;
} }
void audio_sample_stop(struct ModAudio* audio) { void audio_sample_stop(struct ModAudio* audio) {
@ -530,18 +525,21 @@ void audio_sample_play(struct ModAudio* audio, Vec3f position, f32 volume) {
ma_sound *sound = &audio->sound; ma_sound *sound = &audio->sound;
if (ma_sound_is_playing(sound)) { if (ma_sound_is_playing(sound)) {
struct ModAudioSampleCopies* copy = calloc(1, sizeof(struct ModAudioSampleCopies)); struct ModAudioSampleCopies* copy = calloc(1, sizeof(struct ModAudioSampleCopies));
ma_sound_init_copy(&sModAudioEngine, sound, MA_SOUND_SAMPLE_FLAGS, NULL, &copy->sound); ma_result result = ma_decoder_init_memory(audio->buffer, audio->bufferSize, NULL, &copy->decoder);
if (result != MA_SUCCESS) { return; }
result = ma_sound_init_from_data_source(&sModAudioEngine, &copy->decoder, MA_SOUND_SAMPLE_FLAGS, NULL, &copy->sound);
if (result != MA_SUCCESS) { return; }
ma_sound_set_end_callback(&copy->sound, audio_sample_copy_end_callback, copy);
copy->parent = audio; copy->parent = audio;
if (!audio->sampleCopiesTail) { // Add to list
audio->sampleCopiesTail = copy; if (audio->sampleCopiesTail) {
} else {
copy->prev = audio->sampleCopiesTail; copy->prev = audio->sampleCopiesTail;
audio->sampleCopiesTail->next = copy; audio->sampleCopiesTail->next = copy;
audio->sampleCopiesTail = copy;
} }
audio->sampleCopiesTail = copy;
sound = &copy->sound; sound = &copy->sound;
ma_sound_set_end_callback(sound, audio_sample_copy_end_callback, copy);
} }
f32 dist = 0; f32 dist = 0;
@ -590,9 +588,16 @@ void audio_custom_shutdown(void) {
struct DynamicPoolNode* prev = node->prev; struct DynamicPoolNode* prev = node->prev;
struct ModAudio* audio = node->ptr; struct ModAudio* audio = node->ptr;
if (audio->isStream) { if (audio->isStream) {
audio_stream_destroy(audio); if (audio->loaded) { ma_sound_uninit(&audio->sound); }
dynamic_pool_free(sModAudioPool, audio);
} else { } else {
audio_sample_destroy(audio); if (audio->loaded) {
if (audio->sampleCopiesTail) {
audio_sample_destroy_copies(audio);
}
ma_sound_uninit(&audio->sound);
}
dynamic_pool_free(sModAudioPool, audio);
} }
node = prev; node = prev;
} }

View file

@ -13,6 +13,7 @@ void smlua_audio_utils_replace_sequence(u8 sequenceId, u8 bankId, u8 defaultVolu
struct ModAudioSampleCopies { struct ModAudioSampleCopies {
ma_sound sound; ma_sound sound;
ma_decoder decoder;
struct ModAudioSampleCopies *next; struct ModAudioSampleCopies *next;
struct ModAudioSampleCopies *prev; struct ModAudioSampleCopies *prev;
struct ModAudio *parent; struct ModAudio *parent;
@ -21,6 +22,9 @@ struct ModAudioSampleCopies {
struct ModAudio { struct ModAudio {
struct ModFile* file; struct ModFile* file;
ma_sound sound; ma_sound sound;
ma_decoder decoder;
void *buffer;
u32 bufferSize;
struct ModAudioSampleCopies* sampleCopiesTail; struct ModAudioSampleCopies* sampleCopiesTail;
bool isStream; bool isStream;
f32 baseVolume; f32 baseVolume;

View file

@ -175,23 +175,29 @@ void produce_interpolation_frames_and_delay(void) {
gRenderingInterpolated = true; gRenderingInterpolated = true;
// sanity check target time to deal with hangs and such
if (fabs(sFrameTargetTime - curTime) > 1) { sFrameTargetTime = curTime - 0.01f; }
// interpolate and render // interpolate and render
while ((curTime = clock_elapsed_f64()) < sFrameTargetTime) { while ((curTime = clock_elapsed_f64()) < sFrameTargetTime) {
gfx_start_frame(); gfx_start_frame();
f32 delta = (!configUncappedFramerate && configFrameLimit == FRAMERATE) ? 1 : MAX(MIN((curTime - sFrameTimeStart) / (sFrameTargetTime - sFrameTimeStart), 1), 0); f32 delta = ((!configUncappedFramerate && configFrameLimit == FRAMERATE)
? 1.0f
: MAX(MIN((curTime - sFrameTimeStart) / (sFrameTargetTime - sFrameTimeStart), 1.0f), 0.0f)
);
gRenderingDelta = delta; gRenderingDelta = delta;
if (!gSkipInterpolationTitleScreen) { patch_interpolations(delta); } if (!gSkipInterpolationTitleScreen) { patch_interpolations(delta); }
send_display_list(gGfxSPTask); send_display_list(gGfxSPTask);
gfx_end_frame(); gfx_end_frame();
// delay // delay
if (!configUncappedFramerate && !configWindow.vsync) { if (!configUncappedFramerate) {
f64 targetDelta = 1.0 / (f64) configFrameLimit; f64 targetDelta = 1.0 / (f64) configFrameLimit;
f64 now = clock_elapsed_f64(); f64 now = clock_elapsed_f64();
f64 actualDelta = now - curTime; f64 actualDelta = now - curTime;
if (actualDelta < targetDelta) { if (actualDelta < targetDelta) {
f64 delay = ((targetDelta - actualDelta) * 1000.0); f64 delay = ((targetDelta - actualDelta) * 1000.0);
if (delay > 0) { WAPI.delay((u32) delay * 0.9); } if (delay > 0.0f) { WAPI.delay((u32) delay); }
} }
} }