From 52f230ca79ac6657f8e283d77c46cb01f3b25b18 Mon Sep 17 00:00:00 2001 From: Carlos Pereira Atencio Date: Mon, 15 May 2023 11:07:25 +0100 Subject: [PATCH] docs: Add initial proposal for recording & playback API. --- docs/audio.rst | 54 +++++++++++++++++++++-- docs/microphone.rst | 102 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 147 insertions(+), 9 deletions(-) diff --git a/docs/audio.rst b/docs/audio.rst index c607101b4..9bf5b1e67 100644 --- a/docs/audio.rst +++ b/docs/audio.rst @@ -12,18 +12,25 @@ 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 +There are four different kinds of audio sources that can be played using the :py:meth:`audio.play` function: 1. `Built in sounds <#built-in-sounds-v2>`_ (**V2**), e.g. ``audio.play(Sound.HAPPY)`` + 2. `Sound Effects <#sound-effects-v2>`_ (**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) -3. `Audio Frames <#audioframe>`_, an iterable (like a list or a generator) +3. `AudioBuffer <#audiobuffer>`_ (**V2**), a generic buffer for audio that can + be used to record sound from the micro:bit V2 built-in microphone:: + + my_audio_buffer = microphone.record() + audio.play(my_audio_buffer) + +4. `Audio Frames <#audioframe>`_, 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() @@ -40,13 +47,16 @@ Functions Play the audio source to completion. - :param source: There are three types of data that can be used as a source: + :param source: There are four types of data that can be used as a source: - ``Sound``: The ``microbit`` 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 <#built-in-sounds-v2>`_ section. - ``SoundEffect``: A sound effect, or an iterable of sound effects, created via the :py:meth:`audio.SoundEffect` class + - ``AudioBuffer``: An audio buffer, or an iterable of audio buffers, + created via the :py:meth:`audio.AudioBuffer` class or + :doc:`microphone.record() ` function - ``AudioFrame``: An iterable of ``AudioFrame`` instances as described in the `AudioFrame Technical Details <#id2>`_ section @@ -215,6 +225,44 @@ Sound Effects Example .. include:: ../examples/soundeffects.py :code: python + +Audio Buffer **V2** +=================== + +.. py:class:: + AudioBuffer(duration=3000, rate=11000) + + Create a buffer to contain audio data and its sampling rate. + + The sampling rate is used by the ``microphone.record_into()`` and + ``audio.play()`` functions to configure the recording and playback rates. + This value can be changed as an attribute to increase or decrease the + recording quality or the playback speed. + + :param duration: Indicates in milliseconds, how much sound data the buffer + can contained at the configured ``data_rate``. + :param rate: Sampling rate of for the data in the buffer. This value is + used for recording and playback, and can be edited as an attribute. + + .. py:function:: copy() + + :returns: A copy of the Audio Buffer. + + .. py:attribute:: rate + + The sampling rate for the data inside the buffer. + TODO: Indicate range of valid values here. + +Audio Buffer Example +-------------------- + +:: + + my_buffer = audio.AudioBuffer(duration=5000) + microphone.record_into(my_buffer) + audio.play(my_buffer) + + AudioFrame ========== diff --git a/docs/microphone.rst b/docs/microphone.rst index 3cc74c8e9..b904cf33e 100644 --- a/docs/microphone.rst +++ b/docs/microphone.rst @@ -4,9 +4,9 @@ Microphone **V2** .. py:module:: microbit.microphone This object lets you access the built-in microphone available on the -micro:bit **V2**. It can be used to respond to sound. The microphone input -is located on the front of the board alongside a microphone activity LED, -which is lit when the microphone is in use. +micro:bit **V2**. It can be used to record and respond to sound. +The microphone input is located on the front of the board alongside a +microphone activity LED, which is lit when the microphone is in use. .. image:: microphone.png :width: 300px @@ -28,6 +28,25 @@ accessible via variables in ``microbit.SoundEvent``: - ``microbit.SoundEvent.LOUD``: Represents the transition of sound events, from ``quiet`` to ``loud`` like clapping or shouting. +Recording +========= + +TODO: +* Describe the feature. +* Indicate how the sampling rate relates to recording quality. +* Indicate how changing the sampling rate on the fly affects playback speed. +* What happens if the user changes the sampling rate while recording? + +:: + + from microbit import * + + while True: + if button_a.is_pressed(): + my_recording = microphone.record(duration=5000) + audio.play(my_recording) + sleep(200) + Functions ========= @@ -70,11 +89,43 @@ Functions * **return**: a representation of the sound pressure level in the range 0 to 255. +.. py:function:: record(duration=3000, rate=11000, wait=True) + + Record sound for the amount of time indicated by ``duration`` at the + sampling rate indicated by ``rate``. + + The amount of memory consumed is directly related to the length of the + recording and the sampling rate. The higher these values, the more memory + it will use. + If there isn't enough memory available a ``MemoryError`` will be raised. + + :param duration: How long to record in milliseconds. + :param rate: Number of samples per second. + :returns: An ``AudioBuffer``, configured at the provided ``duration`` + and ``rate``, with the sound data. + +.. py:function:: record_into(buffer, wait=True) + + Description. + + :param buffer: An ``AudioBuffer`` to record the microphone sound. -Example -======= +.. py:function:: is_recording() -An example that runs through some of the functions of the microphone API:: + :returns: ``True`` if the microphone is currently recording sound, or + ``False`` otherwise. + +.. py:function:: set_sensitivity(gain) + + TODO: Decide if we want to admit values or create "3 levels". + + :param gain: Description. + +Examples +======== + +An example that runs through some of the functions of the microphone +Sound Events API:: # Basic test for microphone. This test should update the display when # Button A is pressed and a loud or quiet sound *is* heard, printing the @@ -122,3 +173,42 @@ An example that runs through some of the functions of the microphone API:: display.clear() print(sound) sleep(500) + + +An example of recording and playback with an animation:: + + from microbit import * + + talk_open = Image( + "09090:" + "00000:" + "09990:" + "90009:" + "09990" + ) + talk_closed = Image( + "09090:" + "00000:" + "00000:" + "99999:" + "00000" + ) + + my_recording = audio.AudioBuffer(duration=5000, rate=5500) + + while True: + if button_a.is_pressed(): + my_recording.rate = 5500 + microphone.record_into(my_recording, wait=False) + display.show([talk_open, talk_closed], loop=True, wait=False, delay=150) + while button_a.is_pressed(): + sleep(50) + display.show(mouth_open, loop=False) # workaround issue #150 + display.clear() + if button_b.is_pressed(): + audio.play(my_recording, wait=False) + while audio.is_playing(): + x = accelerometer.get_x() + my_recording.rate = scale(x, (-1000, 1000), (2250, 11000)) + sleep(50) + sleep(100)