~cnx/palace

ref: 708f23b35a7e232273ba0a63a65b3ef778a84540 palace/docs/source/tutorial/play-audio.rst -rw-r--r-- 3.1 KiB
708f23b3 — Ngô Ngọc Đức Huy Write tutorial for source effect 1 year, 7 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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.