Skip to content

Commit bf9591f

Browse files
committed
fix: Update the sound group package to include sound volume multipliers
1 parent 4a5438c commit bf9591f

File tree

8 files changed

+222
-23
lines changed

8 files changed

+222
-23
lines changed

src/soundgroups/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,20 @@
2626
],
2727
"dependencies": {
2828
"@quenty/baseobject": "file:../baseobject",
29+
"@quenty/binder": "file:../binder",
2930
"@quenty/brio": "file:../brio",
3031
"@quenty/counter": "file:../counter",
3132
"@quenty/instanceutils": "file:../instanceutils",
3233
"@quenty/loader": "file:../loader",
3334
"@quenty/maid": "file:../maid",
3435
"@quenty/observablecollection": "file:../observablecollection",
36+
"@quenty/promise": "file:../promise",
37+
"@quenty/rogue-properties": "file:../rogue-properties",
3538
"@quenty/rx": "file:../rx",
3639
"@quenty/servicebag": "file:../servicebag",
3740
"@quenty/signal": "file:../signal",
3841
"@quenty/table": "file:../table",
42+
"@quenty/tie": "file:../tie",
3943
"@quenty/valueobject": "file:../valueobject"
4044
},
4145
"publishConfig": {

src/soundgroups/src/Client/SoundGroupServiceClient.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ function SoundGroupServiceClient:Init(serviceBag: ServiceBag.ServiceBag)
1616
self._serviceBag = assert(serviceBag, "No serviceBag")
1717
self._maid = Maid.new()
1818

19+
-- External
20+
self._serviceBag:GetService(require("TieRealmService"))
21+
self._serviceBag:GetService(require("RoguePropertyService"))
22+
1923
-- Internal
2024
self._serviceBag:GetService(require("SoundEffectService"))
2125
end

src/soundgroups/src/Server/SoundGroupService.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ function SoundGroupService:Init(serviceBag: ServiceBag.ServiceBag)
1717
self._serviceBag = assert(serviceBag, "No serviceBag")
1818
self._maid = Maid.new()
1919

20+
-- External
21+
self._serviceBag:GetService(require("TieRealmService"))
22+
self._serviceBag:GetService(require("RoguePropertyService"))
23+
2024
-- Internal
2125
self._soundEffectService = self._serviceBag:GetService(require("SoundEffectService"))
2226
end

src/soundgroups/src/Shared/SoundEffectService.lua

Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
--!nonstrict
1+
--!strict
22
--[=[
33
Handles applying global volume and effects to specific sounds in a group based upon a path.
44
@@ -11,25 +11,46 @@ local RunService = game:GetService("RunService")
1111
local SoundService = game:GetService("SoundService")
1212

1313
local Maid = require("Maid")
14+
local Promise = require("Promise")
1415
local ServiceBag = require("ServiceBag")
16+
local SoundEffectsList = require("SoundEffectsList")
1517
local SoundEffectsRegistry = require("SoundEffectsRegistry")
1618
local SoundGroupPathUtils = require("SoundGroupPathUtils")
1719
local SoundGroupTracker = require("SoundGroupTracker")
20+
local SoundGroupVolume = require("SoundGroupVolume")
1821
local WellKnownSoundGroups = require("WellKnownSoundGroups")
1922

2023
local SoundEffectService = {}
2124
SoundEffectService.ServiceName = "SoundEffectService"
2225

23-
function SoundEffectService:Init(serviceBag: ServiceBag.ServiceBag)
24-
assert(not self._serviceBag, "Already initialized")
26+
export type SoundEffectService = typeof(setmetatable(
27+
{} :: {
28+
_serviceBag: ServiceBag.ServiceBag,
29+
_maid: Maid.Maid,
30+
_soundEffectsRegister: any, -- SoundEffectsRegistry.SoundEffectsRegistry,
31+
_tracker: any, -- SoundGroupTracker.SoundGroupTracker,
32+
},
33+
{} :: typeof({ __index = SoundEffectService })
34+
))
35+
36+
function SoundEffectService.Init(self: SoundEffectService, serviceBag: ServiceBag.ServiceBag)
37+
assert(not (self :: any)._serviceBag, "Already initialized")
2538
self._serviceBag = assert(serviceBag, "No serviceBag")
2639
self._maid = Maid.new()
2740

41+
-- External
42+
self._serviceBag:GetService(require("TieRealmService"))
43+
self._serviceBag:GetService(require("RoguePropertyService"))
44+
45+
-- State
2846
self._soundEffectsRegister = self._maid:Add(SoundEffectsRegistry.new())
2947
self._tracker = self._maid:Add(SoundGroupTracker.new(SoundService))
48+
49+
-- Binders
50+
self._serviceBag:GetService(require("SoundGroupVolume"))
3051
end
3152

32-
function SoundEffectService:Start()
53+
function SoundEffectService.Start(self: SoundEffectService): ()
3354
self:_setupEffectApplication()
3455
end
3556

@@ -38,14 +59,42 @@ end
3859
@param sound Sound
3960
@param soundGroupPath string? -- Optional
4061
]=]
41-
function SoundEffectService:RegisterSFX(sound: Sound, soundGroupPath: string?)
62+
function SoundEffectService.RegisterSFX(self: SoundEffectService, sound: Sound, soundGroupPath: string): ()
4263
assert(typeof(sound) == "Instance" and sound:IsA("Sound"), "Bad sound")
4364
assert(SoundGroupPathUtils.isSoundGroupPath(soundGroupPath) or soundGroupPath == nil, "Bad soundGroupPath")
4465

4566
sound.SoundGroup = self:GetOrCreateSoundGroup(soundGroupPath or WellKnownSoundGroups.SFX)
4667
end
4768

48-
function SoundEffectService:GetOrCreateSoundGroup(soundGroupPath: string): SoundGroup
69+
--[=[
70+
Creates a NumberValue multiplier for the given sound group path.
71+
72+
Destroy (or unparent) the returned NumberValue to remove the multiplier.
73+
74+
@param soundGroupPath string
75+
@return Promise<NumberValue>
76+
]=]
77+
function SoundEffectService:PromiseCreateVolumeMultiplier(soundGroupPath: string): Promise.Promise<NumberValue>
78+
local soundGroup = self:GetOrCreateSoundGroup(soundGroupPath)
79+
if soundGroup == nil then
80+
return Promise.rejected("Failed to get or create sound group for path: " .. soundGroupPath)
81+
end
82+
83+
local soundGroupVolumeBinder = self._serviceBag:GetService(require("SoundGroupVolume"))
84+
soundGroupVolumeBinder:Tag(soundGroup)
85+
86+
return soundGroupVolumeBinder:Promise(soundGroup):Then(function(soundGroupVolume)
87+
return soundGroupVolume:CreateMultiplier()
88+
end)
89+
end
90+
91+
--[=[
92+
Returns the SoundGroup for the given path, creating it if it does not exist.
93+
94+
@param soundGroupPath string
95+
@return SoundGroup
96+
]=]
97+
function SoundEffectService.GetOrCreateSoundGroup(self: SoundEffectService, soundGroupPath: string): SoundGroup
4998
assert(SoundGroupPathUtils.isSoundGroupPath(soundGroupPath), "Bad soundGroupPath")
5099

51100
local found = self:GetSoundGroup(soundGroupPath)
@@ -54,10 +103,21 @@ function SoundEffectService:GetOrCreateSoundGroup(soundGroupPath: string): Sound
54103
end
55104

56105
-- Handle deferred mode
57-
return SoundGroupPathUtils.findOrCreateSoundGroup(soundGroupPath)
106+
found = SoundGroupPathUtils.findOrCreateSoundGroup(soundGroupPath)
107+
assert(found, "Failed to create sound group for path")
108+
109+
SoundGroupVolume:Tag(found)
110+
111+
return found
58112
end
59113

60-
function SoundEffectService:GetSoundGroup(soundGroupPath: string): SoundGroup
114+
--[=[
115+
Returns the SoundGroup for the given path, or nil if it does not exist.
116+
117+
@param soundGroupPath string
118+
@return SoundGroup
119+
]=]
120+
function SoundEffectService.GetSoundGroup(self: SoundEffectService, soundGroupPath: string): SoundGroup?
61121
assert(SoundGroupPathUtils.isSoundGroupPath(soundGroupPath), "Bad soundGroupPath")
62122

63123
if not self._tracker then
@@ -71,27 +131,41 @@ function SoundEffectService:GetSoundGroup(soundGroupPath: string): SoundGroup
71131

72132
local found = self._tracker:GetFirstSoundGroup(soundGroupPath)
73133
if found then
134+
SoundGroupVolume:Tag(found)
74135
return found
75136
end
76137

77-
return SoundGroupPathUtils.findOrCreateSoundGroup(soundGroupPath)
138+
found = SoundGroupPathUtils.findSoundGroup(soundGroupPath)
139+
if found then
140+
SoundGroupVolume:Tag(found)
141+
end
142+
143+
return found
78144
end
79145

80-
function SoundEffectService:PushEffect(soundGroupPath: string, effect)
146+
function SoundEffectService.PushEffect(
147+
self: SoundEffectService,
148+
soundGroupPath: string,
149+
effect: SoundEffectsList.SoundEffectApplier
150+
): ()
81151
assert(SoundGroupPathUtils.isSoundGroupPath(soundGroupPath), "Bad soundGroupPath")
82152
assert(type(effect) == "function", "Bad effect")
83153

84154
return self._soundEffectsRegister:PushEffect(soundGroupPath, effect)
85155
end
86156

87-
function SoundEffectService:ApplyEffects(soundGroupPath, instance)
157+
function SoundEffectService.ApplyEffects(
158+
self: SoundEffectService,
159+
soundGroupPath: string,
160+
instance: SoundGroup | Sound
161+
): () -> ()
88162
assert(SoundGroupPathUtils.isSoundGroupPath(soundGroupPath), "Bad soundGroupPath")
89163
assert(typeof(instance) == "Instance" and (instance:IsA("SoundGroup") or instance:IsA("Sound")), "Bad instance")
90164

91165
return self._soundEffectsRegister:ApplyEffects(soundGroupPath, instance)
92166
end
93167

94-
function SoundEffectService:_setupEffectApplication()
168+
function SoundEffectService._setupEffectApplication(self: SoundEffectService): ()
95169
self._maid:GiveTask(self._tracker:ObserveSoundGroupsBrio():Subscribe(function(brio)
96170
if brio:IsDead() then
97171
return
@@ -102,7 +176,7 @@ function SoundEffectService:_setupEffectApplication()
102176
if soundGroupPath then
103177
maid._currentEffects = self._soundEffectsRegister:ApplyEffects(soundGroupPath, soundGroup)
104178
else
105-
maid._currentEffects = nil
179+
maid._currentEffects = nil :: any
106180
end
107181
end))
108182
end))
@@ -122,7 +196,7 @@ function SoundEffectService:_setupEffectApplication()
122196
end))
123197
end
124198

125-
function SoundEffectService:Destroy()
199+
function SoundEffectService.Destroy(self: SoundEffectService): ()
126200
self._maid:DoCleaning()
127201
end
128202

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
--!strict
2+
local SoundGroupVolumeInterface = require(script.Parent.SoundGroupVolumeInterface)
3+
--[=[
4+
@class SoundGroupVolume
5+
]=]
6+
7+
local require = require(script.Parent.loader).load(script)
8+
9+
local BaseObject = require("BaseObject")
10+
local Binder = require("Binder")
11+
local ServiceBag = require("ServiceBag")
12+
local SoundGroupVolumeProperties = require("SoundGroupVolumeProperties")
13+
local TieRealms = require("TieRealms")
14+
15+
local SoundGroupVolume = setmetatable({}, BaseObject)
16+
SoundGroupVolume.ClassName = "SoundGroupVolume"
17+
SoundGroupVolume.__index = SoundGroupVolume
18+
19+
export type SoundGroupVolume =
20+
typeof(setmetatable(
21+
{} :: {
22+
_obj: SoundGroup,
23+
_serviceBag: ServiceBag.ServiceBag,
24+
_tieRealmService: any,
25+
_properties: any,
26+
RenderedVolume: any,
27+
},
28+
{} :: typeof({ __index = SoundGroupVolume })
29+
))
30+
& BaseObject.BaseObject
31+
32+
function SoundGroupVolume.new(instance: SoundGroup, serviceBag: ServiceBag.ServiceBag): SoundGroupVolume
33+
local self: SoundGroupVolume = setmetatable(BaseObject.new(instance) :: any, SoundGroupVolume)
34+
35+
self._serviceBag = assert(serviceBag, "No serviceBag")
36+
self._tieRealmService = self._serviceBag:GetService(require("TieRealmService"))
37+
38+
self._properties = SoundGroupVolumeProperties:Get(self._serviceBag, self._obj)
39+
self.RenderedVolume = self._properties.Volume
40+
41+
self._maid:GiveTask(SoundGroupVolumeInterface:Implement(self._obj, self, self._tieRealmService:GetTieRealm()))
42+
43+
-- Assign our volume to the current volume if we're on the server
44+
if self._tieRealmService:GetTieRealm() == TieRealms.SERVER then
45+
self._properties.Volume:SetBaseValue(self._obj.Volume)
46+
end
47+
48+
self._maid:GiveTask(self._properties.Volume:Observe():Subscribe(function(volume)
49+
self._obj.Volume = volume
50+
end))
51+
52+
return self
53+
end
54+
55+
--[=[
56+
Creates a volume multiplier for this sound group volume.
57+
58+
@param amount number?
59+
@return NumberValue
60+
]=]
61+
function SoundGroupVolume.CreateMultiplier(self: SoundGroupVolume, amount: number?): NumberValue
62+
return self._properties.Volume:CreateMultiplier(amount or 1)
63+
end
64+
65+
return Binder.new("SoundGroupVolume", SoundGroupVolume :: any) :: Binder.Binder<SoundGroupVolume>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--!strict
2+
--[=[
3+
@class SoundGroupVolumeInterface
4+
]=]
5+
6+
local require = require(script.Parent.loader).load(script)
7+
8+
local TieDefinition = require("TieDefinition")
9+
10+
return TieDefinition.new("SoundGroupVolume", {
11+
CreateMultiplier = TieDefinition.Types.METHOD,
12+
})
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--!strict
2+
--[=[
3+
@class SoundGroupVolumeProperties
4+
]=]
5+
6+
local require = require(script.Parent.loader).load(script)
7+
8+
local RoguePropertyTableDefinition = require("RoguePropertyTableDefinition")
9+
10+
return RoguePropertyTableDefinition.new("SoundGroupVolume", {
11+
Volume = 1,
12+
})

0 commit comments

Comments
 (0)