Skip to content

Commit e7ff826

Browse files
docs: Add Sound Effects documentation.
1 parent ec326a9 commit e7ff826

File tree

1 file changed

+246
-36
lines changed

1 file changed

+246
-36
lines changed

docs/audio.rst

Lines changed: 246 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,57 @@ Audio
66
This module allows you play sounds with the micro:bit.
77

88
By default sound output will be via the edge connector on pin 0 and the
9-
:doc:`built-in speaker <speaker>` **V2**. You can connect wired headphones or
9+
:doc:`built-in speaker <speaker>` (**V2**). You can connect wired headphones or
1010
a speaker to pin 0 and GND on the edge connector to hear the sounds.
1111

1212
The ``audio`` module can be imported as ``import audio`` or accessed via
1313
the ``microbit`` module as ``microbit.audio``.
1414

15+
There are three different kinds of audio sources that can be played using the
16+
:py:meth:`audio.play` function:
17+
18+
1. `Built in sounds <#built-in-sounds-v2>`_ (**V2**),
19+
e.g. ``audio.play(Sound.HAPPY)``
20+
2. `Sound Effects <#sound-effects-v2>`_ (**V2**), a way to create custom sounds
21+
by configuring its parameters::
22+
23+
my_effect = audio.Effect(freq_start=400, freq_end=2500, duration=500)
24+
audio.play(my_effect)
25+
26+
3. `Audio Frames <##audioframe>`_, an iterable (like a list or a generator)
27+
of Audio Frames, which are lists of 32 samples with values from 0 to 255::
28+
29+
square_wave = audio.AudioFrame()
30+
for i in range(16):
31+
square_wave[i] = 0
32+
square_wave[i + 16] = 255
33+
audio.play([square_wave] * 64)
34+
35+
1536
Functions
1637
=========
1738

1839
.. py:function:: play(source, wait=True, pin=pin0, return_pin=None)
1940
20-
Play the source to completion.
41+
Play the audio source to completion.
2142

22-
:param source: ``Sound``: The ``microbit`` module contains a list of
23-
built-in sounds that your can pass to ``audio.play()``.
43+
:param source: There are three types of data that can be used as a source:
44+
45+
- ``Sound``: The ``microbit`` module contains a list of
46+
built-in sounds, e.g. ``audio.play(Sound.TWINKLE)``. A full list can
47+
be found in the `Built in sounds <#built-in-sounds-v2>`_ section.
48+
- ``Effect``: A sound effect, or an iterable of sound effects, created
49+
via the :py:meth:`audio.Effect` class
50+
- ``AudioFrame``: An iterable of ``AudioFrame`` instances as described
51+
in the `AudioFrame Technical Details <#id2>`_ section
2452

25-
``AudioFrame``: The source agrument can also be an iterable
26-
of ``AudioFrame`` elements as described below.
2753
:param wait: If ``wait`` is ``True``, this function will block until the
2854
source is exhausted.
55+
2956
:param pin: An optional argument to specify the output pin can be used to
3057
override the default of ``pin0``. If we do not want any sound to play
3158
we can use ``pin=None``.
59+
3260
:param return_pin: specifies a differential edge connector pin to connect
3361
to an external speaker instead of ground. This is ignored for the **V2**
3462
revision.
@@ -41,34 +69,9 @@ Functions
4169
4270
Stops all audio playback.
4371

44-
Classes
45-
=======
46-
47-
.. py:class::
48-
AudioFrame
49-
50-
An ``AudioFrame`` object is a list of 32 samples each of which is an unsigned byte
51-
(whole number between 0 and 255).
52-
53-
It takes just over 4 ms to play a single frame.
54-
55-
.. py:function:: copyfrom(other)
56-
57-
Overwrite the data in this ``AudioFrame`` with the data from another
58-
``AudioFrame`` instance.
59-
60-
:param other: ``AudioFrame`` instance from which to copy the data.
61-
62-
63-
Using audio
64-
===========
65-
66-
You will need a sound source, as input to the ``play`` function. You can use
67-
the built-in sounds **V2** from the ``microbit`` module, ``microbit.Sound``, or
68-
generate your own, like in ``examples/waveforms.py``.
6972

7073
Built-in sounds **V2**
71-
----------------------
74+
======================
7275

7376
The built-in sounds can be called using ``audio.play(Sound.NAME)``.
7477

@@ -83,8 +86,215 @@ The built-in sounds can be called using ``audio.play(Sound.NAME)``.
8386
* ``Sound.TWINKLE``
8487
* ``Sound.YAWN``
8588

89+
Sounds Example
90+
--------------
91+
92+
::
93+
94+
from microbit import *
95+
96+
while True:
97+
if button_a.is_pressed() and button_b.is_pressed():
98+
# When pressing both buttons only play via the edge connector
99+
audio.play(Sound.HELLO, pin=pin0)
100+
elif button_a.is_pressed():
101+
# On button A play a sound and when it's done show an image
102+
audio.play(Sound.HAPPY)
103+
display.show(Image.HAPPY)
104+
elif button_b.is_pressed():
105+
# On button B play a sound and show an image at the same time
106+
audio.play(Sound.TWINKLE, wait=False)
107+
display.show(Image.BUTTERFLY)
108+
109+
sleep(500)
110+
display.clear()
111+
112+
113+
Sound Effects **V2**
114+
====================
115+
116+
.. py:class::
117+
Effect(preset=None, freq_start=400, freq_end=200, duration=500, vol_start=100, vol_end=255, wave=WAVE_SQUARE, fx=None, interpolation=INTER_LINEAR)
118+
119+
An ``Effect`` instance represents a sound effect, composed by a set of
120+
parameters configured via the constructor or attributes.
121+
122+
All the parameters are optional, with default values as shown above, and
123+
they can all be modified via attributes of the same name. For example, we
124+
can first create an effect ``my_effect = Effect(duration=1000)``, and then
125+
change its attributes ``my_effect.duration = 500``.
126+
127+
:param preset: An existing Effect instance to use as a base, its values
128+
are cloned in the new instance, and any additional arguments provided
129+
overwrite the base values.
130+
:param freq_start: Start Frequency in Hertz (Hz), eg: ``400``
131+
:param freq_end: End Frequency in Hertz (Hz), eg: ``2000``
132+
:param duration: Duration of the sound (ms), eg: ``500``
133+
:param vol_start: Start volume value, range 0-255, eg: ``120``
134+
:param vol_end: End volume value, range 0-255, eg: ``255``
135+
:param wave: Type of wave shape, one of these values: ``WAVE_SINE``,
136+
``WAVE_SAWTOOTH``, ``WAVE_TRIANGLE``, ``WAVE_SQUARE``,
137+
``WAVE_NOISE`` (randomly generated noise).
138+
:param fx: Effect to add on the sound, one of the following values:
139+
``FX_TREMOLO``, ``FX_VIBRATO``, ``FX_WARBLE``, or ``None``.
140+
:param interpolation: The type of curve between the start and end
141+
frequencies, different wave shapes have different rates of change
142+
in frequency. One of the following values: ``INTER_LINEAR``,
143+
``INTER_CURVE``, ``INTER_LOG``.
144+
145+
.. py:attribute:: freq_start
146+
147+
Start Frequency in Hertz (Hz)
148+
149+
.. py:attribute:: freq_end
150+
151+
End Frequency in Hertz (Hz)
152+
153+
.. py:attribute:: duration
154+
155+
Duration of the sound (ms), eg: ``500``
156+
157+
.. py:attribute:: vol_start
158+
159+
Start volume value, range 0-255, eg: ``120``
160+
161+
.. py:attribute:: vol_end
162+
163+
End volume value, range 0-255, eg: ``255``
164+
165+
.. py:attribute:: wave
166+
167+
Type of wave shape, one of these values: ``WAVE_SINE``,
168+
``WAVE_SAWTOOTH``, ``WAVE_TRIANGLE``, ``WAVE_SQUARE``,
169+
``WAVE_NOISE`` (randomly generated noise).
170+
171+
.. py:attribute:: fx
172+
173+
Effect to add on the sound, one of the following values:
174+
``FX_TREMOLO``, ``FX_VIBRATO``, ``FX_WARBLE``, or ``None``.
175+
176+
.. py:attribute:: interpolation
177+
178+
The type of curve between the start and end
179+
frequencies, different wave shapes have different rates of change
180+
in frequency. One of the following values: ``INTER_LINEAR``,
181+
``INTER_CURVE``, ``INTER_LOG``.
182+
183+
The arguments used to create any Sound Effect, including the built in effects,
184+
can be inspected by looking at each of the Effect instance attributes, or by
185+
converting the instance into a string (which can be done via ``str()``
186+
function, or by using a function that does the conversion automatically like
187+
``print()``).
188+
189+
For example, with the :doc:`REPL </devguide/repl>` you can inspect the built
190+
in Effects::
191+
192+
>>> audio.Effect.CROAK
193+
Effect(freq_start=..., freq_end=..., duration=..., vol_start=..., vol_end=..., wave=..., fx=..., interpolation=...)
194+
195+
The built in Effects are immutable, so they cannot be changed. Trying to modify
196+
a built in Effect will throw an exception::
197+
198+
>>> audio.Effect.CLICK.duration = 1000
199+
Traceback (most recent call last):
200+
File "<stdin>", line 1, in <module>
201+
TypeError: effect cannot be modified
202+
203+
But a new one can be created like this::
204+
205+
>>> click_clone = Effect(audio.Effect.CLICK)
206+
>>> click_clone.duration = 1000
207+
>>>
208+
209+
Built in Sound Effects
210+
----------------------
211+
212+
Some pre-created Sound Effects are already available as examples. These can
213+
be played directly ``audio.play(audio.Effect.SQUEAK)``, or used as a base to
214+
create new effects ``audio.Effect(audio.Effect.SQUEAK, duration=2000)``.
215+
216+
* ``audio.Effect.SQUEAK``
217+
* ``audio.Effect.WARBLE``
218+
* ``audio.Effect.CHIRP``
219+
* ``audio.Effect.CROAK``
220+
* ``audio.Effect.CLICK``
221+
222+
Sound Effects Example
223+
---------------------
224+
225+
::
226+
227+
from microbit import *
228+
229+
# Play a built in Sound Effect
230+
audio.play(audio.Effect.CHIRP)
231+
232+
# Create a Sound Effect and immediately play it
233+
audio.play(Effect(
234+
freq_start=400,
235+
freq_end=2000,
236+
duration=500,
237+
vol_start=100,
238+
vol_end=255,
239+
wave=audio.WAVE_TRIANGLE,
240+
fx=audio.FX_VIBRATO,
241+
interpolation=audio.LOG
242+
))
243+
244+
# Play a Sound Effect instance, modify an attribute, and play it again
245+
my_effect = Effect(
246+
preset=audio.CHIRP
247+
freq_start=400,
248+
freq_end=2000,
249+
)
250+
audio.play(my_effect)
251+
my_effect.duration = 1000
252+
audio.play(my_effect)
253+
254+
# You can also create a new effect based on an existing one, and modify
255+
# any of its characteristics via arguments
256+
audio.play(audio.Effect.WARBLE)
257+
my_modified_effect = Effect(audio.Effect.WARBLE, duration=1000)
258+
audio.play(my_modified_effect)
259+
260+
# Use sensor data to modify and play the existing Sound Effect instance
261+
while True:
262+
my_effect.freq_start=accelerometer.get_x()
263+
my_effect.freq_end=accelerometer.get_y()
264+
audio.play(my_effect)
265+
266+
if button_a.is_pressed():
267+
# On button A play an effect and once it's done show an image
268+
audio.play(audio.Effect.CHIRP)
269+
display.show(Image.DUCK)
270+
sleep(500)
271+
elif button_b.is_pressed():
272+
# On button B play an effect while showing an image
273+
audio.play(audio.Effect.CLICK, wait=False)
274+
display.show(Image.SQUARE)
275+
sleep(500)
276+
277+
278+
AudioFrame
279+
==========
280+
281+
.. py:class::
282+
AudioFrame
283+
284+
An ``AudioFrame`` object is a list of 32 samples each of which is an unsigned byte
285+
(whole number between 0 and 255).
286+
287+
It takes just over 4 ms to play a single frame.
288+
289+
.. py:function:: copyfrom(other)
290+
291+
Overwrite the data in this ``AudioFrame`` with the data from another
292+
``AudioFrame`` instance.
293+
294+
:param other: ``AudioFrame`` instance from which to copy the data.
295+
86296
Technical Details
87-
=================
297+
-----------------
88298

89299
.. note::
90300
You don't need to understand this section to use the ``audio`` module.
@@ -104,11 +314,11 @@ samples. When reading reaches the start or the mid-point of the buffer, it
104314
triggers a callback to fetch the next ``AudioFrame`` which is then copied into
105315
the buffer. This means that a sound source has under 4ms to compute the next
106316
``AudioFrame``, and for reliable operation needs to take less 2ms (which is
107-
32000 cycles, so should be plenty).
317+
32k cycles in micro:bit V1 or 128k in V2, so should be plenty).
108318

109319

110-
Example
111-
=======
320+
AudioFrame Example
321+
------------------
112322

113323
.. include:: ../examples/waveforms.py
114324
:code: python

0 commit comments

Comments
 (0)