Skip to content

Commit 46d53fe

Browse files
authored
Merge pull request #1 from carbonengine/minor-update-dates
Changed dates to 2025
2 parents db645e9 + baa51f8 commit 46d53fe

File tree

7 files changed

+74
-19
lines changed

7 files changed

+74
-19
lines changed

NOTICE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Spatial Audio Object Clustering Plugin for Wwise
22

3-
Copyright 2024 CCP Games
3+
Copyright 2025 CCP Games
44

55
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
66

ObjectCluster/SoundEnginePlugin/KMeans.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2024 CCP ehf.
2+
* Copyright 2025 CCP ehf.
33
*
44
* This software was developed by CCP Games for spatial audio object clustering
55
* in EVE Online and EVE Frontier.
@@ -223,6 +223,15 @@ class KMeans {
223223
float minDistanceThreshold = 10.f,
224224
float maxDistanceThreshold = 1000.f);
225225

226+
227+
void reinitializeClustering() {
228+
centroids.clear();
229+
labels.clear();
230+
clusters.clear();
231+
sse_values.clear();
232+
unassignedPoints.clear();
233+
}
234+
226235
/**
227236
* @brief Sets the convergence tolerance.
228237
* @param newValue The new tolerance value.

ObjectCluster/SoundEnginePlugin/Kmeans.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ void KMeans::initializeCentroids(const std::vector<ObjectPosition>& objects) {
3636
std::vector<ObjectMetadata> objectsMetadata;
3737
objectsMetadata.reserve(objects.size());
3838

39-
// Calculate local density including origin region
40-
const float densityRadius = m_distanceThreshold * 0.5f;
39+
// Use a smaller radius for density calculation when threshold is small
40+
const float densityRadius = m_distanceThreshold * 0.25f; // More sensitive to local density
4141
const float densityRadiusSq = densityRadius * densityRadius;
4242

4343
// Track density around origin specifically
@@ -109,25 +109,22 @@ void KMeans::initializeCentroids(const std::vector<ObjectPosition>& objects) {
109109
size_t bestCandidate = 0;
110110
bool candidateFound = false;
111111

112-
// Find point with maximum minimum distance to existing centroids
113112
for (size_t i = 0; i < objectsMetadata.size(); ++i) {
114113
float minDist = std::numeric_limits<float>::max();
115114
for (const auto& centroid : centroids) {
116115
float dist = calculateDistance(objectsMetadata[i].object.position, centroid);
117116
minDist = std::min(minDist, dist);
118117
}
119118

120-
if (minDist > maxMinDistance) {
119+
// More likely to create new centroids with smaller thresholds
120+
if (minDist > maxMinDistance && minDist > m_distanceThreshold * 0.5f) {
121121
maxMinDistance = minDist;
122122
bestCandidate = i;
123123
candidateFound = true;
124124
}
125125
}
126126

127-
if (!candidateFound || maxMinDistance < m_distanceThreshold) {
128-
break;
129-
}
130-
127+
if (!candidateFound) break;
131128
centroids.push_back(objectsMetadata[bestCandidate].object.position);
132129
}
133130
}
@@ -347,16 +344,30 @@ void KMeans::setTolerance(float newValue) {
347344
}
348345

349346
void KMeans::setDistanceThreshold(float newValue) {
350-
m_distanceThreshold = clamp(newValue, m_minThreshold, m_maxThreshold);
347+
348+
if (newValue != m_distanceThreshold) {
349+
m_distanceThreshold = clamp(newValue, m_minThreshold, m_maxThreshold);
350+
351+
// Clear existing state to force recalculation
352+
centroids.clear();
353+
labels.clear();
354+
clusters.clear();
355+
sse_values.clear();
356+
unassignedPoints.clear();
357+
}
351358
}
352359

353360
void KMeans::performClustering(const std::vector<ObjectPosition>& objects, unsigned int max_iterations) {
361+
// Resize labels vector to match input size
354362
labels.resize(objects.size(), -1);
363+
364+
// Recalculate max clusters based on current objects
355365
maxClusters = determineMaxClusters(objects.size());
366+
367+
// Always reinitialize centroids
356368
initializeCentroids(objects);
357369

358370
for (unsigned int iter = 0; iter < max_iterations; ++iter) {
359-
360371
bool changed = assignPointsToClusters(objects);
361372
adjustClusterCount();
362373
bool centroidsUpdated = updateCentroids();

ObjectCluster/SoundEnginePlugin/ObjectClusterFX.cpp

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
2222
the specific language governing permissions and limitations under the License.
2323
2424
Copyright (c) 2023 Audiokinetic Inc.
25-
Copyright (c) 2024 CCP ehf.
25+
Copyright (c) 2025 CCP ehf.
2626
2727
This implementation was developed by CCP Games for spatial audio object clustering
2828
in EVE Online and EVE Frontier. This implementation does not grant any rights to
@@ -369,33 +369,64 @@ void ObjectClusterFX::MixToCluster(const AkAudioObject* inObject, AkAudioBuffer*
369369
AKPLATFORM::AkMemCpy(pGeneratedObject->volumeMatrix, currentVolumes, uTransmixSize);
370370
}
371371

372+
void ObjectClusterFX::SafeCleanupForThresholdChange()
373+
{
374+
auto it = m_mapInObjsToOutObjs.Begin();
375+
while (it != m_mapInObjsToOutObjs.End()) {
376+
if ((*it).pUserData) {
377+
// Don't delete the object, just mark it as unclustered
378+
(*it).pUserData->isClustered = false;
379+
// Reset index to force reassignment
380+
(*it).pUserData->index = -1;
381+
}
382+
++it;
383+
}
384+
385+
// Clear cluster assignments but maintain existing objects
386+
m_clusters.clear();
387+
}
388+
372389
void ObjectClusterFX::FeedPositionsToKMeans(const AkAudioObjects& inObjects)
373390
{
391+
bool thresholdChanged = false;
392+
bool thresholdDecreased = false;
374393

375394
if (m_lastDistanceThreshold != m_pParams->RTPC.distanceThreshold) {
395+
thresholdChanged = true;
396+
thresholdDecreased = m_pParams->RTPC.distanceThreshold < m_lastDistanceThreshold;
397+
376398
m_kmeans->setDistanceThreshold(m_pParams->RTPC.distanceThreshold);
377399
m_lastDistanceThreshold = m_pParams->RTPC.distanceThreshold;
400+
401+
// Safe cleanup when threshold changes
402+
SafeCleanupForThresholdChange();
378403
}
379404

380405
std::vector<ObjectPosition> objectPositions;
381406
objectPositions.reserve(inObjects.uNumObjects);
382407

408+
// Collect positions and ensure proper redistribution
383409
for (AkUInt32 i = 0; i < inObjects.uNumObjects; ++i) {
384410
AkAudioObject* inobj = inObjects.ppObjects[i];
385411

386-
// Check if this is either position-only or position+orientation
387412
bool shouldCluster = (inobj->positioning.behavioral.spatMode == AK_SpatializationMode_PositionOnly ||
388413
inobj->positioning.behavioral.spatMode == AK_SpatializationMode_PositionAndOrientation);
389414

390415
if (shouldCluster) {
391416
objectPositions.push_back({ inobj->positioning.threeD.xform.Position(), inobj->key });
392417
}
393418
}
394-
// Perform clustering only if there are objects
395-
m_clusters.clear();
419+
396420
if (!objectPositions.empty()) {
421+
// Force reinitialization of KMeans when threshold decreases
422+
if (thresholdDecreased) {
423+
m_kmeans->reinitializeClustering();
424+
}
425+
397426
m_kmeans->performClustering(objectPositions);
398427

428+
// Update clusters with new assignments
429+
m_clusters.clear();
399430
auto tempClusters = m_kmeans->getClusters();
400431
m_clusters.reserve(tempClusters.size());
401432

ObjectCluster/SoundEnginePlugin/ObjectClusterFX.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
2222
the specific language governing permissions and limitations under the License.
2323
2424
Copyright (c) 2023 Audiokinetic Inc.
25-
Copyright (c) 2024 CCP ehf.
25+
Copyright (c) 2025 CCP ehf.
2626
2727
This implementation was developed by CCP Games for spatial audio object clustering
2828
in EVE Online and EVE Frontier. This implementation does not grant any rights to
@@ -114,6 +114,10 @@ class ObjectClusterFX : public AK::IAkOutOfPlaceObjectPlugin
114114
AK::IAkPluginMemAlloc* m_pAllocator;
115115
AK::IAkEffectPluginContext* m_pContext;
116116

117+
bool thresholdChanged = false;
118+
119+
void SafeCleanupForThresholdChange();
120+
117121
/**
118122
* @brief Updates KMeans algorithm with input object positions
119123
* @param inObjects Input audio objects

ObjectCluster/SoundEnginePlugin/Utilities.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2024 CCP ehf.
2+
* Copyright 2025 CCP ehf.
33
*
44
* This software was developed by CCP Games for spatial audio object clustering
55
* in EVE Online and EVE Frontier.

ObjectCluster/SoundEnginePlugin/Utilities.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2024 CCP ehf.
2+
* Copyright 2025 CCP ehf.
33
*
44
* This software was developed by CCP Games for spatial audio object clustering
55
* in EVE Online and EVE Frontier.

0 commit comments

Comments
 (0)