2
2
"""
3
3
4
4
from ..microbit import MicroBitDigitalPin , Sound , pin0
5
- from typing import ClassVar , Iterable , Union
5
+ from typing import ClassVar , Iterable , Optional , Union
6
6
7
7
def play (
8
8
source : Union [AudioFrame , Iterable [AudioFrame ], Sound , SoundEffect ],
@@ -143,63 +143,159 @@ class SoundEffect:
143
143
:return: A copy of the SoundEffect.
144
144
"""
145
145
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).
149
146
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) .
153
150
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.
156
154
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.
161
158
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.
165
167
"""
166
168
167
169
def __init__ (
168
170
self ,
169
171
duration : int = - 1 ,
170
- rate : int = 7812
172
+ rate : int = 11_000
171
173
):
172
- """Create a new ``AudioFrame ``.
174
+ """Create a new ``AudioRecording ``.
173
175
174
- Example: ``my_recording = AudioFrame (duration=5000)``
176
+ Example: ``my_recording = AudioRecording (duration=5000)``
175
177
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.
178
251
"""
179
252
180
253
def set_rate (self , sample_rate : int ) -> None :
181
254
"""Configure the sampling rate associated with the data in the
182
- ``AudioFrame `` instance (V2 only) .
255
+ ``AudioTrack `` instance.
183
256
184
- Example: ``my_frame.set_rate(7812)``
185
257
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 .
189
261
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)``
192
263
"""
193
264
194
265
def get_rate (self ) -> int :
195
266
"""Get the sampling rate associated with the data in the
196
- ``AudioFrame `` instance (V2 only) .
267
+ ``AudioRecording `` instance.
197
268
198
- Example: ``current_rate = my_frame .get_rate()``
269
+ Example: ``current_rate = my_track .get_rate()``
199
270
200
- :return: The configured sampling rate for this ``AudioFrame`` instance .
271
+ :return: The configured sample rate.
201
272
"""
202
273
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
+
203
299
def copyfrom (self , other : AudioFrame ) -> None :
204
300
"""Overwrite the data in this ``AudioFrame`` with the data from another ``AudioFrame`` instance.
205
301
@@ -209,10 +305,4 @@ class AudioFrame:
209
305
"""
210
306
def __len__ (self ) -> int : ...
211
307
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