|
1 | 1 | #!/usr/bin/env python |
2 | | -"""Shows how to use tcod.sdl.audio to play a custom-made audio stream. |
| 2 | +"""Shows how to use tcod.sdl.audio to play audio. |
3 | 3 |
|
4 | | -Opens an audio device using SDL and plays a square wave for 1 second. |
| 4 | +Opens an audio device using SDL then plays tones using various methods. |
5 | 5 | """ |
6 | 6 |
|
7 | 7 | import math |
8 | 8 | import time |
9 | | -from typing import Any |
10 | 9 |
|
11 | 10 | import attrs |
12 | 11 | import numpy as np |
13 | | -from numpy.typing import NDArray |
14 | | -from scipy import signal # type: ignore |
| 12 | +from scipy import signal # type: ignore[import-untyped] |
15 | 13 |
|
16 | 14 | import tcod.sdl.audio |
17 | 15 |
|
|
22 | 20 | class PullWave: |
23 | 21 | """Square wave stream generator for an SDL audio device in pull mode.""" |
24 | 22 |
|
| 23 | + frequency: float |
25 | 24 | time: float = 0.0 |
26 | 25 |
|
27 | | - def __call__(self, device: tcod.sdl.audio.AudioDevice, stream: NDArray[Any]) -> None: |
| 26 | + def __call__(self, stream: tcod.sdl.audio.AudioStream, request: tcod.sdl.audio.AudioStreamCallbackData) -> None: |
28 | 27 | """Stream a square wave to SDL on demand. |
29 | 28 |
|
30 | 29 | This function must run faster than the stream duration. |
31 | 30 | Numpy is used to keep performance within these limits. |
32 | 31 | """ |
33 | | - sample_rate = device.frequency |
34 | | - n_samples = device.buffer_samples |
35 | | - duration = n_samples / sample_rate |
36 | | - print(f"{duration=} {self.time=}") |
| 32 | + duration = request.additional_samples / self.frequency |
37 | 33 |
|
38 | | - t = np.linspace(self.time, self.time + duration, n_samples, endpoint=False) |
| 34 | + t = np.linspace(self.time, self.time + duration, request.additional_samples, endpoint=False) |
39 | 35 | self.time += duration |
40 | 36 | wave = signal.square(t * (math.tau * 440)).astype(np.float32) |
41 | | - wave *= VOLUME |
42 | | - |
43 | | - stream[:] = device.convert(wave) |
| 37 | + stream.queue_audio(wave) |
44 | 38 |
|
45 | 39 |
|
46 | 40 | if __name__ == "__main__": |
47 | | - with tcod.sdl.audio.open(callback=PullWave()) as device: |
48 | | - print(device) |
49 | | - time.sleep(1) |
| 41 | + device = tcod.sdl.audio.get_default_playback().open(channels=1, frequency=44100) |
| 42 | + print(f"{device.name=}") |
| 43 | + device.gain = VOLUME |
| 44 | + print(device) |
| 45 | + |
| 46 | + print("Sawtooth wave queued with AudioStream.queue_audio") |
| 47 | + stream = device.new_stream(format=np.float32, channels=1, frequency=44100) |
| 48 | + t = np.linspace(0, 1.0, 44100, endpoint=False) |
| 49 | + wave = signal.sawtooth(t * (math.tau * 440)).astype(np.float32) |
| 50 | + stream.queue_audio(wave) |
| 51 | + stream.flush() |
| 52 | + while stream.queued_samples: |
| 53 | + time.sleep(0.01) |
| 54 | + |
| 55 | + print("---") |
| 56 | + time.sleep(0.5) |
| 57 | + |
| 58 | + print("Square wave attached to AudioStream.getter_callback") |
| 59 | + stream = device.new_stream(format=np.float32, channels=1, frequency=44100) |
| 60 | + stream.getter_callback = PullWave(device.frequency) |
| 61 | + |
| 62 | + time.sleep(1) |
| 63 | + stream.getter_callback = None |
| 64 | + |
| 65 | + print("---") |
| 66 | + time.sleep(0.5) |
| 67 | + |
| 68 | + print("Sawtooth wave played with BasicMixer.play") |
| 69 | + mixer = tcod.sdl.audio.BasicMixer(device, frequency=44100, channels=2) |
| 70 | + channel = mixer.play(wave) |
| 71 | + while channel.busy: |
| 72 | + time.sleep(0.01) |
| 73 | + |
| 74 | + print("---") |
| 75 | + device.close() |
0 commit comments