Skip to content

refactor(audio): Simplify available audio samples management#2773

Open
xezon wants to merge 6 commits into
TheSuperHackers:mainfrom
xezon:xezon/refactor-miles-available-samples
Open

refactor(audio): Simplify available audio samples management#2773
xezon wants to merge 6 commits into
TheSuperHackers:mainfrom
xezon:xezon/refactor-miles-available-samples

Conversation

@xezon

@xezon xezon commented Jun 7, 2026

Copy link
Copy Markdown

This change simplifies the available audio samples management.

Instead of manually counting at various callsites, it now simply calculates the available audio samples from the vectors. The numbers are used mostly for debug purposes, except in SoundManager::canPlayNow.

@xezon xezon added Audio Is audio related Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Refactor Edits the code with insignificant behavior changes, is never user facing labels Jun 7, 2026
@greptile-apps

greptile-apps Bot commented Jun 7, 2026

Copy link
Copy Markdown

Greptile Summary

This PR replaces the manual increment/decrement counter approach for tracking available audio samples (m_numPlaying2DSamples, m_numPlaying3DSamples) with direct queries against the actual sample-pool vectors, which are the ground truth. The SoundManager notification methods and counters are removed; canPlayNow now asks getNumAvailable2DSamples/3DSamples() directly.

  • Removes four notification methods (notifyOf2DSampleStart, notifyOf3DSampleStart, notifyOf2DSampleCompletion, notifyOf3DSampleCompletion) and their counter state, adding two new AudioManager virtual methods that simply return m_availableSamples.size() / m_available3DSamples.size().
  • Changes the sample pool containers from std::list to std::vector, fixes the freeAllMilesHandles iterator loop, and adds reserve calls in initSamplePools for performance.
  • Corrects the previous copy-paste bug in audioDebugDisplay where both file-output fprintf lines showed the 3D available count.

Confidence Score: 5/5

Safe to merge — the refactor correctly replaces manual counters with direct vector-size queries, and all acquire/release paths keep the pool consistent.

The vector is the single source of truth: handles are popped on acquire and pushed back on release (including error paths via stopPlayingAudio → releaseMilesHandles). The old manual counter approach had a latent drift risk (notifications were only sent for AT_SoundEffect), while the new approach is unconditional. The freeAllMilesHandles iterator fix and audioDebugDisplay copy-paste fix are both correct. No callers of the removed notification methods remain in the codebase.

No files require special attention.

Important Files Changed

Filename Overview
Core/GameEngine/Include/Common/GameAudio.h Adds two pure virtual methods getNumAvailable2DSamples() and getNumAvailable3DSamples() to the AudioManager interface.
Core/GameEngine/Include/Common/GameSounds.h Removes the four notify methods, getAvailableSamples(), getAvailable3DSamples(), and the four counter member variables from SoundManager.
Core/GameEngine/Source/Common/Audio/GameSounds.cpp Removes all counter management and notification method implementations; canPlayNow now delegates to TheAudio->getNumAvailable2/3DSamples() for availability checks.
Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h Adds override declarations for the two new virtual methods, renames getFirst2/3DSample to getAvailable2/3DSample, and changes pool containers from std::list to std::vector.
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp Implements getNumAvailable2/3DSamples() as m_availableSamples.size(), fixes the freeAllMilesHandles iterator loop, adds reserve in initSamplePools, removes all notifyOf* call sites, and fixes the audioDebugDisplay copy-paste bug.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant SM as SoundManager
    participant AM as AudioManager (interface)
    participant MAM as MilesAudioManager

    Note over SM,MAM: canPlayNow() — availability check
    SM->>AM: getNumAvailable3DSamples()
    AM->>MAM: (virtual dispatch)
    MAM-->>SM: m_available3DSamples.size()

    Note over SM,MAM: playAudioEvent() — acquire handle
    SM->>MAM: addAudioEvent(event)
    MAM->>MAM: getAvailable3DSample() → pop_back()
    MAM->>MAM: playSample3D(event, sample)
    alt play succeeded
        MAM->>MAM: m_playing3DSounds.push_back(audio)
    else play failed
        MAM->>MAM: stopPlayingAudio(audio)
        MAM->>MAM: releaseMilesHandles() → m_available3DSamples.push_back(sample)
    end

    Note over SM,MAM: stopPlayingAudio() — return handle
    MAM->>MAM: releaseMilesHandles(release)
    MAM->>MAM: m_available3DSamples.push_back(sample)

    Note over MAM: getNumAvailable3DSamples() == m_available3DSamples.size() (ground truth)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant SM as SoundManager
    participant AM as AudioManager (interface)
    participant MAM as MilesAudioManager

    Note over SM,MAM: canPlayNow() — availability check
    SM->>AM: getNumAvailable3DSamples()
    AM->>MAM: (virtual dispatch)
    MAM-->>SM: m_available3DSamples.size()

    Note over SM,MAM: playAudioEvent() — acquire handle
    SM->>MAM: addAudioEvent(event)
    MAM->>MAM: getAvailable3DSample() → pop_back()
    MAM->>MAM: playSample3D(event, sample)
    alt play succeeded
        MAM->>MAM: m_playing3DSounds.push_back(audio)
    else play failed
        MAM->>MAM: stopPlayingAudio(audio)
        MAM->>MAM: releaseMilesHandles() → m_available3DSamples.push_back(sample)
    end

    Note over SM,MAM: stopPlayingAudio() — return handle
    MAM->>MAM: releaseMilesHandles(release)
    MAM->>MAM: m_available3DSamples.push_back(sample)

    Note over MAM: getNumAvailable3DSamples() == m_available3DSamples.size() (ground truth)
Loading

Reviews (3): Last reviewed commit: "Rename getAvailable3DSample" | Re-trigger Greptile

Comment thread Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp
Comment thread Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp Outdated
Comment thread Core/GameEngine/Source/Common/Audio/GameSounds.cpp Outdated
HSAMPLE retSample = *m_availableSamples.begin();
m_availableSamples.erase(m_availableSamples.begin());
return (retSample);
if (!m_availableSamples.empty()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gets the last sample in the vector, but the function name says first. Originally it would also get the first sample in the list.

I presume this is for performance (FILO instead of FIFO), but the naming of function and comments - that talk about 'first' are confusing.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Renamed to getAvailableXXSample

for ( it3D = m_available3DSamples.begin(); it3D != m_available3DSamples.end(); ) {
std::vector<H3DSAMPLE>::iterator it3D;
for ( it3D = m_available3DSamples.begin(); it3D != m_available3DSamples.end(); ++it3D ) {
H3DSAMPLE sample3D = *it3D;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temporary variable not needed I think

AIL_release_3D_sample_handle(*it3D);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

std::vector<HSAMPLE>::iterator it;
for ( it = m_availableSamples.begin(); it != m_availableSamples.end(); ++it ) {
HSAMPLE sample = *it;
AIL_release_sample_handle(sample);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temporary variable not needed I think

AIL_release_3D_sample_handle(*it);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@xezon xezon requested a review from Skyaero42 June 20, 2026 08:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Audio Is audio related Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker Refactor Edits the code with insignificant behavior changes, is never user facing ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants