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:
parent
2b6a173f8b
commit
594ff262bc
|
@ -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 = {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:](#)
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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]));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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, ©->sound);
|
ma_result result = ma_decoder_init_memory(audio->buffer, audio->bufferSize, NULL, ©->decoder);
|
||||||
|
if (result != MA_SUCCESS) { return; }
|
||||||
|
result = ma_sound_init_from_data_source(&sModAudioEngine, ©->decoder, MA_SOUND_SAMPLE_FLAGS, NULL, ©->sound);
|
||||||
|
if (result != MA_SUCCESS) { return; }
|
||||||
|
ma_sound_set_end_callback(©->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 = ©->sound;
|
sound = ©->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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue