# Examples

{% hint style="info" %}
**In general, examples are given on the client side. Because playing on the server side works in the same way. Only the first parameter is must be a source id**
{% endhint %}

### Play sound via file

```lua
local coords = GetEntityCoords(PlayerPedId())
local soundId = exports['mx-surround']:Play(nil, '/ui/sounds/beltalarm.ogg', coords)
```

***

### Play sound via url (Youtube, Spotify, SoundCloud)

```lua
local coords = GetEntityCoords(PlayerPedId())
local url = 'https://www.youtube.com/watch?v=RP0_8J7uxhs&ab_channel=RHINO'
local soundId = exports['mx-surround']:Play(nil, url, coords)
```

***

### Play sound via another resource

```lua
local path = 'https://cfx-nui-qs-smartphone-pro/'
local sound_path = path .. 'html/sounds/test.mp3'
local soundId = exports['mx-surround']:Play(nil, sound_path, coords)
```

***

### Play sound in an interior (with special 3d properties)

{% hint style="info" %}
What we do is that the sound gets more out and the sound behavior changes. So you don't need to specify whether a sound is interior or not. S**cript detects it directly**.
{% endhint %}

```lua
local url = 'https://www.youtube.com/watch?v=r2LpOUwca94&ab_channel=MajorLazerOfficial'
local unicornLocation = vec(108.65, -1288.81, 28.86) -- Vanilla Unicorn' location
local panner = {
    panningModel = 'HRTF',                           -- https://developer.mozilla.org/en-US/docs/Web/API/PannerNode
    refDistance = 20.0,                              -- Distance of the volume dropoff start
    rolloffFactor = 1.8,                             -- How fast the volume drops off 
    distanceModel = 'exponential',                   -- How the volume drops off (linear, inverse, exponential)
    coneInnerAngle = 360.0,                          -- https://developer.mozilla.org/en-US/docs/Web/API/PannerNode/coneInnerAngle
    coneOuterAngle = 0.0,                            -- https://developer.mozilla.org/en-US/docs/Web/API/PannerNode/coneOuterAngle
}
exports['mx-surround']:Play(nil, url, unicornLocation, false, 1.0, panner)
```

{% hint style="info" %}
Don't think this complicated. You can do it without special panner.
{% endhint %}

```lua
local url = 'https://www.youtube.com/watch?v=OiC1rgCPmUQ&ab_channel=DuaLipa'
local unicornLocation = vec(108.65, -1288.81, 28.86) -- Vanilla Unicorn' location
exports['mx-surround']:Play(nil, url, unicornLocation)
```

***

### Attach a sound to an entity

```lua
local url = 'https://www.youtube.com/watch?v=AMYWaWYQp6I'
local ped = PlayerPedId()
local coords = GetEntityCoords(ped)
local vehicle = GetVehiclePedIsIn(ped, false)

local soundId = exports['mx-surround']:Play(nil, url, coords)
if not soundId then return end
if vehicle then
    local networkId = VehToNet(vehicle)
    exports['mx-surround']:attachEntity(soundId, networkId)
end
```

***

### Attach a sound to a player

{% hint style="info" %}
The difference from `attachEntity` is that it detects whether the player is getting into the car or not. And performs filtering.
{% endhint %}

```lua
local url = 'https://www.youtube.com/watch?v=AMYWaWYQp6I'
local coords = GetEntityCoords(PlayerPedId())
local soundId = exports['mx-surround']:Play(nil, url, coords)
local playerId = GetPlayerServerId(PlayerId())
exports['mx-surround']:attachPlayer(soundId, playerId)
```

***

### Add handler to a sound

```lua
local coords = GetEntityCoords(PlayerPedId())
local url = 'https://www.youtube.com/watch?v=AMYWaWYQp6I'

local soundId = exports['mx-surround']:createUniqueId()
exports['mx-surround']:onStop(soundId, function(soundData)
    print('stopped', soundId)
end)
exports['mx-surround']:onPause(soundId, function(soundData)
    print('paused', soundId)
end)
exports['mx-surround']:onResume(soundId, function(soundData)
    print('resumed', soundId)
end)
exports['mx-surround']:onDestroy(soundId, function(soundData)
    print('destroyed', soundId)
end)
exports['mx-surround']:Play(soundId, url, coords)
print('Started', soundId)
Wait(1000)
exports['mx-surround']:Stop(soundId)
Wait(1000)
exports['mx-surround']:Resume(soundId)
Wait(1500)
exports['mx-surround']:Pause(soundId)
Wait(2000)
exports['mx-surround']:Resume(soundId)
Wait(5000)
exports['mx-surround']:Destroy(soundId)
```

### Another way to add handler to a sound

```lua
local coords = GetEntityCoords(PlayerPedId())
local url = 'https://www.youtube.com/watch?v=AMYWaWYQp6I'

local soundId = exports['mx-surround']:createUniqueId()
exports['mx-surround']:setSoundHandler(soundId, {
    loading = function()
        print('loading', soundId)
    end,
    stop = function()
        print('stopped', soundId)
    end,
    pause = function()
        print('paused', soundId)
    end,
    resume = function()
        print('resumed', soundId)
    end,
    destroy = function()
        print('destroyed', soundId)
    end
})
exports['mx-surround']:Play(soundId, url, coords)
print('Started', soundId)
Wait(1000)
exports['mx-surround']:Stop(soundId)
Wait(1000)
exports['mx-surround']:Resume(soundId)
Wait(1500)
exports['mx-surround']:Pause(soundId)
Wait(2000)
exports['mx-surround']:Resume(soundId)
Wait(5000)
exports['mx-surround']:Destroy(soundId)
```

***

### **Play Async (Server Side)**

```lua
RegisterCommand('asset', function(source, args)
    local sound = 'beltalarm'
    local player = GetPlayerPed(source)
    local vehicle = GetVehiclePedIsIn(player, true)
    local vehNetId = NetworkGetNetworkIdFromEntity(vehicle)
    local coords = GetEntityCoords(vehicle)
    exports['mx-surround']:PlayAsync(-1, nil, '/ui/sounds/' .. sound .. '.ogg', coords, false, 1.0, nil, {
        attachEntity = vehNetId
    })
end, false)
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.moxha.dev/documentation/paid-scripts/surround-spatial-audio/examples.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
