Skip to content

Commit 19784d3

Browse files
committed
Finish SDL3 port of API
All known issues with the API resolved and tests pass
1 parent 70863c3 commit 19784d3

File tree

16 files changed

+797
-340
lines changed

16 files changed

+797
-340
lines changed

.vscode/settings.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"condlist",
9797
"consolas",
9898
"contextdata",
99+
"contextlib",
99100
"CONTROLLERAXISMOTION",
100101
"CONTROLLERBUTTONDOWN",
101102
"CONTROLLERBUTTONUP",
@@ -112,6 +113,7 @@
112113
"dataclasses",
113114
"datas",
114115
"DBLAMPERSAND",
116+
"DBLAPOSTROPHE",
115117
"DBLVERTICALBAR",
116118
"dcost",
117119
"DCROSS",
@@ -139,6 +141,7 @@
139141
"dunder",
140142
"DVLINE",
141143
"elif",
144+
"ENDCALL",
142145
"endianness",
143146
"epel",
144147
"epub",
@@ -250,6 +253,7 @@
250253
"lerp",
251254
"letterpaper",
252255
"LGUI",
256+
"LHYPER",
253257
"libsdl",
254258
"libtcod",
255259
"libtcodpy",
@@ -305,6 +309,7 @@
305309
"neww",
306310
"noarchive",
307311
"NODISCARD",
312+
"NOMESSAGE",
308313
"Nonrepresentable",
309314
"NONUSBACKSLASH",
310315
"NONUSHASH",
@@ -315,6 +320,7 @@
315320
"numpy",
316321
"ogrid",
317322
"ogrids",
323+
"oldnames",
318324
"onefile",
319325
"OPENGL",
320326
"opensearch",
@@ -366,6 +372,7 @@
366372
"repr",
367373
"rgba",
368374
"RGUI",
375+
"RHYPER",
369376
"RIGHTBRACE",
370377
"RIGHTBRACKET",
371378
"RIGHTDOWN",
@@ -407,6 +414,8 @@
407414
"SIZEWE",
408415
"SMILIE",
409416
"snprintf",
417+
"SOFTLEFT",
418+
"SOFTRIGHT",
410419
"soundfile",
411420
"sourcelink",
412421
"sphinxstrong",
@@ -445,6 +454,7 @@
445454
"typestr",
446455
"undoc",
447456
"Unifont",
457+
"UNISTD",
448458
"unraisable",
449459
"unraisablehook",
450460
"unraiseable",

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,31 @@ This project adheres to [Semantic Versioning](https://semver.org/) since version
1616
- `tcod.sdl.render.new_renderer`: Removed `software` and `target_textures` parameters, `vsync` takes `int`, `driver` takes `str` instead of `int`.
1717
- SDL renderer logical
1818
- `tcod.sdl.render.Renderer`: `integer_scaling` and `logical_size` are now set with `set_logical_presentation` method.
19+
- `tcod.sdl.render.Renderer.geometry` now takes float values for `color` instead of 8-bit integers.
20+
- `tcod.event.Point` and other mouse/tile coordinate types now use `float` instead of `int`.
21+
SDL3 has decided that mouse events have subpixel precision.
22+
If you see any usual `float` types in your code then this is why.
23+
- `tcod.sdl.audio` has been affected by major changes to SDL3.
24+
- `tcod.sdl.audio.open` has new behavior due to SDL3 and should be avoided.
25+
- Callbacks which were assigned to `AudioDevice`'s must now be applied to `AudioStream`'s instead.
26+
- `AudioDevice`'s are now opened using references to existing devices.
27+
- Sound queueing methods were moved from `AudioDevice` to a new `AudioStream` class.
28+
- `BasicMixer` may require manually specifying `frequency` and `channels` to replicate old behavior.
29+
- `get_devices` and `get_capture_devices` now return `dict[str, AudioDevice]`.
30+
31+
### Deprecated
32+
33+
- `tcod.sdl.audio.open` was replaced with a newer API, get a default device with `tcod.sdl.audio.get_default_playback().open()`.
34+
- `tcod.sdl.audio.BasicMixer` should be replaced with `AudioStream`'s.
35+
- Should no longer use `tcod.sdl.audio.AudioDevice` in a context, use `contextlib.closing` for the old behavior.
1936

2037
### Removed
2138

2239
- Support dropped for Python 3.8 and 3.9.
2340
- Removed `Joystick.get_current_power` due to SDL3 changes.
2441
- `WindowFlags.FULLSCREEN_DESKTOP` is now just `WindowFlags.FULLSCREEN`
2542
- `tcod.sdl.render.Renderer.integer_scaling` removed.
43+
- Removed `callback`, `spec`, `queued_samples`, `queue_audio`, and `dequeue_audio` attributes from `tcod.sdl.audio.AudioDevice`.
2644

2745
### Fixed
2846

build_sdl.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848

4949
# These structs have an unusual size when packed by SDL on 32-bit platforms.
5050
FLEXIBLE_STRUCTS = (
51-
"SDL_AudioCVT",
5251
"SDL_TouchFingerEvent",
5352
"SDL_MultiGestureEvent",
5453
"SDL_DollarGestureEvent",
@@ -237,7 +236,7 @@ def on_directive_handle(
237236
238237
extern "Python" {
239238
// SDL_AudioCallback callback.
240-
void _sdl_audio_callback(void* userdata, uint8_t* stream, int len);
239+
void _sdl_audio_stream_callback(void* userdata, SDL_AudioStream *stream, int additional_amount, int total_amount);
241240
// SDL to Python log function.
242241
void _sdl_log_output_function(void *userdata, int category, SDL_LogPriority priority, const char *message);
243242
// Generic event watcher callback.

examples/audio_tone.py

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
#!/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.
33
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.
55
"""
66

77
import math
88
import time
9-
from typing import Any
109

1110
import attrs
1211
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]
1513

1614
import tcod.sdl.audio
1715

@@ -22,28 +20,56 @@
2220
class PullWave:
2321
"""Square wave stream generator for an SDL audio device in pull mode."""
2422

23+
frequency: float
2524
time: float = 0.0
2625

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:
2827
"""Stream a square wave to SDL on demand.
2928
3029
This function must run faster than the stream duration.
3130
Numpy is used to keep performance within these limits.
3231
"""
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
3733

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)
3935
self.time += duration
4036
wave = signal.square(t * (math.tau * 440)).astype(np.float32)
41-
wave *= VOLUME
42-
43-
stream[:] = device.convert(wave)
37+
stream.queue_audio(wave)
4438

4539

4640
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()

examples/samples_tcod.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -757,8 +757,8 @@ def ev_mousemotion(self, event: tcod.event.MouseMotion) -> None:
757757
mx = event.tile.x - SAMPLE_SCREEN_X
758758
my = event.tile.y - SAMPLE_SCREEN_Y
759759
if 0 <= mx < SAMPLE_SCREEN_WIDTH and 0 <= my < SAMPLE_SCREEN_HEIGHT:
760-
self.dest_x = mx
761-
self.dest_y = my
760+
self.dest_x = int(mx)
761+
self.dest_y = int(my)
762762

763763

764764
#############################################
@@ -1028,9 +1028,9 @@ def on_draw(self) -> None:
10281028
sample_console.print(
10291029
1,
10301030
1,
1031-
f"Pixel position : {self.motion.position.x:4d}x{self.motion.position.y:4d}\n"
1032-
f"Tile position : {self.motion.tile.x:4d}x{self.motion.tile.y:4d}\n"
1033-
f"Tile movement : {self.motion.tile_motion.x:4d}x{self.motion.tile_motion.y:4d}\n"
1031+
f"Pixel position : {self.motion.position.x:4.0f}x{self.motion.position.y:4.0f}\n"
1032+
f"Tile position : {self.motion.tile.x:4.0f}x{self.motion.tile.y:4.0f}\n"
1033+
f"Tile movement : {self.motion.tile_motion.x:4.0f}x{self.motion.tile_motion.y:4.0f}\n"
10341034
f"Left button : {'ON' if self.mouse_left else 'OFF'}\n"
10351035
f"Right button : {'ON' if self.mouse_right else 'OFF'}\n"
10361036
f"Middle button : {'ON' if self.mouse_middle else 'OFF'}\n",

tcod/_libtcod.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7717,8 +7717,8 @@ class _lib:
77177717
"""void _pycall_sdl_hook(struct SDL_Surface *)"""
77187718

77197719
@staticmethod
7720-
def _sdl_audio_callback(userdata: Any, stream: Any, len: int, /) -> None:
7721-
"""void _sdl_audio_callback(void *userdata, uint8_t *stream, int len)"""
7720+
def _sdl_audio_stream_callback(userdata: Any, stream: Any, additional_amount: int, total_amount: int, /) -> None:
7721+
"""void _sdl_audio_stream_callback(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount)"""
77227722

77237723
@staticmethod
77247724
def _sdl_event_watcher(userdata: Any, event: Any, /) -> int:

tcod/context.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,13 +220,14 @@ def present(
220220
)
221221
_check(lib.TCOD_context_present(self._p, console.console_c, viewport_args))
222222

223-
def pixel_to_tile(self, x: int, y: int) -> tuple[int, int]:
223+
def pixel_to_tile(self, x: float, y: float) -> tuple[float, float]:
224224
"""Convert window pixel coordinates to tile coordinates."""
225-
with ffi.new("int[2]", (x, y)) as xy:
226-
_check(lib.TCOD_context_screen_pixel_to_tile_i(self._p, xy, xy + 1))
225+
with ffi.new("double[2]", (x, y)) as xy:
226+
_check(lib.TCOD_context_screen_pixel_to_tile_d(self._p, xy, xy + 1))
227227
return xy[0], xy[1]
228228

229-
def pixel_to_subtile(self, x: int, y: int) -> tuple[float, float]:
229+
@deprecated("Use pixel_to_tile method instead.")
230+
def pixel_to_subtile(self, x: float, y: float) -> tuple[float, float]:
230231
"""Convert window pixel coordinates to sub-tile coordinates."""
231232
with ffi.new("double[2]", (x, y)) as xy:
232233
_check(lib.TCOD_context_screen_pixel_to_tile_d(self._p, xy, xy + 1))
@@ -262,7 +263,7 @@ def convert_event(self, event: _Event) -> _Event:
262263
event.position[1] - event.motion[1],
263264
)
264265
event_copy.motion = event._tile_motion = tcod.event.Point(
265-
event._tile[0] - prev_tile[0], event._tile[1] - prev_tile[1]
266+
int(event._tile[0]) - int(prev_tile[0]), int(event._tile[1]) - int(prev_tile[1])
266267
)
267268
return event_copy
268269

0 commit comments

Comments
 (0)