implementation of drecon in unity 2022 lts forked from: https://github.com/joanllobera/marathon-envs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
13 KiB

// 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
{
/// 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;
// 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 = FMOD.MarshalHelper.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;
/// 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);
}
[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);
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]);
busses[currentBus].lockChannelGroup();
RuntimeManager.StudioSystem.flushCommands();
FMOD.ChannelGroup channelGroup;
busses[currentBus].getChannelGroup(out channelGroup);
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;
}
}
}
busses[currentBus].unlockChannelGroup();
}
}
RuntimeUtils.DebugLogError(listenerPluginName + " not found in the FMOD project.");
return dsp;
}
}
}