Play an Audio
=============

.. currentmodule:: palace

Now that you know how to create a context,
let's get into the most essential use case: playing audio.

Creating a Source
-----------------

To play an audio, you have to create a source.  This source
is an imaginary sound broadcaster, whose positions and properties
can be changed to create desired effects.

.. code-block:: python

   from palace import Device, Context, Source

   with Device() as dev, Context(dev) as ctx:
       with Source() as src:
           # to be written

Just like for the case of :py:class:`Context`, :py:class:`Source` creation
requires a context, but here the context is passed implicitly.

Decode the Audio File
---------------------

Palace has a module level function :py:func:`decode`, which decodes audio file
automatically, and this decoded file is a :py:class:`Decoder` object.  This object
can be played by a simple :py:meth:`Decoder.play` method.

.. code-block:: python

   from palace import Device, Context, Source, decode

   filename = 'some_audio.ogg'
   with Device() as dev, Context(dev) as ctx:
       with Source() as src:
           dec = decode(filename)

We are almost there.  Now, let's look at the document for :py:meth:`Decoder.play`.
The method takes 3 parameters: ``chunk_len``, ``queue_size``, and ``source``.

The source object is optional, because if you don't have it, a new source
will be generated by default.

The audio is divided into chunks, each of which is of length ``chunk_len``.
Then ``queue_size`` is the number of these chunks that it will play.

.. TODO: I think it's better to include a diagram here. Add later

.. code-block:: python

   from palace import Device, Context, Source, decode

   filename = 'some_audio.ogg'
   with Device() as dev, Context(dev) as ctx:
       with Source() as src:
           dec = decode(filename)
           dec.play(12000, 4, src)

But we don't want it to play only a small part of the audio.  We want it to
play all of it.  How do we do that? The answer is a loop.

There is a method, :py:meth:`Context.update`, which update the context and the source.
When the source is updated, it will be filled with new chunks of data from
the decoder.

.. code-block:: python

   from palace import Device, Context, Source, decode

   filename = 'some_audio.ogg'
   with Device() as dev, Context(dev) as ctx:
       with Source() as src:
           dec = decode(filename)
           dec.play(12000, 4, src)
           while src.playing:
               ctx.update()

If you tried this code for a song, you will find that it's a bit rush.
That is because the source is renewed too fast.  So, a simple solution
is to ``sleep`` for a while.

.. code-block:: python

   from time import sleep
   from palace import Device, Context, Source, decode

   filename = 'some_audio.ogg'
   with Device() as dev, Context(dev) as ctx:
       with Source() as src:
           dec = decode(filename)
           dec.play(12000, 4, src)
           while src.playing:
               sleep(0.025)
               ctx.update()

Congratulation!  Enjoy your music before we get to the next part of this tutorial.
