Audio

This module allows you to play your own sounds. If you are using a micro:bit V2, audio is also part of the microbit module.

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.

Functions

audio.play(source, wait=True, pin=pin0, return_pin=None)

Play the source to completion.

  • source: Sound - The microbit module contains a list of built-in sounds that your can pass to audio.play().
  • source: AudioFrame - The source agrument can also be an iterable of AudioFrame elements as described below.
  • wait: If wait is True, 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 use pin=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()

Return True if audio is playing, otherwise return False.

audio.stop()

Stops all audio playback.

Classes

class audio.AudioFrame

An AudioFrame object is a list of 32 samples each of which is a signed byte (whole number between -128 and 127).

It takes just over 4 ms to play a single frame.

Using audio

You will need a sound source, as input to the play function. You can use the built-in sounds V2 from the microbit module, microbit.Sound, or generate your own, like in examples/waveforms.py.

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

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 consumes AudioFrame 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, so should be plenty).

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))