Skip to content

Commit 26a1a8f

Browse files
docs: Update Recording & Playback to use AudioRecording & AudioTrack.
1 parent a0f6908 commit 26a1a8f

File tree

3 files changed

+171
-51
lines changed

3 files changed

+171
-51
lines changed

docs/audio.rst

+152-35
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,22 @@ There are three 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. `Audio Frames <#audioframe>`_, an instance or an iterable (like a list or
27+
3. `Audio Recordings <#audiorecording-audiotrack-v2>`_, a way to record audio
28+
data from the microphone::
29+
30+
recording = audio.AudioRecording(duration=4000)
31+
microphone.record(recording)
32+
audio.play(recording)
33+
34+
4. `Audio Tracks <#audiorecording-audiotrack-v2>`_, a way to point to a portion
35+
of the data in an ``AudioRecording`` or a ``bytearray`` and/or modify it::
36+
37+
recording = audio.AudioRecording(duration=4000)
38+
microphone.record(recording)
39+
track = AudioTrack(recording)[1000:2000]
40+
audio.play(track)
41+
42+
5. `Audio Frames <#audioframe>`_, an instance or an iterable (like a list or
2843
generator) of Audio Frames, which are lists of samples with values
2944
from 0 to 255::
3045

@@ -49,6 +64,12 @@ Functions
4964
be found in the `Built in sounds <#built-in-sounds-v2>`_ section.
5065
- ``SoundEffect``: A sound effect, or an iterable of sound effects,
5166
created via the :py:meth:`audio.SoundEffect` class
67+
- ``AudioRecording``: An instance or an iterable of ``AudioRecording``
68+
instances as described in the
69+
`AudioRecording Technical Details <#technical-details>`_ section
70+
- ``AudioTrack``: An instance or an iterable of ``AudioTrack``
71+
instances as described in the
72+
`AudioTrack Technical Details <#technical-details>`_ section
5273
- ``AudioFrame``: An instance or an iterable of ``AudioFrame``
5374
instances as described in the
5475
`AudioFrame Technical Details <#technical-details>`_ section
@@ -226,47 +247,150 @@ Sound Effects Example
226247
:code: python
227248

228249

229-
AudioFrame
230-
==========
250+
AudioRecording & AudioTrack **V2**
251+
==================================
231252

232-
.. py:class::
233-
AudioFrame(duration=-1, rate=7812)
253+
There are two classes that contain audio data with an associated sampling rate:
234254

235-
An ``AudioFrame`` object is a list of samples, each of which is an unsigned
236-
byte (whole number between 0 and 255).
255+
- ``AudioRecording`` contains its own buffer, it's initialised with a size
256+
defined in time, and it's the object type that ``microphone.record()``
257+
returns.
258+
- ``AudioTrack`` does not hold its own buffer and instead points to a buffer
259+
externally created. This buffer could be an ``AudioRecording``, or a basic
260+
type like a ``bytearray``. It's similar to a
261+
`memoryview <https://docs.micropython.org/en/v1.9.3/pyboard/reference/speed_python.html#arrays>`_
262+
and it can be used to easily chop a portion of the audio data in the
263+
``AudioRecording``.
237264

238-
The number of samples in an AudioFrame will depend on the
239-
``rate`` (number of samples per second) and ``duration`` parameters.
240-
The total number of samples will always be a round up multiple of 32.
265+
AudioRecording
266+
--------------
241267

242-
On micro:bit V1 the constructor does not take any arguments,
243-
and an AudioFrame instance is always 32 bytes.
268+
.. py:class::
269+
AudioRecording(duration, rate=7812)
244270

245-
:param duration: (**V2**) Indicates how many milliseconds of audio this
271+
The ``AudioRecording`` object contains audio data and the sampling rate
272+
associated to it.
273+
274+
The size of the internal buffer will depend on the ``rate``
275+
(number of samples per second) and ``duration`` parameters.
276+
277+
:param duration: Indicates how many milliseconds of audio this
246278
instance can store.
247-
:param rate: (**V2**) The sampling rate at which data will be stored
279+
:param rate: The sampling rate at which data will be stored
248280
via the microphone, or played via the ``audio.play()`` function.
249281

250282
.. py:function:: set_rate(sample_rate)
251283
252-
(**V2 only**) Configure the sampling rate associated with the data
253-
in the ``AudioFrame`` instance.
284+
Configure the sampling rate associated with the data in the
285+
``AudioRecording`` instance.
286+
287+
:param sample_rate: The sample rate to set.
288+
289+
.. py:function:: get_rate()
290+
291+
Return the configured sampling rate for this
292+
``AudioRecording`` instance.
293+
294+
:return: The configured sample rate.
295+
296+
.. py:function:: track(start_ms=0, end_ms=-1)
297+
298+
Create an `AudioTrack <#audio.AudioTrack>`_ instance from a portion of
299+
the data in this ``AudioRecording`` instance.
300+
301+
:param start_ms: Where to start of the track in milliseconds.
302+
:param end_ms: The end of the track in milliseconds.
303+
If the default value of ``-1`` is provided it will end the track
304+
at the end of the AudioRecording.
305+
306+
When an AudioRecording is used to record data from the microphone,
307+
increasing the sampling rate increases the sound quality,
308+
but it also increases the amount of memory used.
309+
310+
During playback, increasing the sampling rate speeds up the sound
311+
and decreasing the sample rate slows it down.
312+
313+
AudioTrack
314+
----------
315+
316+
``AudioTrack`` individual bytes can be accessed like an element in a list
317+
318+
.. py:class::
319+
AudioTrack(buffer, rate=7812)
320+
321+
The ``AudioTrack`` object is a ``memoryview`` of an audio buffer,
322+
like ``AudioRecording`` or ``bytearray``, which also contains its own
323+
sampling rate.
324+
325+
:param buffer: The buffer containing the audio data.
326+
:param rate: The sampling rate at which data will be stored
327+
via the microphone, or played via the ``audio.play()`` function.
254328

255-
For recording from the microphone, increasing the sampling rate
256-
increases the sound quality, but reduces the length of audio it
257-
can store.
258-
During playback, increasing the sampling rate speeds up the sound
259-
and decreasing it slows it down.
329+
.. py:function:: set_rate(sample_rate)
330+
331+
Configure the sampling rate associated with the data in the
332+
``AudioTrack`` instance.
260333

261334
:param sample_rate: The sample rate to set.
262335

263336
.. py:function:: get_rate()
264337
265-
(**V2 only**) Return the configured sampling rate for this
266-
``AudioFrame`` instance.
338+
Return the configured sampling rate for this
339+
``AudioTrack`` instance.
267340

268341
:return: The configured sample rate.
269342

343+
.. py:function:: copyfrom(other)
344+
345+
Overwrite the data in this ``AudioTrack`` with the data from another
346+
``AudioTrack``, ``AudioRecording`` or buffer-like object like
347+
a ``bytes`` or ``bytearray`` instance.
348+
349+
:param other: Buffer-like instance from which to copy the data.
350+
351+
Example
352+
-------
353+
354+
::
355+
356+
from microbit import *
357+
358+
# An AudioRecording holds the audio data
359+
recording = audio.AudioRecording(duration=4000)
360+
361+
# AudioTracks point to a portion of the data in the AudioRecording
362+
# We can obtain the an AudioTrack from the AudioRecording.track() method
363+
first_half = recording.track(end_ms=2000)
364+
# Or we can create an AudioTrack from an AudioRecording and slice it
365+
full_track = audio.AudioTrack(recording)
366+
second_half = full_track[full_track.length() // 2:]
367+
368+
while True:
369+
if button_a.is_pressed():
370+
# We can record directly inside the AudioRecording
371+
microphone.record(recording)
372+
if button_b.is_pressed():
373+
audio.play(recording, wait=False)
374+
# The rate can be changed while playing
375+
first_half.set_rate(
376+
scale(accelerometer.get_x(), from_=(-1000, 1000), to=(3_000, 30_000))
377+
)
378+
if pin_logo.is_touched():
379+
# We can also play the AudioTrack pointing to the AudioRecording
380+
audio.play(first_half)
381+
382+
383+
AudioFrame
384+
==========
385+
386+
.. py:class::
387+
AudioFrame
388+
389+
An ``AudioFrame`` object is a list of 32 samples each of which is an unsigned byte
390+
(whole number between 0 and 255).
391+
392+
It takes just over 4 ms to play a single frame.
393+
270394
.. py:function:: copyfrom(other)
271395
272396
Overwrite the data in this ``AudioFrame`` with the data from another
@@ -281,21 +405,14 @@ Technical Details
281405
You don't need to understand this section to use the ``audio`` module.
282406
It is just here in case you wanted to know how it works.
283407

284-
The ``audio.play()`` function can consume an instance or iterable
285-
(sequence, like list or tuple, or generator) of ``AudioFrame`` instances,
286-
The ``AudioFrame`` default playback rate is 7812 Hz, and can be configured
287-
at any point with the ``AudioFrame.set_rate()`` method.
288-
The ``AudioFrame.set_rate()`` also works while the ``AudioFrame`` is being
289-
played, which will affect the playback speed.
290-
291-
Each ``AudioFrame`` instance is 32 samples by default, but it can be
292-
configured to a different size via constructor parameters.
408+
The ``audio`` module can consumes an iterable (sequence, like list or tuple, or
409+
generator) of ``AudioFrame`` instances, each 32 samples at 7812.5 Hz.
293410

294-
So, for example, playing 32 samples at 7812 Hz takes just over 4 milliseconds
411+
So, for example, playing 32 samples at 7812.5 Hz takes just over 4 milliseconds
295412
(1/7812.5 * 32 = 0.004096 = 4096 microseconds).
296413

297-
The function ``play()`` fully copies all data from each ``AudioFrame`` before
298-
it calls ``next()`` for the next frame, so a sound source can use the same
414+
The function ``play`` fully copies all data from each ``AudioFrame`` before it
415+
calls ``next()`` for the next frame, so a sound source can use the same
299416
``AudioFrame`` repeatedly.
300417

301418
The ``audio`` module has an internal 64 sample buffer from which it reads

docs/microbit_micropython_api.rst

+4-4
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,10 @@ The Microphone is accessed via the `microphone` object::
108108
set_threshold(128)
109109
# Returns a representation of the sound pressure level in the range 0 to 255.
110110
sound_level()
111-
# Record audio into a new `AudioFrame`
112-
record(duration, rate=7812)
113-
# Record audio into an existing `AudioFrame`
114-
record_into(buffer, rate=7812)
111+
# Record audio into a new `AudioRecording`
112+
recording = record(duration, rate=7812)
113+
# Record audio into an existing `AudioRecording`
114+
record_into(recording, rate=7812)
115115
# Returns `True` if the microphone is currently recording audio
116116
is_recording()
117117
# Stop any active audio recording

docs/microphone.rst

+15-12
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ accessible via variables in ``microbit.SoundEvent``:
3131
Recording
3232
=========
3333

34-
The microphone can record audio into an :doc:`AudioFrame <audio>`, which can
35-
then be played with the ``audio.play()`` function.
34+
The microphone can record audio into an :doc:`AudioRecording <audio>`,
35+
which can then be played with the ``audio.play()`` function.
3636

3737
Audio sampling is the process of converting sound into a digital format.
3838
To do this, the microphone takes samples of the sound waves at regular
@@ -41,15 +41,17 @@ intervals. The number of samples recorded per second is known as the
4141
quality, but as more samples are saved, it also consumes more memory.
4242

4343
The microphone sampling rate can be configured during sound recording via
44-
the ``AudioFrame.rate()`` method functions.
44+
the :py:meth:`AudioRecording.set_rate()<audio.AudioRecording.set_rate>` or
45+
:py:meth:`AudioTrack.set_rate()<audio.AudioTrack.set_rate>` methods.
4546

4647
At the other side, the audio playback sampling rate indicates how many samples
4748
are played per second. So if audio is played back with a higher sampling rate
4849
than the rate used during recording, then the audio will sound speeded up.
4950
If the playback sampling rate is twice the recording rate, the sound will take
5051
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.
52+
is halved, it will play half as many samples per second, so it will
53+
take twice as long to play the same amount of samples, and it will sound
54+
slowed down.
5355

5456
How do you think a voice recording will sound if the playback rate is
5557
increased or decreased? Let's try it out!::
@@ -141,7 +143,7 @@ Functions
141143

142144
.. py:function:: record(duration, rate=7812)
143145
144-
Record sound into an ``AudioFrame`` for the amount of time indicated by
146+
Record sound into an ``AudioRecording`` for the amount of time indicated by
145147
``duration`` at the sampling rate indicated by ``rate``.
146148

147149
The amount of memory consumed is directly related to the length of the
@@ -155,15 +157,16 @@ Functions
155157

156158
:param duration: How long to record in milliseconds.
157159
:param rate: Number of samples to capture per second.
158-
:returns: An ``AudioFrame`` with the sound samples.
160+
:returns: An ``AudioRecording`` with the sound samples.
159161

160162
.. py:function:: record_into(buffer, rate=7812, wait=True)
161163
162-
Record sound into an existing ``AudioFrame`` until it is filled,
163-
or the ``stop_recording()`` function is called.
164+
Record sound into an existing ``AudioRecording`` or ``AudioTrack``
165+
until it is filled, or the ``stop_recording()`` function is called.
164166

165-
:param buffer: An ``AudioFrame`` to record sound.
167+
:param buffer: ``AudioRecording`` or ``AudioTrack`` to record sound into.
166168
:param rate: Number of samples to capture per second.
169+
This will overwrite the rate set in the buffer object.
167170
:param wait: When set to ``True`` it blocks until the recording is
168171
done, if it is set to ``False`` it will run in the background.
169172

@@ -263,11 +266,11 @@ An example of recording and playback with a display animation::
263266
RECORDING_RATE = 3906
264267
RECORDING_MS = 5000
265268

266-
my_recording = audio.AudioBuffer(duration=RECORDING_MS, rate=RECORDING_RATE)
269+
my_recording = audio.AudioRecording(duration=RECORDING_MS, rate=RECORDING_RATE)
267270

268271
while True:
269272
if button_a.is_pressed():
270-
microphone.record_into(my_recording, rate=RECORDING_RATE, wait=False)
273+
microphone.record_into(my_recording, wait=False)
271274
display.show([mouth_open, mouth_closed], loop=True, wait=False, delay=150)
272275
while button_a.is_pressed() and microphone.is_recording():
273276
sleep(50)

0 commit comments

Comments
 (0)