> 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, 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. |

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.

**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']: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)
```
