-
Notifications
You must be signed in to change notification settings - Fork 20
Voice: server-side proximity voice chat (M1), on a fetched MafiaNet #243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
ff8e6c6
Vendors: fetch MafiaNet instead of vendoring it
Segfaultd 7b239df
Voice: add server-side proximity voice chat (M1)
Segfaultd 22468e0
Voice: fix Windows build and address review findings
Segfaultd 0ae06b8
Vendors: pin fetched MafiaNet targets to this build's MSVC runtime
Segfaultd dc1c7e3
Vendors: force MSVC runtime on fetched targets, with diagnostics
Segfaultd ecb8261
Vendors: override the debug CRT on fetched targets with /MD
Segfaultd a8f176e
Vendors: reconcile fetched deps with Framework's CRT convention
Segfaultd 20f7868
CI: bound the version-bump path matcher
Segfaultd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # MafiaNet dependency pin. | ||
| # | ||
| # Deliberately its own file rather than a line inside vendors/CMakeLists.txt. | ||
| # MafiaNet's message-id enum is positional: inserting an id shifts every id after | ||
| # it and breaks every peer built against the old header. Framework's release | ||
| # tooling classifies a version bump by which paths a change touches | ||
| # (.github/bump_version.sh), so the pin needs a path of its own that means | ||
| # exactly one thing -- "the wire format may have moved" -- instead of being | ||
| # buried among unrelated vendor edits. | ||
| # | ||
| # Raising this pin across a MAJOR or MINOR MafiaNet version is a breaking change | ||
| # for the Framework too, and bump_version.sh treats a change to this file as a | ||
| # major bump on that basis. A PATCH-only bump is wire-compatible by MafiaNet's own | ||
| # versioning, but still lands here so the pin has a single home. | ||
| # | ||
| # Note it must NOT live under vendors/: .gitignore carries `vendors/**/*.cmake`, | ||
| # which would silently exclude it from the repository. | ||
|
|
||
| # Pinned by commit, not by tag. A tag is a mutable ref -- repointing it would | ||
| # change what every future build fetches while this file still reads the same -- | ||
| # whereas a commit is what it is. Keep the human-readable release beside it. | ||
| # | ||
| # Plain set(), not a CACHE entry: a cached value survives in an existing build | ||
| # tree, so bumping the pin here and rebuilding incrementally would silently keep | ||
| # fetching the old revision. This file is the single source of truth, and there is | ||
| # no reason to let -D override the wire format of the protocol. | ||
| set(MAFIANET_PIN "a515c827e01868ecc6be26ee82e4da7a04955f77") # v0.13.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| /* | ||
| * MafiaHub OSS license | ||
| * Copyright (c) 2026, MafiaHub. All rights reserved. | ||
| * | ||
| * This file comes from MafiaHub, hosted at https://github.com/MafiaHub/Framework. | ||
| * See LICENSE file in the source repository for information regarding licensing. | ||
| */ | ||
|
|
||
| #include "mixer.h" | ||
|
|
||
| #include <algorithm> | ||
| #include <cmath> | ||
|
|
||
| namespace Framework::Voice { | ||
| namespace { | ||
| constexpr float kInt16Scale = 1.0f / 32768.0f; | ||
|
|
||
| // Below this distance a speaker is at full volume; attenuation starts beyond it. | ||
| // Without it, a speaker standing on top of the listener produces a division blow-up | ||
| // and an unpleasant volume spike as they cross the origin. | ||
| constexpr float kMinDistance = 1.0f; | ||
|
|
||
| // How far the pan is allowed to swing. A full hard pan sounds wrong on headphones | ||
| // for a speaker only slightly off-axis, so the effect is deliberately partial. | ||
| constexpr float kMaxPan = 0.6f; | ||
| } // namespace | ||
|
|
||
| SpeakerGain ComputeGain(const ListenerTransform &listener, const glm::vec3 &speakerPos, float range) { | ||
| SpeakerGain gain; | ||
|
|
||
| const glm::vec3 delta = speakerPos - listener.position; | ||
| const float distance = glm::length(delta); | ||
|
|
||
| if (range <= 0.0f || distance > range) { | ||
| return gain; // silent | ||
| } | ||
|
|
||
| // Inverse-distance rolloff, normalised so it reaches zero exactly at `range` rather | ||
| // than trailing off asymptotically and leaving a faint always-audible tail. | ||
| const float clamped = std::max(distance, kMinDistance); | ||
| const float rolloff = kMinDistance / clamped; | ||
| const float edgeFade = 1.0f - (distance / range); | ||
| const float attenuation = std::clamp(rolloff * edgeFade, 0.0f, 1.0f); | ||
|
|
||
| // Pan on the listener's right axis. cross(up, forward) — not cross(forward, up), | ||
| // which yields the left axis in a right-handed system and inverts the whole pan. | ||
| // Degenerate transforms fall back to centred. | ||
| float pan = 0.0f; | ||
| if (distance > 0.0001f) { | ||
| const glm::vec3 right = glm::cross(listener.up, listener.forward); | ||
| const float rightLen = glm::length(right); | ||
| if (rightLen > 0.0001f) { | ||
| pan = glm::dot(delta / distance, right / rightLen) * kMaxPan; | ||
| } | ||
| } | ||
|
|
||
| // Constant-power pan: gains follow a quarter-circle so total energy stays flat as a | ||
| // speaker sweeps across, instead of dipping in the middle as linear panning does. | ||
| // A centred speaker therefore sits at cos(45 degrees) = ~0.707 per ear, not 1.0 — | ||
| // that is the property that keeps perceived loudness constant, so it is not | ||
| // normalised away. | ||
| const float angle = (pan + 1.0f) * 0.25f * 3.14159265358979323846f; | ||
|
|
||
| gain.left = std::clamp(attenuation * std::cos(angle), 0.0f, 1.0f); | ||
| gain.right = std::clamp(attenuation * std::sin(angle), 0.0f, 1.0f); | ||
| return gain; | ||
| } | ||
|
|
||
| void MixFrameInto(float *stereoOut, const int16_t *monoIn, uint32_t samples, SpeakerGain gain) { | ||
| for (uint32_t i = 0; i < samples; i++) { | ||
| const float sample = static_cast<float>(monoIn[i]) * kInt16Scale; | ||
| stereoOut[i * 2] += sample * gain.left; | ||
| stereoOut[i * 2 + 1] += sample * gain.right; | ||
| } | ||
| } | ||
| } // namespace Framework::Voice |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| /* | ||
| * MafiaHub OSS license | ||
| * Copyright (c) 2026, MafiaHub. All rights reserved. | ||
| * | ||
| * This file comes from MafiaHub, hosted at https://github.com/MafiaHub/Framework. | ||
| * See LICENSE file in the source repository for information regarding licensing. | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <glm/glm.hpp> | ||
|
|
||
| #include <cstdint> | ||
|
|
||
| namespace Framework::Voice { | ||
| // Where the local player is listening from. Published by the game each frame; consumed | ||
| // by the audio thread through an atomically swapped snapshot. | ||
| struct ListenerTransform { | ||
| glm::vec3 position {0.0f}; | ||
| glm::vec3 forward {0.0f, 0.0f, 1.0f}; | ||
| glm::vec3 up {0.0f, 1.0f, 0.0f}; | ||
| }; | ||
|
|
||
| // Per-ear linear gain for one speaker, in [0, 1]. | ||
| struct SpeakerGain { | ||
| float left = 0.0f; | ||
| float right = 0.0f; | ||
| }; | ||
|
|
||
| // Distance attenuation and constant-power stereo pan for one speaker relative to the | ||
| // listener. Returns silence beyond `range`. Pure: no state, safe on the audio thread. | ||
| SpeakerGain ComputeGain(const ListenerTransform &listener, const glm::vec3 &speakerPos, float range); | ||
|
|
||
| // Accumulates `samples` mono int16 samples into an interleaved stereo float buffer, | ||
| // applying `gain`. Adds rather than assigns so several speakers can be layered. | ||
| // `stereoOut` must hold at least samples * 2 floats. | ||
| void MixFrameInto(float *stereoOut, const int16_t *monoIn, uint32_t samples, SpeakerGain gain); | ||
| } // namespace Framework::Voice |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.