Audio
This module allows you play sounds with the micro:bit.
By default sound output will be via the edge connector on pin 0 and the built-in speaker (V2). You can connect wired headphones or a speaker to pin 0 and GND on the edge connector to hear the sounds.
The audio
module can be imported as import audio
or accessed via
the microbit
module as microbit.audio
.
There are three different kinds of audio sources that can be played using the
audio.play()
function:
Built in sounds (V2), e.g.
audio.play(Sound.HAPPY)
Sound Effects (V2), a way to create custom sounds by configuring its parameters:
my_effect = audio.SoundEffect(freq_start=400, freq_end=2500, duration=500) audio.play(my_effect)
Audio Frames, an iterable (like a list or a generator) of Audio Frames, which are lists of 32 samples with values from 0 to 255:
square_wave = audio.AudioFrame() for i in range(16): square_wave[i] = 0 square_wave[i + 16] = 255 audio.play([square_wave] * 64)
Functions
- audio.play(source, wait=True, pin=pin0, return_pin=None)
Play the audio source to completion.
- Parameters:
source –
There are three types of data that can be used as a source:
Sound
: Themicrobit
module contains a list of built-in sounds, e.g.audio.play(Sound.TWINKLE)
. A full list can be found in the Built in sounds section.SoundEffect
: A sound effect, or an iterable of sound effects, created via theaudio.SoundEffect()
classAudioFrame
: An iterable ofAudioFrame
instances as described in the AudioFrame Technical Details section
wait – If
wait
isTrue
, this function will block until the source is exhausted.pin – An optional argument to specify the output pin can be used to override the default of
pin0
. If we do not want any sound to play we can usepin=None
.return_pin – specifies a differential edge connector pin to connect to an external speaker instead of ground. This is ignored for the V2 revision.
- audio.is_playing()
- Returns:
True
if audio is playing, otherwise returnsFalse
.
- audio.stop()
Stops all audio playback.
Built-in sounds V2
The built-in sounds can be called using audio.play(Sound.NAME)
.
Sound.GIGGLE
Sound.HAPPY
Sound.HELLO
Sound.MYSTERIOUS
Sound.SAD
Sound.SLIDE
Sound.SOARING
Sound.SPRING
Sound.TWINKLE
Sound.YAWN
Sounds Example
from microbit import *
while True:
if button_a.is_pressed() and button_b.is_pressed():
# When pressing both buttons only play via the edge connector
audio.play(Sound.HELLO, pin=pin0)
elif button_a.is_pressed():
# On button A play a sound and when it's done show an image
audio.play(Sound.HAPPY)
display.show(Image.HAPPY)
elif button_b.is_pressed():
# On button B play a sound and show an image at the same time
audio.play(Sound.TWINKLE, wait=False)
display.show(Image.BUTTERFLY)
sleep(500)
display.clear()
Sound Effects V2
- class audio.SoundEffect(freq_start=500, freq_end=2500, duration=500, vol_start=255, vol_end=0, waveform=WAVEFORM_SQUARE, fx=FX_NONE, shape=SHAPE_LOG)
An
SoundEffect
instance represents a sound effect, composed by a set of parameters configured via the constructor or attributes.All the parameters are optional, with default values as shown above, and they can all be modified via attributes of the same name. For example, we can first create an effect
my_effect = SoundEffect(duration=1000)
, and then change its attributesmy_effect.duration = 500
.- Parameters:
freq_start – Start frequency in Hertz (Hz), default:
500
freq_end – End frequency in Hertz (Hz), default:
2500
duration – Duration of the sound (ms), default:
500
vol_start – Start volume value, range 0-255, default:
255
vol_end – End volume value, range 0-255, default:
0
waveform – Type of waveform shape, one of these values:
WAVEFORM_SINE
,WAVEFORM_SAWTOOTH
,WAVEFORM_TRIANGLE
,WAVEFORM_SQUARE
,WAVEFORM_NOISE
(randomly generated noise). Default:WAVEFORM_SQUARE
fx – Effect to add on the sound, one of the following values:
FX_TREMOLO
,FX_VIBRATO
,FX_WARBLE
, orFX_NONE
. Default:FX_NONE
shape – The type of the interpolation curve between the start and end frequencies, different wave shapes have different rates of change in frequency. One of the following values:
SHAPE_LINEAR
,SHAPE_CURVE
,SHAPE_LOG
. Default:SHAPE_LOG
- copy()
- Returns:
A copy of the SoundEffect.
- freq_start
Start frequency in Hertz (Hz), a number between
0
and9999
.
- freq_end
End frequency in Hertz (Hz), a number between
0
and9999`
.
- duration
Duration of the sound in milliseconds, a number between
0
and9999
.
- vol_start
Start volume value, a number between
0
and255
.
- vol_end
End volume value, a number between
0
and255
.
- waveform
Type of waveform shape, one of these values:
WAVEFORM_SINE
,WAVEFORM_SAWTOOTH
,WAVEFORM_TRIANGLE
,WAVEFORM_SQUARE
,WAVEFORM_NOISE
(randomly generated noise).
- fx
Effect to add on the sound, one of the following values:
FX_TREMOLO
,FX_VIBRATO
,FX_WARBLE
, orNone
.
- shape
The type of interpolation curve between the start and end frequencies, different wave shapes have different rates of change in frequency. One of the following values:
SHAPE_LINEAR
,SHAPE_CURVE
,SHAPE_LOG
.
The arguments used to create any Sound Effect,
can be inspected by looking at each of the SoundEffect instance attributes,
or by converting the instance into a string (which can be done via str()
function, or by using a function that does the conversion automatically like
print()
).
For example, with the REPL you can inspect the default SoundEffects:
>>> print(audio.SoundEffect())
SoundEffect(freq_start=500, freq_end=2500, duration=500, vol_start=255, vol_end=0, waveform=WAVE_SQUARE, fx=FX_NONE, shape=SHAPE_LOG)
This format is “human readable”, which means it is easy for us to read,
and it looks very similar to the code needed to create that SoundEffect,
but it’s not quite right. The repr()
function can be used to create a
string of Python code that can be stored or transferred
(you could transmit sounds via micro:bit radio!) and be executed with the
eval()
function:
>>> from audio import SoundEffect
>>> sound_code = repr(SoundEffect())
>>> print(sound_code)
SoundEffect(500, 2500, 500, 255, 0, 3, 0, 18)
>>> eval("audio.play({})".format(sound_code))
Sound Effects Example
from microbit import *
# Play the default Sound Effect
audio.play(audio.SoundEffect())
# Create a new Sound Effect and immediately play it
audio.play(audio.SoundEffect(
freq_start=400,
freq_end=2000,
duration=500,
vol_start=100,
vol_end=255,
waveform=audio.SoundEffect.WAVEFORM_TRIANGLE,
fx=audio.SoundEffect.FX_VIBRATO,
shape=audio.SoundEffect.SHAPE_LOG
))
# Play a Sound Effect instance, modify an attribute, and play it again
my_effect = audio.SoundEffect(
freq_start=400,
freq_end=2000,
)
audio.play(my_effect)
my_effect.duration = 1000
audio.play(my_effect)
# You can also create a new effect based on an existing one, and modify
# any of its characteristics via arguments
my_modified_effect = my_effect.copy()
my_modified_effect.waveform = audio.SoundEffect.WAVEFORM_NOISE
audio.play(my_modified_effect)
# Use sensor data to modify and play an existing Sound Effect instance
my_effect.duration = 600
while True:
# int() might be temporarily needed: https://github.com/microbit-foundation/micropython-microbit-v2/issues/121
my_effect.freq_start = int(scale(accelerometer.get_x(), from_=(-2000, 2000), to=(0, 9999)))
my_effect.freq_end = int(scale(accelerometer.get_y(), from_=(-2000, 2000), to=(0, 9999)))
audio.play(my_effect)
if button_a.is_pressed():
# Button A silences the micro:bit
speaker.off()
display.show(Image("09090:00000:00900:09990:00900"))
sleep(500)
elif button_b.is_pressed():
# Button B re-enables the speaker & plays an effect while showing an image
speaker.on()
audio.play(audio.SoundEffect(), wait=False)
display.show(Image.MUSIC_QUAVER)
sleep(500)
sleep(150)
AudioFrame
- class audio.AudioFrame
An
AudioFrame
object is a list of 32 samples each of which is an unsigned byte (whole number between 0 and 255).It takes just over 4 ms to play a single frame.
- copyfrom(other)
Overwrite the data in this
AudioFrame
with the data from anotherAudioFrame
instance.- Parameters:
other –
AudioFrame
instance from which to copy the data.
Technical Details
Note
You don’t need to understand this section to use the audio
module.
It is just here in case you wanted to know how it works.
The audio
module can consumes an iterable (sequence, like list or tuple, or
generator) of AudioFrame
instances, each 32 samples at 7812.5 Hz, and uses
linear interpolation to output a PWM signal at 32.5 kHz, which gives tolerable
sound quality.
The function play
fully copies all data from each AudioFrame
before it
calls next()
for the next frame, so a sound source can use the same
AudioFrame
repeatedly.
The audio
module has an internal 64 sample buffer from which it reads
samples. When reading reaches the start or the mid-point of the buffer, it
triggers a callback to fetch the next AudioFrame
which is then copied into
the buffer. This means that a sound source has under 4ms to compute the next
AudioFrame
, and for reliable operation needs to take less 2ms (which is
32000 cycles in micro:bit V1 or 128000 in V2, so should be plenty).
AudioFrame Example
from microbit import display, sleep, button_a
import audio
import math
def repeated_frame(frame, count):
for i in range(count):
yield frame
# Press button A to skip to next wave.
def show_wave(name, frame, duration=1500):
display.scroll(name + " wave", wait=False,delay=100)
audio.play(repeated_frame(frame, duration),wait=False)
for i in range(75):
sleep(100)
if button_a.is_pressed():
display.clear()
audio.stop()
break
frame = audio.AudioFrame()
for i in range(len(frame)):
frame[i] = int(math.sin(math.pi*i/16)*124+128.5)
show_wave("Sine", frame)
triangle = audio.AudioFrame()
QUARTER = len(triangle)//4
for i in range(QUARTER):
triangle[i] = i*15
triangle[i+QUARTER] = 248-i*15
triangle[i+QUARTER*2] = 128-i*15
triangle[i+QUARTER*3] = i*15+8
show_wave("Triangle", triangle)
square = audio.AudioFrame()
HALF = len(square)//2
for i in range(HALF):
square[i] = 8
square[i+HALF] = 248
show_wave("Square", square)
sleep(1000)
for i in range(len(frame)):
frame[i] = 252-i*8
show_wave("Sawtooth", frame)
del frame
#Generate a waveform that goes from triangle to square wave, reasonably smoothly.
frames = [ None ] * 32
for i in range(32):
frames[i] = frame = audio.AudioFrame()
for j in range(len(triangle)):
frame[j] = (triangle[j]*(32-i) + square[j]*i)>>5
def repeated_frames(frames, count):
for frame in frames:
for i in range(count):
yield frame
display.scroll("Ascending wave", wait=False)
audio.play(repeated_frames(frames, 60))