From 791689a80027e04ec96baf4632a08f58f66743d7 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Tue, 19 Mar 2024 17:09:00 +0000 Subject: [PATCH 01/25] Add was_touched I think the docs PRs are missing get_touches too but will revisit that. --- lang/en/typeshed/stdlib/microbit/__init__.pyi | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/__init__.pyi b/lang/en/typeshed/stdlib/microbit/__init__.pyi index 5e03529..163df7f 100644 --- a/lang/en/typeshed/stdlib/microbit/__init__.pyi +++ b/lang/en/typeshed/stdlib/microbit/__init__.pyi @@ -278,24 +278,19 @@ class MicroBitTouchPin(MicroBitAnalogDigitalPin): Example: ``pin0.is_touched()`` - The default touch mode for the pins on the edge connector is ``resistive``. - The default for the logo pin **V2** is ``capacitive``. + :return: ``True`` if the pin is being touched with a finger, otherwise return ``False``. + """ + ... - **Resistive touch** - This test is done by measuring how much resistance there is between the - pin and ground. A low resistance gives a reading of ``True``. To get - a reliable reading using a finger you may need to touch the ground pin - with another part of your body, for example your other hand. + def was_touched(self) -> bool: + """Check if the pin was touched since the last time this method was called. - **Capacitive touch** - This test is done by interacting with the electric field of a capacitor - using a finger as a conductor. `Capacitive touch - `_ - does not require you to make a ground connection as part of a circuit. + Example: ``pin0.was_touched()`` - :return: ``True`` if the pin is being touched with a finger, otherwise return ``False``. + :return: ``True`` or ``False`` to indicate if the pin was touched since the device started or since the last time this method was called. """ ... + def set_touch_mode(self, value: int) -> None: """Set the touch mode for the pin. @@ -304,6 +299,18 @@ class MicroBitTouchPin(MicroBitAnalogDigitalPin): The default touch mode for the pins on the edge connector is ``resistive``. The default for the logo pin **V2** is ``capacitive``. + **Resistive touch** + This test is done by measuring how much resistance there is between the + pin and ground. A low resistance gives a reading of ``True``. To get + a reliable reading using a finger you may need to touch the ground pin + with another part of your body, for example your other hand. + + **Capacitive touch** + This test is done by interacting with the electric field of a capacitor + using a finger as a conductor. `Capacitive touch + `_ + does not require you to make a ground connection as part of a circuit. + :param value: ``CAPACITIVE`` or ``RESISTIVE`` from the relevant pin. """ ... From 506c92f533fa54c7683cb9b2036664a8a6ac8611 Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 20 Mar 2024 09:45:12 +0000 Subject: [PATCH 02/25] Add `get_touches` method docs --- lang/en/typeshed/stdlib/microbit/__init__.pyi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lang/en/typeshed/stdlib/microbit/__init__.pyi b/lang/en/typeshed/stdlib/microbit/__init__.pyi index 163df7f..08ed2d1 100644 --- a/lang/en/typeshed/stdlib/microbit/__init__.pyi +++ b/lang/en/typeshed/stdlib/microbit/__init__.pyi @@ -290,6 +290,15 @@ class MicroBitTouchPin(MicroBitAnalogDigitalPin): :return: ``True`` or ``False`` to indicate if the pin was touched since the device started or since the last time this method was called. """ ... + + def get_touches(self) -> int: + """Get the number of times the pin was touched since the last time this method was called. + + Example: ``pin0.get_touches()`` + + :return: the number of times the pin was touched since the device started or since the last time this method was called. + """ + ... def set_touch_mode(self, value: int) -> None: """Set the touch mode for the pin. From 92215207e039ce69f14a075c8f7f885239fa2008 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Wed, 20 Mar 2024 11:41:22 +0000 Subject: [PATCH 03/25] WIP recording playback APIs These are not final and we have outstanding queries. --- lang/en/typeshed/stdlib/microbit/audio.pyi | 49 +++++++++++++-- .../typeshed/stdlib/microbit/microphone.pyi | 63 +++++++++++++++++++ 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index 3b1e327..d537ff3 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -5,16 +5,16 @@ from ..microbit import MicroBitDigitalPin, Sound, pin0 from typing import ClassVar, Iterable, Union def play( - source: Union[Iterable[AudioFrame], Sound, SoundEffect], + source: Union[AudioFrame, Iterable[AudioFrame], Sound, SoundEffect], wait: bool = True, pin: MicroBitDigitalPin = pin0, return_pin: Union[MicroBitDigitalPin, None] = None, ) -> None: - """Play a built-in sound, sound effect or custom audio frames. + """Play a built-in sound, sound effect or audio samples using ``AudioFrame``. Example: ``audio.play(Sound.GIGGLE)`` - :param source: A built-in ``Sound`` such as ``Sound.GIGGLE``, a ``SoundEffect`` or sample data as an iterable of ``AudioFrame`` objects. + :param source: A built-in ``Sound`` such as ``Sound.GIGGLE``, a ``SoundEffect`` or sample data as an ``AudioFrame`` object or an iterable of ``AudioFrame`` objects. :param wait: If ``wait`` is ``True``, this function will block until the sound is complete. :param 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``. :param return_pin: Specifies a differential edge connector pin to connect to an external speaker instead of ground. This is ignored for the **V2** revision. @@ -136,10 +136,18 @@ class SoundEffect: """ class AudioFrame: - """An ``AudioFrame`` object is a list of 32 samples each of which is a unsigned byte + """An ``AudioFrame`` object is a list of 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. + The number of samples in an AudioFrame will depend on the + ``rate`` (number of samples per second) and ``duration`` parameters. + The total number of samples will always be a round up multiple of 32. + + On micro:bit V1 the constructor does not take any arguments, + and an AudioFrame instance is always 32 bytes. + + For example, playing 32 samples at 7812 Hz takes just over 4 milliseconds + (1/7812.5 * 32 = 0.004096 = 4096 microseconds). Example:: @@ -148,6 +156,37 @@ class AudioFrame: frame[i] = 252 - i * 8 """ + def __init__( + self, + duration: int = -1, + rate: int = 7812 + ): + """Create a new ``AudioFrame``. + + Example: ``my_recording = AudioFrame(duration=5000)`` + + :param duration: Indicates how many milliseconds of audio this instance can store (V2 only). + :param rate: The sampling rate at which data will be stored via the microphone, or played via the ``audio.play()`` function (V2 only). + """ + + def set_rate(self, sample_rate: int) -> None: + """Configure the sampling rate associated with the data in the + ``AudioFrame`` instance (V2 only). + + For recording from the microphone, increasing the sampling rate + increases the sound quality, but reduces the length of audio it + can store. + During playback, increasing the sampling rate speeds up the sound + and decreasing it slows it down. + """ + + def get_rate(self) -> int: + """Get the sampling rate associated with the data in the + ``AudioFrame`` instance (V2 only). + + :returns: The configured sampling rate for this ``AudioFrame`` instance. + """ + def copyfrom(self, other: AudioFrame) -> None: """Overwrite the data in this ``AudioFrame`` with the data from another ``AudioFrame`` instance. diff --git a/lang/en/typeshed/stdlib/microbit/microphone.pyi b/lang/en/typeshed/stdlib/microbit/microphone.pyi index 68e8f3a..5dc255e 100644 --- a/lang/en/typeshed/stdlib/microbit/microphone.pyi +++ b/lang/en/typeshed/stdlib/microbit/microphone.pyi @@ -3,6 +3,7 @@ from typing import Optional, Tuple from ..microbit import SoundEvent +from ..microbit.audio import AudioFrame def current_event() -> Optional[SoundEvent]: """Get the last recorded sound event @@ -68,3 +69,65 @@ def sound_level() -> int: :return: A representation of the sound pressure level in the range 0 to 255. """ ... + +def record(duration: int = 3000, rate: int = 7812) -> AudioFrame: + """Record sound into an ``AudioFrame`` 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. + + A lower sampling rate will reduce both memory consumption and sound + quality. + + 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 to capture per second. + :returns: An ``AudioFrame`` with the sound samples. + """ + ... + +def record_into(buffer: AudioFrame, rate: int = 7812, wait: bool = True) -> None: + """Record sound into an existing ``AudioFrame`` until it is filled, + or the ``stop_recording()`` function is called. + + :param buffer: An ``AudioFrame`` to record sound. + :param rate: Number of samples to capture per second. + :param wait: When set to ``True`` it blocks until the recording is + done, if it is set to ``False`` it will run in the background. + """ + ... + +def is_recording() -> bool: + """Checks whether the microphone is currently recording. + + :returns: ``True`` if the microphone is currently recording sound, or + ``False`` otherwise. + """ + ... + +def stop_recording() -> None: + """Stops a recording running in the background. + """ + ... + +SENSITIVITY_LOW: float; +"""Low microphone sensitivity.""" + +SENSITIVITY_MEDIUM: float; +"""Medium microphone sensitivity.""" + +SENSITIVITY_HIGH: float; +"""High microphone sensitivity.""" + + +def set_sensitivity(gain: float) -> None: + """Configure the microphone sensitivity. + + The default sensitivity is ``microphone.SENSITIVITY_MEDIUM``. + + :param gain: The microphone gain. Use ``microphone.SENSITIVITY_LOW``, ``microphone.SENSITIVITY_MEDIUM``, ``microphone.SENSITIVITY_HIGH``, or a value between these levels. + """ + ... \ No newline at end of file From 12a25f1e0ca0764b7e679a8ee686ab8825209ce1 Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 20 Mar 2024 11:53:41 +0000 Subject: [PATCH 04/25] Change :returns: -> :return: --- lang/en/typeshed/stdlib/microbit/audio.pyi | 2 +- lang/en/typeshed/stdlib/microbit/microphone.pyi | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index d537ff3..fe64689 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -184,7 +184,7 @@ class AudioFrame: """Get the sampling rate associated with the data in the ``AudioFrame`` instance (V2 only). - :returns: The configured sampling rate for this ``AudioFrame`` instance. + :return: The configured sampling rate for this ``AudioFrame`` instance. """ def copyfrom(self, other: AudioFrame) -> None: diff --git a/lang/en/typeshed/stdlib/microbit/microphone.pyi b/lang/en/typeshed/stdlib/microbit/microphone.pyi index 5dc255e..19cb2dd 100644 --- a/lang/en/typeshed/stdlib/microbit/microphone.pyi +++ b/lang/en/typeshed/stdlib/microbit/microphone.pyi @@ -85,7 +85,7 @@ def record(duration: int = 3000, rate: int = 7812) -> AudioFrame: :param duration: How long to record in milliseconds. :param rate: Number of samples to capture per second. - :returns: An ``AudioFrame`` with the sound samples. + :return: An ``AudioFrame`` with the sound samples. """ ... @@ -103,7 +103,7 @@ def record_into(buffer: AudioFrame, rate: int = 7812, wait: bool = True) -> None def is_recording() -> bool: """Checks whether the microphone is currently recording. - :returns: ``True`` if the microphone is currently recording sound, or + :return: ``True`` if the microphone is currently recording sound, or ``False`` otherwise. """ ... From d9b3ffb02020a4cfe63ee01e5b17154cabc7fef5 Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 20 Mar 2024 12:33:53 +0000 Subject: [PATCH 05/25] Add examples --- lang/en/typeshed/stdlib/microbit/audio.pyi | 5 +++++ lang/en/typeshed/stdlib/microbit/microphone.pyi | 13 +++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index fe64689..3ae4510 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -173,9 +173,12 @@ class AudioFrame: """Configure the sampling rate associated with the data in the ``AudioFrame`` instance (V2 only). + Example: ``my_frame.set_rate(7812)`` + For recording from the microphone, increasing the sampling rate increases the sound quality, but reduces the length of audio it can store. + During playback, increasing the sampling rate speeds up the sound and decreasing it slows it down. """ @@ -184,6 +187,8 @@ class AudioFrame: """Get the sampling rate associated with the data in the ``AudioFrame`` instance (V2 only). + Example: ``current_rate = my_frame.get_rate()`` + :return: The configured sampling rate for this ``AudioFrame`` instance. """ diff --git a/lang/en/typeshed/stdlib/microbit/microphone.pyi b/lang/en/typeshed/stdlib/microbit/microphone.pyi index 19cb2dd..fbd91a0 100644 --- a/lang/en/typeshed/stdlib/microbit/microphone.pyi +++ b/lang/en/typeshed/stdlib/microbit/microphone.pyi @@ -74,6 +74,8 @@ def record(duration: int = 3000, rate: int = 7812) -> AudioFrame: """Record sound into an ``AudioFrame`` for the amount of time indicated by ``duration`` at the sampling rate indicated by ``rate``. + Example: ``my_frame = microphone.record()`` + 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. @@ -93,6 +95,8 @@ def record_into(buffer: AudioFrame, rate: int = 7812, wait: bool = True) -> None """Record sound into an existing ``AudioFrame`` until it is filled, or the ``stop_recording()`` function is called. + Example: ``microphone.record_into()`` + :param buffer: An ``AudioFrame`` to record sound. :param rate: Number of samples to capture per second. :param wait: When set to ``True`` it blocks until the recording is @@ -103,13 +107,16 @@ def record_into(buffer: AudioFrame, rate: int = 7812, wait: bool = True) -> None def is_recording() -> bool: """Checks whether the microphone is currently recording. - :return: ``True`` if the microphone is currently recording sound, or - ``False`` otherwise. + Example: ``is_recording = microphone.is_recording()`` + + :return: ``True`` if the microphone is currently recording sound, otherwise returns ``False``. """ ... def stop_recording() -> None: """Stops a recording running in the background. + + Example: ``microphone.stop_recording()`` """ ... @@ -126,6 +133,8 @@ SENSITIVITY_HIGH: float; def set_sensitivity(gain: float) -> None: """Configure the microphone sensitivity. + Example: ``microphone.set_sensitivity(microphone.SENSITIVITY_HIGH)`` + The default sensitivity is ``microphone.SENSITIVITY_MEDIUM``. :param gain: The microphone gain. Use ``microphone.SENSITIVITY_LOW``, ``microphone.SENSITIVITY_MEDIUM``, ``microphone.SENSITIVITY_HIGH``, or a value between these levels. From 44af467e4e3a69083268ca86aad57d4e16d917f4 Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 20 Mar 2024 12:41:00 +0000 Subject: [PATCH 06/25] Tweak --- lang/en/typeshed/stdlib/microbit/__init__.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/en/typeshed/stdlib/microbit/__init__.pyi b/lang/en/typeshed/stdlib/microbit/__init__.pyi index 08ed2d1..ea08cb4 100644 --- a/lang/en/typeshed/stdlib/microbit/__init__.pyi +++ b/lang/en/typeshed/stdlib/microbit/__init__.pyi @@ -296,7 +296,7 @@ class MicroBitTouchPin(MicroBitAnalogDigitalPin): Example: ``pin0.get_touches()`` - :return: the number of times the pin was touched since the device started or since the last time this method was called. + :return: The number of times the pin was touched since the device started or since the last time this method was called. """ ... From 5ff1eb7aaaec8816ac9b0451ea889a6b98013a3b Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 20 Mar 2024 12:53:43 +0000 Subject: [PATCH 07/25] Update to deep_sleep doc To match changes in docs: Update Power Mgm to change run_every behaviour #769 --- lang/ca/typeshed/stdlib/power.pyi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lang/ca/typeshed/stdlib/power.pyi b/lang/ca/typeshed/stdlib/power.pyi index 2be8b27..64be646 100644 --- a/lang/ca/typeshed/stdlib/power.pyi +++ b/lang/ca/typeshed/stdlib/power.pyi @@ -43,8 +43,9 @@ def deep_sleep( when the USB cable is inserted. When the ``run_every`` parameter is set to ``True`` (the default), any - function scheduled with ``run_every`` will momentarily wake up the board - to run and when it finishes it will go back to sleep. + function scheduled with :py:meth:`microbit.run_every` + will momentarily wake up the board to run and when it finishes it will go + back to sleep. :param ms: A time in milliseconds to wait before it wakes up. :param wake_on: A single instance or a tuple of pins and/or buttons to wake up the board, e.g. ``deep_sleep(wake_on=button_a)`` or ``deep_sleep(wake_on=(pin0, pin2, button_b))``. From 6190ec7ee41f55c0468b7fa271b70ef7c716fdc6 Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 20 Mar 2024 13:08:37 +0000 Subject: [PATCH 08/25] Update run_every microbit doc To match PR docs: Add missing days parameter to microbit.run_every. (#767) --- lang/en/typeshed/stdlib/microbit/__init__.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/en/typeshed/stdlib/microbit/__init__.pyi b/lang/en/typeshed/stdlib/microbit/__init__.pyi index ea08cb4..d1e039e 100644 --- a/lang/en/typeshed/stdlib/microbit/__init__.pyi +++ b/lang/en/typeshed/stdlib/microbit/__init__.pyi @@ -32,7 +32,7 @@ def run_every( As a Decorator - placed on top of the function to schedule. For example:: - @run_every(h=1, min=20, s=30, ms=50) + @run_every(days=1, h=1, min=20, s=30, ms=50) def my_function(): # Do something here From 9704523fe86bfb8ea2b0e35851f0793ce27a6127 Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 20 Mar 2024 13:21:09 +0000 Subject: [PATCH 09/25] Change the en/typeshed instead of welsh typeshed --- lang/en/typeshed/stdlib/power.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/en/typeshed/stdlib/power.pyi b/lang/en/typeshed/stdlib/power.pyi index 2be8b27..7d3da44 100644 --- a/lang/en/typeshed/stdlib/power.pyi +++ b/lang/en/typeshed/stdlib/power.pyi @@ -43,8 +43,8 @@ def deep_sleep( when the USB cable is inserted. When the ``run_every`` parameter is set to ``True`` (the default), any - function scheduled with ``run_every`` will momentarily wake up the board - to run and when it finishes it will go back to sleep. + function scheduled with ``run_every`` will momentarily wake up the board to + run and when it finishes it will go back to sleep. :param ms: A time in milliseconds to wait before it wakes up. :param wake_on: A single instance or a tuple of pins and/or buttons to wake up the board, e.g. ``deep_sleep(wake_on=button_a)`` or ``deep_sleep(wake_on=(pin0, pin2, button_b))``. From e0a459368cc26705c1e6dbdfc66ad75c7446b191 Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 20 Mar 2024 13:21:55 +0000 Subject: [PATCH 10/25] Revert "Update to deep_sleep doc" This reverts commit 5ff1eb7aaaec8816ac9b0451ea889a6b98013a3b. Accidentally changed lang/ca/typeshed (Welsh one) instead of en. --- lang/ca/typeshed/stdlib/power.pyi | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lang/ca/typeshed/stdlib/power.pyi b/lang/ca/typeshed/stdlib/power.pyi index 64be646..2be8b27 100644 --- a/lang/ca/typeshed/stdlib/power.pyi +++ b/lang/ca/typeshed/stdlib/power.pyi @@ -43,9 +43,8 @@ def deep_sleep( when the USB cable is inserted. When the ``run_every`` parameter is set to ``True`` (the default), any - function scheduled with :py:meth:`microbit.run_every` - will momentarily wake up the board to run and when it finishes it will go - back to sleep. + function scheduled with ``run_every`` will momentarily wake up the board + to run and when it finishes it will go back to sleep. :param ms: A time in milliseconds to wait before it wakes up. :param wake_on: A single instance or a tuple of pins and/or buttons to wake up the board, e.g. ``deep_sleep(wake_on=button_a)`` or ``deep_sleep(wake_on=(pin0, pin2, button_b))``. From b7f91ec288a7ca64cddead3204286ffb7d3c8106 Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 20 Mar 2024 13:24:07 +0000 Subject: [PATCH 11/25] Revert "Change the en/typeshed instead of welsh typeshed" This reverts commit 9704523fe86bfb8ea2b0e35851f0793ce27a6127. --- lang/en/typeshed/stdlib/power.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/en/typeshed/stdlib/power.pyi b/lang/en/typeshed/stdlib/power.pyi index 7d3da44..2be8b27 100644 --- a/lang/en/typeshed/stdlib/power.pyi +++ b/lang/en/typeshed/stdlib/power.pyi @@ -43,8 +43,8 @@ def deep_sleep( when the USB cable is inserted. When the ``run_every`` parameter is set to ``True`` (the default), any - function scheduled with ``run_every`` will momentarily wake up the board to - run and when it finishes it will go back to sleep. + function scheduled with ``run_every`` will momentarily wake up the board + to run and when it finishes it will go back to sleep. :param ms: A time in milliseconds to wait before it wakes up. :param wake_on: A single instance or a tuple of pins and/or buttons to wake up the board, e.g. ``deep_sleep(wake_on=button_a)`` or ``deep_sleep(wake_on=(pin0, pin2, button_b))``. From 79b44b618321cc2e4d69fe107e070de6f2c58634 Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 3 Apr 2024 10:45:07 +0100 Subject: [PATCH 12/25] ticks_cpu doc --- lang/en/typeshed/stdlib/time.pyi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lang/en/typeshed/stdlib/time.pyi b/lang/en/typeshed/stdlib/time.pyi index 598c483..d4da912 100644 --- a/lang/en/typeshed/stdlib/time.pyi +++ b/lang/en/typeshed/stdlib/time.pyi @@ -56,6 +56,16 @@ def ticks_us() -> int: """ ... +def ticks_cpu() -> int: + """ + Similar to ticks_ms and ticks_us, but with higher resolution in CPU cycles. + + Example: ``time.ticks_cpu()`` + + :return: The counter value in CPU cycles. + """ + ... + def ticks_add(ticks: int, delta: int) -> int: """ Offset ticks value by a given number, which can be either positive or From b90c4862b0eabb8b03261dfef0912f0be9deabdf Mon Sep 17 00:00:00 2001 From: Grace Date: Wed, 3 Apr 2024 11:43:48 +0100 Subject: [PATCH 13/25] Add WIP audio.sound_level stub To be updated once there is a doc for it. --- lang/en/typeshed/stdlib/microbit/audio.pyi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index 3ae4510..99334bb 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -28,6 +28,14 @@ def is_playing() -> bool: :return: ``True`` if audio is playing, otherwise ``False``.""" ... +def sound_level() -> int: + """Returns the average intensity of the sound played. + + Example: ``audio.sound_level()`` + + :return: A number between 0 and 254, being the average intensity of the sound played from the most recent chunk of data.""" + ... + def stop() -> None: """Stop all audio playback. From 609444fa9cb14649ce666978ec018f0d440bc954 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Wed, 3 Apr 2024 12:03:56 +0100 Subject: [PATCH 14/25] Add stubs for AudioFrame operations --- lang/en/typeshed/stdlib/microbit/audio.pyi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index 99334bb..4cd2ac4 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -210,3 +210,9 @@ class AudioFrame: def __len__(self) -> int: ... def __setitem__(self, key: int, value: int) -> None: ... def __getitem__(self, key: int) -> int: ... + def __add__(self, v: AudioFrame) -> AudioFrame: ... + def __iadd__(self, v: AudioFrame) -> AudioFrame: ... + def __sub__(self, v: AudioFrame) -> AudioFrame: ... + def __isub__(self, v: AudioFrame) -> AudioFrame: ... + def __mul__(self, v: float) -> AudioFrame: ... + def __imul__(self, v: float) -> AudioFrame: ... From 7cb527747cbcd98f733268808ff208fca8d18100 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Wed, 3 Apr 2024 13:20:15 +0100 Subject: [PATCH 15/25] Duration doesn't have a default in practice I've flagged this in the docs - it's possible the implementation will be corrected instead. --- lang/en/typeshed/stdlib/microbit/microphone.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/microphone.pyi b/lang/en/typeshed/stdlib/microbit/microphone.pyi index fbd91a0..47d4786 100644 --- a/lang/en/typeshed/stdlib/microbit/microphone.pyi +++ b/lang/en/typeshed/stdlib/microbit/microphone.pyi @@ -70,11 +70,11 @@ def sound_level() -> int: """ ... -def record(duration: int = 3000, rate: int = 7812) -> AudioFrame: +def record(duration: int, rate: int = 7812) -> AudioFrame: """Record sound into an ``AudioFrame`` for the amount of time indicated by ``duration`` at the sampling rate indicated by ``rate``. - Example: ``my_frame = microphone.record()`` + Example: ``my_frame = microphone.record(3000)`` 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 @@ -95,7 +95,7 @@ def record_into(buffer: AudioFrame, rate: int = 7812, wait: bool = True) -> None """Record sound into an existing ``AudioFrame`` until it is filled, or the ``stop_recording()`` function is called. - Example: ``microphone.record_into()`` + Example: ``microphone.record_into(my_frame)`` :param buffer: An ``AudioFrame`` to record sound. :param rate: Number of samples to capture per second. From f5ca4aaf4f75db225cb50cd2c1b90e7b7487d46e Mon Sep 17 00:00:00 2001 From: Grace Date: Fri, 12 Apr 2024 16:54:53 +0100 Subject: [PATCH 16/25] Update set_threshold doc to copy micropython doc --- lang/en/typeshed/stdlib/microbit/microphone.pyi | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/microphone.pyi b/lang/en/typeshed/stdlib/microbit/microphone.pyi index 47d4786..08f8a79 100644 --- a/lang/en/typeshed/stdlib/microbit/microphone.pyi +++ b/lang/en/typeshed/stdlib/microbit/microphone.pyi @@ -54,10 +54,18 @@ def set_threshold(event: SoundEvent, value: int) -> None: Example: ``microphone.set_threshold(SoundEvent.LOUD, 250)`` - A high threshold means the event will only trigger if the sound is very loud (>= 250 in the example). + The ``SoundEvent.LOUD`` event will be triggered when the sound level + crosses this threshold upwards (from "quiet" to "loud"), + and ``SoundEvent.QUIET`` event is triggered when crossing the threshold + downwards (from "loud" to "quiet"). + + If the ``SoundEvent.LOUD`` value set is lower than ``SoundEvent.QUIET``, + then "quiet" threshold will be decreased to one unit below the "loud" + threshold. If the ``SoundEvent.QUIET`` value is set higher than + ``SoundEvent.LOUD``, then the "loud" threshold will be set one unit above. :param event: A sound event, such as ``SoundEvent.LOUD`` or ``SoundEvent.QUIET``. - :param value: The threshold level in the range 0-255. + :param value: The threshold level in the range 0-255. Values outside this range will be clamped. """ ... From 936b1723bb85541d66b82e3976a4477e1c7e1322 Mon Sep 17 00:00:00 2001 From: Grace Date: Fri, 12 Apr 2024 17:13:59 +0100 Subject: [PATCH 17/25] Suggested ammendments for set_threshold doc --- .../typeshed/stdlib/microbit/microphone.pyi | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/microphone.pyi b/lang/en/typeshed/stdlib/microbit/microphone.pyi index 08f8a79..0f68887 100644 --- a/lang/en/typeshed/stdlib/microbit/microphone.pyi +++ b/lang/en/typeshed/stdlib/microbit/microphone.pyi @@ -54,15 +54,16 @@ def set_threshold(event: SoundEvent, value: int) -> None: Example: ``microphone.set_threshold(SoundEvent.LOUD, 250)`` - The ``SoundEvent.LOUD`` event will be triggered when the sound level - crosses this threshold upwards (from "quiet" to "loud"), - and ``SoundEvent.QUIET`` event is triggered when crossing the threshold - downwards (from "loud" to "quiet"). - - If the ``SoundEvent.LOUD`` value set is lower than ``SoundEvent.QUIET``, - then "quiet" threshold will be decreased to one unit below the "loud" - threshold. If the ``SoundEvent.QUIET`` value is set higher than - ``SoundEvent.LOUD``, then the "loud" threshold will be set one unit above. + The ``SoundEvent.LOUD`` event is triggered when the sound level crosses the + threshold from "quiet" to "loud", and the ``SoundEvent.QUIET`` event is + triggered when the sound level crosses from "loud" to "quiet". + + If the ``SoundEvent.LOUD`` threshold is set lower than the + ``SoundEvent.QUIET`` threshold, then the ``SoundEvent.QUIET`` threshold + will decrease by one unit below the ``SoundEvent.LOUD`` threshold. If the + ``SoundEvent.QUIET`` threshold is set higher than the ``SoundEvent.LOUD`` + threshold, then the ``SoundEvent.LOUD`` threshold will increase by one unit + above the ``SoundEvent.QUIET`` threshold. :param event: A sound event, such as ``SoundEvent.LOUD`` or ``SoundEvent.QUIET``. :param value: The threshold level in the range 0-255. Values outside this range will be clamped. From 70578370697bcf25df0aa857184efcfe2f8b2c52 Mon Sep 17 00:00:00 2001 From: Grace Date: Mon, 15 Apr 2024 12:52:55 +0100 Subject: [PATCH 18/25] Update audio.sound_level doc --- lang/en/typeshed/stdlib/microbit/audio.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index 4cd2ac4..3dc244a 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -29,11 +29,11 @@ def is_playing() -> bool: ... def sound_level() -> int: - """Returns the average intensity of the sound played. + """Returns the sound pressure level produced by audio currently being played. Example: ``audio.sound_level()`` - :return: A number between 0 and 254, being the average intensity of the sound played from the most recent chunk of data.""" + :return: A representation of the output sound pressure level in the range 0 to 255.""" ... def stop() -> None: From f4c9898bfb9c77aeb74056b9f47b6f6706842bb9 Mon Sep 17 00:00:00 2001 From: Grace Date: Fri, 3 May 2024 15:37:20 +0100 Subject: [PATCH 19/25] Add microphone sound_level_db doc --- lang/en/typeshed/stdlib/microbit/microphone.pyi | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lang/en/typeshed/stdlib/microbit/microphone.pyi b/lang/en/typeshed/stdlib/microbit/microphone.pyi index 0f68887..368e5dc 100644 --- a/lang/en/typeshed/stdlib/microbit/microphone.pyi +++ b/lang/en/typeshed/stdlib/microbit/microphone.pyi @@ -71,7 +71,7 @@ def set_threshold(event: SoundEvent, value: int) -> None: ... def sound_level() -> int: - """Get the sound pressure level. + """Get the sound pressure level in the range 0 to 255. Example: ``microphone.sound_level()`` @@ -79,6 +79,15 @@ def sound_level() -> int: """ ... +def sound_level_db() -> int: + """Get the sound pressure level in decibels. + + Example: ``microphone.sound_level_db()`` + + :return: A representation of the sound pressure level in decibels (dB). + """ + ... + def record(duration: int, rate: int = 7812) -> AudioFrame: """Record sound into an ``AudioFrame`` for the amount of time indicated by ``duration`` at the sampling rate indicated by ``rate``. From 263b68946ec04f62be71ed673c253f838cd5c257 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Tue, 20 Aug 2024 17:52:10 +0100 Subject: [PATCH 20/25] Initial stubs updates We'll have to do something about dunder docs as they're really key to this API --- lang/en/typeshed/stdlib/audio.pyi | 2 + lang/en/typeshed/stdlib/microbit/audio.pyi | 166 ++++++++++++++++----- 2 files changed, 130 insertions(+), 38 deletions(-) diff --git a/lang/en/typeshed/stdlib/audio.pyi b/lang/en/typeshed/stdlib/audio.pyi index b1d39c7..be1d13d 100644 --- a/lang/en/typeshed/stdlib/audio.pyi +++ b/lang/en/typeshed/stdlib/audio.pyi @@ -6,6 +6,8 @@ from .microbit.audio import ( is_playing as is_playing, play as play, stop as stop, + AudioRecording as AudioRecording, + AudioTrack as AudioTrack, AudioFrame as AudioFrame, SoundEffect as SoundEffect, ) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index 3dc244a..5a625cf 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -2,7 +2,7 @@ """ from ..microbit import MicroBitDigitalPin, Sound, pin0 -from typing import ClassVar, Iterable, Union +from typing import ClassVar, Iterable, Optional, Union def play( source: Union[AudioFrame, Iterable[AudioFrame], Sound, SoundEffect], @@ -143,63 +143,159 @@ class SoundEffect: :return: A copy of the SoundEffect. """ -class AudioFrame: - """An ``AudioFrame`` object is a list of samples, each of which is an unsigned byte - (whole number between 0 and 255). - The number of samples in an AudioFrame will depend on the - ``rate`` (number of samples per second) and ``duration`` parameters. - The total number of samples will always be a round up multiple of 32. +class AudioRecording: + """The ``AudioRecording`` object contains audio data and the sampling rate + associated to it (V2 only). - On micro:bit V1 the constructor does not take any arguments, - and an AudioFrame instance is always 32 bytes. + The size of the internal buffer will depend on the ``rate`` + (number of samples per second) and ``duration`` parameters. + The larger these values are, the more memory that will be used. - For example, playing 32 samples at 7812 Hz takes just over 4 milliseconds - (1/7812.5 * 32 = 0.004096 = 4096 microseconds). - - Example:: + When an ``AudioRecording`` is used to record data from the microphone, + a higher sampling rate produces better sound quality, + but it also uses more memory. - frame = AudioFrame() - for i in range(len(frame)): - frame[i] = 252 - i * 8 + During playback, increasing the sampling rate speeds up the sound + and decreasing the sample rate slows it down. + + The data inside an ``AudioRecording`` is not easy to modify, so the + ``AudioTrack`` class is provided to help access the audio data like a list. + The method ``AudioRecording.track()`` can be used to create an ``AudioTrack``, + and its arguments ``start_ms`` and ``end_ms`` can be used to slice portions + of the data. """ def __init__( self, duration: int = -1, - rate: int = 7812 + rate: int = 11_000 ): - """Create a new ``AudioFrame``. + """Create a new ``AudioRecording``. - Example: ``my_recording = AudioFrame(duration=5000)`` + Example: ``my_recording = AudioRecording(duration=5000)`` - :param duration: Indicates how many milliseconds of audio this instance can store (V2 only). - :param rate: The sampling rate at which data will be stored via the microphone, or played via the ``audio.play()`` function (V2 only). + :param duration: Indicates how many milliseconds of audio this instance can store. + :param rate: The sampling rate at which data will be stored via the microphone, or played via the ``audio.play()`` function. + """ + + def copy(self) -> None: + """Create a copy of the ``AudioRecording``. + + Example: ``copy = my_recording.copy()`` + + :return: A copy of the ``AudioRecording``. + """ + + def track(self, start_ms: int = 0, end_ms: int = -1) -> None: + """Create an ``AudioTrack`` instance from a portion of the data in this ``AudioRecording`` instance. + + Example: ``first_second = my_recording.track(0, 1000)`` + + :param start_ms: (default=0) Where to start of the track in milliseconds. + :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. + :return: An ``AudioTrack`` backed by the sample data between ``start_ms`` and ``end_ms``. + """ + def __len__(self) -> int: ... + def __setitem__(self, key: int, value: int) -> None: ... + def __getitem__(self, key: int) -> int: ... + def __add__(self, v: AudioRecording) -> AudioRecording: ... + def __iadd__(self, v: AudioRecording) -> AudioRecording: ... + def __sub__(self, v: AudioRecording) -> AudioRecording: ... + def __isub__(self, v: AudioRecording) -> AudioRecording: ... + def __mul__(self, v: float) -> AudioRecording: ... + def __imul__(self, v: float) -> AudioRecording: ... + +class AudioTrack: + """ The ``AudioTrack`` object points to the data provided by the input buffer, + which can be an ``AudioRecording``, another ``AudioTrack``, + or a buffer-like object like a ``bytearray`` (V2 only). + """ + + def __init__( + self, + buffer: Union[bytearray, AudioRecording, AudioTrack], + rate: Optional[int] = None + ): + """Create a new ``AudioTrack``. + + When the input buffer has an associated rate (e.g. an ``AudioRecording`` + or ``AudioTrack``), the rate is copied. If the buffer object does not have + a rate, the default value of 11_000 is used. + + Example: ``my_track = AudioTrack(bytearray(4096))`` + + An ``AudioTrack`` can be created from an ``AudioRecording``, another + ``AudioTrack``, or a ``bytearray`` and individual bytes can be accessed and + modified like elements in a list:: + + my_track = AudioTrack(bytearray(100)) + # Create a square wave + half_length = len(my_track) // 2 + for i in range(half_length): + my_track[i] = 255 + for i in range(half_length, len(my_track)): + my_track[i] = 0 + + Or smaller AudioTracks can be created using slices, useful to send them + via radio or serial:: + + recording = microphone.record(duration=2000) + track = AudioTrack(recording) + packet_size = 32 + for i in range(0, len(track), packet_size): + radio.send_bytes(track[i:i+packet_size]) + + :param buffer: The buffer containing the audio data. + :param rate: (default=None) The sampling rate at which data will be stored via the microphone, or played via the ``audio.play()`` function. """ def set_rate(self, sample_rate: int) -> None: """Configure the sampling rate associated with the data in the - ``AudioFrame`` instance (V2 only). + ``AudioTrack`` instance. - Example: ``my_frame.set_rate(7812)`` - For recording from the microphone, increasing the sampling rate - increases the sound quality, but reduces the length of audio it - can store. + Changes to an ``AudioTrack`` rate won't affect the original source rate, + so multiple instances pointing to the same buffer can have different + rates and the original buffer rate would stay unmodified. - During playback, increasing the sampling rate speeds up the sound - and decreasing it slows it down. + Example: ``my_track.set_rate(22_000)`` """ def get_rate(self) -> int: """Get the sampling rate associated with the data in the - ``AudioFrame`` instance (V2 only). + ``AudioRecording`` instance. - Example: ``current_rate = my_frame.get_rate()`` + Example: ``current_rate = my_track.get_rate()`` - :return: The configured sampling rate for this ``AudioFrame`` instance. + :return: The configured sample rate. """ + + def __len__(self) -> int: ... + def __setitem__(self, key: int, value: int) -> None: ... + def __getitem__(self, key: int) -> int: ... + def __add__(self, v: AudioTrack) -> AudioTrack: ... + def __iadd__(self, v: AudioTrack) -> AudioTrack: ... + def __sub__(self, v: AudioTrack) -> AudioTrack: ... + def __isub__(self, v: AudioTrack) -> AudioTrack: ... + def __mul__(self, v: float) -> AudioTrack: ... + def __imul__(self, v: float) -> AudioTrack: ... + + +class AudioFrame: + """An ``AudioFrame`` object is a list of 32 samples each of which is a unsigned byte + (whole number between 0 and 255). + + It takes just over 4 ms to play a single frame. + + Example:: + + frame = AudioFrame() + for i in range(len(frame)): + frame[i] = 252 - i * 8 + """ + def copyfrom(self, other: AudioFrame) -> None: """Overwrite the data in this ``AudioFrame`` with the data from another ``AudioFrame`` instance. @@ -209,10 +305,4 @@ class AudioFrame: """ def __len__(self) -> int: ... def __setitem__(self, key: int, value: int) -> None: ... - def __getitem__(self, key: int) -> int: ... - def __add__(self, v: AudioFrame) -> AudioFrame: ... - def __iadd__(self, v: AudioFrame) -> AudioFrame: ... - def __sub__(self, v: AudioFrame) -> AudioFrame: ... - def __isub__(self, v: AudioFrame) -> AudioFrame: ... - def __mul__(self, v: float) -> AudioFrame: ... - def __imul__(self, v: float) -> AudioFrame: ... + def __getitem__(self, key: int) -> int: ... \ No newline at end of file From 3826bceb0e8f287455bf60f0bf195bf7be5353ef Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Wed, 21 Aug 2024 09:56:45 +0100 Subject: [PATCH 21/25] Corrections --- lang/en/typeshed/stdlib/microbit/audio.pyi | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index 5a625cf..6badf18 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -187,7 +187,7 @@ class AudioRecording: :return: A copy of the ``AudioRecording``. """ - def track(self, start_ms: int = 0, end_ms: int = -1) -> None: + def track(self, start_ms: int = 0, end_ms: int = -1) -> AudioTrack: """Create an ``AudioTrack`` instance from a portion of the data in this ``AudioRecording`` instance. Example: ``first_second = my_recording.track(0, 1000)`` @@ -196,15 +196,6 @@ class AudioRecording: :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. :return: An ``AudioTrack`` backed by the sample data between ``start_ms`` and ``end_ms``. """ - def __len__(self) -> int: ... - def __setitem__(self, key: int, value: int) -> None: ... - def __getitem__(self, key: int) -> int: ... - def __add__(self, v: AudioRecording) -> AudioRecording: ... - def __iadd__(self, v: AudioRecording) -> AudioRecording: ... - def __sub__(self, v: AudioRecording) -> AudioRecording: ... - def __isub__(self, v: AudioRecording) -> AudioRecording: ... - def __mul__(self, v: float) -> AudioRecording: ... - def __imul__(self, v: float) -> AudioRecording: ... class AudioTrack: """ The ``AudioTrack`` object points to the data provided by the input buffer, From 6dcc5ab49ef16006547f3e77b549448e13f264a9 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Wed, 21 Aug 2024 13:38:15 +0100 Subject: [PATCH 22/25] Corrections --- lang/en/typeshed/stdlib/microbit/audio.pyi | 23 +++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index 6badf18..e385d71 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -2,7 +2,7 @@ """ from ..microbit import MicroBitDigitalPin, Sound, pin0 -from typing import ClassVar, Iterable, Optional, Union +from typing import ClassVar, Iterable, Optional, Union, overload def play( source: Union[AudioFrame, Iterable[AudioFrame], Sound, SoundEffect], @@ -262,10 +262,27 @@ class AudioTrack: :return: The configured sample rate. """ + def copyfrom(self, other: Union[bytearray, AudioRecording, AudioTrack]) -> None: + """Overwrite the data in this ``AudioTrack`` with the data from another + ``AudioTrack``, ``AudioRecording``, or buffer-like object like a + ``bytearray`` instance. + + If the input buffer is smaller than the available space in this + instance, the rest of the data is left untouched. + If it is larger, it will stop copying once this instance is filled. + + :param other: Buffer-like instance from which to copy the data. + """ def __len__(self) -> int: ... - def __setitem__(self, key: int, value: int) -> None: ... - def __getitem__(self, key: int) -> int: ... + + + @overload + def __getitem__(self, i: int) -> int: ... + @overload + def __getitem__(self, s: slice) -> AudioTrack: ... + def __setitem__(self, i: int, x: int) -> None: ... + def __add__(self, v: AudioTrack) -> AudioTrack: ... def __iadd__(self, v: AudioTrack) -> AudioTrack: ... def __sub__(self, v: AudioTrack) -> AudioTrack: ... From fc8537799543fb924b5c5813cb6ff30a73c7df88 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Wed, 21 Aug 2024 17:38:55 +0100 Subject: [PATCH 23/25] Microphone stubs --- .../typeshed/stdlib/microbit/microphone.pyi | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/microphone.pyi b/lang/en/typeshed/stdlib/microbit/microphone.pyi index 368e5dc..f7cefa3 100644 --- a/lang/en/typeshed/stdlib/microbit/microphone.pyi +++ b/lang/en/typeshed/stdlib/microbit/microphone.pyi @@ -1,9 +1,9 @@ """Respond to sound using the built-in microphone (V2 only). """ -from typing import Optional, Tuple +from typing import Optional, Tuple, Union from ..microbit import SoundEvent -from ..microbit.audio import AudioFrame +from ..microbit.audio import AudioRecording, AudioTrack def current_event() -> Optional[SoundEvent]: """Get the last recorded sound event @@ -88,12 +88,10 @@ def sound_level_db() -> int: """ ... -def record(duration: int, rate: int = 7812) -> AudioFrame: - """Record sound into an ``AudioFrame`` for the amount of time indicated by +def record(duration: int, rate: int = 11_000) -> AudioRecording: + """Record sound into an ``AudioRecording`` for the amount of time indicated by ``duration`` at the sampling rate indicated by ``rate``. - Example: ``my_frame = microphone.record(3000)`` - 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. @@ -105,20 +103,23 @@ def record(duration: int, rate: int = 7812) -> AudioFrame: :param duration: How long to record in milliseconds. :param rate: Number of samples to capture per second. - :return: An ``AudioFrame`` with the sound samples. + :returns: An ``AudioRecording`` with the sound samples. """ ... -def record_into(buffer: AudioFrame, rate: int = 7812, wait: bool = True) -> None: - """Record sound into an existing ``AudioFrame`` until it is filled, - or the ``stop_recording()`` function is called. +def record_into(buffer: Union[AudioRecording, AudioTrack], wait: bool = True) -> AudioTrack: + """Record sound into an existing ``AudioRecording`` or ``AudioTrack`` + until it is filled, or the ``stop_recording()`` function is called. - Example: ``microphone.record_into(my_frame)`` + This function also returns an ``AudioTrack`` created from the provided + input buffer, which length matches the recording duration. + This is useful when recording with ``wait`` set to ``False``, and the + recording is stopped before the input buffer is filled. - :param buffer: An ``AudioFrame`` to record sound. - :param rate: Number of samples to capture per second. + :param buffer: ``AudioRecording`` or ``AudioTrack`` to record sound into. :param wait: When set to ``True`` it blocks until the recording is done, if it is set to ``False`` it will run in the background. + :returns: An ``AudioTrack`` which ends where the recording ended. """ ... From 69aaab7945dcf34c8469cac2db3f6646b8f0e4c3 Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Wed, 21 Aug 2024 17:43:12 +0100 Subject: [PATCH 24/25] Update play stubs --- lang/en/typeshed/stdlib/microbit/audio.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index e385d71..ae4bd95 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -5,7 +5,7 @@ from ..microbit import MicroBitDigitalPin, Sound, pin0 from typing import ClassVar, Iterable, Optional, Union, overload def play( - source: Union[AudioFrame, Iterable[AudioFrame], Sound, SoundEffect], + source: Union[AudioFrame, Iterable[AudioFrame], AudioRecording, AudioTrack, Sound, SoundEffect], wait: bool = True, pin: MicroBitDigitalPin = pin0, return_pin: Union[MicroBitDigitalPin, None] = None, From 91eb337c312c18043da4c05dd61dc3c63f81139d Mon Sep 17 00:00:00 2001 From: Matt Hillsdon Date: Wed, 21 Aug 2024 17:46:21 +0100 Subject: [PATCH 25/25] Docs for audio.play --- lang/en/typeshed/stdlib/microbit/audio.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/en/typeshed/stdlib/microbit/audio.pyi b/lang/en/typeshed/stdlib/microbit/audio.pyi index ae4bd95..028419e 100644 --- a/lang/en/typeshed/stdlib/microbit/audio.pyi +++ b/lang/en/typeshed/stdlib/microbit/audio.pyi @@ -10,11 +10,11 @@ def play( pin: MicroBitDigitalPin = pin0, return_pin: Union[MicroBitDigitalPin, None] = None, ) -> None: - """Play a built-in sound, sound effect or audio samples using ``AudioFrame``. + """Play a built-in sound, sound effect or audio samples. Example: ``audio.play(Sound.GIGGLE)`` - :param source: A built-in ``Sound`` such as ``Sound.GIGGLE``, a ``SoundEffect`` or sample data as an ``AudioFrame`` object or an iterable of ``AudioFrame`` objects. + :param source: A built-in ``Sound`` such as ``Sound.GIGGLE``, a ``SoundEffect`` or sample data as an ``AudioFrame``, ``AudioRecording`` or ``AudioTrack`` object or an iterable of ``AudioFrame`` objects. :param wait: If ``wait`` is ``True``, this function will block until the sound is complete. :param 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``. :param return_pin: Specifies a differential edge connector pin to connect to an external speaker instead of ground. This is ignored for the **V2** revision.