# Sound Library

The sound library is an external library for managing audio. It provides an interface for working with streams of sound data that is similar to the IO part of the standard library (but works on 32-bit floating point values instead of bytes). It also provides decoding of common audio formats (currently, mp3, ogg, flac, and wav), and playback of audio streams. The library also defines a thread, `sound.Audio`, for executing sound-related code.

The remainder of this part of the manual provides an overview of these interfaces.

## Sound

The type `sound.Sound` represents a stream of audio samples. As such, it is analogous to the type `core.io.IStream` in the standard library. The type itself does not provide any audio data. Any of the derived types may be used for this purpose.

A sound stream is considered to consist of a sequence of samples. Each sample is represented by a 32-bit floating point number (`core.Float`). If the sound stream contains multiple channels, samples for all channels are interleaved in the stream as specified by the vorbis format. For example, for 2 channels, the first sample is for the left channel, the second is for the right, and so on. The interface expects consumers of the sound data to work in multiples of the channel size.

Audio streams may be seekable or non-seekable. Seekable streams return a non-zero length, while non-seekable streams return a zero length.

The type has the following members:

- `core.Nat sampleFreq()`

  Get the sample frequency of the stream, measured in samples per second.

- `core.Nat channels()`

  Get the number of channels for this stream.

- `void close()`

  Close the stream now. Also closes any underlying input streams for this stream.

- `core.Bool more()`

  Is more data available in the stream? Might return false only after reading zero bytes for the first time.

- `core.Word length()`

  Get the length of the stream, measured in samples. Returns zero if the stream is not seekable.

- `core.Bool seek(core.Word to)`

  Seek in the input stream. Returns `false` if seeking is not supported, or an error occurred. The position is measured in samples. The position is expected to be a multiple of the number of channels.

- `core.Word tell()`

  Get the current position, measured in samples. May return zero for non-seekable streams.

- `sound.Buffer read(sound.Buffer to)`

  Attempt to fill the buffer `to` with samples from the stream. Fills the bytes from `filled` to `count` in the buffer. Only reads a multiple of `channels` samples from the stream. If zero samples are read, then the end of the stream is reached.

- `sound.Buffer read(core.Nat samples)`

  Read data from the buffer into a new, empty buffer with space for the specified number of samples.

### Reading Sound

As mentioned above, the library contains support for some common audio formats, namely mp3, ogg, flac, and wav. Support for most of these are provided by external libraries that are compiled into the library on most platforms. Support for wav is native to the library, and as such support for compressed wav-files is limited.

The library provides the following classes to decode the different formats:

- `sound.Mp3Sound`
- `sound.OggSound`
- `sound.FlacSound`
- `sound.WavSound`

These are generally created by the functions `openX` or `openXStream`. The former accepts a `core.io.RIStream` and creates a seekable stream, while the latter accepts a `core.io.IStream` and creates a non-seekable stream.

The library also provides generic operations for opening sound files and automatically deducing the file format based on the header in the file:

- `sound.Sound sound(core.io.IStream src)`

  Create a sound stream for reading `src` based on the header in `src`. Will make `src` into a seekable stream to provide a seekable audio stream.

- `sound.Sound soundStream(core.io.IStream src)`

  Open sound from a streaming source. The resulting stream will not be seekable.

- `sound.Sound readSound(core.io.Url file)`

  Calls `sound(file.read())`.

- `sound.Sound readSoundStream(core.io.Url file)`

  Calls `soundStream(file.read())`.

## Buffer

The `sound.Buffer` represents a series of samples, represented as 32-bit floating point values in the range 1.0 to -1.0. The interface closely resembles that of `core.io.Buffer`, which is documented here.

As with the buffers in the IO library, copies of buffers generally refer to the same data, but are copied across thread boundaries. As such, when using the `read` function in a `Sound` stream, it is important to use the returned buffer, even though the buffer that was passed to the function is updated in most cases.

The `Buffer` has the following members:

- `init()`

  Default constructor. Create an empty buffer. Use the function `buffer` to create a buffer with non-zero size.

- `core.Nat count()`

  Get the number of samples in the buffer in total.

- `core.Nat filled()`

  Get the number of samples from the beginning of the buffer that are considered to contain valid data. The buffer itself generally does not use this value. Rather, it is used as an universal marker for how much of the buffer is used for actual data, and how much is free.

- `void filled(core.Nat p)`

  Set the number of samples that are used. Limits the value to be maximum `count`. Marked as an assign functions, so that `filled` can be used as a member variable in languages like Basic Storm.

- `core.Nat free()`

  Get the number of free samples in the buffer, based on the `filled` member.

- `core.Float& [](core.Nat id)`

  Access individual samples.

- `core.Bool empty()`

  Is the buffer empty according to the `filled` member?

- `core.Bool full()`

  Is the buffer full, according to the `filled` member?

- `void toS(core.StrBuf to)`

  Output. A toS() is generated automatically.

- `void outputMark(core.StrBuf to, core.Nat markAt)`

  Output the buffer, specifying an additional mark.

The buffer also has the following free function `buffer` to create buffers:

- `sound.Buffer buffer(core.Nat count)`

  Create a buffer with room for `count` bytes. It will be empty initially.

## Player

The type `sound.Player` represents an audio stream that is being played on the system's default speakers. On Windows, it uses the DirectSound API, and on Linux it relies on OpenAL. The implementation typicallby buffers some amount of sound data internally to avoid artifacts. The `Player` provides basic controls for the audio playback:

- `init(sound.Sound sound)`

  Create a player that plays the specified `sound`. The `Player` takes responsibility for closing the sound stream eventually, and assumes that the sound stream is not modified externally. Will not play the sound until `play` is called.

- `void close()`

  Destroy any resources associated with the `Player`. The destructor automatically calls `close` eventually, but since this does not always happen promptly, it is a good idea to manually call `close` whenever possible.

- `void play()`

  Start playing the sound.

- `core.Bool playing()`

  Is the stream currently playing?

- `void pause()`

  Pause the sound.

- `void stop()`

  Stop playing the sound. This also resets the playback position to zero (for seekable streams).

- `core.Duration time()`

  Get the time of playback.

- `core.Float volume()`

  Get the current volume.

- `void volume(core.Float level)`

  Set the sound volume (between 0 and 1). Marked as an assign function, so that `volume` can be treated as a member variable.

- `void wait()`

  Wait until playback reaches the end of the stream, or until playback is stopped. Do not call from the UThread that manages callbacks.

- `void waitUntil(core.Duration t)`

  Wait until playback reaches or passes the specific duration since start, or if the player is stopped. Do not call from the UThread managing callbacks.