pygameControls 0.0.4__tar.gz → 0.0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/PKG-INFO +1 -1
  2. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls/controller.py +1 -1
  3. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls/dualsense_controller.py +27 -0
  4. pygamecontrols-0.0.6/pygameControls/dualsense_edge_controller.py +93 -0
  5. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls/generic_controller.py +22 -0
  6. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls/logitech_dual_action_controller.py +23 -1
  7. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls/logitech_f310_controller.py +22 -0
  8. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls/logitech_f510_controller.py +22 -1
  9. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls/logitech_f710_controller.py +22 -1
  10. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls/xbox_series_x_controller.py +23 -0
  11. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls.egg-info/PKG-INFO +1 -1
  12. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls.egg-info/SOURCES.txt +0 -1
  13. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/setup.py +1 -1
  14. pygamecontrols-0.0.4/pygameControls/dualsense_audio.py +0 -70
  15. pygamecontrols-0.0.4/pygameControls/dualsense_edge_controller.py +0 -199
  16. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/LICENSE +0 -0
  17. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/README.md +0 -0
  18. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls/__init__.py +0 -0
  19. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls/controlsbase.py +0 -0
  20. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls.egg-info/dependency_links.txt +0 -0
  21. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/pygameControls.egg-info/top_level.txt +0 -0
  22. {pygamecontrols-0.0.4 → pygamecontrols-0.0.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygameControls
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: A simple controller class for pygame.
5
5
  Home-page:
6
6
  Author: Jan Lerking
@@ -9,7 +9,7 @@ from .xbox_series_x_controller import XboxSeriesXController
9
9
  from .generic_controller import GenericController
10
10
  from .logitech_dual_action_controller import LogitechDualActionController
11
11
 
12
- __version__ = "0.0.4"
12
+ __version__ = "0.0.6"
13
13
 
14
14
  CONTROLLERS = {
15
15
  "DualSense Wireless Controller": DualSenseController,
@@ -18,6 +18,33 @@ class DualSenseController(ControlsBase):
18
18
  self.powerlevel = self.device.battery.Level
19
19
  self.batterystate = BATTERY_STATE[str(self.device.battery.State)]
20
20
  self.set_player_id(PlayerID.PLAYER_1)
21
+ self.numaxis: int = self.device.get_numaxes()
22
+ self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
23
+ self.numhats: int = self.device.get_numhats()
24
+ self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
25
+ self.numbuttons: int = self.device.get_numbuttons()
26
+ self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
27
+ self.mapping = {
28
+ "left stick x": self.axis[0],
29
+ "left stick y": self.axis[1],
30
+ "right stick x": self.axis[3],
31
+ "right stick y": self.axis[4],
32
+ "right trigger": self.buttons[5],
33
+ "left trigger": self.buttons[2],
34
+ "dhat x": self.hats[0][0],
35
+ "dhat y": self.hats[0][1],
36
+ "left button": self.buttons[4],
37
+ "right button": self.buttons[5],
38
+ "cross button": self.buttons[0],
39
+ "triangle button": self.buttons[2],
40
+ "circle button": self.buttons[1],
41
+ "square button": self.buttons[3],
42
+ "left stick button": self.buttons[11],
43
+ "right stick button": self.buttons[12],
44
+ "connect button": self.buttons[8],
45
+ "list button": self.buttons[9],
46
+ "logo button": self.buttons[10]
47
+ }
21
48
  print(f"{self.name} connected")
22
49
  print(f"Power level: {self.powerlevel}")
23
50
  print(f"Battery state: {self.batterystate}")
@@ -0,0 +1,93 @@
1
+ from pygameControls.controlsbase import ControlsBase
2
+ from pydualsense import *
3
+
4
+
5
+ class DualSenseEdgeController(ControlsBase):
6
+ def __init__(self, joy):
7
+ self.device = pydualsense()
8
+ self.device.init()
9
+ self.name = self.device.device.get_product_string()
10
+ self.powerlevel = self.device.battery.Level
11
+ self.batterystate = BATTERY_STATE[str(self.device.battery.State)]
12
+ self.set_player_id(PlayerID.PLAYER_1)
13
+ self.numaxis: int = self.device.get_numaxes()
14
+ self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
15
+ self.numhats: int = self.device.get_numhats()
16
+ self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
17
+ self.numbuttons: int = self.device.get_numbuttons()
18
+ self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
19
+ self.mapping = {
20
+ "left stick x": self.axis[0],
21
+ "left stick y": self.axis[1],
22
+ "right stick x": self.axis[3],
23
+ "right stick y": self.axis[4],
24
+ "right trigger": self.buttons[5],
25
+ "left trigger": self.buttons[2],
26
+ "dhat x": self.hats[0][0],
27
+ "dhat y": self.hats[0][1],
28
+ "left button": self.buttons[4],
29
+ "right button": self.buttons[5],
30
+ "cross button": self.buttons[0],
31
+ "triangle button": self.buttons[2],
32
+ "circle button": self.buttons[1],
33
+ "square button": self.buttons[3],
34
+ "left stick button": self.buttons[11],
35
+ "right stick button": self.buttons[12],
36
+ "connect button": self.buttons[8],
37
+ "list button": self.buttons[9],
38
+ "logo button": self.buttons[10]
39
+ }
40
+ print(f"{self.name} connected")
41
+ print(f"Power level: {self.powerlevel}")
42
+ print(f"Battery state: {self.batterystate}")
43
+
44
+ def handle_input(self, event):
45
+ pass
46
+
47
+ def set_led(self, red: int, green: int, blue: int):
48
+ self.device.light.setColorI(red, green, blue)
49
+
50
+ def set_player_id(self, playerid: PlayerID):
51
+ self.device.light.setPlayerID(playerid)
52
+
53
+ def left(self):
54
+ pass
55
+
56
+ def right(self):
57
+ pass
58
+
59
+ def up(self):
60
+ pass
61
+
62
+ def down(self):
63
+ pass
64
+
65
+ def pause(self):
66
+ pass
67
+
68
+ def rumble(self):
69
+ pass
70
+
71
+ @property
72
+ def name(self) -> str:
73
+ return self._name
74
+
75
+ @name.setter
76
+ def name(self, name: str) -> None:
77
+ self._name = name
78
+
79
+ @property
80
+ def powerlevel(self) -> str:
81
+ return self._powerlevel
82
+
83
+ @powerlevel.setter
84
+ def powerlevel(self, lvl: str) -> None:
85
+ self._powerlevel = lvl
86
+
87
+ @property
88
+ def batterystate(self) -> int:
89
+ return self._batterystate
90
+
91
+ @batterystate.setter
92
+ def batterystate(self, state) -> None:
93
+ self._batterystate = state
@@ -13,6 +13,28 @@ class GenericController(ControlsBase):
13
13
  self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
14
14
  self.numbuttons: int = self.device.get_numbuttons()
15
15
  self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
16
+ self.mapping = {
17
+ "left stick x": self.axis[0],
18
+ "left stick y": self.axis[1],
19
+ "right stick x": self.axis[2],
20
+ "right stick y": self.axis[3],
21
+ "right trigger": self.buttons[7],
22
+ "left trigger": self.buttons[6],
23
+ "dhat x": self.hats[0][0],
24
+ "dhat y": self.hats[0][1],
25
+ "left button": self.buttons[4],
26
+ "right button": self.buttons[5],
27
+ "X button": self.buttons[0],
28
+ "Y button": self.buttons[3],
29
+ "A button": self.buttons[1],
30
+ "B button": self.buttons[2],
31
+ "left stick button": self.buttons[10],
32
+ "right stick button": self.buttons[11],
33
+ "back button": self.buttons[8],
34
+ "start button": self.buttons[9],
35
+ "logo button": None
36
+ }
37
+ print(f"{self.name} connected.")
16
38
 
17
39
  def handle_input(self, event):
18
40
  pass
@@ -34,7 +34,29 @@ class LogitechDualActionController(ControlsBase):
34
34
  self.numbuttons: int = self.device.get_numbuttons()
35
35
  self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
36
36
  self.input_mode = InputMode.DirectInput
37
-
37
+ self.mapping = {
38
+ "left stick x": self.axis[0],
39
+ "left stick y": self.axis[1],
40
+ "right stick x": self.axis[2],
41
+ "right stick y": self.axis[3],
42
+ "right trigger": self.buttons[7],
43
+ "left trigger": self.buttons[6],
44
+ "dhat x": self.hats[0][0],
45
+ "dhat y": self.hats[0][1],
46
+ "left button": self.buttons[4],
47
+ "right button": self.buttons[5],
48
+ "X button": self.buttons[0],
49
+ "Y button": self.buttons[3],
50
+ "A button": self.buttons[1],
51
+ "B button": self.buttons[2],
52
+ "left stick button": self.buttons[10],
53
+ "right stick button": self.buttons[11],
54
+ "back button": self.buttons[8],
55
+ "start button": self.buttons[9],
56
+ "logo button": None
57
+ }
58
+ print(f"{self.name} connected.")
59
+
38
60
  def handle_input(self, event):
39
61
  pass
40
62
 
@@ -34,6 +34,28 @@ class LogitechF310Controller(ControlsBase):
34
34
  self.numbuttons: int = self.device.get_numbuttons()
35
35
  self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
36
36
  self.input_mode = InputMode.XInput
37
+ self.mapping = {
38
+ "left stick x": self.axis[0],
39
+ "left stick y": self.axis[1],
40
+ "right stick x": self.axis[3],
41
+ "right stick y": self.axis[4],
42
+ "right trigger": self.axis[2],
43
+ "left trigger": self.axis[5],
44
+ "dhat x": self.hats[0][0],
45
+ "dhat y": self.hats[0][1],
46
+ "left button": self.buttons[4],
47
+ "right button": self.buttons[5],
48
+ "X button": self.buttons[2],
49
+ "Y button": self.buttons[3],
50
+ "A button": self.buttons[0],
51
+ "B button": self.buttons[1],
52
+ "left stick button": self.buttons[9],
53
+ "right stick button": self.buttons[10],
54
+ "back button": self.buttons[6],
55
+ "start button": self.buttons[7],
56
+ "logo button": self.buttons[8]
57
+ }
58
+ print(f"{self.name} connected.")
37
59
 
38
60
  def handle_input(self, event):
39
61
  pass
@@ -36,7 +36,28 @@ class LogitechF510Controller(ControlsBase):
36
36
  self.numbuttons: int = self.device.get_numbuttons()
37
37
  self.buttons: list = []
38
38
  self.input_mode: InputMode.DirectInput
39
- self.input_connection: ConnectionType.WIRED
39
+ self.mapping = {
40
+ "left stick x": self.axis[0],
41
+ "left stick y": self.axis[1],
42
+ "right stick x": self.axis[3],
43
+ "right stick y": self.axis[4],
44
+ "right trigger": self.axis[2],
45
+ "left trigger": self.axis[5],
46
+ "dhat x": self.hats[0][0],
47
+ "dhat y": self.hats[0][1],
48
+ "left button": self.buttons[4],
49
+ "right button": self.buttons[5],
50
+ "X button": self.buttons[2],
51
+ "Y button": self.buttons[3],
52
+ "A button": self.buttons[0],
53
+ "B button": self.buttons[1],
54
+ "left stick button": self.buttons[9],
55
+ "right stick button": self.buttons[10],
56
+ "back button": self.buttons[6],
57
+ "start button": self.buttons[7],
58
+ "logo button": self.buttons[8]
59
+ }
60
+ print(f"{self.name} connected.")
40
61
 
41
62
  def handle_input(self, event):
42
63
  pass
@@ -36,7 +36,28 @@ class LogitechF710Controller(ControlsBase):
36
36
  self.numbuttons: int = self.device.get_numbuttons()
37
37
  self.buttons: list = []
38
38
  self.input_mode: InputMode.DirectInput
39
- self.input_connection: ConnectionType.WIRED
39
+ self.mapping = {
40
+ "left stick x": self.axis[0],
41
+ "left stick y": self.axis[1],
42
+ "right stick x": self.axis[3],
43
+ "right stick y": self.axis[4],
44
+ "right trigger": self.axis[2],
45
+ "left trigger": self.axis[5],
46
+ "dhat x": self.hats[0][0],
47
+ "dhat y": self.hats[0][1],
48
+ "left button": self.buttons[4],
49
+ "right button": self.buttons[5],
50
+ "X button": self.buttons[2],
51
+ "Y button": self.buttons[3],
52
+ "A button": self.buttons[0],
53
+ "B button": self.buttons[1],
54
+ "left stick button": self.buttons[9],
55
+ "right stick button": self.buttons[10],
56
+ "back button": self.buttons[6],
57
+ "start button": self.buttons[7],
58
+ "logo button": self.buttons[8]
59
+ }
60
+ print(f"{self.name} connected.")
40
61
 
41
62
  def handle_input(self, event):
42
63
  pass
@@ -13,6 +13,29 @@ class XboxSeriesXController:
13
13
  self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
14
14
  self.numbuttons: int = self.device.get_numbuttons()
15
15
  self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
16
+ self.mapping = {
17
+ "left stick x": self.axis[0],
18
+ "left stick y": self.axis[1],
19
+ "right stick x": self.axis[2],
20
+ "right stick y": self.axis[3],
21
+ "right trigger": self.axis[4],
22
+ "left trigger": self.axis[5],
23
+ "dhat x": self.hats[0][0],
24
+ "dhat y": self.hats[0][1],
25
+ "left button": self.buttons[6],
26
+ "right button": self.buttons[7],
27
+ "X button": self.buttons[3],
28
+ "Y button": self.buttons[4],
29
+ "A button": self.buttons[0],
30
+ "B button": self.buttons[1],
31
+ "left stick button": self.buttons[13],
32
+ "right stick button": self.buttons[14],
33
+ "logo button": self.buttons[12],
34
+ "share button": self.buttons[15],
35
+ "list button": self.buttons[11],
36
+ "copy button": self.buttons[10]
37
+ }
38
+ print(f"{self.name} connected.")
16
39
 
17
40
  def handle_input(self, event):
18
41
  pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygameControls
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: A simple controller class for pygame.
5
5
  Home-page:
6
6
  Author: Jan Lerking
@@ -4,7 +4,6 @@ setup.py
4
4
  pygameControls/__init__.py
5
5
  pygameControls/controller.py
6
6
  pygameControls/controlsbase.py
7
- pygameControls/dualsense_audio.py
8
7
  pygameControls/dualsense_controller.py
9
8
  pygameControls/dualsense_edge_controller.py
10
9
  pygameControls/generic_controller.py
@@ -3,7 +3,7 @@ if __name__ == "__main__":
3
3
 
4
4
  setup(
5
5
  name='pygameControls',
6
- version='0.0.4',
6
+ version='0.0.6',
7
7
  packages=find_packages(),
8
8
  install_requires=[],
9
9
  author='Jan Lerking',
@@ -1,70 +0,0 @@
1
- import os
2
- import time
3
- import numpy as np
4
- import sounddevice as sd
5
- import alsaaudio
6
- import pulsectl
7
-
8
- class DualSenseAudio:
9
- def __init__(self):
10
- self.alsa_devices = self._get_alsa_devices()
11
- self.pulse_devices = self._get_pulseaudio_devices()
12
- self.dualsense_device = self._detect_dualsense()
13
-
14
- def _get_alsa_devices(self):
15
- try:
16
- cards = alsaaudio.cards()
17
- return cards
18
- except Exception as e:
19
- print("ALSA detection failed:", e)
20
- return []
21
-
22
- def _get_pulseaudio_devices(self):
23
- try:
24
- pulse = pulsectl.Pulse("dualsense-audio")
25
- sinks = pulse.sink_list()
26
- return sinks
27
- except Exception as e:
28
- print("PulseAudio detection failed:", e)
29
- return []
30
-
31
- def _detect_dualsense(self):
32
- # Check ALSA names
33
- for card in self.alsa_devices:
34
- if "DualSense" in card:
35
- return {'type': 'alsa', 'name': card}
36
-
37
- # Check PulseAudio sinks
38
- for sink in self.pulse_devices:
39
- if "dualsense" in sink.description.lower():
40
- return {'type': 'pulse', 'name': sink.name}
41
-
42
- return None
43
-
44
- def play_tone(self, frequency=440.0, duration=2.0, volume=0.5):
45
- if not self.dualsense_device:
46
- print("DualSense speaker not found.")
47
- return
48
-
49
- print(f"Playing tone on DualSense ({self.dualsense_device['type']})...")
50
-
51
- fs = 48000 # Sample rate
52
- t = np.linspace(0, duration, int(fs * duration), False)
53
- tone = np.sin(frequency * 2 * np.pi * t) * volume
54
- audio = tone.astype(np.float32)
55
-
56
- if self.dualsense_device['type'] == 'pulse':
57
- sd.play(audio, samplerate=fs, device=self.dualsense_device['name'])
58
- elif self.dualsense_device['type'] == 'alsa':
59
- device_index = self.alsa_devices.index(self.dualsense_device['name'])
60
- sd.play(audio, samplerate=fs, device=device_index)
61
- sd.wait()
62
-
63
- def list_devices(self):
64
- print("ALSA Devices:")
65
- for card in self.alsa_devices:
66
- print(f" - {card}")
67
- print("\nPulseAudio Devices:")
68
- for sink in self.pulse_devices:
69
- print(f" - {sink.name} ({sink.description})")
70
-
@@ -1,199 +0,0 @@
1
- import time
2
- import threading
3
- import numpy as np
4
- import sounddevice as sd
5
- import alsaaudio
6
- import pulsectl
7
- from pydualsense import *
8
-
9
-
10
- class DualSenseEdgeController:
11
- def __init__(self):
12
- # DualSense input/output interface
13
- self.ds = pydualsense()
14
- self.ds.init()
15
- self._listening = False
16
- self._bindings = {}
17
-
18
- # Audio detection
19
- self.alsa_devices = self._get_alsa_devices()
20
- self.pulse_devices = self._get_pulseaudio_devices()
21
- self.dualsense_audio_device = self._detect_dualsense_audio()
22
-
23
- print("DualSense initialized.")
24
-
25
- # ---------------------- Device Controls ----------------------
26
-
27
- def set_rumble(self, small_motor: int, big_motor: int):
28
- self.ds.setRumble(small_motor, big_motor)
29
-
30
- def stop_rumble(self):
31
- self.set_rumble(0, 0)
32
-
33
- def set_led_color(self, r: int, g: int, b: int):
34
- self.ds.setLightBarColor(r, g, b)
35
-
36
- def set_trigger_effects(self, left_mode='Off', right_mode='Off', force=0):
37
- left = getattr(TriggerModes, left_mode.upper(), TriggerModes.Off)
38
- right = getattr(TriggerModes, right_mode.upper(), TriggerModes.Off)
39
- self.ds.triggerL.setMode(left)
40
- self.ds.triggerR.setMode(right)
41
- if force > 0:
42
- self.ds.triggerL.setForce(force)
43
- self.ds.triggerR.setForce(force)
44
-
45
- # ---------------------- Predefined Rumble Patterns ----------------------
46
-
47
- def rumble_pattern(self, pattern: str, duration: float = 1.0):
48
- patterns = {
49
- "pulse": self._pulse_rumble,
50
- "heartbeat": self._heartbeat_rumble,
51
- "buzz": self._buzz_rumble,
52
- "wave": self._wave_rumble,
53
- "alarm": self._alarm_rumble,
54
- }
55
- if pattern in patterns:
56
- threading.Thread(target=patterns[pattern], args=(duration,), daemon=True).start()
57
- else:
58
- print(f"Unknown rumble pattern: {pattern}")
59
-
60
- def _pulse_rumble(self, duration):
61
- end = time.time() + duration
62
- while time.time() < end:
63
- self.set_rumble(50, 150)
64
- time.sleep(0.2)
65
- self.stop_rumble()
66
- time.sleep(0.2)
67
-
68
- def _heartbeat_rumble(self, duration):
69
- end = time.time() + duration
70
- while time.time() < end:
71
- self.set_rumble(200, 200)
72
- time.sleep(0.1)
73
- self.stop_rumble()
74
- time.sleep(0.1)
75
- self.set_rumble(100, 100)
76
- time.sleep(0.1)
77
- self.stop_rumble()
78
- time.sleep(0.4)
79
-
80
- def _buzz_rumble(self, duration):
81
- self.set_rumble(80, 255)
82
- time.sleep(duration)
83
- self.stop_rumble()
84
-
85
- def _wave_rumble(self, duration):
86
- start = time.time()
87
- while time.time() - start < duration:
88
- for i in range(0, 256, 25):
89
- self.set_rumble(i, 255 - i)
90
- time.sleep(0.05)
91
- for i in reversed(range(0, 256, 25)):
92
- self.set_rumble(i, 255 - i)
93
- time.sleep(0.05)
94
- self.stop_rumble()
95
-
96
- def _alarm_rumble(self, duration):
97
- end = time.time() + duration
98
- while time.time() < end:
99
- self.set_rumble(255, 0)
100
- time.sleep(0.1)
101
- self.set_rumble(0, 255)
102
- time.sleep(0.1)
103
- self.stop_rumble()
104
-
105
- # ---------------------- Input Listener + Bindings ----------------------
106
-
107
- def bind(self, button: str, action: callable):
108
- """Bind a button to a callable. Ex: controller.bind('cross', lambda: rumble_pattern('buzz'))"""
109
- self._bindings[button] = action
110
-
111
- def start_input_listener(self):
112
- def listen():
113
- while self._listening:
114
- #self.ds.update()
115
- for button, action in self._bindings.items():
116
- if getattr(self.ds, button, False):
117
- action()
118
- self._listening = True
119
- thread = threading.Thread(target=listen, daemon=True)
120
- thread.start()
121
-
122
- def stop_input_listener(self):
123
- self._listening = False
124
-
125
- # ---------------------- Audio Output ----------------------
126
-
127
- def _get_alsa_devices(self):
128
- try:
129
- return alsaaudio.cards()
130
- except Exception:
131
- return []
132
-
133
- def _get_pulseaudio_devices(self):
134
- try:
135
- pulse = pulsectl.Pulse("dualsense-audio")
136
- return pulse.sink_list()
137
- except Exception:
138
- return []
139
-
140
- def _detect_dualsense_audio(self):
141
- # Check ALSA names
142
- for card in self.alsa_devices:
143
- if "DualSense" in card:
144
- return {'type': 'alsa', 'name': card}
145
-
146
- # Check PulseAudio sinks
147
- for sink in self.pulse_devices:
148
- if "dualsense" in sink.description.lower():
149
- return {'type': 'pulse', 'name': sink.name}
150
-
151
- return None
152
-
153
- def play_tone(self, frequency=440.0, duration=2.0, volume=0.5):
154
- if not self.dualsense_audio_device:
155
- print("DualSense speaker not detected.")
156
- return
157
-
158
- print(f"Playing tone on DualSense ({self.dualsense_audio_device['type']})...")
159
-
160
- fs = 48000 # Sample rate
161
- t = np.linspace(0, duration, int(fs * duration), False)
162
- tone = np.sin(frequency * 2 * np.pi * t) * volume
163
- audio = tone.astype(np.float32)
164
-
165
- try:
166
- if self.dualsense_audio_device['type'] == 'pulse':
167
- sd.play(audio, samplerate=fs, device=self.dualsense_audio_device['name'])
168
- elif self.dualsense_audio_device['type'] == 'alsa':
169
- device_index = self.alsa_devices.index(self.dualsense_audio_device['name'])
170
- sd.play(audio, samplerate=fs, device=device_index)
171
- sd.wait()
172
- except Exception as e:
173
- print("Failed to play tone:", e)
174
-
175
- def list_audio_devices(self):
176
- print("ALSA Devices:")
177
- for card in self.alsa_devices:
178
- print(f" - {card}")
179
- print("\nPulseAudio Devices:")
180
- for sink in self.pulse_devices:
181
- print(f" - {sink.name} ({sink.description})")
182
-
183
- # ---------------------- Cleanup ----------------------
184
-
185
- def close(self):
186
- self.ds.close()
187
-
188
- if __name__ == "__main__":
189
-
190
- controller = DualSenseController()
191
-
192
- # Bind buttons to patterns
193
- controller.bind("cross", lambda: controller.rumble_pattern("heartbeat", 1.5))
194
- controller.bind("circle", lambda: controller.rumble_pattern("buzz", 0.5))
195
- controller.bind("triangle", lambda: controller.rumble_pattern("pulse", 2))
196
- controller.bind("square", lambda: controller.set_led_color(255, 0, 0))
197
-
198
- # Start listening
199
- controller.start_input_listener()
File without changes
File without changes
File without changes