Source code for tuxemon.rumble.libshake

# SPDX-License-Identifier: GPL-3.0
# Copyright (c) 2014-2023 William Edwards <shadowapex@gmail.com>, Benjamin Bean <superman2k5@gmail.com>
from ctypes import *
from threading import Thread
from time import sleep
from typing import Any

from tuxemon.rumble.tools import Rumble

Shake_EffectType = c_int
SHAKE_EFFECT_RUMBLE = Shake_EffectType(0)
SHAKE_EFFECT_PERIODIC = Shake_EffectType(1)
SHAKE_EFFECT_CONSTANT = Shake_EffectType(2)
SHAKE_EFFECT_SPRING = Shake_EffectType(3)
SHAKE_EFFECT_FRICTION = Shake_EffectType(4)
SHAKE_EFFECT_DAMPER = Shake_EffectType(5)
SHAKE_EFFECT_INERTIA = Shake_EffectType(6)
SHAKE_EFFECT_RAMP = Shake_EffectType(7)
SHAKE_EFFECT_COUNT = Shake_EffectType(8)

Shake_PeriodicWaveform = c_int
SHAKE_PERIODIC_SQUARE = Shake_PeriodicWaveform(0)
SHAKE_PERIODIC_TRIANGLE = Shake_PeriodicWaveform(1)
SHAKE_PERIODIC_SINE = Shake_PeriodicWaveform(2)
SHAKE_PERIODIC_SAW_UP = Shake_PeriodicWaveform(3)
SHAKE_PERIODIC_SAW_DOWN = Shake_PeriodicWaveform(4)
SHAKE_PERIODIC_CUSTOM = Shake_PeriodicWaveform(5)
SHAKE_PERIODIC_COUNT = Shake_PeriodicWaveform(6)


[docs]class Shake_EffectRumble(Structure): _fields_ = [("strongMagnitude", c_int), ("weakMagnitude", c_int)]
[docs]class Shake_Envelope(Structure): _fields_ = [ ("attackLength", c_int), ("attackLevel", c_int), ("fadeLength", c_int), ("fadeLevel", c_int), ]
[docs]class Shake_EffectPeriodic(Structure): _fields_ = [ ("waveform", Shake_PeriodicWaveform), ("period", c_int), ("magnitude", c_int), ("offset", c_int), ("phase", c_int), ("envelope", Shake_Envelope), ]
[docs]class Shake_Union(Union): _fields_ = [ ("rumble", Shake_EffectRumble), ("periodic", Shake_EffectPeriodic), ]
[docs]class Shake_Effect(Structure): _anonymous_ = "u" _fields_ = [ ("type", Shake_EffectType), ("id", c_int), ("direction", c_int), ("length", c_int), ("delay", c_int), ("u", Shake_Union), ]
[docs]class LibShakeRumble(Rumble): def __init__(self, library: str = "libshake.so") -> None: self.libShake = cdll.LoadLibrary(library) self.libShake.Shake_Init() self.effect_type = SHAKE_EFFECT_PERIODIC self.periodic_waveform = SHAKE_PERIODIC_SINE
[docs] def rumble( self, target: float = 0, period: float = 25, magnitude: float = 24576, length: float = 2, delay: float = 0, attack_length: float = 256, attack_level: float = 0, fade_length: float = 256, fade_level: float = 0, direction: float = 16384, ) -> None: # Target -1 will target all available devices if target == -1: for i in range(self.libShake.Shake_NumOfDevices()): self._start_thread( i, period, magnitude, length, delay, attack_length, attack_level, fade_length, fade_level, direction, ) else: self._start_thread( target, period, magnitude, length, delay, attack_length, attack_level, fade_length, fade_level, direction, )
def _rumble_thread( self, target: float = 0, period: float = 25, magnitude: float = 24576, length: float = 2, delay: float = 0, attack_length: float = 256, attack_level: float = 0, fade_length: float = 256, fade_level: float = 0, direction: float = 16384, ) -> None: if self.libShake.Shake_NumOfDevices() > 0: device = self.libShake.Shake_Open(target) effect = Shake_Effect() self.libShake.Shake_InitEffect(pointer(effect), self.effect_type) if self.effect_type == SHAKE_EFFECT_PERIODIC: effect.periodic.waveform = self.periodic_waveform effect.periodic.period = period effect.periodic.magnitude = magnitude effect.periodic.envelope.attackLengeth = attack_length effect.periodic.envelope.attackLevel = attack_level effect.periodic.envelope.fadeLength = fade_length effect.periodic.envelope.fadeLevel = fade_level effect.direction = direction effect.length = int(length * 1000) effect.delay = delay id = self.libShake.Shake_UploadEffect(device, pointer(effect)) self.libShake.Shake_Play(device, id) sleep(length) self.libShake.Shake_EraseEffect(device, id) self.libShake.Shake_Close(device) def _start_thread( self, target: float = 0, period: float = 25, magnitude: float = 24576, length: float = 2, delay: float = 0, attack_length: float = 256, attack_level: float = 0, fade_length: float = 256, fade_level: float = 0, direction: float = 16384, ) -> None: t = Thread( target=self._rumble_thread, args=( target, period, magnitude, length, delay, attack_length, attack_level, fade_length, fade_level, direction, ), ) t.daemon = True t.start()
[docs] def device_info(self, device: Any) -> None: print("Device #%d" % self.libShake.Shake_DeviceId(device)) print(" Name:", self.libShake.Shake_DeviceName(device)) print( " Adjustable gain:", self.libShake.Shake_QueryGainSupport(device) ) print( " Adjustable autocenter:", self.libShake.Shake_QueryAutocenterSupport(device), ) print( " Effect capacity:", self.libShake.Shake_DeviceEffectCapacity(device), ) print(" Supported effects:") if self.libShake.Shake_QueryEffectSupport(device, SHAKE_EFFECT_RUMBLE): print(" SHAKE_EFFECT_RUMBLE") if self.libShake.Shake_QueryEffectSupport( device, SHAKE_EFFECT_PERIODIC ): print(" SHAKE_EFFECT_PERIODIC") if self.libShake.Shake_QueryWaveformSupport( device, SHAKE_PERIODIC_SQUARE ): print(" * SHAKE_PERIODIC_SQUARE") if self.libShake.Shake_QueryWaveformSupport( device, SHAKE_PERIODIC_TRIANGLE ): print(" * SHAKE_PERIODIC_TRIANGLE") if self.libShake.Shake_QueryWaveformSupport( device, SHAKE_PERIODIC_SINE ): print(" * SHAKE_PERIODIC_SINE") if self.libShake.Shake_QueryWaveformSupport( device, SHAKE_PERIODIC_SAW_UP ): print(" * SHAKE_PERIODIC_SAW_UP") if self.libShake.Shake_QueryWaveformSupport( device, SHAKE_PERIODIC_SAW_DOWN ): print(" * SHAKE_PERIODIC_SAW_DOWN") if self.libShake.Shake_QueryWaveformSupport( device, SHAKE_PERIODIC_CUSTOM ): print(" * SHAKE_PERIODIC_CUSTOM") if self.libShake.Shake_QueryEffectSupport( device, SHAKE_EFFECT_CONSTANT ): print(" SHAKE_EFFECT_CONSTANT") if self.libShake.Shake_QueryEffectSupport(device, SHAKE_EFFECT_SPRING): print(" SHAKE_EFFECT_SPRING") if self.libShake.Shake_QueryEffectSupport( device, SHAKE_EFFECT_FRICTION ): print(" SHAKE_EFFECT_FRICTION") if self.libShake.Shake_QueryEffectSupport(device, SHAKE_EFFECT_DAMPER): print(" SHAKE_EFFECT_DAMPER") if self.libShake.Shake_QueryEffectSupport( device, SHAKE_EFFECT_INERTIA ): print(" SHAKE_EFFECT_INERTIA") if self.libShake.Shake_QueryEffectSupport(device, SHAKE_EFFECT_RAMP): print(" SHAKE_EFFECT_RAMP")
[docs] def device_count(self) -> Any: # Shake_NumOfDevices is supposed to return int return self.libShake.Shake_NumOfDevices()
[docs] def quit(self) -> None: self.libShake.Shake_Quit()