Hi there,
I am making a game where I take the player’s mic input, send it to a programmer instrument for real time processing, then play it. I have had a consistent 0.5 second latency. I took out the programmer instrument portion, and the latency remains so I figure the latency probably ocurrs during the recording part. As someone who is not a programmer, looking through forums of people discussing similar issues and Core API resource page is only helpful to a limit. Would love to have some help!
Unity: 2022.3.441f1
FMOD Studio 2.02.21
Computer: MacBook Pro (2020, M1, 16GB Memory), Big Sur 11.7.2 >Yes I am aware Mac is not the best option for game development and am thinking about getting PC
Here’s the codes for FMOD Recording/Programmer Instrument (it’s a merge of scripts )
using System;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
using FMOD.Studio;
public class ProgrammingInstrument : MonoBehaviour
{
/// <summary>
/// Recording into a FMOD.Sound, then assign it to a progammer instrument
/// </summary>
FMOD.Studio.EVENT_CALLBACK dialogueCallback;
public FMODUnity.EventReference EventName;
#if UNITY_EDITOR
void Reset()
{
EventName = FMODUnity.EventReference.Find("event:/Record");
}
#endif
//Recording varaibles
private uint samplesRecorded, samplesPlayed = 0;
private int nativeRate, nativeChannels = 0;
private uint recSoundLength = 0;
//FMOD Sound variables
private FMOD.CREATESOUNDEXINFO exInfo = new FMOD.CREATESOUNDEXINFO();
public FMOD.Sound recSound;
private FMOD.Channel channel;
//Programmer instrument
public IntPtr TempInstPtr;
public IntPtr TempParaPtr;
void Start()
{
//recording
/*
Determine latency in samples.
*/
FMODUnity.RuntimeManager.CoreSystem.getRecordDriverInfo(0, out _, 0, out _, out nativeRate, out _, out nativeChannels, out _);
/*
Create user sound to record into, then start recording.
*/
exInfo.cbsize = Marshal.SizeOf(typeof(FMOD.CREATESOUNDEXINFO));
exInfo.numchannels = nativeChannels;
exInfo.format = FMOD.SOUND_FORMAT.PCM16;
exInfo.defaultfrequency = nativeRate;
exInfo.length = (uint)(nativeRate * sizeof(short) * nativeChannels);
//Create recSound as an FMOD Sound and record into it
FMODUnity.RuntimeManager.CoreSystem.createSound("Record", FMOD.MODE.LOOP_NORMAL | FMOD.MODE.OPENUSER, ref exInfo, out recSound);
FMODUnity.RuntimeManager.CoreSystem.recordStart(0, recSound, true);
recSound.getLength(out recSoundLength, FMOD.TIMEUNIT.PCM);
//FMODUnity.RuntimeManager.CoreSystem.getMasterChannelGroup(out FMOD.ChannelGroup mCG);
//FMODUnity.RuntimeManager.CoreSystem.playSound(recSound, mCG, false, out channel);
/// <summary>
/// Create switch for programmer instrument
/// </summary>
// 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
dialogueCallback = new FMOD.Studio.EVENT_CALLBACK(DialogueEventCallback);
TempParaPtr = System.IntPtr.Zero;
[AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
FMOD.RESULT DialogueEventCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
{
FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);
// Retrieve the user data
IntPtr stringPtr;
instance.getUserData(out stringPtr);
// Get the string object
GCHandle stringHandle = GCHandle.FromIntPtr(stringPtr);
String key = stringHandle.Target as String;
TempInstPtr = instancePtr;
TempParaPtr = parameterPtr;
switch (type)
{
case FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
{
var parameter = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
// We now need to pass the Sound to the programmer instrument
parameter.sound = recSound.handle;
Marshal.StructureToPtr(parameter, parameterPtr, false);
Debug.Log("Programmer Instrument Created");
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
{
var parameter = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
var sound = new FMOD.Sound(parameter.sound);
sound.release();
Debug.Log("Destroy Programme Instruemnt");
break;
}
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
{
// Now the event has been destroyed, unpin the string memory so it can be garbage collected
stringHandle.Free();
Debug.Log("destroyed");
break;
}
}
return FMOD.RESULT.OK;
}
}
void PlayDialogue()
{
//create event instance to play
var dialogueInstance = FMODUnity.RuntimeManager.CreateInstance(EventName);
// Pin the key string in memory and pass a pointer through the user data
GCHandle stringHandle2 = GCHandle.Alloc(recSound);
IntPtr pointer = GCHandle.ToIntPtr(stringHandle2);
dialogueInstance.setUserData(pointer);
dialogueInstance.setCallback(dialogueCallback);
dialogueInstance.start();
dialogueInstance.release();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
PlayDialogue();
}
}
}