Skip to content

Commit 263b689

Browse files
Initial stubs updates
We'll have to do something about dunder docs as they're really key to this API
1 parent f4c9898 commit 263b689

File tree

2 files changed

+130
-38
lines changed

2 files changed

+130
-38
lines changed

lang/en/typeshed/stdlib/audio.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ from .microbit.audio import (
66
is_playing as is_playing,
77
play as play,
88
stop as stop,
9+
AudioRecording as AudioRecording,
10+
AudioTrack as AudioTrack,
911
AudioFrame as AudioFrame,
1012
SoundEffect as SoundEffect,
1113
)

lang/en/typeshed/stdlib/microbit/audio.pyi

Lines changed: 128 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"""
33

44
from ..microbit import MicroBitDigitalPin, Sound, pin0
5-
from typing import ClassVar, Iterable, Union
5+
from typing import ClassVar, Iterable, Optional, Union
66

77
def play(
88
source: Union[AudioFrame, Iterable[AudioFrame], Sound, SoundEffect],
@@ -143,63 +143,159 @@ class SoundEffect:
143143
:return: A copy of the SoundEffect.
144144
"""
145145

146-
class AudioFrame:
147-
"""An ``AudioFrame`` object is a list of samples, each of which is an unsigned byte
148-
(whole number between 0 and 255).
149146

150-
The number of samples in an AudioFrame will depend on the
151-
``rate`` (number of samples per second) and ``duration`` parameters.
152-
The total number of samples will always be a round up multiple of 32.
147+
class AudioRecording:
148+
"""The ``AudioRecording`` object contains audio data and the sampling rate
149+
associated to it (V2 only).
153150
154-
On micro:bit V1 the constructor does not take any arguments,
155-
and an AudioFrame instance is always 32 bytes.
151+
The size of the internal buffer will depend on the ``rate``
152+
(number of samples per second) and ``duration`` parameters.
153+
The larger these values are, the more memory that will be used.
156154
157-
For example, playing 32 samples at 7812 Hz takes just over 4 milliseconds
158-
(1/7812.5 * 32 = 0.004096 = 4096 microseconds).
159-
160-
Example::
155+
When an ``AudioRecording`` is used to record data from the microphone,
156+
a higher sampling rate produces better sound quality,
157+
but it also uses more memory.
161158
162-
frame = AudioFrame()
163-
for i in range(len(frame)):
164-
frame[i] = 252 - i * 8
159+
During playback, increasing the sampling rate speeds up the sound
160+
and decreasing the sample rate slows it down.
161+
162+
The data inside an ``AudioRecording`` is not easy to modify, so the
163+
``AudioTrack`` class is provided to help access the audio data like a list.
164+
The method ``AudioRecording.track()`` can be used to create an ``AudioTrack``,
165+
and its arguments ``start_ms`` and ``end_ms`` can be used to slice portions
166+
of the data.
165167
"""
166168

167169
def __init__(
168170
self,
169171
duration: int = -1,
170-
rate: int = 7812
172+
rate: int = 11_000
171173
):
172-
"""Create a new ``AudioFrame``.
174+
"""Create a new ``AudioRecording``.
173175
174-
Example: ``my_recording = AudioFrame(duration=5000)``
176+
Example: ``my_recording = AudioRecording(duration=5000)``
175177
176-
:param duration: Indicates how many milliseconds of audio this instance can store (V2 only).
177-
:param rate: The sampling rate at which data will be stored via the microphone, or played via the ``audio.play()`` function (V2 only).
178+
:param duration: Indicates how many milliseconds of audio this instance can store.
179+
:param rate: The sampling rate at which data will be stored via the microphone, or played via the ``audio.play()`` function.
180+
"""
181+
182+
def copy(self) -> None:
183+
"""Create a copy of the ``AudioRecording``.
184+
185+
Example: ``copy = my_recording.copy()``
186+
187+
:return: A copy of the ``AudioRecording``.
188+
"""
189+
190+
def track(self, start_ms: int = 0, end_ms: int = -1) -> None:
191+
"""Create an ``AudioTrack`` instance from a portion of the data in this ``AudioRecording`` instance.
192+
193+
Example: ``first_second = my_recording.track(0, 1000)``
194+
195+
:param start_ms: (default=0) Where to start of the track in milliseconds.
196+
:param end_ms: (default=-1) The end of the track in milliseconds. If the default value of ``-1`` is provided it will end the track at the end of the AudioRecording.
197+
:return: An ``AudioTrack`` backed by the sample data between ``start_ms`` and ``end_ms``.
198+
"""
199+
def __len__(self) -> int: ...
200+
def __setitem__(self, key: int, value: int) -> None: ...
201+
def __getitem__(self, key: int) -> int: ...
202+
def __add__(self, v: AudioRecording) -> AudioRecording: ...
203+
def __iadd__(self, v: AudioRecording) -> AudioRecording: ...
204+
def __sub__(self, v: AudioRecording) -> AudioRecording: ...
205+
def __isub__(self, v: AudioRecording) -> AudioRecording: ...
206+
def __mul__(self, v: float) -> AudioRecording: ...
207+
def __imul__(self, v: float) -> AudioRecording: ...
208+
209+
class AudioTrack:
210+
""" The ``AudioTrack`` object points to the data provided by the input buffer,
211+
which can be an ``AudioRecording``, another ``AudioTrack``,
212+
or a buffer-like object like a ``bytearray`` (V2 only).
213+
"""
214+
215+
def __init__(
216+
self,
217+
buffer: Union[bytearray, AudioRecording, AudioTrack],
218+
rate: Optional[int] = None
219+
):
220+
"""Create a new ``AudioTrack``.
221+
222+
When the input buffer has an associated rate (e.g. an ``AudioRecording``
223+
or ``AudioTrack``), the rate is copied. If the buffer object does not have
224+
a rate, the default value of 11_000 is used.
225+
226+
Example: ``my_track = AudioTrack(bytearray(4096))``
227+
228+
An ``AudioTrack`` can be created from an ``AudioRecording``, another
229+
``AudioTrack``, or a ``bytearray`` and individual bytes can be accessed and
230+
modified like elements in a list::
231+
232+
my_track = AudioTrack(bytearray(100))
233+
# Create a square wave
234+
half_length = len(my_track) // 2
235+
for i in range(half_length):
236+
my_track[i] = 255
237+
for i in range(half_length, len(my_track)):
238+
my_track[i] = 0
239+
240+
Or smaller AudioTracks can be created using slices, useful to send them
241+
via radio or serial::
242+
243+
recording = microphone.record(duration=2000)
244+
track = AudioTrack(recording)
245+
packet_size = 32
246+
for i in range(0, len(track), packet_size):
247+
radio.send_bytes(track[i:i+packet_size])
248+
249+
:param buffer: The buffer containing the audio data.
250+
:param rate: (default=None) The sampling rate at which data will be stored via the microphone, or played via the ``audio.play()`` function.
178251
"""
179252

180253
def set_rate(self, sample_rate: int) -> None:
181254
"""Configure the sampling rate associated with the data in the
182-
``AudioFrame`` instance (V2 only).
255+
``AudioTrack`` instance.
183256
184-
Example: ``my_frame.set_rate(7812)``
185257
186-
For recording from the microphone, increasing the sampling rate
187-
increases the sound quality, but reduces the length of audio it
188-
can store.
258+
Changes to an ``AudioTrack`` rate won't affect the original source rate,
259+
so multiple instances pointing to the same buffer can have different
260+
rates and the original buffer rate would stay unmodified.
189261
190-
During playback, increasing the sampling rate speeds up the sound
191-
and decreasing it slows it down.
262+
Example: ``my_track.set_rate(22_000)``
192263
"""
193264

194265
def get_rate(self) -> int:
195266
"""Get the sampling rate associated with the data in the
196-
``AudioFrame`` instance (V2 only).
267+
``AudioRecording`` instance.
197268
198-
Example: ``current_rate = my_frame.get_rate()``
269+
Example: ``current_rate = my_track.get_rate()``
199270
200-
:return: The configured sampling rate for this ``AudioFrame`` instance.
271+
:return: The configured sample rate.
201272
"""
202273

274+
275+
def __len__(self) -> int: ...
276+
def __setitem__(self, key: int, value: int) -> None: ...
277+
def __getitem__(self, key: int) -> int: ...
278+
def __add__(self, v: AudioTrack) -> AudioTrack: ...
279+
def __iadd__(self, v: AudioTrack) -> AudioTrack: ...
280+
def __sub__(self, v: AudioTrack) -> AudioTrack: ...
281+
def __isub__(self, v: AudioTrack) -> AudioTrack: ...
282+
def __mul__(self, v: float) -> AudioTrack: ...
283+
def __imul__(self, v: float) -> AudioTrack: ...
284+
285+
286+
class AudioFrame:
287+
"""An ``AudioFrame`` object is a list of 32 samples each of which is a unsigned byte
288+
(whole number between 0 and 255).
289+
290+
It takes just over 4 ms to play a single frame.
291+
292+
Example::
293+
294+
frame = AudioFrame()
295+
for i in range(len(frame)):
296+
frame[i] = 252 - i * 8
297+
"""
298+
203299
def copyfrom(self, other: AudioFrame) -> None:
204300
"""Overwrite the data in this ``AudioFrame`` with the data from another ``AudioFrame`` instance.
205301
@@ -209,10 +305,4 @@ class AudioFrame:
209305
"""
210306
def __len__(self) -> int: ...
211307
def __setitem__(self, key: int, value: int) -> None: ...
212-
def __getitem__(self, key: int) -> int: ...
213-
def __add__(self, v: AudioFrame) -> AudioFrame: ...
214-
def __iadd__(self, v: AudioFrame) -> AudioFrame: ...
215-
def __sub__(self, v: AudioFrame) -> AudioFrame: ...
216-
def __isub__(self, v: AudioFrame) -> AudioFrame: ...
217-
def __mul__(self, v: float) -> AudioFrame: ...
218-
def __imul__(self, v: float) -> AudioFrame: ...
308+
def __getitem__(self, key: int) -> int: ...

0 commit comments

Comments
 (0)