Add audio_stream_get/set_volume_channel (#1205)
Some checks are pending
Build coop / build-linux (push) Waiting to run
Build coop / build-steamos (push) Waiting to run
Build coop / build-windows-opengl (push) Waiting to run
Build coop / build-windows-directx (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run

Allows modders to play audio streams on channels other than level background music.
4 constants have been added for this purpose:
- `MOD_AUDIO_CHANNEL_MASTER` - sound is only affected by master volume
- `MOD_AUDIO_CHANNEL_MUSIC` - sound is affected by music volume, same as previous behaviour
- `MOD_AUDIO_CHANNEL_SFX` - sound is affected by sfx volume, same as sample behaviour
- `MOD_AUDIO_CHANNEL_ENV` - sound is affected by env volume 
This was done instead of using the existing `SEQ_PLAYER_*` constants to avoid confusion and because there isn't a `NONE`/`MASTER` option.

Additionally, sets the default to `MOD_AUDIO_CHANNEL_MUSIC` as to not break compatibility.

```lua
audio_stream_set_volume_channel(stream, MOD_AUDIO_CHANNEL_SFX) -- wow its just like a sample
audio_stream_get_volume_channel(stream) -- returns MOD_AUDIO_CHANNEL_SFX (its actually 2)
```
This commit is contained in:
jayden 2026-05-03 08:59:11 +01:00 committed by GitHub
parent de7ad4b0d6
commit 5dabcaa313
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 195 additions and 19 deletions

View file

@ -56,6 +56,7 @@ in_files = [
"include/PR/gbi.h",
"include/PR/gbi_extension.h",
"src/engine/surface_load.h",
"src/pc/lua/utils/smlua_audio_utils.h",
]
exclude_constants = {
@ -77,6 +78,7 @@ include_constants = {
"include/geo_commands.h": [ "BACKGROUND" ],
"include/level_commands.h": [ "WARP_CHECKPOINT", "WARP_NO_CHECKPOINT" ],
"src/audio/external.h": [ "SEQ_PLAYER", "DS_" ],
"src/pc/lua/utils/smlua_audio_utils.h": ["MOD_AUDIO_CHANNEL"],
"src/pc/mods/mod_storage.h": [ "MAX_KEYS", "MAX_KEY_VALUE_LENGTH" ],
"include/PR/gbi.h": [
"^G_NOOP$",

View file

@ -97,7 +97,7 @@ override_field_invisible = {
"FnGraphNode": [ "luaTokenIndex" ],
"Object": [ "firstSurface" ],
"Animation": [ "unusedBoneCount" ],
"ModAudio": [ "sound", "decoder", "buffer", "bufferSize", "sampleCopiesTail" ],
"ModAudio": [ "sound", "decoder", "buffer", "bufferSize", "sampleCopiesTail", "volChannel" ],
"Painting": [ "normalDisplayList", "textureMaps", "rippleDisplayList", "ripples" ],
"DialogEntry": [ "str" ],
"ModFsFile": [ "data", "capacity" ],

View file

@ -8171,6 +8171,18 @@ VALID_BUTTONS = (A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON | U_JPAD | D_JPAD |
--- @type integer
C_BUTTONS = (U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS )
--- @type integer
MOD_AUDIO_CHANNEL_MASTER = 0
--- @type integer
MOD_AUDIO_CHANNEL_MUSIC = 1
--- @type integer
MOD_AUDIO_CHANNEL_SFX = 2
--- @type integer
MOD_AUDIO_CHANNEL_ENV = 3
HOOK_UPDATE = 0 --- @type LuaHookedEventType
HOOK_MARIO_UPDATE = 1 --- @type LuaHookedEventType
HOOK_BEFORE_MARIO_UPDATE = 2 --- @type LuaHookedEventType

View file

@ -10334,6 +10334,20 @@ function audio_stream_set_volume(audio, volume)
-- ...
end
--- @param audio ModAudio
--- @return integer
--- Gets the volume channel of an `audio` stream
function audio_stream_get_volume_channel(audio)
-- ...
end
--- @param audio ModAudio
--- @param channel integer
--- Sets the volume channel of an `audio` stream
function audio_stream_set_volume_channel(audio, channel)
-- ...
end
--- @param filename string
--- @return ModAudio
--- Loads an `audio` sample

View file

@ -1212,6 +1212,7 @@
--- @field public looping boolean
--- @field public frequency number
--- @field public volume number
--- @field public channel integer
--- @class ModFs
--- @field public mod Mod

View file

@ -79,6 +79,7 @@
- [seq_ids.h](#seq_idsh)
- [enum SeqId](#enum-SeqId)
- [sm64.h](#sm64h)
- [smlua_audio_utils.h](#smlua_audio_utilsh)
- [smlua_hooks.h](#smlua_hooksh)
- [enum LuaHookedEventType](#enum-LuaHookedEventType)
- [enum LuaHookedEventReturn](#enum-LuaHookedEventReturn)
@ -3486,6 +3487,16 @@
<br />
## [smlua_audio_utils.h](#smlua_audio_utils.h)
- MOD_AUDIO_CHANNEL_MASTER
- MOD_AUDIO_CHANNEL_MUSIC
- MOD_AUDIO_CHANNEL_SFX
- MOD_AUDIO_CHANNEL_ENV
[:arrow_up_small:](#)
<br />
## [smlua_hooks.h](#smlua_hooks.h)
### [enum LuaHookedEventType](#LuaHookedEventType)

View file

@ -5947,6 +5947,53 @@ Sets the volume of an `audio` stream
<br />
## [audio_stream_get_volume_channel](#audio_stream_get_volume_channel)
### Description
Gets the volume channel of an `audio` stream
### Lua Example
`local integerValue = audio_stream_get_volume_channel(audio)`
### Parameters
| Field | Type |
| ----- | ---- |
| audio | [ModAudio](structs.md#ModAudio) |
### Returns
- `integer`
### C Prototype
`u8 audio_stream_get_volume_channel(struct ModAudio *audio);`
[:arrow_up_small:](#)
<br />
## [audio_stream_set_volume_channel](#audio_stream_set_volume_channel)
### Description
Sets the volume channel of an `audio` stream
### Lua Example
`audio_stream_set_volume_channel(audio, channel)`
### Parameters
| Field | Type |
| ----- | ---- |
| audio | [ModAudio](structs.md#ModAudio) |
| channel | `integer` |
### Returns
- None
### C Prototype
`void audio_stream_set_volume_channel(struct ModAudio *audio, u8 channel);`
[:arrow_up_small:](#)
<br />
## [audio_sample_load](#audio_sample_load)
### Description

View file

@ -1849,6 +1849,8 @@
- [audio_stream_set_frequency](functions-6.md#audio_stream_set_frequency)
- [audio_stream_get_volume](functions-6.md#audio_stream_get_volume)
- [audio_stream_set_volume](functions-6.md#audio_stream_set_volume)
- [audio_stream_get_volume_channel](functions-6.md#audio_stream_get_volume_channel)
- [audio_stream_set_volume_channel](functions-6.md#audio_stream_set_volume_channel)
- [audio_sample_load](functions-6.md#audio_sample_load)
- [audio_sample_destroy](functions-6.md#audio_sample_destroy)
- [audio_sample_stop](functions-6.md#audio_sample_stop)

View file

@ -1768,6 +1768,7 @@
| looping | `boolean` | |
| frequency | `number` | |
| volume | `number` | |
| channel | `integer` | |
[:arrow_up_small:](#)

View file

@ -1494,18 +1494,19 @@ static struct LuaObjectField sModFields[LUA_MOD_FIELD_COUNT] = {
{ "size", LVT_U64, offsetof(struct Mod, size), true, LOT_NONE },
};
#define LUA_MOD_AUDIO_FIELD_COUNT 10
#define LUA_MOD_AUDIO_FIELD_COUNT 11
static struct LuaObjectField sModAudioFields[LUA_MOD_AUDIO_FIELD_COUNT] = {
{ "baseVolume", LVT_F32, offsetof(struct ModAudio, baseVolume), false, LOT_NONE },
{ "file", LVT_PROPERTY, .get = "return_self" },
{ "filepath", LVT_STRING_P, offsetof(struct ModAudio, filepath), true, LOT_NONE },
{ "frequency", LVT_PROPERTY, .get = "audio_stream_get_frequency", .set = "audio_stream_set_frequency" },
{ "isStream", LVT_BOOL, offsetof(struct ModAudio, isStream), true, LOT_NONE },
{ "loaded", LVT_BOOL, offsetof(struct ModAudio, loaded), true, LOT_NONE },
{ "looping", LVT_PROPERTY, .get = "audio_stream_get_looping", .set = "audio_stream_set_looping" },
{ "position", LVT_PROPERTY, .get = "audio_stream_get_position", .set = "audio_stream_set_position" },
{ "relativePath", LVT_STRING_P, offsetof(struct ModAudio, relativePath), true, LOT_NONE },
{ "volume", LVT_PROPERTY, .get = "audio_stream_get_volume", .set = "audio_stream_set_volume" },
{ "baseVolume", LVT_F32, offsetof(struct ModAudio, baseVolume), false, LOT_NONE },
{ "channel", LVT_PROPERTY, .get = "audio_stream_get_volume_channel", .set = "audio_stream_set_volume_channel" },
{ "file", LVT_PROPERTY, .get = "return_self" },
{ "filepath", LVT_STRING_P, offsetof(struct ModAudio, filepath), true, LOT_NONE },
{ "frequency", LVT_PROPERTY, .get = "audio_stream_get_frequency", .set = "audio_stream_set_frequency" },
{ "isStream", LVT_BOOL, offsetof(struct ModAudio, isStream), true, LOT_NONE },
{ "loaded", LVT_BOOL, offsetof(struct ModAudio, loaded), true, LOT_NONE },
{ "looping", LVT_PROPERTY, .get = "audio_stream_get_looping", .set = "audio_stream_set_looping" },
{ "position", LVT_PROPERTY, .get = "audio_stream_get_position", .set = "audio_stream_set_position" },
{ "relativePath", LVT_STRING_P, offsetof(struct ModAudio, relativePath), true, LOT_NONE },
{ "volume", LVT_PROPERTY, .get = "audio_stream_get_volume", .set = "audio_stream_set_volume" },
};
#define LUA_MOD_FS_FIELD_COUNT 15

View file

@ -3495,6 +3495,10 @@ char gSmluaConstants[] = ""
"ACT_RELEASING_BOWSER=0x00000392\n"
"VALID_BUTTONS=(A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON | U_JPAD | D_JPAD | L_JPAD | R_JPAD | L_TRIG | R_TRIG | X_BUTTON | Y_BUTTON | U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS )\n"
"C_BUTTONS=(U_CBUTTONS | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS )\n"
"MOD_AUDIO_CHANNEL_MASTER=0\n"
"MOD_AUDIO_CHANNEL_MUSIC=1\n"
"MOD_AUDIO_CHANNEL_SFX=2\n"
"MOD_AUDIO_CHANNEL_ENV=3\n"
"HOOK_UPDATE=0\n"
"HOOK_MARIO_UPDATE=1\n"
"HOOK_BEFORE_MARIO_UPDATE=2\n"

View file

@ -30774,6 +30774,42 @@ int smlua_func_audio_stream_set_volume(lua_State* L) {
return 1;
}
int smlua_func_audio_stream_get_volume_channel(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "audio_stream_get_volume_channel", 1, top);
return 0;
}
struct ModAudio* audio = (struct ModAudio*)smlua_to_cobject(L, 1, LOT_MODAUDIO);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "audio_stream_get_volume_channel"); return 0; }
lua_pushinteger(L, audio_stream_get_volume_channel(audio));
return 1;
}
int smlua_func_audio_stream_set_volume_channel(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 2) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "audio_stream_set_volume_channel", 2, top);
return 0;
}
struct ModAudio* audio = (struct ModAudio*)smlua_to_cobject(L, 1, LOT_MODAUDIO);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "audio_stream_set_volume_channel"); return 0; }
u8 channel = smlua_to_integer(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "audio_stream_set_volume_channel"); return 0; }
audio_stream_set_volume_channel(audio, channel);
return 1;
}
int smlua_func_audio_sample_load(lua_State* L) {
if (L == NULL) { return 0; }
@ -38680,6 +38716,8 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "audio_stream_set_frequency", smlua_func_audio_stream_set_frequency);
smlua_bind_function(L, "audio_stream_get_volume", smlua_func_audio_stream_get_volume);
smlua_bind_function(L, "audio_stream_set_volume", smlua_func_audio_stream_set_volume);
smlua_bind_function(L, "audio_stream_get_volume_channel", smlua_func_audio_stream_get_volume_channel);
smlua_bind_function(L, "audio_stream_set_volume_channel", smlua_func_audio_stream_set_volume_channel);
smlua_bind_function(L, "audio_sample_load", smlua_func_audio_sample_load);
smlua_bind_function(L, "audio_sample_destroy", smlua_func_audio_sample_destroy);
smlua_bind_function(L, "audio_sample_stop", smlua_func_audio_sample_stop);

View file

@ -363,10 +363,24 @@ struct ModAudio* audio_load_internal(const char* filename, bool isStream) {
audio->buffer = buffer;
audio->bufferSize = size;
audio->isStream = isStream;
audio->baseVolume = 1.0f;
audio->volChannel = MOD_AUDIO_CHANNEL_MUSIC;
audio->loaded = true;
return audio;
}
static f32 get_audio_volume(struct ModAudio* audio) {
f32 volume = audio->baseVolume;
if (audio->volChannel == MOD_AUDIO_CHANNEL_MUSIC) {
volume *= (f32)configMusicVolume / 127.0f * (f32)gLuaVolumeLevel / 127.0f;
} else if (audio->volChannel == MOD_AUDIO_CHANNEL_SFX) {
volume *= (f32)configSfxVolume / 127.0f * (f32)gLuaVolumeSfx / 127.0f;
} else if (audio->volChannel == MOD_AUDIO_CHANNEL_ENV) {
volume *= (f32)configEnvVolume / 127.0f * (f32)gLuaVolumeEnv / 127.0f;
}
return gMasterVolume * volume;
}
struct ModAudio* audio_stream_load(const char* filename) {
return audio_load_internal(filename, true);
}
@ -388,6 +402,7 @@ void audio_stream_play(struct ModAudio* audio, bool restart, f32 volume) {
ma_sound_set_volume(&audio->sound, gMasterVolume * musicVolume * volume);
}
audio->baseVolume = volume;
ma_sound_set_volume(&audio->sound, get_audio_volume(audio));
if (restart || !ma_sound_is_playing(&audio->sound)) { ma_sound_seek_to_pcm_frame(&audio->sound, 0); }
ma_sound_start(&audio->sound);
}
@ -473,14 +488,9 @@ f32 audio_stream_get_volume(struct ModAudio* audio) {
void audio_stream_set_volume(struct ModAudio* audio, f32 volume) {
if (!audio_sanity_check(audio, true, "set stream volume for")) { return; }
if (configMuteFocusLoss && !WAPI.has_focus()) {
ma_sound_set_volume(&audio->sound, 0);
} else {
f32 musicVolume = (f32)configMusicVolume / 127.0f * (f32)gLuaVolumeLevel / 127.0f;
ma_sound_set_volume(&audio->sound, gMasterVolume * musicVolume * volume);
}
audio->baseVolume = volume;
ma_sound_set_volume(&audio->sound, get_audio_volume(audio));
}
// void audio_stream_set_speed(struct ModAudio* audio, f32 initial_freq, f32 speed, bool pitch) {
@ -489,6 +499,28 @@ void audio_stream_set_volume(struct ModAudio* audio, f32 volume) {
// bassh_set_speed(audio->handle, initial_freq, speed, pitch);
// }
u8 audio_stream_get_volume_channel(struct ModAudio* audio) {
if (!audio_sanity_check(audio, true, "get stream volume channel from")) {
return 0;
}
return audio->volChannel;
}
void audio_stream_set_volume_channel(struct ModAudio* audio, u8 channel) {
if (!audio_sanity_check(audio, true, "set stream volume channel for")) {
return;
}
if (channel > MOD_AUDIO_CHANNEL_ENV) {
LOG_LUA_LINE("Tried to set volume channel to invalid value: %d", channel);
return;
}
audio->volChannel = channel;
ma_sound_set_volume(&audio->sound, get_audio_volume(audio));
}
//////////////////////////////////////
// MA calls the end callback from its audio thread

View file

@ -15,6 +15,11 @@ u8 smlua_audio_utils_allocate_sequence(void);
// mod sounds //
////////////////
#define MOD_AUDIO_CHANNEL_MASTER 0
#define MOD_AUDIO_CHANNEL_MUSIC 1
#define MOD_AUDIO_CHANNEL_SFX 2
#define MOD_AUDIO_CHANNEL_ENV 3
struct ModAudioSampleCopies {
ma_sound sound;
ma_decoder decoder;
@ -35,12 +40,14 @@ struct ModAudio {
struct ModAudioSampleCopies* sampleCopiesTail;
bool isStream;
f32 baseVolume;
u8 volChannel;
bool loaded;
PROPERTY(position, audio_stream_get_position, audio_stream_set_position);
PROPERTY(looping, audio_stream_get_looping, audio_stream_set_looping);
PROPERTY(frequency, audio_stream_get_frequency, audio_stream_set_frequency);
PROPERTY(volume, audio_stream_get_volume, audio_stream_set_volume);
PROPERTY(channel, audio_stream_get_volume_channel, audio_stream_set_volume_channel);
PROPERTY(file, return_self, NULL); // compatibility band-aid
};
@ -73,6 +80,10 @@ void audio_stream_set_frequency(struct ModAudio* audio, f32 freq);
f32 audio_stream_get_volume(struct ModAudio* audio);
/* |description|Sets the volume of an `audio` stream|descriptionEnd| */
void audio_stream_set_volume(struct ModAudio* audio, f32 volume);
/* |description|Gets the volume channel of an `audio` stream|descriptionEnd| */
u8 audio_stream_get_volume_channel(struct ModAudio *audio);
/* |description|Sets the volume channel of an `audio` stream|descriptionEnd| */
void audio_stream_set_volume_channel(struct ModAudio *audio, u8 channel);
void audio_sample_destroy_pending_copies(void);
/* |description|Loads an `audio` sample|descriptionEnd| */