using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.Analytics; public class EventDataAndBus : MonoBehaviour { //------------------------------------------ public string BusName; //------------------------------------------ private FMOD.DSP_READ_CALLBACK mReadCallback; private FMOD.DSP mCaptureDSP; private float[] mDataBuffer; private GCHandle mObjHandle;// = null; private uint mBufferLength; private int mChannels = 0; private FMOD.ChannelGroup currentMaster; //------------------------------------------ private bool success = false; private bool dspCreated = false; //------------------------------------------ const float WIDTH = 10.0f; const float HEIGHT = 1.0f; private void Start() { StartCoroutine(GetBus()); } IEnumerator GetBus() { yield return new WaitForSeconds(1.0f); FMOD.RESULT result = FMODUnity.RuntimeManager.StudioSystem.getBus("bus:/Dialogue/Voice", out FMOD.Studio.Bus bus); if (result != FMOD.RESULT.OK) { Debug.Log(result.ToString() + "Get bus"); yield return null; } bus.lockChannelGroup(); FMODUnity.RuntimeManager.StudioSystem.flushCommands(); FMODUnity.RuntimeManager.StudioSystem.flushSampleLoading(); result = bus.getChannelGroup(out currentMaster); if (result != FMOD.RESULT.OK) { Debug.Log(result.ToString() + "Get CG"); yield return null; } if (currentMaster.hasHandle() == false) Debug.Log("No master in start"); success = true; } void Update() { if (success && !dspCreated) { // Assign the callback to a member variable to avoid garbage collection mReadCallback = CaptureDSPReadCallback; // Allocate a data buffer large enough for 8 channels, pin the memory to avoid garbage collection uint bufferLength; int numBuffers; FMODUnity.RuntimeManager.CoreSystem.getDSPBufferSize(out bufferLength, out numBuffers); mDataBuffer = new float[bufferLength * 8]; mBufferLength = bufferLength; // Get a handle to this object to pass into the callback mObjHandle = GCHandle.Alloc(this); if (mObjHandle != null) { // Define a basic DSP that receives a callback each mix to capture audio FMOD.DSP_DESCRIPTION desc = new FMOD.DSP_DESCRIPTION(); desc.numinputbuffers = 1; desc.numoutputbuffers = 1; desc.read = mReadCallback; desc.userdata = GCHandle.ToIntPtr(mObjHandle); if (FMODUnity.RuntimeManager.CoreSystem.createDSP(ref desc, out mCaptureDSP) == FMOD.RESULT.OK) { if (!currentMaster.hasHandle()) { Debug.Log("No master"); return; } FMOD.RESULT result = currentMaster.addDSP(0, mCaptureDSP); Debug.Log(result.ToString()); if (result != FMOD.RESULT.OK) { Debug.LogWarningFormat("FMOD: Unable to add mCaptureDSP to the master channel group"); } else dspCreated = true; } else { Debug.LogWarningFormat("FMOD: Unable to create a DSP: mCaptureDSP"); } } else { Debug.LogWarningFormat("FMOD: Unable to create a GCHandle: mObjHandle"); } } if (dspCreated) { // Do what you want with the captured data if (mChannels != 0) { float yOffset = 5.7f; for (int j = 0; j < mChannels; j++) { var pos = Vector3.zero; pos.x = WIDTH * -0.5f; for (int i = 0; i < mBufferLength; ++i) { pos.x += (WIDTH / mBufferLength); pos.y = mDataBuffer[i + j * mBufferLength] * HEIGHT; // Make sure Gizmos is enabled in the Unity Editor to show debug line draw for the captured channel data Debug.DrawLine(new Vector3(pos.x, yOffset + pos.y, 0), new Vector3(pos.x, yOffset - pos.y, 0), Color.green); } yOffset -= 1.9f; } } } } [AOT.MonoPInvokeCallback(typeof(FMOD.DSP_READ_CALLBACK))] static FMOD.RESULT CaptureDSPReadCallback(ref FMOD.DSP_STATE dsp_state, IntPtr inbuffer, IntPtr outbuffer, uint length, int inchannels, ref int outchannels) { FMOD.DSP_STATE_FUNCTIONS functions = (FMOD.DSP_STATE_FUNCTIONS)Marshal.PtrToStructure(dsp_state.functions, typeof(FMOD.DSP_STATE_FUNCTIONS)); IntPtr userData; functions.getuserdata(ref dsp_state, out userData); GCHandle objHandle = GCHandle.FromIntPtr(userData); EventDataAndBus obj = objHandle.Target as EventDataAndBus; // Save the channel count out for the update function obj.mChannels = inchannels; // Copy the incoming buffer to process later int lengthElements = (int)length * inchannels; Marshal.Copy(inbuffer, obj.mDataBuffer, 0, lengthElements); // Copy the inbuffer to the outbuffer so we can still hear it Marshal.Copy(obj.mDataBuffer, 0, outbuffer, lengthElements); return FMOD.RESULT.OK; } void OnDestroy() { if (mObjHandle != null)// && success) { if (mCaptureDSP.hasHandle()) { currentMaster.removeDSP(mCaptureDSP); // Release the DSP and free the object handle mCaptureDSP.release(); } mObjHandle.Free(); } } }