How to make tons of skill sounds with fmod

I’m trying to use fmod to make skill sound effects for my unity project, these sound effects are only very short and there are a lot of sound effects. Do I need to make an event event for each sound effect? Or a single event and call different sound effects with parameters? I don’t think either of these methods are very manageable with a large number of sound effects and would be a pain in the ass to modify at a later date.

Use the multi instrument. Drag and drop all of your samples into FMOD, and select “2d timeline with multi instrument”, which will allow to play a random sound each time the event is fired.

Thanks for your answer. Because a character in the project will have dozens of skills and their sound effects correspond one to one. So I want to trigger a specific sound effect when calling a skill in unity instead of playing it randomly. multi Instrument doesn’t seem to support playing a specific audio.

There are two main ways to achieve what you want.

The first way is to create one event for each skill sound you want to be able to play. This is easier than it sounds: Just select all of the audio assets and drag them into the events browser, and this dialog will appear:
image
Select the appropriate options (probably “3D Action” and “Create a new event for each asset”), and click “Create” to automatically create one event for each sound file.

If you would prefer not to create one event for each skill sound, the alternative is to create one event containing a programmer instrument. Whenever a programmer instrument is triggered, it generates a callback that prompts your game’s code to specify an asset to be played; you can use this to specify any asset in an audio table or any loose sound file on disk.

I have successfully used programmer instrument as per the sample code. but the problem I’m having is that I can run the game in unity and hear the sound properly, but after packaging the whole project to my phone, triggering the callback flashes back.
This is the fmod project


And here is the associated script

        private EVENT_CALLBACK dialogueCallback;

        public async void InitFmod()
        {
            List<UniTask> uniTasks = new();
            foreach (var a in _game.mLoad.m_banks.banks)
            {
                try
                {
                    UniTaskCompletionSource uniTaskCompletionSource = new UniTaskCompletionSource();
                    RuntimeManager.LoadBank(a, true, () =>
                    {
                        uniTaskCompletionSource.TrySetResult();
                        Debug.Log("加载成功");
                    });
                    uniTasks.Add(uniTaskCompletionSource.Task);
                }
                catch (Exception e)
                {
                    Debug.LogError("banks加载错误" + e);
                    throw;
                }
            }

            await UniTask.WhenAll(uniTasks);
            RuntimeManager.WaitForAllSampleLoading();
            //bgm直接添加
            var fmodEvent = RuntimeManager.CreateInstance("event:/BG");
            _fmodSoundHelper.Add("event:/BG", fmodEvent);
            
            //设置音效效果
            soundFX = RuntimeManager.GetVCA("vca:/SoundFX");
            BGM = RuntimeManager.GetVCA("vca:/BGMusic");
            dialogueCallback = new EVENT_CALLBACK(skillCallBack);
        }

        [AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
        public static RESULT skillCallBack(EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
        {
            FMOD.Studio.EventInstance skillEvent = new EventInstance(instancePtr);
            IntPtr stringPtr;
            skillEvent.getUserData(out stringPtr);

            // Get the string object
            GCHandle stringHandle = GCHandle.FromIntPtr(stringPtr);
            String key = stringHandle.Target as String;
            Debug.Log(key);

            switch (type)
            {
                case EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
                {
                    var parameter = (PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(PROGRAMMER_SOUND_PROPERTIES));
                    Sound sound;
                    RuntimeManager.StudioSystem.getSoundInfo(key, out var soundInfo);
                    RuntimeManager.CoreSystem.createSound(soundInfo.name_or_data, MODE.DEFAULT, ref soundInfo.exinfo, out sound);
                    sound.getSubSound(soundInfo.subsoundindex, out var subSound);
                    sound = subSound;
                    subSound.getLength(out var maxLength, TIMEUNIT.MS);

                    parameter.sound = sound.handle;
                    parameter.subsoundIndex = -1;
                    Marshal.StructureToPtr(parameter, parameterPtr, false);
                    Debug.Log("播放完毕");
                    break;
                }
                case EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
                {
                    var parameter = (PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(PROGRAMMER_SOUND_PROPERTIES));
                    var sound = new Sound(parameter.sound);
                    sound.release();
                    Debug.Log("回收了");
                    break;
                }
            }
            return RESULT.OK;
        }

        public void PlaySkillSound(string key)
        {
            Debug.Log("准备播放" + key);
            GCHandle stringHandle = GCHandle.Alloc(key);
            var skillEvent = RuntimeManager.CreateInstance("event:/SkillSound/SkillSoundCallBack");
            skillEvent.setUserData(GCHandle.ToIntPtr(stringHandle));
            skillEvent.setCallback(dialogueCallback);
            skillEvent.start();
            skillEvent.release();
        }

Here is the debugging information


What do you mean by “flashes back?”

program crash, I used a translation program to translate it, and I think it mistranslated it.

Thanks for the clarification.

Unfortunately, we can’t really tell what’s happening from that debugging information - possibly because you’re filtering for “unity.” If you set your logging level to “log,” enable API error logging in the FMOD for Unity settings, and filter for “FMOD” in their Logcat output instead, you may get more relevant information.

Oh, and would it be possible for you to copy and paste the text of the log instead of posting a screenshot? It’s easier for us to read that way.

I get these errors at the start of the game after I set it up like you said, but I think they’re caused by the fact that I didn’t load the vac at the start (I loaded all of them when I got into the game).

E  [FMOD] VCA::setVolume(1) returned ERR_INVALID_HANDLE for STUDIO_VCA (0x0).
FMODUnity.RuntimeManager:ERROR_CALLBACK(IntPtr, SYSTEM_CALLBACK_TYPE, IntPtr, IntPtr, IntPtr)

E  [FMOD] VCA::setVolume(1) returned ERR_INVALID_HANDLE for STUDIO_VCA (0x0).
FMODUnity.RuntimeManager:ERROR_CALLBACK(IntPtr, SYSTEM_CALLBACK_TYPE, IntPtr, IntPtr, IntPtr)

E  [FMOD] VCA::setVolume(1) returned ERR_INVALID_HANDLE for STUDIO_VCA (0x0).
FMODUnity.RuntimeManager:ERROR_CALLBACK(IntPtr, SYSTEM_CALLBACK_TYPE, IntPtr, IntPtr, IntPtr)

Also, there is an error when the program crashes

E  pid: 27974, tid: 29019, name: FMOD Studio upd  >>> MyPackage <<<
E        #07 pc 00000000000dd830  /data/app/~~3YS7AJM04lElLc6MRJbVLQ==/MyPackage-xtcdCEeGPLX21roL55fPFA==/lib/arm64/libfmodstudio.so

Hi,

There are a couple of problems unrelated to the crash:

  • The programmer sounds callback doesn’t free stringHandle at any point - this will cause a memory leak. You can fix this by freeing stringHandle when the event destroyed callback is fired:
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
{
    stringHandle.Free();
    break;
}
  • The ERR_INVALID_HANDLE VCA error is occurring because the VCA you’re calling setVolume() on is null.

Again, it’s unlikely that either of the above issues are causing the crash though. Can I get some more information from you? Specifically:

  • A complete log from Logcat where you have reproduced the crash
  • Your full Unity, FMOD for Unity, and NDK version numbers so I can resolve the internal call stack