Skip to content

Commit e5c1b73

Browse files
docs: Update recording & playback based on review.
1 parent d430151 commit e5c1b73

File tree

2 files changed

+93
-103
lines changed

2 files changed

+93
-103
lines changed

docs/audio.rst

+34-79
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ a speaker to pin 0 and GND on the edge connector to hear the sounds.
1212
The ``audio`` module can be imported as ``import audio`` or accessed via
1313
the ``microbit`` module as ``microbit.audio``.
1414

15-
There are four different kinds of audio sources that can be played using the
15+
There are three different kinds of audio sources that can be played using the
1616
:py:meth:`audio.play` function:
1717

1818
1. `Built in sounds <#built-in-sounds-v2>`_ (**V2**),
@@ -24,14 +24,9 @@ There are four different kinds of audio sources that can be played using the
2424
my_effect = audio.SoundEffect(freq_start=400, freq_end=2500, duration=500)
2525
audio.play(my_effect)
2626

27-
3. `AudioBuffer <#audiobuffer>`_ (**V2**), a generic buffer for audio that can
28-
be used to record sound from the micro:bit V2 built-in microphone::
29-
30-
my_audio_buffer = microphone.record()
31-
audio.play(my_audio_buffer)
32-
33-
4. `Audio Frames <#audioframe>`_, an iterable (like a list or a generator)
34-
of Audio Frames, which are lists of 32 samples with values from 0 to 255::
27+
3. `Audio Frames <#audioframe>`_, an instance or an iterable (like a list or
28+
generator) of Audio Frames, which are lists of samples with values
29+
from 0 to 255::
3530

3631
square_wave = audio.AudioFrame()
3732
for i in range(16):
@@ -47,18 +42,16 @@ Functions
4742
4843
Play the audio source to completion.
4944

50-
:param source: There are four types of data that can be used as a source:
45+
:param source: There are three types of data that can be used as a source:
5146

5247
- ``Sound``: The ``microbit`` module contains a list of
5348
built-in sounds, e.g. ``audio.play(Sound.TWINKLE)``. A full list can
5449
be found in the `Built in sounds <#built-in-sounds-v2>`_ section.
5550
- ``SoundEffect``: A sound effect, or an iterable of sound effects,
5651
created via the :py:meth:`audio.SoundEffect` class
57-
- ``AudioBuffer``: An audio buffer, or an iterable of audio buffers,
58-
created via the :py:meth:`audio.AudioBuffer` class or
59-
:doc:`microphone.record() <microphone>` function
60-
- ``AudioFrame``: An iterable of ``AudioFrame`` instances as described
61-
in the `AudioFrame Technical Details <#id2>`_ section
52+
- ``AudioFrame``: An instance or an iterable of ``AudioFrame``
53+
instances as described in the
54+
`AudioFrame Technical Details <#technical-details>`_ section
6255

6356
:param wait: If ``wait`` is ``True``, this function will block until the
6457
source is exhausted.
@@ -79,6 +72,13 @@ Functions
7972
8073
Stops all audio playback.
8174

75+
.. py:function:: set_rate(sample_rate)
76+
77+
Changes the sampling rate of ``AudioFrame`` playback.
78+
The default playback rate is 7812 samples per second.
79+
Decreasing the playback sampling rate results in slowed down sound, and
80+
increasing it speeds it up.
81+
8282

8383
Built-in sounds **V2**
8484
======================
@@ -226,70 +226,16 @@ Sound Effects Example
226226
:code: python
227227

228228

229-
Audio Buffer **V2**
230-
===================
231-
232-
.. py:class::
233-
AudioBuffer(duration=3000, rate=11000)
234-
235-
Create a buffer to contain audio data and its sampling rate.
236-
237-
The sampling rate is configured via constructor or instance attribute,
238-
and is used by the ``microphone.record_into()`` and
239-
``audio.play()`` functions to configure the recording and playback rates.
240-
241-
For audio recording, reducing the number of samples recorded per second
242-
will reduce the size of the data buffer, but also reduce the sound quality.
243-
And increasing the sampling rate increases the buffer size and sound
244-
quality.
245-
246-
For audio playback, reducing the sampling rate compared with the recording
247-
rate, will slow down the audio. And increasing the playback rate
248-
will speed it up.
249-
250-
The size of the buffer will be determined by the samples per second
251-
and the ``duration`` configured when creating a new instance.
252-
253-
:param duration: Indicates in milliseconds, how much sound data the buffer
254-
can contained at the configured ``data_rate``.
255-
:param rate: Sampling rate of for the data in the buffer. This value is
256-
used for recording and playback, and can be edited as an attribute.
257-
258-
.. py:function:: copy()
259-
260-
:returns: A copy of the Audio Buffer.
261-
262-
.. py:attribute:: rate
263-
264-
The sampling rate for the data inside the buffer.
265-
TODO: Indicate range of valid values here.
266-
267-
Audio Buffer Example
268-
--------------------
269-
270-
::
271-
272-
my_buffer = audio.AudioBuffer(duration=5000)
273-
microphone.record_into(my_buffer)
274-
audio.play(my_buffer)
275-
276-
# A smaller buffer can be generated with the same duration by using
277-
# a lower sampling rate
278-
smaller_buffer = audio.AudioBuffer(duration=5000, rate=5500)
279-
microphone.record_into(my_buffer)
280-
audio.play(my_buffer)
281-
282-
283229
AudioFrame
284230
==========
285231

286232
.. py:class::
287-
AudioFrame
233+
AudioFrame(size=32)
288234

289-
An ``AudioFrame`` object is a list of 32 samples each of which is an unsigned byte
290-
(whole number between 0 and 255).
235+
An ``AudioFrame`` object is a list of samples each of which is an unsigned
236+
byte (whole number between 0 and 255).
291237

292-
It takes just over 4 ms to play a single frame.
238+
:param size: How many samples to contain in this instance.
293239

294240
.. py:function:: copyfrom(other)
295241
@@ -305,13 +251,19 @@ Technical Details
305251
You don't need to understand this section to use the ``audio`` module.
306252
It is just here in case you wanted to know how it works.
307253

308-
The ``audio`` module can consumes an iterable (sequence, like list or tuple, or
309-
generator) of ``AudioFrame`` instances, each 32 samples at 7812.5 Hz, and uses
310-
linear interpolation to output a PWM signal at 32.5 kHz, which gives tolerable
311-
sound quality.
254+
The ``audio.play()`` function can consume an instance or iterable
255+
(sequence, like list or tuple, or generator) of ``AudioFrame`` instances.
256+
Its default playback rate is 7812 Hz, and uses linear interpolation to output
257+
a PWM signal at 32.5 kHz.
312258

313-
The function ``play`` fully copies all data from each ``AudioFrame`` before it
314-
calls ``next()`` for the next frame, so a sound source can use the same
259+
Each ``AudioFrame`` instance is 32 samples by default, but it can be
260+
configured to a different size via constructor.
261+
262+
So, for example, playing 32 samples at 7812 Hz takes just over 4 milliseconds
263+
(1/7812.5 * 32 = 0.004096 = 4096 microseconds).
264+
265+
The function ``play()`` fully copies all data from each ``AudioFrame`` before
266+
it calls ``next()`` for the next frame, so a sound source can use the same
315267
``AudioFrame`` repeatedly.
316268

317269
The ``audio`` module has an internal 64 sample buffer from which it reads
@@ -325,5 +277,8 @@ the buffer. This means that a sound source has under 4ms to compute the next
325277
AudioFrame Example
326278
------------------
327279

280+
Creating and populating ``AudioFrame`` iterables and generators with
281+
different sound waveforms:
282+
328283
.. include:: ../examples/waveforms.py
329284
:code: python

docs/microphone.rst

+59-24
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,51 @@ accessible via variables in ``microbit.SoundEvent``:
3131
Recording
3232
=========
3333

34-
TODO:
35-
* Describe the feature.
36-
* Indicate how the sampling rate relates to recording quality.
37-
* Indicate how changing the sampling rate on the fly affects playback speed.
38-
* What happens if the user changes the sampling rate while recording?
34+
The microphone can record audio into an :doc:`AudioFrame <audio>`, which can
35+
then be played with the ``audio.play()`` function.
3936

40-
::
37+
Audio sampling is the process of converting sound into a digital format.
38+
To do this, the microphone takes samples of the sound waves at regular
39+
intervals. How many samples are recorded per second is known as the
40+
"sampling rate", so recording at a higher sampling rate increases the sound
41+
quality, but as more samples are saved, it also takes more memory.
42+
43+
The microphone sampling rate can be configured during sound recording via
44+
the ``rate`` argument in the ``record()`` and ``record_into()`` functions.
45+
46+
At the other side, the audio playback sampling rate indicates how many samples
47+
are played per second. So if audio is played back with a higher sampling rate
48+
than the rate used during recording, then the audio will sound speeded up.
49+
If the playback sampling rate is twice the recording rate, the sound will take
50+
half the time to be played to completion. Similarly, if the playback rate
51+
is halved, it will play half as many samples per second, and so it will
52+
take twice as long to play the same amount of samples.
53+
54+
How do you think a voice recording will sound if the playback rate is
55+
increased or decreased? Let's try it out!::
4156

4257
from microbit import *
4358

59+
RECORDING_SAMPLING_RATE = 11000
60+
4461
while True:
62+
if pin_logo.is_touched():
63+
# Record and play back at the same rate
64+
my_recording = microphone.record(duration=3000, rate=RECORDING_SAMPLING_RATE)
65+
audio.play(my_recording)
66+
4567
if button_a.is_pressed():
46-
my_recording = microphone.record(duration=5000)
68+
# Play back at half the sampling rate
69+
my_recording = microphone.record(duration=3000, rate=RECORDING_SAMPLING_RATE)
70+
audio.set_rate(RECORDING_SAMPLING_RATE / 2)
4771
audio.play(my_recording)
72+
73+
if button_b.is_pressed():
74+
# Play back at twice the sampling rate
75+
my_recording = microphone.record(duration=3000, rate=RECORDING_SAMPLING_RATE)
76+
audio.set_rate(RECORDING_SAMPLING_RATE * 2)
77+
audio.play(my_recording)
78+
4879
sleep(200)
4980

5081
Functions
@@ -79,7 +110,6 @@ Functions
79110
80111
* **event**: a sound event, such as ``SoundEvent.LOUD`` or
81112
``SoundEvent.QUIET``.
82-
83113
* **value**: The threshold level in the range 0-255. For example,
84114
``set_threshold(SoundEvent.LOUD, 250)`` will only trigger if the sound is
85115
very loud (>= 250).
@@ -89,7 +119,7 @@ Functions
89119
* **return**: a representation of the sound pressure level in the range 0 to
90120
255.
91121

92-
.. py:function:: record(duration=3000, rate=11000, wait=True)
122+
.. py:function:: record(duration=3000, rate=7812, wait=True)
93123
94124
Record sound for the amount of time indicated by ``duration`` at the
95125
sampling rate indicated by ``rate``.
@@ -98,22 +128,23 @@ Functions
98128
recording and the sampling rate. The higher these values, the more memory
99129
it will use.
100130

101-
A lower sampling rate will reduce memory consumption and sound quality.
131+
A lower sampling rate will reduce both memory consumption and sound
132+
quality.
102133

103134
If there isn't enough memory available a ``MemoryError`` will be raised.
104135

105136
:param duration: How much time to record in milliseconds.
106137
:param rate: Number of samples to capture per second.
107138
:param wait: When set to ``True`` it blocks until the recording is
108139
done, if it is set to ``False`` it will run in the background.
109-
:returns: An ``AudioBuffer``, configured at the provided ``duration``
110-
and ``rate``, with the sound data.
140+
:returns: An ``AudioFrame`` with the sound samples.
111141

112-
.. py:function:: record_into(buffer, rate=11000, wait=True)
142+
.. py:function:: record_into(buffer, rate=7812, wait=True)
113143
114-
Record sound into an existing ``AudioBuffer``.
144+
Record sound into an existing ``AudioFrame`` until it is filled,
145+
or the ``stop_recording()`` function is called.
115146

116-
:param buffer: An ``AudioBuffer`` to record the microphone sound.
147+
:param buffer: An ``AudioFrame`` to record sound.
117148
:param rate: Number of samples to capture per second.
118149
:param wait: When set to ``True`` it blocks until the recording is
119150
done, if it is set to ``False`` it will run in the background.
@@ -134,7 +165,7 @@ Functions
134165
``microphone.SENSITIVITY_HIGH``.
135166

136167
These constants correspond to a number, and any values between these
137-
constants are valid arguments
168+
constants are valid arguments.
138169

139170
:param gain: Microphone gain.
140171

@@ -196,35 +227,39 @@ An example of recording and playback with a display animation::
196227

197228
from microbit import *
198229

199-
talk_open = Image(
230+
mouth_open = Image(
200231
"09090:"
201232
"00000:"
202233
"09990:"
203234
"90009:"
204235
"09990"
205236
)
206-
talk_closed = Image(
237+
mouth_closed = Image(
207238
"09090:"
208239
"00000:"
209240
"00000:"
210241
"99999:"
211242
"00000"
212243
)
213244

214-
my_recording = audio.AudioBuffer(duration=5000, rate=5500)
245+
RECORDING_RATE = 5500
246+
RECORDING_SECONDS = 5
247+
RECORDING_SIZE = RECORDING_RATE * RECORDING_SECONDS
248+
249+
my_recording = audio.AudioBuffer(size=RECORDING_SIZE)
215250

216251
while True:
217252
if button_a.is_pressed():
218-
microphone.record_into(my_recording, rate=5500, wait=False)
219-
display.show([talk_open, talk_closed], loop=True, wait=False, delay=150)
220-
while button_a.is_pressed():
253+
microphone.record_into(my_recording, rate=RECORDING_RATE, wait=False)
254+
display.show([mouth_open, mouth_closed], loop=True, wait=False, delay=150)
255+
while button_a.is_pressed() and microphone.is_recording():
221256
sleep(50)
222-
display.show(mouth_open, loop=False) # workaround issue #150
257+
microphone.stop_recording()
223258
display.clear()
224259
if button_b.is_pressed():
225260
audio.play(my_recording, wait=False)
226261
while audio.is_playing():
227262
x = accelerometer.get_x()
228-
my_recording.rate = scale(x, (-1000, 1000), (2250, 11000))
263+
audio.set_rate(scale(x, (-1000, 1000), (2250, 11000)))
229264
sleep(50)
230265
sleep(100)

0 commit comments

Comments
 (0)