What features does the speaker script offer? What is it?
📻 Music Everywhere!
Play songs anywhere, in your car or with boomboxes!
🎧 Spatial (3D) Audio
Players experience sounds from their actual locations, with a sense of distance and direction.
🎯 Audio Effects
Muffled Sound: Songs sound muffled and distant when outside the vehicle, creating a realistic outdoor feel.
Realistic Echo: Dynamic reverb is applied to corridors, rooms, and enclosed spaces to create an echo effect appropriate for the space.
Interior Muffle: Speakers or boomboxes inside buildings and structures sound muffled and distant from outside, creating a realistic outdoor feeling.
🔊 Boomboxes
Enjoy yourself with 6 different Boombox models! (4 Portable, 2 Stationary)
Place the Boomboxwherever you like
Carry your boomboxes in your hands or on your back!
🪄 User-Friendly Menu (UI - User Interface)
Manage your music enjoyment with a compact and simple interface!
View and play your recently played songs!Save your favorite songs and play them whenever you want!
🔗 YouTube Integration - Song Upload Speed
Play any song you want on YouTube! (Using the video ID)
All YouTube operations are performed entirely by another server, so it does not cause issues like NUI (CEF) crashes!
The loading speed for a song that has not been played before varies between 1 and 3 seconds. (This time was tested with a song with a maximum length of 5 minutes.)
Clients load songs in 1ms to 7ms, providing very fast performance.
⚙️ Performance
NUI (CEF): The JavaScript Instance allocates an average of 100KB of RAM for a new song. Thanks to the Garbage Collector and optimizations, usage decreases over time.
Client Side: 0.00 when idle, but varies between 0.00 and 0.01ms when 1 speaker/boombox is rendered.
Server Side: 0.00 during idle time, but varies between 0.00 and 0.03ms during a new song loading process. Under load, it performs at an average of 0.00 to 0.05ms.
♻️ Sync & OneSync Compatibility
Music is synchronized among all players, so everyone hears the same song at the same time!
Music synchronization is maintained in cases such as reconnecting to the server, dying, or changing regions!
🚫 Blacklisted locations - Vehicles
Prevent music from playing in specific regions and vehicles! (You can add specific coordinates and vehicle models and claases)
📑Config File
ConfigServer Config
🚩Supporting 7 Languages / You can add more
Currently, ar, cz, ro, it, fr, de, and tr language support is available. You can add more from the locale files.
Config = {}
Config.Framework = {
["Framework"] = "auto", -- auto, esx, qbcore or qbox
["ResourceName"] = "auto", -- auto, es_extended or qb-core or your resource name. If you using qbx you should write qb-core
["SharedEvent"] = "" -- Event name for old cores.
}
Config.Language = "en" -- ar, cz, ro, it, fr, de, tr
Config.ShowDebug = false -- Show debug messages
Config.Reverb = true -- Enable reverb/echo effects based on ceiling height. If `true`, it will increase the use of resmon. While there is a more pronounced reverb in low ceilings, there is no reverb in open areas, resulting in a cleaner sound.
Config.RateLimit = 2.5 -- Time (in seconds) a player must wait before playing another sound.
Config.ActionCooldown = 0.05 -- Time (in seconds) a player must wait before performing another action (like change seek, distance, volume etc.)
Config.SpatialUpdateRate = 200 -- How often (in ms) to update spatial audio positions and volumes (düşük = daha smooth)
Config.PlayerBoomBoxLimit = 2 -- Maximum number of boomboxes a player can have active at once.
Config.MaxCeilingDistance = 25.0 -- The maximum ceiling height to be checked in the area where the speaker or car is located. This allows echo/reverb sounds to be added.
Config.InteractionDistances = {
--[[
🔉🔉🔉🎶🎶
These distances are selectable by users.
Even if a user renders a vehicle or speaker, they will not be able to hear the sound unless they approach within the selected distance.
When it enters within the selected distance, the sound will play at 0.0 volume. The level will increase as it approaches.
]]
["vehicles"] = 15.0, -- Maximum distance to hear speaker from vehicle
["speakers"] = 10.0, -- Maximum distance to hear speaker from ground speaker
}
Config.BoomBoxes = {
--[[
📻📻📻
Add your boombox items and models here.
Example: ["boombox_item_name"] = { ["model"] = "model_name", ["attach"] = { ... } }
]]
["boombox_a"] = {
["model"] = "qua_b_speaker_a",
},
["boombox_b"] = {
["model"] = "qua_b_speaker_b",
["attach"] = {
["bone"] = 4154, -- Bone index to attach to
["offsets"] = vector3(0.0065000279928427, 0.014985923761626, 0.03601949922086), -- Offsets from the bone (x, y, z)
["rotation"] = vector3(0.0, 0.0, 0.0), -- Rotation offsets (x, y, z)
["animation"] = {
["dict"] = "anim@heists@humane_labs@finale@keycards",
["clip"] = "ped_a_enter_loop",
["flag"] = 49,
}
},
},
["boombox_c"] = {
["model"] = "qua_b_speaker_c",
["attach"] = {
["bone"] = 4154, -- Bone index to attach to
["offsets"] = vector3(0.0065000279928427, 0.014985923761626, 0.03601949922086), -- Offsets from the bone (x, y, z)
["rotation"] = vector3(0.0, 0.0, 0.0), -- Rotation offsets (x, y, z)
["animation"] = {
["dict"] = "anim@heists@humane_labs@finale@keycards",
["clip"] = "ped_a_enter_loop",
["flag"] = 49,
}
},
},
["boombox_d"] = {
["model"] = "qua_b_speaker_d",
["attach"] = {
["bone"] = 60309, -- Bone index to attach to
["offsets"] = vector3(0.076437357549594, 0.0067159641248784, 0.074606438615931), -- Offsets from the bone (x, y, z)
["rotation"] = vector3(-97.361141027512, 0.61234434151617, 1.8357067867561), -- Rotation offsets (x, y, z)
["animation"] = {
["dict"] = "impexp_int-0",
["clip"] = "mp_m_waremech_01_dual-0",
["flag"] = 51,
}
},
},
["boombox_e"] = {
["model"] = "qua_b_speaker_e",
["attach"] = {
["bone"] = 57005, -- Bone index to attach to
["offsets"] = vector3(0.21548992346879, 0, -0.031528220090249), -- Offsets from the bone (x, y, z)
["rotation"] = vector3(1.0652214653109, -81.414172039437, -19.730610318178), -- Rotation offsets (x, y, z)
["animation"] = {
["dict"] = "move_weapon@jerrycan@generic",
["clip"] = "idle",
["flag"] = 51,
}
},
},
["boombox_f"] = {
["model"] = "qua_b_speaker_f",
},
}
Config.Actions = {
--[[
You can control features such as boombox placement, removal, and attachment from here.
Also, you can set the key to open the car speaker menu here. (Default is G)
]]
["place"] = {
["select_speaker_location"] = true, -- Enable/Disable boombox placement feature
["timeout"] = 10 * 1000, -- Time (in ms default is 10 sec) to wait for player to place boombox
["offsets"] = vector4(0.75, 0.0, 0.0, 180.0), -- Offset from player position to spawn boombox (x, y, z, heading)
["distance"] = 8.0, -- Max distance to place boombox from player
["buttons"] = {
["accept"] = "E", -- Key to place boombox
["cancel"] = "G" -- Key to cancel boombox placement
},
["animations"] = {
["dict"] = "amb@medic@standing@tendtodead@base",
["clip"] = "base",
["flag"] = 1,
["duration"] = 2 * 1000,
}
},
["carmenu"] = {
["key"] = "G" -- Key to open car speaker menu.
},
["detach"] = {
["key"] = "X" -- Key to detach boombox from your character and drop it on the ground
}
}
Config.BlacklistedVehicles = {
--[[
⚠️⚠️⚠️
From here, you can disable the speaker menu for the vehicle class or specific models of your choice,
so that the song menu will no longer open and songs will not play in those vehicles.
]]
["class"] = {
--[[
You can find all other vehicle classes here:
0: Compacts
1: Sedans
2: SUVs
3: Coupes
4: Muscle
5: Sports Classics
6: Sports
7: Super
8: Motorcycles
9: Off-road
10: Industrial
11: Utility
12: Vans
13: Cycles
14: Boats
15: Helicopters
16: Planes
17: Service
18: Emergency
19: Military
20: Commercial
21: Trains
22: Open Wheel
]]
[8] = true, -- Motorcycles
[13] = true, -- Cycles
[14] = true, -- Boats
[15] = true, -- Helicopters
[16] = true, -- Planes
},
["models"] = {
--[[
Example: Add specific vehicle models to blacklist by their hash. You can add as many as you want.
]]
[`issi2`] = true,
}
}
Config.BlacklistedCoords = {
--[[
🚫🚫🚫
You can add blacklist coordinates so that people cannot place speakers there.
If someone dies in that area, the speaker is returned to the inventory.
Songs cannot be played in vehicles within that area.
⚠️❓❌
If you have a speaker in your hand or enter the area with a song playing in your car,
the song will not stop. Because why should it stop? I think that much force is unnecessary.
Example: { coords = vector3(x, y, z), radius = 10.0 }
]]
{ coords = vector3(455.5057, -994.2595, 26.9876), radius = 45.0 }, -- Mission Row Police Department [MRPD]
{ coords = vector3(320.7686, -590.9871, 45.0281), radius = 40.0 } -- Pillbox Hill Medical Center [PHMC]
}
Config.Debug = function(...)
if Config.ShowDebug then
print(...)
end
end
Config.Notification = function(title, text, type, time)
title = title or "Speaker"
time = time or 5000
if lib ~= nil then
return lib.notify({
title = title,
type = type,
duration = time,
description = text,
iconAnimation = "beatFade",
position = "center-right"
})
end
if GetResourceState("okokNotify"):find("start") then
return exports['okokNotify']:Alert(title, text, time, type, true)
end
end
ConfigSv = {}
ConfigSv.Inventorys = {
-- [[ 🟢 Inventory detections, to work automatically compatible with some inventories. 🟢 ]]
["qb_inventory"] = GetResourceState("qb-inventory"):find("start") and true or false,
["qs_inventory"] = GetResourceState("qs-inventory"):find("start") and true or false,
["ox_inventory"] = GetResourceState("ox_inventory"):find("start") and true or false,
["export"] = nil
}
---------------------------------------------------------------------------------------------------------------
---Function that takes care of player items giving
---@enum [parent=#ConfigSv] AddItem
---@param source
---@param item
---@param amount
---@return #boolean
ConfigSv.AddItem = function(src, item, amount)
local p = promise:new()
if Config.Framework.Framework == "esx" then
local xPlayer = wFramework.Framework.GetPlayerFromId(src)
if xPlayer ~= nil then
xPlayer.addInventoryItem(item, amount)
p:resolve(true)
else
Config.Debug(("[^1ERROR - ADDITEM^0] Could not find player with source %s - ConfigSv.AddItem"):format(src))
p:resolve(false)
end
elseif Config.Framework.Framework == "qbcore" or Config.Framework.Framework == "qbx" then
local Player = wFramework.Framework.Functions.GetPlayer(src)
if Player ~= nil then
if ConfigSv.Inventorys.export:AddItem(src, item, amount) == nil then
Player.Functions.AddItem(item, amount)
end
p:resolve(true)
else
Config.Debug(("[^1ERROR - ADDITEM^0] Could not find player with source %s - ConfigSv.AddItem"):format(src))
p:resolve(false)
end
else
Config.Debug(("[^1ERROR - ADDITEM^0] No compatible inventory found for adding item to player with source %s - ConfigSv.AddItem"):format(src))
p:resolve(false)
end
return Citizen.Await(p)
end
---------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------
---Function that takes care of player items removing
---@enum [parent=#ConfigSv] RemoveItem
---@param source
---@param item
---@param amount
---@return #boolean
ConfigSv.RemoveItem = function(src, item, amount)
local p = promise:new()
local Player = Config.Framework.Framework == "esx" and wFramework.Framework.GetPlayerFromId(src) or ((Config.Framework.Framework == "qbcore" or Config.Framework.Framework == "qbx") and wFramework.Framework.Functions.GetPlayer(src) or nil)
if not Player then
p:resolve(false)
Config.Debug(("[^1ERROR - REMOVEITEM^0] Could not find player with source %s - ConfigSv.RemoveItem"):format(src))
return Citizen.Await(p)
end
if Config.Framework.Framework == "qbcore" or Config.Framework.Framework == "qbx" then
p:resolve(Player.Functions.RemoveItem(item, amount))
else
if ConfigSv.Inventorys.qs_inventory or ConfigSv.Inventorys.ox_inventory or ConfigSv.Inventorys.qb_inventory then
p:resolve(ConfigSv.Inventorys.export:RemoveItem(src, item, amount))
else
if Player.getInventoryItem(item).count >= amount then
Player.removeInventoryItem(item, amount)
p:resolve(true)
else
p:resolve(false)
end
end
end
return Citizen.Await(p)
end
---------------------------------------------------------------------------------------------------------------
CreateThread(function()
ConfigSv.Inventorys.export = ConfigSv.Inventorys.qs_inventory and exports['qs-inventory'] or ConfigSv.Inventorys.ox_inventory and exports.ox_inventory or nil or ConfigSv.Inventorys.qb_inventory and exports['qb-inventory'] or nil
if not ConfigSv.Inventorys.export then
Config.Debug("No compatible inventory found, please set the export method manually in config_sv.lua")
end
end)