revival/game/Assets/Plugins/FMOD/addons/ResonanceAudio/Scripts/FmodResonanceAudio.cs

291 lines
13 KiB
C#

// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using FMODUnity;
namespace FMODUnityResonance
{
/// This is the main Resonance Audio class that communicates with the FMOD Unity integration. Native
/// functions of the system can only be called through this class to preserve the internal system
/// functionality.
public static class FmodResonanceAudio
{
/// Updates the room effects of the environment with given |room| properties.
/// @note This should only be called from the main Unity thread.
public static void UpdateAudioRoom(FmodResonanceAudioRoom room, bool roomEnabled)
{
// Update the enabled rooms list.
if (roomEnabled)
{
if (!enabledRooms.Contains(room))
{
enabledRooms.Add(room);
}
}
else
{
enabledRooms.Remove(room);
}
// Update the current room effects to be applied.
if (enabledRooms.Count > 0)
{
FmodResonanceAudioRoom currentRoom = enabledRooms[enabledRooms.Count - 1];
RoomProperties roomProperties = GetRoomProperties(currentRoom);
// Pass the room properties into a pointer.
IntPtr roomPropertiesPtr = Marshal.AllocHGlobal(roomPropertiesSize);
Marshal.StructureToPtr(roomProperties, roomPropertiesPtr, false);
ListenerPlugin.setParameterData(roomPropertiesIndex, GetBytes(roomPropertiesPtr,
roomPropertiesSize));
Marshal.FreeHGlobal(roomPropertiesPtr);
}
else
{
// Set the room properties to a null room, which will effectively disable the room effects.
ListenerPlugin.setParameterData(roomPropertiesIndex, GetBytes(IntPtr.Zero, 0));
}
}
/// Returns whether the listener is currently inside the given |room| boundaries.
public static bool IsListenerInsideRoom(FmodResonanceAudioRoom room)
{
// Compute the room position relative to the listener.
FMOD.VECTOR unused;
RuntimeManager.CoreSystem.get3DListenerAttributes(0, out listenerPositionFmod, out unused,
out unused, out unused);
Vector3 listenerPosition = new Vector3(listenerPositionFmod.x, listenerPositionFmod.y,
listenerPositionFmod.z);
Vector3 relativePosition = listenerPosition - room.transform.position;
Quaternion rotationInverse = Quaternion.Inverse(room.transform.rotation);
// Set the size of the room as the boundary and return whether the listener is inside.
bounds.size = Vector3.Scale(room.transform.lossyScale, room.size);
return bounds.Contains(rotationInverse * relativePosition);
}
/// Maximum allowed gain value in decibels.
public const float maxGainDb = 24.0f;
/// Minimum allowed gain value in decibels.
public const float minGainDb = -24.0f;
/// Maximum allowed reverb brightness modifier value.
public const float maxReverbBrightness = 1.0f;
/// Minimum allowed reverb brightness modifier value.
public const float minReverbBrightness = -1.0f;
/// Maximum allowed reverb time modifier value.
public const float maxReverbTime = 3.0f;
/// Maximum allowed reflectivity multiplier of a room surface material.
public const float maxReflectivity = 2.0f;
[StructLayout(LayoutKind.Sequential)]
private struct RoomProperties
{
// Center position of the room in world space.
public float positionX;
public float positionY;
public float positionZ;
// Rotation (quaternion) of the room in world space.
public float rotationX;
public float rotationY;
public float rotationZ;
public float rotationW;
// Size of the shoebox room in world space.
public float dimensionsX;
public float dimensionsY;
public float dimensionsZ;
// Material name of each surface of the shoebox room.
public FmodResonanceAudioRoom.SurfaceMaterial materialLeft;
public FmodResonanceAudioRoom.SurfaceMaterial materialRight;
public FmodResonanceAudioRoom.SurfaceMaterial materialBottom;
public FmodResonanceAudioRoom.SurfaceMaterial materialTop;
public FmodResonanceAudioRoom.SurfaceMaterial materialFront;
public FmodResonanceAudioRoom.SurfaceMaterial materialBack;
// User defined uniform scaling factor for reflectivity. This parameter has no effect when set
// to 1.0f.
public float reflectionScalar;
// User defined reverb tail gain multiplier. This parameter has no effect when set to 0.0f.
public float reverbGain;
// Adjusts the reverberation time across all frequency bands. RT60 values are multiplied by this
// factor. Has no effect when set to 1.0f.
public float reverbTime;
// Controls the slope of a line from the lowest to the highest RT60 values (increases high
// frequency RT60s when positive, decreases when negative). Has no effect when set to 0.0f.
public float reverbBrightness;
};
// Returns the FMOD Resonance Audio Listener Plugin.
private static FMOD.DSP ListenerPlugin
{
get
{
if (!listenerPlugin.hasHandle())
{
listenerPlugin = Initialize();
}
return listenerPlugin;
}
}
// Converts given |db| value to its amplitude equivalent where 'dB = 20 * log10(amplitude)'.
private static float ConvertAmplitudeFromDb(float db)
{
return Mathf.Pow(10.0f, 0.05f * db);
}
// Converts given |position| and |rotation| from Unity space to audio space.
private static void ConvertAudioTransformFromUnity(ref Vector3 position,
ref Quaternion rotation)
{
// Compose the transformation matrix.
Matrix4x4 transformMatrix = Matrix4x4.TRS(position, rotation, Vector3.one);
// Convert the transformation matrix from left-handed to right-handed.
transformMatrix = flipZ * transformMatrix * flipZ;
// Update |position| and |rotation| respectively.
position = transformMatrix.GetColumn(3);
rotation = Quaternion.LookRotation(transformMatrix.GetColumn(2), transformMatrix.GetColumn(1));
}
// Returns a byte array of |length| created from |ptr|.
private static byte[] GetBytes(IntPtr ptr, int length)
{
if (ptr != IntPtr.Zero)
{
byte[] byteArray = new byte[length];
Marshal.Copy(ptr, byteArray, 0, length);
return byteArray;
}
// Return an empty array if the pointer is null.
return new byte[1];
}
// Returns room properties of the given |room|.
private static RoomProperties GetRoomProperties(FmodResonanceAudioRoom room)
{
RoomProperties roomProperties;
Vector3 position = room.transform.position;
Quaternion rotation = room.transform.rotation;
Vector3 scale = Vector3.Scale(room.transform.lossyScale, room.size);
ConvertAudioTransformFromUnity(ref position, ref rotation);
roomProperties.positionX = position.x;
roomProperties.positionY = position.y;
roomProperties.positionZ = position.z;
roomProperties.rotationX = rotation.x;
roomProperties.rotationY = rotation.y;
roomProperties.rotationZ = rotation.z;
roomProperties.rotationW = rotation.w;
roomProperties.dimensionsX = scale.x;
roomProperties.dimensionsY = scale.y;
roomProperties.dimensionsZ = scale.z;
roomProperties.materialLeft = room.leftWall;
roomProperties.materialRight = room.rightWall;
roomProperties.materialBottom = room.floor;
roomProperties.materialTop = room.ceiling;
roomProperties.materialFront = room.frontWall;
roomProperties.materialBack = room.backWall;
roomProperties.reverbGain = ConvertAmplitudeFromDb(room.reverbGainDb);
roomProperties.reverbTime = room.reverbTime;
roomProperties.reverbBrightness = room.reverbBrightness;
roomProperties.reflectionScalar = room.reflectivity;
return roomProperties;
}
// Initializes and returns the FMOD Resonance Audio Listener Plugin.
private static FMOD.DSP Initialize()
{
// Search through all busses on in banks.
int numBanks = 0;
FMOD.DSP dsp = new FMOD.DSP();
FMOD.Studio.Bank[] banks = null;
RuntimeManager.StudioSystem.getBankCount(out numBanks);
RuntimeManager.StudioSystem.getBankList(out banks);
for (int currentBank = 0; currentBank < numBanks; ++currentBank)
{
int numBusses = 0;
FMOD.Studio.Bus[] busses = null;
banks[currentBank].getBusCount(out numBusses);
banks[currentBank].getBusList(out busses);
RuntimeManager.StudioSystem.flushCommands();
for (int currentBus = 0; currentBus < numBusses; ++currentBus)
{
// Make sure the channel group of the current bus is assigned properly.
string busPath = null;
busses[currentBus].getPath(out busPath);
RuntimeManager.StudioSystem.getBus(busPath, out busses[currentBus]);
RuntimeManager.StudioSystem.flushCommands();
FMOD.ChannelGroup channelGroup;
busses[currentBus].getChannelGroup(out channelGroup);
RuntimeManager.StudioSystem.flushCommands();
if (channelGroup.hasHandle())
{
int numDsps = 0;
channelGroup.getNumDSPs(out numDsps);
for (int currentDsp = 0; currentDsp < numDsps; ++currentDsp)
{
channelGroup.getDSP(currentDsp, out dsp);
string dspNameSb;
int unusedInt = 0;
uint unusedUint = 0;
dsp.getInfo(out dspNameSb, out unusedUint, out unusedInt, out unusedInt, out unusedInt);
if (dspNameSb.ToString().Equals(listenerPluginName) && dsp.hasHandle())
{
return dsp;
}
}
}
}
}
Debug.LogError(listenerPluginName + " not found in the FMOD project.");
return dsp;
}
// Right-handed to left-handed matrix converter (and vice versa).
private static readonly Matrix4x4 flipZ = Matrix4x4.Scale(new Vector3(1, 1, -1));
// Get a handle to the Resonance Audio Listener FMOD Plugin.
private static readonly string listenerPluginName = "Resonance Audio Listener";
// Size of |RoomProperties| struct in bytes.
private static readonly int roomPropertiesSize = Marshal.SizeOf(typeof(RoomProperties));
// Plugin data parameter index for the room properties.
private static readonly int roomPropertiesIndex = 1;
// Boundaries instance to be used in room detection logic.
private static Bounds bounds = new Bounds(Vector3.zero, Vector3.zero);
// Container to store the currently active rooms in the scene.
private static List<FmodResonanceAudioRoom> enabledRooms = new List<FmodResonanceAudioRoom>();
// Current listener position.
private static FMOD.VECTOR listenerPositionFmod = new FMOD.VECTOR();
// FMOD Resonance Audio Listener Plugin.
private static FMOD.DSP listenerPlugin;
}
}