SA-MP Audio Plugin v0.5
Copyright  Incognito 2011

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

Preface
-------
This plugin creates a TCP server that can communicate with external
clients to transfer and play back audio files, stream audio files
from the Internet, and control in-game radio stations. It has several
features, including:

* Seamless integration with SA-MP
* Audio playback with looping, pausing, resuming, and stopping,
  restarting, seeking, and volume adjusting
* Internet audio file streaming that supports nearly all online
  stations, including SHOUTcast and Icecast
* Sequence system for gapless playback of multiple audio files
* Support for multiple audio streams per client
* In-game 3D sound support with dynamic volume adjustment and panning
* Support for MOD, WAV, AIFF, MP3/MP2/MP1, OGG, WMA, FLAC, MIDI, WV,
  SPX, MPC, AC3, AAC, ALAC, TTA, and APE formats
* Support for multiple sound effects that can be applied instantly
* In-game radio station adjustment support
* Audio pack system for organizing audio files and ensuring easy
  distribution among clients
* Local file transfers with CRC checks and remote file transfers with
  file size checks to ensure that files do not get re-downloaded
* Player authentication system with name and IP address verification

Information
-----------
The Windows version is audio.dll (you will need the Microsoft .NET
Framework 3.5 SP1 or higher), and the Linux version is audio.so.

The audio.ini file and the audiopacks directory must be present in
the root SA-MP directory for local file transfers to work properly.
See the tutorial near the end of this document for more detailed
information on this subject.

Changelog
---------
v0.5:
- Completely rewrote the networking code and greatly optimized many
  parts of both the client plugin and the server plugin
- Added panning (directional sound) support to Audio_Set3DPosition
- Added Audio_Remove3DPosition
- Added MIDI file support and MOD music support
- Added native and callback for getting an audio file's current
  position in seconds via Audio_GetPosition and Audio_OnGetPosition
- Renamed Audio_Seek to Audio_SetPosition
- Added three natives and one callback for in-game radio station
  adjustment via Audio_SetRadioStation, Audio_StopRadio, and
  Audio_OnRadioStationChange
- Added native for sending custom messages to players via
  Audio_SendMessage
- Added extra parameter to Audio_SetPack for automated file transfers
- Removed the audio file extraction system, OptimFrog (OFR) support,
  EAX support via Audio_SetEAX and Audio_RemoveEAX, manual 3D offset
  adjustment via Audio_Set3DOffsets, and the Audio_OnSetPack callback
  (Audio_SetPack now returns a result)

Natives
-------
* Audio_CreateTCPServer(port);
      o Creates the TCP server
        Note #1: This must be on the same port that the SA-MP server
        is using. It must also be forwarded properly.
        Note #2: This is done automatically via callback hooking.

* Audio_DestroyTCPServer();
      o Destroys the TCP server

* Audio_SetPack(const audiopack[], bool:transferable = true, bool:automated = true);
      o Maps audio files specified under the audio pack name in
        audio.ini and specifies whether the audio pack should be
        transferable and automated
        Note #1: If the pack is not transferable, no CRC or file size
        checks will take place server-side. The files in the pack
        will only be checked if they exist client-side.
        Note #2: If the pack is automated, it will transfer to all
        connected players as soon as it is set and to all future
        players as soon as they connect. If it is not automated, the
        Audio_TransferPack native must be used instead.

* Audio_IsClientConnected(playerid);
      o Returns the player's TCP server connection status

* Audio_SendMessage(playerid, const message[]);
      o Sends a custom message to a player
        Note: This message will appear in the player's log if
        logging is enabled client-side.

* Audio_TransferPack(playerid);
      o Transfers the currently set audio pack to a player
        Note: If automatic transfers are enabled, this native will
        not work.

* Audio_CreateSequence();
      o Creates a sequence
        Note: This returns a sequence ID.

* Audio_DestroySequence(sequenceid);
      o Destroys a sequence

* Audio_AddToSequence(sequenceid, audioid);
      o Adds a mapped audio file to a sequence

* Audio_RemoveFromSequence(sequenceid, audioid);
      o Removes all instances of a mapped audio file from a sequence

* Audio_Play(playerid, audioid, bool:pause = false, bool:loop = false, bool:downmix = false);
      o Plays a mapped audio file for a player and specifies whether
        it should start paused, whether it should be looped, and
        whether the audio stream should be downmixed to mono
        Note: This returns a handle ID.

* Audio_PlayStreamed(playerid, const url[], bool:pause = false, bool:loop = false, bool:downmix = false);
      o Streams a URL for a player and specifies whether it should
        start paused, whether it should be looped, and whether the
        audio stream should be downmixed to mono
        Note: This returns a handle ID.

* Audio_PlaySequence(playerid, sequenceid, bool:pause = false, bool:loop = false, bool:downmix = false);
      o Plays a sequence for a player and specifies whether it should
        start paused, whether it should be looped, and whether the
        audio stream should be downmixed to mono
        Note: This returns a handle ID.

* Audio_Pause(playerid, handleid);
      o Pauses playback for an audio stream assigned to a player's
        handle ID

* Audio_Resume(playerid, handleid);
      o Resumes playback for an audio stream assigned to a player's
        handle ID

* Audio_Stop(playerid, handleid);
      o Stops playback for an audio stream assigned to a player's
        handle ID

* Audio_Restart(playerid, handleid);
      o Restarts playback for an audio stream assigned to a player's
        handle ID

* Audio_GetPosition(playerid, handleid, const callback[] = "Audio_OnGetPosition");
      o Gets the position in seconds for an audio stream assigned to
        a player's handle ID and stores it in the specified callback
        Note: The callback, by default, is Audio_OnGetPosition. A
        custom callback may be used that resembles the form of the
        default callback, but it must be forwarded in the script.

* Audio_SetPosition(playerid, handleid, seconds);
      o Sets position in seconds for an audio stream assigned to a
        player's handle ID

* Audio_SetVolume(playerid, handleid, volume);
      o Adjusts volume (0-100) for an audio stream assigned to a
        player's handle ID

* Audio_SetFX(playerid, handleid, type);
      o Applies a sound effect to an audio stream assigned to a
        player's handle ID
        Note: Valid values for type are as follows:
            + 0: Chorus
            + 1: Compression
            + 2: Distortion
            + 3: Echo
            + 4: Flanger
            + 5: Gargle
            + 6: I3DL2 Reverb
            + 7: Parametric Equalizer
            + 8: Reverb

* Audio_RemoveFX(playerid, handleid, type);
      o Removes a sound effect from an audio stream assigned to a
        player's handle ID
        Note: Valid values for type are listed above.

* Audio_Set3DPosition(playerid, handleid, Float:x, Float:y, Float:z, Float:distance);
      o Sets the 3D position (game world coordinates) of an audio
        stream assigned to a player's handle ID
        Note: The audio stream must be downmixed to mono (see the
        last parameter of Audio_Play, Audio_PlayStreamed, and
        Audio_PlaySequence) for panning to work properly.

* Audio_SetRadioStation(playerid, station);
      o Sets a player's current in-game radio station
        Note: Valid values for station are as follows:
            + 0: Radio Off (Emergency Vehicle Radio)
            + 1: Playback FM
            + 2: K-Rose
            + 3: K-DST
            + 4: Bounce FM
            + 5: SF-UR
            + 6: Radio Los Santos
            + 7: Radio X
            + 8: CSR 103.9
            + 9: K-Jah West
            + 10: Master Sounds 98.3
            + 11: WCTR
            + 12: User Track Player

* Audio_StopRadio(playerid);
      o Stops, or turns off, a player's in-game radio station

Callbacks
---------
* Audio_OnClientConnect(playerid);
      o Called when a player connects to the TCP server

* Audio_OnClientDisconnect(playerid);
      o Called when a player disconnects from the TCP server

* Audio_OnTransferFile(playerid, file[], current, total, result);
      o Called when a player completes the transfer of a file
        Note: The result can be one of the following:
            + 0: Local file downloaded successfully
            + 1: Remote file downloaded successfully
            + 2: File passed CRC check or file size check
            + 3: Error transferring or checking file

* Audio_OnPlay(playerid, handleid);
      o Called when a player starts any event associated with a
        handle ID

* Audio_OnStop(playerid, handleid);
      o Called when a player stops any event associated with a
        handle ID

* Audio_OnTrackChange(playerid, handleid, track[]);
      o Called when a player reports that a track change has occurred
        in an online station

* Audio_OnRadioStationChange(playerid, station);
      o Called when a player changes the radio station in-game

* Audio_OnGetPosition(playerid, handleid, seconds);
      o Called by default when a result from Audio_GetPosition is
        retrieved

Tutorial
--------
Client:

Installation and use of the client plugin is simple. Just run the
installer and extract the files to your GTA: San Andreas directory.
The ASI plugin detects when SA-MP is loaded and obtains your current
player name, server address, and server port automatically. It will
then attempt to connect to the TCP server (if there is one) some time
after the game has started. By default, there will be a total of ten
retry attempts with a delay of tenseconds each. To adjust these
numbers, along with a few other settings, you need to edit audio.ini.
To locate this file, go to Start, click Run, and type in the
following:

%APPDATA%\SA-MP Audio Plugin

An Explorer window should open. In this directory, you should see
your downloaded audio packs, audio.ini, and audio.txt.

Server:

First, create a folder called plugins in your server directory if it
doesn't already exist. Place audio.dll in it if you're using Windows,
or audio.so if you're using Linux.

Add the following line to server.cfg so that the plugin will load the
next time the server starts: 

Windows:
plugins audio

Linux:
plugins audio.so

The server log should indicate that the plugin was loaded
successfully. The include file then needs to be put in a filterscript
or a gamemode (preferably a gamemode so that there will be no
conflicts):

#include <audio>

The server log should also indicate that the TCP server was created
successfully on the same port that the SA-MP sever is using.

Ensure that both the audiopacks folder and the audio.ini file are in
the root directory of the server. Open audio.ini and add a section
for your audio pack name. For demonstration purposes, this will be
called "default_pack":

[default_pack]

Navigate to your audiopacks directory and create a folder called
"default_pack" within it. This is where all of your local audio files
will go. Add an audio file to the "default_pack" folder. This will be
called "example.wav". Map it under the section you just created in
audio.ini:

[default_pack]
1 = example.wav

The number to the left of the file name (1) is the audio ID. It is an
arbitrary number, so it can be whatever you'd like. It can be used in
Audio_Play like this:

Audio_Play(playerid, 1);

You can also map remote files that don't need to be in your
audiopacks directory. They must start with "http://". Here is an
example:

[default_pack]
1 = example.wav
2 = http://www.website.com/file.mp3

Now you simply need to set your audio pack when the gamemode loads:

public OnGameModeInit()
{
	Audio_SetPack("default_pack");
}

Alternatively, it is possible to completely ignore audio.ini and
stream all of your files with the Audio_PlayStreamed native instead.
This will consume more client-side bandwidth, however, if the files
are played repeatedly.

More detailed examples of nearly every native can be found in the
filterscript.
