Chapter 7 — Audio¶
Back to Index | Previous: Asset Bundles | Next: Networking
Overview¶
RMAPI lets you load .wav files from disk and play them as 3D positional audio using RUMBLE's native audio system.
Reminder: All names in these examples are arbitrary — variable names (
hitSound,mySound), folder names (MyMod,HitSound), and file names (explosion.wav,bonk.wav) can be whatever you want. Only the RMAPI method names are real. See Chapter 1 for details.
The workflow is:
- Create an
AudioCallfrom a .wav file (do this once — inOnLateInitializeMelonor on the firstonMapInitialized, which fires for Gym, Park, Map0, and Map1) - Play it whenever you want at a world position (only after a scene has loaded and the game's AudioManager is ready)
Step 1: Create an AudioCall¶
Single Sound¶
AudioCall mySound = AudioManager.CreateAudioCall(
filePath: @"UserData\MyMod\explosion.wav",
volume: 0.8f // 0.0 = silent, 1.0 = full volume
);
Returns null if the file doesn't exist or can't be parsed.
Multiple Sounds at Once¶
string[] paths = new string[]
{
@"UserData\MyMod\hit1.wav",
@"UserData\MyMod\hit2.wav",
@"UserData\MyMod\hit3.wav"
};
AudioCall[] sounds = AudioManager.CreateAudioCalls(paths, volume: 0.5f);
// sounds[0] = hit1, sounds[1] = hit2, sounds[2] = hit3
// Any entry will be null if that file failed to load
What Happens Under the Hood¶
- The .wav file is parsed manually (supports standard PCM WAV)
- A Unity
AudioClipis created in memory - An
AudioCallScriptableObject is created with the clip attached - Both are marked
HideAndDontSaveso they persist across scenes
Step 2: Play the Sound¶
// Play at a specific world position
AudioManager.PlaySound(mySound, new Vector3(0, 1, 0));
// Play with looping
AudioManager.PlaySound(mySound, somePosition, isLooping: true);
PlaySound returns a PooledAudioSource — RUMBLE manages the audio source lifecycle for you.
Play at the Player's Position¶
Vector3 playerPos = Calls.Players.GetLocalPlayer().Controller.transform.position;
AudioManager.PlaySound(mySound, playerPos);
Loading Raw AudioClips¶
If you want just the AudioClip without wrapping it in an AudioCall:
AudioClip clip = AudioManager.LoadWavFile(@"UserData\MyMod\mysound.wav");
// Returns null if the file doesn't exist or is invalid
You can use this clip with your own AudioSource components.
Method Summary¶
| Method | Returns | Description |
|---|---|---|
CreateAudioCall(filePath, volume) |
AudioCall |
Create a playable sound from a .wav file |
CreateAudioCalls(filePaths[], volume) |
AudioCall[] |
Batch-create multiple sounds |
PlaySound(audioCall, position, isLooping?) |
PooledAudioSource |
Play a sound at a world position |
LoadWavFile(filePath) |
AudioClip |
Load a raw AudioClip from a .wav file |
Requirements and Limitations¶
- Only .wav files are supported (not .mp3, .ogg, etc.)
- The .wav must be standard PCM format (16-bit)
- Create your
AudioCallobjects once (e.g., at startup) — don't recreate them every time you play - Sounds are 3D positional — they get quieter with distance from the listener
Full Example: Hit Sound on Damage¶
using MelonLoader;
using RumbleModdingAPI.RMAPI;
using Il2CppRUMBLE.Audio;
using Il2CppRUMBLE.Players;
using UnityEngine;
namespace HitSound
{
public class HitSound : MelonMod
{
private AudioCall hitSound;
public override void OnLateInitializeMelon()
{
hitSound = AudioManager.CreateAudioCall(@"UserData\HitSound\bonk.wav", 0.7f);
if (hitSound == null)
{
Melon<HitSound>.Logger.Error("Failed to load bonk.wav!");
return;
}
Actions.onPlayerHealthChanged += OnDamage;
}
private void OnDamage(Player player, int damage)
{
if (damage <= 0) return; // only on actual damage, not healing
Vector3 pos = player.Controller.transform.position;
AudioManager.PlaySound(hitSound, pos);
}
}
}