mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
347 lines
8.6 KiB
Lua
347 lines
8.6 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
local webaudio = include("pac3/libraries/webaudio.lua")
|
|
pac.webaudio2 = webaudio
|
|
local BUILDER, PART = pac.PartTemplate("base_movable")
|
|
|
|
PART.FriendlyName = "web sound"
|
|
PART.ClassName = "sound2"
|
|
|
|
PART.Icon = 'icon16/music.png'
|
|
PART.Group = 'effects'
|
|
|
|
BUILDER:StartStorableVars()
|
|
BUILDER:SetPropertyGroup("generic")
|
|
BUILDER:GetSet("Path", "", {editor_panel = "sound"})
|
|
BUILDER:GetSet("Volume", 1, {editor_sensitivity = 0.25})
|
|
BUILDER:GetSet("Pitch", 1, {editor_sensitivity = 0.125})
|
|
BUILDER:GetSet("Radius", 1500)
|
|
BUILDER:GetSet("Doppler", false)
|
|
BUILDER:GetSet("MinPitch", 0, {editor_sensitivity = 0.125})
|
|
BUILDER:GetSet("MaxPitch", 0, {editor_sensitivity = 0.125})
|
|
|
|
BUILDER:SetPropertyGroup("playback")
|
|
BUILDER:GetSet("PlayCount", 1,
|
|
{editor_onchange =
|
|
function(self, num)
|
|
self.sens = 0.25
|
|
num = tonumber(num)
|
|
return math.Round(math.max(num, 0))
|
|
end, editor_friendly = "PlayCount (0=loop)"}
|
|
)
|
|
BUILDER:GetSet("Sequential",false,{description = "if there are multiple sounds (separated by ; ), plays these sounds in sequential order instead of randomly"})
|
|
BUILDER:GetSet("SequentialStep", 1,
|
|
{editor_onchange =
|
|
function(self, num)
|
|
self.sens = 0.25
|
|
num = tonumber(num)
|
|
return math.Round(num)
|
|
end})
|
|
BUILDER:GetSet("StopOnHide", false)
|
|
BUILDER:GetSet("PauseOnHide", false)
|
|
BUILDER:GetSet("Overlapping", false)
|
|
BUILDER:GetSet("PlayOnFootstep", false)
|
|
|
|
BUILDER:SetPropertyGroup("filter")
|
|
BUILDER:GetSet("FilterType", 0, {enums = {
|
|
none = "0",
|
|
lowpass = "1",
|
|
highpass = "2",
|
|
}})
|
|
BUILDER:GetSet("FilterFraction", 1, {editor_sensitivity = 0.125, editor_clamp = {0, 1}})
|
|
|
|
BUILDER:SetPropertyGroup("echo")
|
|
BUILDER:GetSet("Echo", false)
|
|
BUILDER:GetSet("EchoDelay", 0.5, {editor_sensitivity = 0.125})
|
|
BUILDER:GetSet("EchoFeedback", 0.75, {editor_sensitivity = 0.125})
|
|
|
|
BUILDER:SetPropertyGroup("lfo")
|
|
BUILDER:GetSet("PitchLFOAmount", 0, {editor_sensitivity = 0.125, editor_friendly = "pitch amount"})
|
|
BUILDER:GetSet("PitchLFOTime", 0, {editor_sensitivity = 0.125, editor_friendly = "pitch time"})
|
|
|
|
BUILDER:GetSet("VolumeLFOAmount", 0, {editor_sensitivity = 0.125, editor_friendly = "volume amount"})
|
|
BUILDER:GetSet("VolumeLFOTime", 0, {editor_sensitivity = 0.125, editor_friendly = "volume time"})
|
|
|
|
BUILDER:EndStorableVars()
|
|
|
|
function PART:Initialize()
|
|
webaudio.Initialize()
|
|
self.streams = {}
|
|
end
|
|
|
|
function PART:GetNiceName()
|
|
local path = self:GetPath() .. ";"
|
|
local tbl = {}
|
|
for i, path in ipairs(path:Split(";")) do
|
|
if path ~= "" then
|
|
if path:StartWith("http") then
|
|
path = path:gsub("%%(..)", function(char)
|
|
local num = tonumber("0x" .. char)
|
|
if num then
|
|
return string.char(num)
|
|
end
|
|
end)
|
|
end
|
|
tbl[i] = pac.PrettifyName(("/".. path):match(".+/(.-)%.") or path:match("(.-)%.")) or "sound"
|
|
end
|
|
end
|
|
return table.concat(tbl, ";")
|
|
end
|
|
|
|
local stream_vars = {}
|
|
|
|
local BIND = function(propertyName, setterMethodName, check)
|
|
table.insert(stream_vars, propertyName)
|
|
setterMethodName = setterMethodName or "Set" .. propertyName
|
|
PART["Set" .. propertyName] = function(self, value)
|
|
if check then
|
|
value = check(value)
|
|
end
|
|
|
|
for url, stream in pairs(self.streams) do
|
|
if stream:IsValid() then
|
|
stream[setterMethodName](stream, value)
|
|
else
|
|
self.streams[url] = nil
|
|
end
|
|
end
|
|
|
|
self[propertyName] = value
|
|
end
|
|
end
|
|
|
|
BIND("Pitch", "SetPlaybackRate")
|
|
BIND("PlayCount", "SetMaxLoopCount" )
|
|
BIND("Volume", nil, function(n) return math.Clamp(n, 0, 4) end)
|
|
BIND("Radius", "SetSourceRadius" )
|
|
|
|
BIND("FilterType")
|
|
BIND("FilterFraction")
|
|
|
|
BIND("Echo")
|
|
BIND("EchoDelay")
|
|
BIND("EchoFeedback", nil, function(n) return math.Clamp(n, 0, 0.99) end)
|
|
|
|
BIND("PitchLFOAmount")
|
|
BIND("PitchLFOTime")
|
|
|
|
BIND("VolumeLFOAmount")
|
|
BIND("VolumeLFOTime")
|
|
|
|
BIND("Doppler")
|
|
|
|
function PART:OnThink()
|
|
local owner = self:GetRootPart():GetOwner()
|
|
|
|
for url, stream in pairs(self.streams) do
|
|
if not stream:IsValid() then self.streams[url] = nil goto CONTINUE end
|
|
|
|
if self.PlayCount == 0 then
|
|
stream:Resume()
|
|
end
|
|
|
|
if stream.owner_set ~= owner and owner:IsValid() then
|
|
stream:SetSourceEntity(owner, true)
|
|
stream.owner_set = owner
|
|
end
|
|
::CONTINUE::
|
|
end
|
|
|
|
if self.last_playonfootstep ~= self.PlayOnFootstep then
|
|
local ent = self:GetOwner()
|
|
if ent:IsValid() and ent:IsPlayer() then
|
|
ent.pac_footstep_override = ent.pac_footstep_override or {}
|
|
|
|
if self.PlayOnFootstep then
|
|
ent.pac_footstep_override[self.UniqueID] = self
|
|
else
|
|
ent.pac_footstep_override[self.UniqueID] = nil
|
|
end
|
|
|
|
if table.Count(ent.pac_footstep_override) == 0 then
|
|
ent.pac_footstep_override = nil
|
|
end
|
|
|
|
self.last_playonfootstep = self.PlayOnFootstep
|
|
end
|
|
end
|
|
end
|
|
|
|
function PART:SetPath(path)
|
|
self.seq_index = 1
|
|
self.Path = path
|
|
|
|
local paths = {}
|
|
|
|
for _, path in ipairs(path:Split(";")) do
|
|
local min, max = path:match(".+%[(.-),(.-)%]")
|
|
|
|
min = tonumber(min)
|
|
max = tonumber(max)
|
|
|
|
if min and max then
|
|
for i = min, max do
|
|
table.insert(paths, (path:gsub("%[.-%]", i)))
|
|
end
|
|
else
|
|
table.insert(paths, path)
|
|
end
|
|
end
|
|
|
|
for _, stream in pairs(self.streams) do
|
|
if stream:IsValid() then
|
|
stream:Remove()
|
|
end
|
|
end
|
|
|
|
self.streams = {}
|
|
|
|
local function load(path)
|
|
local stream = webaudio.CreateStream(path)
|
|
self.streams[path] = stream
|
|
|
|
stream:Set3D(true)
|
|
stream.OnLoad = function()
|
|
for _, key in ipairs(stream_vars) do
|
|
self["Set" .. key](self, self["Get" .. key](self))
|
|
end
|
|
end
|
|
stream.OnError = function(_, err, info)
|
|
info = info or "unknown error"
|
|
if self:IsValid() and pac.LocalPlayer == self:GetPlayerOwner() and pace and pace.IsActive() then
|
|
if pace and pace.current_part == self and not IsValid(pace.BusyWithProperties) then
|
|
pace.MessagePrompt(err .. "\n" .. info, "OGG error for" .. path, "OK")
|
|
else
|
|
pac.Message("OGG error: ", err, " reason: ", err .. "\n" .. info, "OGG error for" .. path)
|
|
self:SetError("OGG error: " .. err .. "\n" .. info .. "\nfor:" .. path)
|
|
end
|
|
end
|
|
end
|
|
|
|
stream.UpdateSourcePosition = function()
|
|
if self:IsValid() then
|
|
stream.SourcePosition = self:GetDrawPosition()
|
|
end
|
|
end
|
|
|
|
if
|
|
pace and
|
|
pace.Editor:IsValid() and
|
|
pace.current_part:IsValid() and
|
|
pace.current_part.ClassName == "ogg2" and
|
|
self:GetPlayerOwner() == pac.LocalPlayer
|
|
then
|
|
stream:Play()
|
|
end
|
|
end
|
|
|
|
for _, path in ipairs(paths) do
|
|
local info = sound.GetProperties(path)
|
|
if info then
|
|
path = info.sound
|
|
end
|
|
|
|
if not string.StartsWith(path, "http") or not pac.resource.Download(path, function(path) load("data/" .. path) end)
|
|
|
|
then load("sound/" .. path)
|
|
end
|
|
end
|
|
self.paths = paths
|
|
end
|
|
|
|
PART.last_stream = NULL
|
|
|
|
function PART:PlaySound(_, additiveVolumeFraction)
|
|
--PrintTable(self.streams)
|
|
additiveVolumeFraction = additiveVolumeFraction or 0
|
|
|
|
local stream = table.Random(self.streams) or NULL
|
|
if not stream:IsValid() then return end
|
|
|
|
if self.Sequential then
|
|
|
|
self.seq_index = self.seq_index or 1
|
|
|
|
local basepath = self.paths[self.seq_index] or self.paths[1]
|
|
local snd = "sound/".. basepath
|
|
|
|
local cached_path = "data/pac3_cache/downloads/" .. pac.Hash(basepath) .. ".dat"
|
|
|
|
if string.find(basepath, "^http") then
|
|
snd = cached_path
|
|
end
|
|
|
|
if self.streams[snd]:IsValid() then
|
|
stream = self.streams[snd]
|
|
print(snd,self.seq_index)
|
|
end
|
|
self.seq_index = self.seq_index + self.SequentialStep
|
|
if self.seq_index > #self.paths then
|
|
self.seq_index = self.seq_index - #self.paths
|
|
elseif self.seq_index < 1 then
|
|
self.seq_index = self.seq_index + #self.paths
|
|
end
|
|
end
|
|
|
|
stream:SetAdditiveVolumeModifier(additiveVolumeFraction)
|
|
|
|
if self.last_stream:IsValid() and not self.Overlapping and not self.PauseOnHide then
|
|
self.last_stream:Stop()
|
|
end
|
|
|
|
if self.MinPitch ~= self.MaxPitch then
|
|
stream:SetAdditivePitchModifier(math.Rand(self.MinPitch, self.MaxPitch))
|
|
else
|
|
stream:SetAdditivePitchModifier(0)
|
|
end
|
|
|
|
if self.PauseOnHide then
|
|
stream:Resume()
|
|
else
|
|
stream:Play()
|
|
end
|
|
|
|
self.last_stream = stream
|
|
end
|
|
|
|
function PART:StopSound()
|
|
for key, stream in pairs(self.streams) do
|
|
if stream:IsValid() then
|
|
if self.PauseOnHide then
|
|
stream:Pause()
|
|
elseif self.StopOnHide then
|
|
stream:Stop()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function PART:OnShow(from_rendering)
|
|
if not from_rendering then
|
|
self:PlaySound()
|
|
end
|
|
end
|
|
|
|
function PART:OnHide()
|
|
self:StopSound()
|
|
end
|
|
|
|
function PART:OnRemove()
|
|
for key, stream in pairs(self.streams) do
|
|
if not stream:IsValid() then self.streams[key] = nil goto CONTINUE end
|
|
|
|
stream:Remove()
|
|
::CONTINUE::
|
|
end
|
|
end
|
|
|
|
BUILDER:Register()
|