I now have an event that embed others in its timeline and I need to be able to receive markers from those embedded events but the callback solution linked above doesn’t react to “nested” events.
I’m sure I just misunderstood something about how FMOD works with event/instance.
Is it achievable ? or do I need to rethink my workflow ?
Starting with 2.00.02 we implemented forwarding of FMOD_STUDIO_EVENT_CALLBACK_TIMELINE_MARKER from nested events so you should be seeing them come through. You shouldn’t need to do anything different on the implementation side either.
Can you double check your event setup and ensure there are no errors printing to the log?
After some reasearch I found that I needed to transform all events instance within an event into “nested” through right click menus) Nested Event Question
I managed to toggle all instance of events within my main event timeline into real nested event.
But I still don’t receive any marker from the nested ones.
I also don’t see my nested events within unity’s fmod event window ( someone already asked for that while ago Accessing nested events in unity )
I couldn’t find anything regarding "FMOD_STUDIO_EVENT_CALLBACK_TIMELINE_MARKER "
I’m using code from the topic I linked in my original question :
case FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_MARKER:
{
//Debug.Log(parameterPtr);
var parameter = (FMOD.Studio.TIMELINE_MARKER_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.TIMELINE_MARKER_PROPERTIES));
I don’t have any issue other than that (logs/errors …)
I tried to update fmod unity integration to the lastest version (2.00.09) and I’m not receiving any marker anymore (event from normal events).
Tried to tweak the callback subscription script but nothing works. The callback is not called.
Here is my full script (slight custom version of original logic) in case I’m doing something obviously wrong.
//--------------------------------------------------------------------
//
// This is a Unity behaviour script that demonstrates how to use
// timeline markers in your game code.
//
// Timeline markers can be implicit - such as beats and bars. Or they
// can be explicity placed by sound designers, in which case they have
// a sound designer specified name attached to them.
//
// Timeline markers can be useful for syncing game events to sound
// events.
//
// The script starts a piece of music and then displays on the screen
// the current bar and the last marker encountered.
//
// This document assumes familiarity with Unity scripting. See
// https://unity3d.com/learn/tutorials/topics/scripting for resources
// on learning Unity scripting.
//
//--------------------------------------------------------------------
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using FMOD.Studio;
public abstract class FMODCallbackHandler : MonoBehaviour
{
// Variables that are modified in the callback need to be part of a seperate class.
// This class needs to be 'blittable' otherwise it can't be pinned in memory.
[StructLayout(LayoutKind.Sequential)]
class TimelineInfo
{
public int currentMusicBar = 0;
public FMOD.StringWrapper lastMarker = new FMOD.StringWrapper();
}
TimelineInfo timelineInfo;
GCHandle timelineHandle;
FMOD.Studio.EVENT_CALLBACK beatCallback;
FMOD.Studio.EventInstance evtInstance;
public FMODUnity.StudioEventEmitter studioEvent;
private void Start()
{
init(studioEvent.EventInstance);
}
void init(FMOD.Studio.EventInstance instance)
{
timelineInfo = new TimelineInfo();
// Explicitly create the delegate object and assign it to a member so it doesn't get freed
// by the garbage collected while it's being used
beatCallback = new FMOD.Studio.EVENT_CALLBACK(BeatEventCallback);
evtInstance = instance;
// Pin the class that will store the data modified during the callback
timelineHandle = GCHandle.Alloc(timelineInfo, GCHandleType.Pinned);
// Pass the object through the userdata of the instance
evtInstance.setUserData(GCHandle.ToIntPtr(timelineHandle));
evtInstance.setCallback(beatCallback, EVENT_CALLBACK_TYPE.TIMELINE_MARKER);
//evtInstance.setCallback(beatCallback, FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_BEAT | FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_MARKER);
Debug.Log("callback is setup for " + instance, transform);
}
void OnDestroy()
{
evtInstance.setUserData(IntPtr.Zero);
evtInstance.release();
if(timelineHandle != null && timelineHandle.IsAllocated) timelineHandle.Free();
//if (studioEvent != null) studioEvent.onCreateInstance -= init;
}
[AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
FMOD.RESULT BeatEventCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, FMOD.Studio.EventInstance instance, IntPtr parameterPtr)
{
// Retrieve the user data
IntPtr timelineInfoPtr;
FMOD.RESULT result = instance.getUserData(out timelineInfoPtr);
//Debug.Log(timelineInfoPtr);
Debug.Log("beat callback : "+type);
if (result != FMOD.RESULT.OK)
{
Debug.LogError("Timeline Callback error: " + result);
}
else if (timelineInfoPtr != IntPtr.Zero)
{
switch (type)
{
case FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_BEAT:
{
var parameter = (FMOD.Studio.TIMELINE_BEAT_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.TIMELINE_BEAT_PROPERTIES));
onBeatReceived(parameter);
}
break;
case FMOD.Studio.EVENT_CALLBACK_TYPE.TIMELINE_MARKER:
{
//Debug.Log(parameterPtr);
var parameter = (FMOD.Studio.TIMELINE_MARKER_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.TIMELINE_MARKER_PROPERTIES));
//Debug.Log(parameter);
//Debug.Log(parameter.name);
onMarkerReceived(parameter);
}
break;
default:
Debug.Log(type);
break;
}
}
return FMOD.RESULT.OK;
}
protected virtual void onBeatReceived(FMOD.Studio.TIMELINE_BEAT_PROPERTIES beat)
{
Debug.Log("[FMODCallBack] Beat received. "+beat);
}
protected virtual void onMarkerReceived(FMOD.Studio.TIMELINE_MARKER_PROPERTIES marker)
{
Debug.Log("[FMODCallBack] Marker received. "+marker);
}
}