<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://g1r-mp.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Client_audio</id>
	<title>Client audio - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://g1r-mp.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Client_audio"/>
	<link rel="alternate" type="text/html" href="https://g1r-mp.com/wiki/index.php?title=Client_audio&amp;action=history"/>
	<updated>2026-09-19T06:25:35Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://g1r-mp.com/wiki/index.php?title=Client_audio&amp;diff=868&amp;oldid=prev</id>
		<title>QCherry: Document expanded scripting capacities and complete audited limits for 0.1.3 BUILD81</title>
		<link rel="alternate" type="text/html" href="https://g1r-mp.com/wiki/index.php?title=Client_audio&amp;diff=868&amp;oldid=prev"/>
		<updated>2026-09-12T11:51:38Z</updated>

		<summary type="html">&lt;p&gt;Document expanded scripting capacities and complete audited limits for 0.1.3 BUILD81&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw-interface=&quot;&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 11:51, 12 September 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l111&quot;&gt;Line 111:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 111:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;== Ownership and limits ==&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;== Ownership and limits ==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;A &lt;/del&gt;resource can own at most &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;32 &lt;/del&gt;active sounds; the client runtime can own at most &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;128 &lt;/del&gt;in total.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;From update 0.1.3 BUILD81, a &lt;/ins&gt;resource can own at most &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;128 &lt;/ins&gt;active sounds; the client runtime can own at most &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;512 &lt;/ins&gt;in total &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;(previously 32/128). See [[Scripting limits]]&lt;/ins&gt;.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* A handle can be controlled only by the resource that created it.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* A handle can be controlled only by the resource that created it.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* Stopping a resource releases all sounds that it still owns.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* Stopping a resource releases all sounds that it still owns.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>QCherry</name></author>
	</entry>
	<entry>
		<id>https://g1r-mp.com/wiki/index.php?title=Client_audio&amp;diff=780&amp;oldid=prev</id>
		<title>QCherry: Add client audio guide for update 0.1.2</title>
		<link rel="alternate" type="text/html" href="https://g1r-mp.com/wiki/index.php?title=Client_audio&amp;diff=780&amp;oldid=prev"/>
		<updated>2026-09-04T19:29:28Z</updated>

		<summary type="html">&lt;p&gt;Add client audio guide for update 0.1.2&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{DISPLAYTITLE:Client audio}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;background:#fff5f5; border:1px solid #d13b3b; border-left:5px solid #d13b3b; color:#111111; padding:0.85rem 1rem; margin:0.75rem 0 1rem;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:#111111; font-weight:bold; letter-spacing:0.04em;&amp;quot;&amp;gt;AVAILABLE FROM UPDATE 0.1.2&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;color:#111111; margin-top:0.25rem;&amp;quot;&amp;gt;Resource-owned OGG Vorbis playback, including positional 3D sound, is available in G1R:MP 0.1.2 and later.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Client audio&amp;#039;&amp;#039;&amp;#039; lets a client-side Lua resource play non-spatial interface sounds and positional world sounds. Audio handles belong to the resource that created them and cannot be controlled by another resource.&lt;br /&gt;
&lt;br /&gt;
== Supported files ==&lt;br /&gt;
&lt;br /&gt;
The first release accepts Ogg containers containing &amp;#039;&amp;#039;&amp;#039;Vorbis&amp;#039;&amp;#039;&amp;#039; audio. Ogg Opus and other codecs are not accepted. Every sound must be declared as a join-time file in the same resource:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;scripts&amp;gt;&lt;br /&gt;
    &amp;lt;script src=&amp;quot;client.lua&amp;quot; type=&amp;quot;client&amp;quot; cache=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;sounds/notification.ogg&amp;quot; download=&amp;quot;join&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;sounds/forge.ogg&amp;quot; download=&amp;quot;join&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;/scripts&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The runtime accepts only the exact relative path declared by the current resource. URLs, absolute paths, traversal with &amp;lt;code&amp;gt;..&amp;lt;/code&amp;gt;, reparse-point escapes, undeclared files, and files owned by another resource are rejected. File size and SHA-256 are checked again against the signed resource catalog before decoding.&lt;br /&gt;
&lt;br /&gt;
== Audio functions ==&lt;br /&gt;
&lt;br /&gt;
* [[playSound]] creates a non-spatial 2D sound.&lt;br /&gt;
* [[playSound3D]] creates a positional sound at world coordinates.&lt;br /&gt;
* [[stopSound]] stops a sound and invalidates its handle.&lt;br /&gt;
* [[setSoundVolume]] and [[getSoundVolume]] control linear volume.&lt;br /&gt;
* [[setSoundPaused]] and [[isSoundPaused]] control and inspect pause state.&lt;br /&gt;
* [[isSoundPlaying]] checks active playback.&lt;br /&gt;
* [[setSoundLooped]] changes looping.&lt;br /&gt;
* [[setSound3DPosition]] moves a positional source.&lt;br /&gt;
* [[setSound3DMinMaxDistance]] changes its attenuation range.&lt;br /&gt;
&lt;br /&gt;
== Playback quality and output device ==&lt;br /&gt;
&lt;br /&gt;
2D playback preserves the source channel layout, so stereo material remains stereo. A positional source is downmixed to mono because it represents one point in the world. When source and output sample rates differ, the runtime converts once with the bundled libsamplerate 0.2.2 sinc converter using &amp;lt;code&amp;gt;SRC_SINC_MEDIUM_QUALITY&amp;lt;/code&amp;gt; and bypasses miniaudio&amp;#039;s pitch-oriented linear converter. Matching sample rates are not resampled.&lt;br /&gt;
&lt;br /&gt;
Resource audio and voice playback use the normal Windows default playback device. The Windows communications-device selection is used only for voice microphone capture; it does not redirect or reduce the quality of 2D or 3D playback.&lt;br /&gt;
&lt;br /&gt;
For 3D sound, volume remains full through &amp;lt;code&amp;gt;minDistance&amp;lt;/code&amp;gt;, then fades linearly and is silent at and beyond &amp;lt;code&amp;gt;maxDistance&amp;lt;/code&amp;gt;. Coordinates and distances use metres. The listener follows the local native player while at least one positional sound exists.&lt;br /&gt;
&lt;br /&gt;
== Local playback ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot; line&amp;gt;&lt;br /&gt;
local notification = playSound(&amp;quot;sounds/notification.ogg&amp;quot;, false, 0.65)&lt;br /&gt;
&lt;br /&gt;
local forge = playSound3D(&lt;br /&gt;
    &amp;quot;sounds/forge.ogg&amp;quot;,&lt;br /&gt;
    125.5, -48.0, 3.25,&lt;br /&gt;
    true, 0.8,&lt;br /&gt;
    2.0, 45.0&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
if forge then&lt;br /&gt;
    setSound3DPosition(forge, 126.0, -48.0, 3.25)&lt;br /&gt;
    setSound3DMinMaxDistance(forge, 2.0, 60.0)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Playing the same 3D sound for every player ==&lt;br /&gt;
&lt;br /&gt;
Audio functions are client-side. To initiate a world sound authoritatively, the server sends a validated event to the client scripts. Using &amp;lt;code&amp;gt;root&amp;lt;/code&amp;gt; as the target broadcasts the same reliable ordered event to every connected player.&lt;br /&gt;
&lt;br /&gt;
Calculate the source position once on the server and send identical world coordinates to all clients. Do not recalculate the source from each receiving player&amp;#039;s position.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;server.lua&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot; line&amp;gt;&lt;br /&gt;
addCommandHandler(&amp;quot;forgeaudio&amp;quot;, function(playerId)&lt;br /&gt;
    local position = getPlayerPosition(playerId)&lt;br /&gt;
    if not position then&lt;br /&gt;
        return&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    triggerClientEvent(&lt;br /&gt;
        root,&lt;br /&gt;
        &amp;quot;forgeAudio:play&amp;quot;,&lt;br /&gt;
        resourceRoot,&lt;br /&gt;
        position.x + 4.0,&lt;br /&gt;
        position.y,&lt;br /&gt;
        position.z&lt;br /&gt;
    )&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;client.lua&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot; line&amp;gt;&lt;br /&gt;
local forgeSound = false&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;forgeAudio:play&amp;quot;, true)&lt;br /&gt;
addEventHandler(&amp;quot;forgeAudio:play&amp;quot;, resourceRoot, function(x, y, z)&lt;br /&gt;
    if forgeSound then&lt;br /&gt;
        stopSound(forgeSound)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    forgeSound = playSound3D(&lt;br /&gt;
        &amp;quot;sounds/forge.ogg&amp;quot;,&lt;br /&gt;
        x, y, z,&lt;br /&gt;
        true, 0.8,&lt;br /&gt;
        1.0, 30.0&lt;br /&gt;
    )&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each client creates its own local handle. Stopping, moving, pausing, or changing a shared sound therefore requires another server event broadcast to the same clients. Delivery is reliable and ordered, but playback start is not sample-accurate and can differ slightly due to network jitter.&lt;br /&gt;
&lt;br /&gt;
== Ownership and limits ==&lt;br /&gt;
&lt;br /&gt;
* A resource can own at most 32 active sounds; the client runtime can own at most 128 in total.&lt;br /&gt;
* A handle can be controlled only by the resource that created it.&lt;br /&gt;
* Stopping a resource releases all sounds that it still owns.&lt;br /&gt;
* A stopped or finished handle must not be reused.&lt;br /&gt;
* Validation and playback failures are recorded in the client runtime log.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua API]]&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;br /&gt;
[[Category:Audio Functions]]&lt;/div&gt;</summary>
		<author><name>QCherry</name></author>
	</entry>
</feed>