Skip to content

Commit b0edf5c

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

File tree

1 file changed

+244
-36
lines changed

1 file changed

+244
-36
lines changed

docs/audio.rst

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

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

109317

110-
Example
111-
=======
318+
AudioFrame Example
319+
------------------
112320

113321
.. include:: ../examples/waveforms.py
114322
:code: python

0 commit comments

Comments
 (0)