> For the complete documentation index, see [llms.txt](https://docs.menanak47.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.menanak47.com/plugins/ak47_lib/interface/soundplayer.md).

# SoundPlayer

The Sound Manager API is a highly structured, high-performance engine allowing for the creation, manipulation, and synchronization of 2D and 3D audio. It features spatialization, occlusion, global networking, automatic entity tracking, server-side time synchronization for late-joiners, full 5-band graphic equalizer support, and automatic resource sweeping to prevent audio leaks.

### **🎵 Accessing the API**

You can access the sound system from any other resource using the OOP wrapper or functional exports:

```lua
-- Option A: OOP Class Instance (Recommended)
local sound = exports['ak47_lib']:CreateSound(data)

-- Option B: Internal Lib Access
local sound = Lib47.CreateSound(data)
```

### **🛠 Constructor**

`CreateSound(data)`

Creates a new sound instance. This is the main entry point for the API.

Parameters (`data` table)

| **Property**     | **Type** | **Default**                             | **Description**                                                                                        |
| ---------------- | -------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `url`            | String   | Required                                | The direct URL or file path to the audio file (mp3, ogg, wav).                                         |
| `coords`         | vector3  | `nil`                                   | The coordinates for 3D audio. If omitted, the sound defaults to 2D (global UI sound).                  |
| `soundId`        | String   | Generated                               | A unique identifier. Provide one if you need to reference it strictly across network events.           |
| `is3d`           | Boolean  | `true` (if coords)                      | Forces the sound to be 3D or 2D.                                                                       |
| `volume`         | Number   | `0.5`                                   | The initial volume of the sound (0.0 to 1.0).                                                          |
| `maxDistance`    | Number   | `20.0`                                  | The distance at which the sound ceases to be heard (for 3D sounds).                                    |
| `rate`           | Number   | `1.0`                                   | The playback speed. `1.0` is normal, `0.5` is half speed, `2.0` is double speed.                       |
| `loop`           | Boolean  | `false`                                 | If `true`, the audio will restart automatically when it finishes.                                      |
| `interiorEffect` | Boolean  | `false`                                 | If `true`, the sound is occluded (muffled) if the player is in a different interior than the source.   |
| `global`         | Boolean  | `false`                                 | If `true`, playback, pausing, and seeking are synced to all clients (and late joiners) via the server. |
| `eq`             | Table    | `{sub=0, bass=0, mid=0, high=0, air=0}` | A 5-band graphic equalizer mix (values in decibels from -24 to +12).                                   |

Returns

Returns a Sound Object containing chainable methods to control the audio.

### **🧬 Sound Object Methods**

Once you have created a sound object, use the following methods to control it dynamically. *Most methods return the Sound Object, allowing for method chaining.*

Playback Controls

* `:play()` - Starts or resumes the audio playback.
* `:pause()` - Pauses the audio playback.
* `:destroy()` - Stops the sound and cleans up NUI resources. (Assign to variable: `mySound = mySound:destroy()`).
* `:seek(seconds)` - *\[NEW]* Jumps the audio to a specific timestamp. If `global = true`, this syncs the exact timestamp across all players via the server.

Parameter Updates

* `:setVolume(volume)` - Updates the volume dynamically (Local).
* `:setVolumeGlobal(volume)` - *\[NEW]* Updates the volume dynamically and syncs the change to all players on the server.
* `:setRate(rate)` - Updates the playback speed dynamically.
* `:setMaxDistance(distance)` - Updates the max hearing distance for 3D sounds.
* `:setEqualizer(eqTable)` - *\[NEW]* Updates the 5-band graphic equalizer dynamically (Local).
* `:setEqualizerGlobal(eqTable)` - *\[NEW]* Updates the equalizer dynamically and syncs the exact audio mix to all players on the server.

Spatial & Tracking Controls

* `:updateCoords(coords)` - Updates the static location of the sound source.
* `:attachToEntity(netId, offset)` - *\[NEW]* Automatically tracks and attaches the sound to a moving network entity (e.g., a vehicle). The API handles the coordinate loop internally.
* `:attachToPlayer(serverId, offset)` - *\[NEW]* Automatically tracks and attaches the sound to a specific player's ped.
* `:detach()` - *\[NEW]* Stops tracking an entity/player and freezes the sound at its current world coordinates.

Utilities

* `:getInfo()` - Asynchronously retrieves the current state of the audio `{ duration, currentTime }`. Yields via `Citizen.Await`.

### **🧰 Functional Exports (Non-OOP)**

If your external script does not wish to retain the Sound Object, you can manage active sounds using direct exports utilizing the `soundId`:

```lua
exports['ak47_lib']:AttachToEntity(soundId, netId, vector3(0, 0, 0))
exports['ak47_lib']:Seek(soundId, timeInSeconds)
exports['ak47_lib']:SetVolumeGlobal(soundId, volume)
exports['ak47_lib']:SetEqualizer(soundId, { sub = 6, bass = 2, mid = 0, high = 0, air = 0 })
exports['ak47_lib']:SetEqualizerGlobal(soundId, { sub = -12, bass = -12, mid = 5, high = 5, air = 10 })
exports['ak47_lib']:Destroy(soundId)
```

**🧹 Automatic Resource Sweeping**

Note to Developers: You do not need to manually destroy sounds when your script restarts. The Sound Manager API actively listens for `onResourceStop`. If your script crashes or is stopped, the API will instantly sweep and destroy all sounds created by your specific resource, preventing ghost audio loops.

### **📚 Examples**

#### Example 1: Looping Background Ambience

Plays a 2D sound that repeats forever. Perfect for weather effects or UI music.

```lua
local rain = exports['ak47_lib']:CreateSound({
    url = "sounds/rain_loop.ogg",
    volume = 0.2,
    is3d = false,
    loop = true
}):play()
```

#### Example 2: Global Siren (Syncs to all players)

A loud alarm that loops and is heard by everyone on the server. Late-joiners will automatically hear this if they enter the area.

```lua
local alarm = exports['ak47_lib']:CreateSound({
    soundId = "prison_alarm",
    url = "https://mysounds.com/alarm.mp3",
    coords = vector3(1800.0, 2600.0, 45.0),
    maxDistance = 300.0,
    volume = 1.0,
    global = true, 
    loop = true    
}):play()

-- Stop it after 30 seconds
SetTimeout(30000, function()
    if alarm then alarm = alarm:destroy() end
end)
```

#### Example 3: Moving Entity Sound (Automated Tracking)

*Updated: You no longer need a manual `Citizen.CreateThread` to update coordinates.* The API handles high-frequency coordinate tracking internally

```lua
local vehicleNetId = VehToNet(myVehicle)

local carRadio = exports['ak47_lib']:CreateSound({
    url = "sounds/music_track.wav",
    maxDistance = 40.0,
    volume = 0.8
})

-- Attach to the vehicle, offset slightly to the trunk, and play
carRadio:attachToEntity(vehicleNetId, vector3(0.0, -2.0, 0.5)):play()
```

#### Example 4: Synchronized Music Player (Seeking)

A perfect setup for a DJ Booth or boombox. Plays a song, seeks to the drop, and syncs the exact timestamp to all players.

```lua
local djBooth = exports['ak47_lib']:CreateSound({
    soundId = "club_dj_booth",
    url = "https://mysounds.com/club_mix.mp3",
    coords = vector3(120.5, -30.0, 15.0),
    maxDistance = 50.0,
    global = true, -- Enables server timestamping
})

djBooth:play()

-- Skip to 1 minute and 30 seconds into the song
-- This will sync instantly for all current players AND any player who logs in 10 minutes later.
djBooth:seek(90.0) 

-- Later on, lower the volume for everyone
djBooth:setVolumeGlobal(0.2)
```

#### Example 5: Audio Shaping with 5-Band Equalizer (Muffled/Bass-Boost)

Applies a custom mix to a sound upon creation, and dynamically alters the mix later. Perfect for simulating muffled music outside a nightclub, or adding bass to a vehicle boombox.

```lua
local clubMusic = exports['ak47_lib']:CreateSound({
    soundId = "nightclub_main",
    url = "https://mysounds.com/club_mix.mp3",
    coords = vector3(120.5, -30.0, 15.0),
    maxDistance = 50.0,
    global = true,
    -- Initial mix: Heavy Sub/Bass, normal mids/highs
    eq = { sub = 8, bass = 6, mid = 0, high = 0, air = 2 } 
})

clubMusic:play()

-- Example: Player walks outside the club door. 
-- Dynamically change the global mix to sound muffled (cut all treble, boost low-mids)
clubMusic:setEqualizerGlobal({ 
    sub = 2, 
    bass = 4, 
    mid = -5, 
    high = -15, 
    air = -24 
})
```
