Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ public enum ReverbPresets
/// <returns> True on success, false otherwise. </returns>
[DllImport(PluginDllName)] public static extern bool PHASESetSourceTransform(long inSourceId, Matrix4x4 inTransform);

/// <summary>
/// Parents a source under the listener or back under the scene root.
/// </summary>
/// <param name="inSourceId"> The unique ID representing the source. </param>
/// <param name="inAnchored"> True to parent under the listener, false to parent under root. </param>
/// <returns> True on success, false otherwise. </returns>
[DllImport(PluginDllName)] public static extern bool PHASESetSourceListenerAnchored(long inSourceId, bool inAnchored);

/// <summary>
/// Set the gain of the source in the PHASE engine.
/// </summary>
Expand Down Expand Up @@ -821,6 +829,17 @@ static public Matrix4x4 GetPhaseTransform(Transform inTransform)
return phaseTransform;
}

/// <summary>
/// Converts a Unity matrix to a PHASE transform (Left-Handed to Right-Handed).
/// </summary>
/// <param name="inTransform"> Unity based matrix to convert to PHASE coordinates. </param>
/// <returns> A <c>Matrix4x4</c> representing a transform in PHASE coordinates. </returns>
static public Matrix4x4 GetPhaseTransform(Matrix4x4 inTransform)
{
// RhConversionMat (S) * M * S, passed transposed because the native side reads it that way.
return RhConversionMat * inTransform.transpose * RhConversionMat;
}

static private Vector3 GetCombinedHierachyScale(Transform inTransform)
{
Vector3 combinedScale = inTransform.localScale;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ void CreateListener()
{
Debug.LogError("Failed to create PHASE Listener");
}
else
{
PHASESource.ReanchorSources();
}
}

// Update is called once per frame.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ enum SourceMode
// Active sound event instance on this source.
private List<long> _soundEventInstance = new List<long>();

// When anchored, the local transform is sent to PHASE as the offset from the listener.
private bool _listenerAnchored = false;

// Source id to store.
private long _sourceId = Helpers.InvalidId;

Expand Down Expand Up @@ -243,7 +246,10 @@ protected virtual void ManualUpdate()
{
if (_transform != null && _sourceId != Helpers.InvalidId)
{
Matrix4x4 phaseTransform = Helpers.GetPhaseTransform(_transform);
// An anchored source sends its local transform, read relative to the listener.
Matrix4x4 phaseTransform = _listenerAnchored
? Helpers.GetPhaseTransform(Matrix4x4.TRS(_transform.localPosition, _transform.localRotation, Vector3.one))
: Helpers.GetPhaseTransform(_transform);
bool result = Helpers.PHASESetSourceTransform(_sourceId, phaseTransform);
if (result == false)
{
Expand All @@ -266,6 +272,19 @@ protected internal static void UpdateSources()
entry.Value.ManualUpdate();
}
}

// Re-parents anchored sources under a newly created listener.
protected internal static void ReanchorSources()
{
foreach (PHASESource source in _registeredSources.Values)
{
if (source._listenerAnchored)
{
source.SetListenerAnchored(true);
}
}
}

private void UpdateGain()
{
var result = Helpers.PHASESetSourceGain(_sourceId, _gain);
Expand Down Expand Up @@ -349,6 +368,35 @@ void SetSendParametersForSpatialMixer(string mixer_name, long instanceId)
}
}

/// <summary>
/// Parents this source under the listener, or back under the scene root.
/// While anchored, the source's local transform is its offset from the listener,
/// so parent the GameObject under the listener's GameObject.
/// </summary>
/// <param name="anchored"> True to parent under the listener, false to parent under root. </param>
/// <returns> True on success, false otherwise. </returns>
public bool SetListenerAnchored(bool anchored)
{
if (_sourceId == Helpers.InvalidId)
{
_listenerAnchored = false;
return false;
}

bool result = Helpers.PHASESetSourceListenerAnchored(_sourceId, anchored);
_listenerAnchored = anchored && result;
return result;
}

/// <summary>
/// Whether this source is currently anchored to the listener.
/// </summary>
/// <returns> True if anchored to the listener, false otherwise. </returns>
public bool IsListenerAnchored()
{
return _listenerAnchored;
}

/// <summary>
/// Set a meta parameter of type integer associated with this source's sound event.
/// </summary>
Expand Down Expand Up @@ -409,6 +457,7 @@ public void DestroyFromPHASE()
Helpers.PHASEDestroySource(_sourceId);
_toBeDestroyed = true;
_sourceId = Helpers.InvalidId;
_listenerAnchored = false;
}

// Stop is called when the object stops.
Expand Down
6 changes: 6 additions & 0 deletions plug-ins/Apple.PHASE/Native/PHASEInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ int64_t PHASECreatePointSource();
*/
bool PHASESetSourceTransform(int64_t inSourceId, Matrix4x4 inTransform);

/*
Parents a source under the listener or back under the scene root.
Returns true on success, false otherwise.
*/
bool PHASESetSourceListenerAnchored(int64_t inSourceId, bool inAnchored);

/*
Sets the gain linear scale value of a given source, range of [0,1].
Given gain values outside of this range will be clamped.
Expand Down
6 changes: 6 additions & 0 deletions plug-ins/Apple.PHASE/Native/PHASEInterface.mm
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ bool PHASESetSourceTransform(int64_t inSourceId, Matrix4x4 inTransform)
return [engineWrapper setSourceTransformWithId:inSourceId transform:sourceTransform];
}

bool PHASESetSourceListenerAnchored(int64_t inSourceId, bool inAnchored)
{
PHASEEngineWrapper* engineWrapper = [PHASEEngineWrapper sharedInstance];
return [engineWrapper setSourceListenerAnchoredWithId:inSourceId anchored:inAnchored];
}

bool PHASESetSourceGain(int64_t inSourceId, double inGain)
{
PHASEEngineWrapper* engineWrapper = [PHASEEngineWrapper sharedInstance];
Expand Down
8 changes: 8 additions & 0 deletions plug-ins/Apple.PHASE/Native/PHASEWrapper/PHASEWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@ enum CalibrationMode
*/
- (BOOL)setSourceTransformWithId:(int64_t)sourceId transform:(simd_float4x4)transform;

/*! @method setSourceListenerAnchoredWithId
@abstract Parents a source under the listener or back under the scene root.
@param sourceId source ID to re-parent
@param anchored true to parent under the listener, false to parent under root
@return true on success, false otherwise
*/
- (BOOL)setSourceListenerAnchoredWithId:(int64_t)sourceId anchored:(BOOL)anchored;

/*! @method setSourceGainWithId
@abstract Sets the gain linear scale value of the source, range of [0,1]. Given gain values outside of this range will be clamped.
@param sourceId source ID to update gain for
Expand Down
55 changes: 54 additions & 1 deletion plug-ins/Apple.PHASE/Native/PHASEWrapper/PHASEWrapper.mm
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,18 @@ - (BOOL)destroyListener
return NO;
}

// Return any anchored sources to the root before the listener goes away.
NSArray<PHASEObject*>* children = mListener.children;
[mListener removeChildren];
for (PHASEObject* child in children)
{
NSError* errorRef = nil;
if (![mEngine.rootObject addChild:child error:&errorRef])
{
NSLog(@"Phase Wrapper: Failed to return PHASE Source to the root %@.", errorRef);
}
}

// Remove from the hierarchy
[mEngine.rootObject removeChild:mListener];

Expand Down Expand Up @@ -409,6 +421,47 @@ - (BOOL)setSourceTransformWithId:(int64_t)sourceId transform:(simd_float4x4)tran
return YES;
}

- (BOOL)setSourceListenerAnchoredWithId:(int64_t)sourceId anchored:(BOOL)anchored
{
PHASESource* source = [mSources objectForKey:[NSNumber numberWithLongLong:sourceId]];
if (source == nil)
{
NSLog(@"Phase Wrapper: Failed to find PHASE Source to anchor.");
return NO;
}

if (anchored && mListener == nil)
{
NSLog(@"Phase Wrapper: Listener does not exist.");
return NO;
}

PHASEObject* newParent = anchored ? mListener : mEngine.rootObject;
if (source.parent == newParent)
{
// Already there. Re-parenting an anchored source again has silenced it on device.
return YES;
}

// addChild fails if the source already has a parent.
[source.parent removeChild:source];

NSError* errorRef = nil;
const BOOL result = [newParent addChild:source error:&errorRef];
if (!result)
{
NSLog(@"Phase Wrapper: Failed to add PHASE Source to the %@ %@.", anchored ? @"Listener" : @"root", errorRef);
// Put it back under the root rather than leave it orphaned.
NSError* rollbackError = nil;
if (![mEngine.rootObject addChild:source error:&rollbackError])
{
NSLog(@"Phase Wrapper: Failed to return PHASE Source to the root %@.", rollbackError);
}
return NO;
}
return YES;
}

- (BOOL)setSourceGainWithId:(int64_t)sourceId sourceGain:(double)sourceGain
{
PHASESource* source = [mSources objectForKey:[NSNumber numberWithLongLong:sourceId]];
Expand Down Expand Up @@ -440,7 +493,7 @@ - (void)destroySourceWithId:(int64_t)sourceId
if (source != nil)
{
// Remove from the hierarchy
[mEngine.rootObject removeChild:source];
[source.parent removeChild:source];

[mSources removeObjectForKey:[NSNumber numberWithLongLong:sourceId]];

Expand Down