22"""
33
44from ..microbit import MicroBitDigitalPin , Sound , pin0
5- from typing import ClassVar , Iterable , Union
5+ from typing import ClassVar , Iterable , Optional , Union
66
77def 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