vmcp.events
events
module of vmcp
package.
1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# SPDX-License-Identifier: AGPL-3.0-or-later 4 5"""``events`` module of ``vmcp`` package.""" 6 7from dataclasses import dataclass 8from abc import ABCMeta, abstractmethod 9from typing import ( 10 ClassVar, 11 Any 12) 13from .typing import ( 14 CoordinateVector, 15 Quaternion, 16 Scale, 17 Bone, 18 DeviceType, 19 ModelState, 20 CalibrationState, 21 CalibrationMode, 22 TrackingState 23) 24 25 26@dataclass(frozen=True, slots=True) # type: ignore 27class Event(metaclass=ABCMeta): 28 """Abstract event class.""" 29 30 ADDRESS_PATTERN: ClassVar[str] 31 """str: OSC address pattern matching.""" 32 33 channel: str 34 """str: Channel name.""" 35 36 address: str 37 """str: Called OSC address.""" 38 39 def __post_init__(self) -> None: 40 """Post event initialization. 41 42 Raises: 43 NotImplementedError: 44 If abstract `Event` is instantiated directly. 45 46 """ 47 # pylint: disable=unidiomatic-typecheck 48 if type(self) is Event: 49 raise NotImplementedError 50 51 @classmethod 52 @abstractmethod 53 def from_message_data( 54 cls, 55 channel: str, 56 address: str, 57 arguments: tuple[Any, ...] 58 ) -> 'Event': 59 """Abstract event constructor. 60 61 Args: 62 channel (str): 63 Channel name. 64 address (str): 65 OSC address. 66 arguments (tuple[Any, ...]): 67 OSC arguments. 68 69 Returns: 70 Event: 71 Instance. 72 73 Raises: 74 ValueError: 75 If invalid arguments are given. 76 77 """ 78 79 80@dataclass(frozen=True, slots=True) # type: ignore 81class TransformEvent(Event, metaclass=ABCMeta): 82 """Abstract transform event class.""" 83 84 joint: str 85 """str: Joint name.""" 86 87 position: CoordinateVector 88 """CoordinateVector: 3D position.""" 89 90 rotation: Quaternion 91 """Quaternion: 3D rotation.""" 92 93 def __post_init__(self) -> None: 94 """Post event initialization. 95 96 Raises: 97 NotImplementedError: 98 If abstract `TransformEvent` is instantiated directly. 99 100 """ 101 # pylint: disable=unidiomatic-typecheck 102 if type(self) is TransformEvent: 103 raise NotImplementedError 104 105 106@dataclass(frozen=True, slots=True) 107class RootTransformEvent(TransformEvent): 108 """Root transform event.""" 109 110 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/Root/Pos" 111 """str: OSC address pattern matching.""" 112 113 scale: Scale 114 """Scale: Additional scaling (division).""" 115 116 offset: CoordinateVector 117 """CoordinateVector: Additional (negative) offset.""" 118 119 @classmethod 120 def from_message_data( 121 cls, 122 channel: str, 123 address: str, 124 arguments: tuple[Any, ...] 125 ) -> 'RootTransformEvent': 126 """Abstract event constructor. 127 128 Args: 129 channel (str): 130 Channel name. 131 address (str): 132 OSC address. 133 arguments (tuple[Any, ...]): 134 OSC arguments. 135 136 Returns: 137 RootTransformEvent: 138 Instance. 139 140 Raises: 141 ValueError: 142 If invalid arguments are given. 143 144 """ 145 scale_width: float = 1.0 146 scale_heigth: float = 1.0 147 scale_length: float = 1.0 148 offset_x: float = 0.0 149 offset_y: float = 0.0 150 offset_z: float = 0.0 151 match len(arguments): 152 case 14: 153 # Since VMC protocol specification v2.1.0. 154 scale_width = arguments[8] 155 scale_heigth = arguments[9] 156 scale_length = arguments[10] 157 offset_x = arguments[11] 158 offset_y = arguments[12] 159 offset_z = arguments[13] 160 case 8: 161 # Since VMC protocol specification v2.0.0. 162 pass 163 case _: 164 raise ValueError(f"Invalid arguments: {arguments}") 165 return cls( 166 str(channel), 167 str(address), 168 joint=str(arguments[0]), 169 position=CoordinateVector( 170 x=arguments[1], 171 y=arguments[2], 172 z=arguments[3] 173 ), 174 rotation=Quaternion( 175 x=arguments[4], 176 y=arguments[5], 177 z=arguments[6], 178 w=arguments[7] 179 ), 180 scale=Scale( 181 scale_width, 182 scale_heigth, 183 scale_length 184 ), 185 offset=CoordinateVector( 186 x=offset_x, 187 y=offset_y, 188 z=offset_z 189 ) 190 ) 191 192 193@dataclass(frozen=True, slots=True) 194class BoneTransformEvent(TransformEvent): 195 """Bone transform event.""" 196 197 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/Bone/Pos" 198 """str: OSC address pattern matching.""" 199 200 joint: Bone 201 """Bone: Joint bone.""" 202 203 @classmethod 204 def from_message_data( 205 cls, 206 channel: str, 207 address: str, 208 arguments: tuple[Any, ...] 209 ) -> 'BoneTransformEvent': 210 """Abstract event constructor. 211 212 Args: 213 channel (str): 214 Channel name. 215 address (str): 216 OSC address. 217 arguments (tuple[Any, ...]): 218 OSC arguments. 219 220 Returns: 221 BoneTransformEvent: 222 Instance. 223 224 Raises: 225 ValueError: 226 If invalid arguments are given. 227 228 """ 229 return cls( 230 str(channel), 231 str(address), 232 joint=Bone(arguments[0]), 233 position=CoordinateVector( 234 x=arguments[1], 235 y=arguments[2], 236 z=arguments[3] 237 ), 238 rotation=Quaternion( 239 x=arguments[4], 240 y=arguments[5], 241 z=arguments[6], 242 w=arguments[7] 243 ) 244 ) 245 246 247@dataclass(frozen=True, slots=True) 248class DeviceTransformEvent(TransformEvent): 249 """Device transform receiving event.""" 250 251 ADDRESS_PATTERN: ClassVar[str] = ( 252 f"/VMC/Ext/{{{','.join([t.value for t in DeviceType])}}}//" 253 ) 254 """str: OSC address pattern matching.""" 255 256 joint: str 257 """str: OpenVR device label or serial.""" 258 259 device_type: DeviceType 260 """DeviceType: Device type.""" 261 262 is_local: bool 263 """bool: If transform is relative to avatar, word space otherwise.""" 264 265 @classmethod 266 def from_message_data( 267 cls, 268 channel: str, 269 address: str, 270 arguments: tuple[Any, ...] 271 ) -> 'DeviceTransformEvent': 272 """Abstract event constructor. 273 274 Args: 275 channel (str): 276 Channel name. 277 address (str): 278 OSC address. 279 arguments (tuple[Any, ...]): 280 OSC arguments. 281 282 Returns: 283 DeviceTransformEvent: 284 Instance. 285 286 Raises: 287 ValueError: 288 If invalid arguments are given. 289 290 """ 291 return cls( 292 str(channel), 293 str(address), 294 joint=str(arguments[0]), 295 position=CoordinateVector( 296 x=arguments[1], 297 y=arguments[2], 298 z=arguments[3] 299 ), 300 rotation=Quaternion( 301 x=arguments[4], 302 y=arguments[5], 303 z=arguments[6], 304 w=arguments[7] 305 ), 306 device_type=DeviceType(address.split('/')[3]), 307 is_local=bool(address.count('/') > 4) 308 ) 309 310 311@dataclass(frozen=True, slots=True) 312class BlendShapeEvent(Event): 313 """Blend shape event.""" 314 315 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/Blend/Val" 316 """str: OSC address pattern matching.""" 317 318 key: str 319 """str: Blend shape key.""" 320 321 value: float 322 """float: Blend shape value.""" 323 324 @classmethod 325 def from_message_data( 326 cls, 327 channel: str, 328 address: str, 329 arguments: tuple[Any, ...] 330 ) -> 'BlendShapeEvent': 331 """Abstract event constructor. 332 333 Args: 334 channel (str): 335 Channel name. 336 address (str): 337 OSC address. 338 arguments (tuple[Any, ...]): 339 OSC arguments. 340 341 Returns: 342 BlendShapeEvent: 343 Instance. 344 345 Raises: 346 ValueError: 347 If invalid arguments are given. 348 349 """ 350 return cls( 351 str(channel), 352 str(address), 353 key=arguments[0], 354 value=arguments[1] 355 ) 356 357 358@dataclass(frozen=True, slots=True) 359class BlendShapeApplyEvent(Event): 360 """Blend shape apply event.""" 361 362 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/Blend/Apply" 363 """str: OSC address pattern matching.""" 364 365 @classmethod 366 def from_message_data( 367 cls, 368 channel: str, 369 address: str, 370 arguments: tuple[Any, ...] 371 ) -> 'BlendShapeApplyEvent': 372 """Abstract event constructor. 373 374 Args: 375 channel (str): 376 Channel name. 377 address (str): 378 OSC address. 379 arguments (tuple[Any, ...]): 380 OSC arguments. 381 382 Returns: 383 BlendShapeApplyEvent: 384 Instance. 385 386 Raises: 387 ValueError: 388 If invalid arguments are given. 389 390 """ 391 if len(arguments) != 0: 392 raise ValueError(f"Arguments not empty: {arguments}") 393 return cls( 394 channel, 395 address 396 ) 397 398 399@dataclass(frozen=True, slots=True) 400class StateEvent(Event): 401 """Availability state event.""" 402 403 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/OK" 404 """str: OSC address pattern matching.""" 405 406 model_state: ModelState 407 """ModelState: Model state.""" 408 409 calibration_state: CalibrationState | None 410 """CalibrationState | None: Calibration state.""" 411 412 calibration_mode: CalibrationMode | None 413 """CalibrationMode | None: Calibration mode.""" 414 415 tracking_state: TrackingState | None 416 """TrackingState | None: Tracking state.""" 417 418 @classmethod 419 def from_message_data( 420 cls, 421 channel: str, 422 address: str, 423 arguments: tuple[Any, ...] 424 ) -> 'StateEvent': 425 """Abstract event constructor. 426 427 Args: 428 channel (str): 429 Channel name. 430 address (str): 431 OSC address. 432 arguments (tuple[Any, ...]): 433 OSC arguments. 434 435 Returns: 436 StateEvent: 437 Instance. 438 439 Raises: 440 ValueError: 441 If invalid arguments are given. 442 443 """ 444 calibration_state: CalibrationState | None = None 445 calibration_mode: CalibrationMode | None = None 446 tracking_state: TrackingState | None = None 447 match len(arguments): 448 case 4: 449 # Since VMC protocol specification v2.7.0. 450 calibration_state = CalibrationState(arguments[1]) 451 calibration_mode = CalibrationMode(arguments[2]) 452 tracking_state = TrackingState(arguments[3]) 453 case 3: 454 # Since VMC protocol specification v2.5.0. 455 calibration_state = CalibrationState(arguments[1]) 456 calibration_mode = CalibrationMode(arguments[2]) 457 case 1: 458 pass 459 case _: 460 raise ValueError(f"Invalid arguments: {arguments}") 461 return cls( 462 str(channel), 463 str(address), 464 model_state=ModelState(arguments[0]), 465 calibration_state=calibration_state, 466 calibration_mode=calibration_mode, 467 tracking_state=tracking_state 468 ) 469 470 471@dataclass(frozen=True, slots=True) 472class RelativeTimeEvent(Event): 473 """Relative time event.""" 474 475 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/T" 476 """str: OSC address pattern matching.""" 477 478 delta: float 479 """float: Relative frame time.""" 480 481 @classmethod 482 def from_message_data( 483 cls, 484 channel: str, 485 address: str, 486 arguments: tuple[Any, ...] 487 ) -> 'RelativeTimeEvent': 488 """Abstract event constructor. 489 490 Args: 491 channel (str): 492 Channel name. 493 address (str): 494 OSC address. 495 arguments (tuple[Any, ...]): 496 OSC arguments. 497 498 Returns: 499 RelativeTimeEvent: 500 Instance. 501 502 Raises: 503 ValueError: 504 If invalid arguments are given. 505 506 """ 507 if len(arguments) != 1: 508 raise ValueError(f"Invalid arguments: {arguments}") 509 return cls( 510 str(channel), 511 str(address), 512 delta=float(arguments[0]) 513 )
27@dataclass(frozen=True, slots=True) # type: ignore 28class Event(metaclass=ABCMeta): 29 """Abstract event class.""" 30 31 ADDRESS_PATTERN: ClassVar[str] 32 """str: OSC address pattern matching.""" 33 34 channel: str 35 """str: Channel name.""" 36 37 address: str 38 """str: Called OSC address.""" 39 40 def __post_init__(self) -> None: 41 """Post event initialization. 42 43 Raises: 44 NotImplementedError: 45 If abstract `Event` is instantiated directly. 46 47 """ 48 # pylint: disable=unidiomatic-typecheck 49 if type(self) is Event: 50 raise NotImplementedError 51 52 @classmethod 53 @abstractmethod 54 def from_message_data( 55 cls, 56 channel: str, 57 address: str, 58 arguments: tuple[Any, ...] 59 ) -> 'Event': 60 """Abstract event constructor. 61 62 Args: 63 channel (str): 64 Channel name. 65 address (str): 66 OSC address. 67 arguments (tuple[Any, ...]): 68 OSC arguments. 69 70 Returns: 71 Event: 72 Instance. 73 74 Raises: 75 ValueError: 76 If invalid arguments are given. 77 78 """
Abstract event class.
52 @classmethod 53 @abstractmethod 54 def from_message_data( 55 cls, 56 channel: str, 57 address: str, 58 arguments: tuple[Any, ...] 59 ) -> 'Event': 60 """Abstract event constructor. 61 62 Args: 63 channel (str): 64 Channel name. 65 address (str): 66 OSC address. 67 arguments (tuple[Any, ...]): 68 OSC arguments. 69 70 Returns: 71 Event: 72 Instance. 73 74 Raises: 75 ValueError: 76 If invalid arguments are given. 77 78 """
Abstract event constructor.
Args: channel (str): Channel name. address (str): OSC address. arguments (tuple[Any, ...]): OSC arguments.
Returns: Event: Instance.
Raises: ValueError: If invalid arguments are given.
81@dataclass(frozen=True, slots=True) # type: ignore 82class TransformEvent(Event, metaclass=ABCMeta): 83 """Abstract transform event class.""" 84 85 joint: str 86 """str: Joint name.""" 87 88 position: CoordinateVector 89 """CoordinateVector: 3D position.""" 90 91 rotation: Quaternion 92 """Quaternion: 3D rotation.""" 93 94 def __post_init__(self) -> None: 95 """Post event initialization. 96 97 Raises: 98 NotImplementedError: 99 If abstract `TransformEvent` is instantiated directly. 100 101 """ 102 # pylint: disable=unidiomatic-typecheck 103 if type(self) is TransformEvent: 104 raise NotImplementedError
Abstract transform event class.
Inherited Members
107@dataclass(frozen=True, slots=True) 108class RootTransformEvent(TransformEvent): 109 """Root transform event.""" 110 111 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/Root/Pos" 112 """str: OSC address pattern matching.""" 113 114 scale: Scale 115 """Scale: Additional scaling (division).""" 116 117 offset: CoordinateVector 118 """CoordinateVector: Additional (negative) offset.""" 119 120 @classmethod 121 def from_message_data( 122 cls, 123 channel: str, 124 address: str, 125 arguments: tuple[Any, ...] 126 ) -> 'RootTransformEvent': 127 """Abstract event constructor. 128 129 Args: 130 channel (str): 131 Channel name. 132 address (str): 133 OSC address. 134 arguments (tuple[Any, ...]): 135 OSC arguments. 136 137 Returns: 138 RootTransformEvent: 139 Instance. 140 141 Raises: 142 ValueError: 143 If invalid arguments are given. 144 145 """ 146 scale_width: float = 1.0 147 scale_heigth: float = 1.0 148 scale_length: float = 1.0 149 offset_x: float = 0.0 150 offset_y: float = 0.0 151 offset_z: float = 0.0 152 match len(arguments): 153 case 14: 154 # Since VMC protocol specification v2.1.0. 155 scale_width = arguments[8] 156 scale_heigth = arguments[9] 157 scale_length = arguments[10] 158 offset_x = arguments[11] 159 offset_y = arguments[12] 160 offset_z = arguments[13] 161 case 8: 162 # Since VMC protocol specification v2.0.0. 163 pass 164 case _: 165 raise ValueError(f"Invalid arguments: {arguments}") 166 return cls( 167 str(channel), 168 str(address), 169 joint=str(arguments[0]), 170 position=CoordinateVector( 171 x=arguments[1], 172 y=arguments[2], 173 z=arguments[3] 174 ), 175 rotation=Quaternion( 176 x=arguments[4], 177 y=arguments[5], 178 z=arguments[6], 179 w=arguments[7] 180 ), 181 scale=Scale( 182 scale_width, 183 scale_heigth, 184 scale_length 185 ), 186 offset=CoordinateVector( 187 x=offset_x, 188 y=offset_y, 189 z=offset_z 190 ) 191 )
Root transform event.
120 @classmethod 121 def from_message_data( 122 cls, 123 channel: str, 124 address: str, 125 arguments: tuple[Any, ...] 126 ) -> 'RootTransformEvent': 127 """Abstract event constructor. 128 129 Args: 130 channel (str): 131 Channel name. 132 address (str): 133 OSC address. 134 arguments (tuple[Any, ...]): 135 OSC arguments. 136 137 Returns: 138 RootTransformEvent: 139 Instance. 140 141 Raises: 142 ValueError: 143 If invalid arguments are given. 144 145 """ 146 scale_width: float = 1.0 147 scale_heigth: float = 1.0 148 scale_length: float = 1.0 149 offset_x: float = 0.0 150 offset_y: float = 0.0 151 offset_z: float = 0.0 152 match len(arguments): 153 case 14: 154 # Since VMC protocol specification v2.1.0. 155 scale_width = arguments[8] 156 scale_heigth = arguments[9] 157 scale_length = arguments[10] 158 offset_x = arguments[11] 159 offset_y = arguments[12] 160 offset_z = arguments[13] 161 case 8: 162 # Since VMC protocol specification v2.0.0. 163 pass 164 case _: 165 raise ValueError(f"Invalid arguments: {arguments}") 166 return cls( 167 str(channel), 168 str(address), 169 joint=str(arguments[0]), 170 position=CoordinateVector( 171 x=arguments[1], 172 y=arguments[2], 173 z=arguments[3] 174 ), 175 rotation=Quaternion( 176 x=arguments[4], 177 y=arguments[5], 178 z=arguments[6], 179 w=arguments[7] 180 ), 181 scale=Scale( 182 scale_width, 183 scale_heigth, 184 scale_length 185 ), 186 offset=CoordinateVector( 187 x=offset_x, 188 y=offset_y, 189 z=offset_z 190 ) 191 )
Abstract event constructor.
Args: channel (str): Channel name. address (str): OSC address. arguments (tuple[Any, ...]): OSC arguments.
Returns: RootTransformEvent: Instance.
Raises: ValueError: If invalid arguments are given.
194@dataclass(frozen=True, slots=True) 195class BoneTransformEvent(TransformEvent): 196 """Bone transform event.""" 197 198 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/Bone/Pos" 199 """str: OSC address pattern matching.""" 200 201 joint: Bone 202 """Bone: Joint bone.""" 203 204 @classmethod 205 def from_message_data( 206 cls, 207 channel: str, 208 address: str, 209 arguments: tuple[Any, ...] 210 ) -> 'BoneTransformEvent': 211 """Abstract event constructor. 212 213 Args: 214 channel (str): 215 Channel name. 216 address (str): 217 OSC address. 218 arguments (tuple[Any, ...]): 219 OSC arguments. 220 221 Returns: 222 BoneTransformEvent: 223 Instance. 224 225 Raises: 226 ValueError: 227 If invalid arguments are given. 228 229 """ 230 return cls( 231 str(channel), 232 str(address), 233 joint=Bone(arguments[0]), 234 position=CoordinateVector( 235 x=arguments[1], 236 y=arguments[2], 237 z=arguments[3] 238 ), 239 rotation=Quaternion( 240 x=arguments[4], 241 y=arguments[5], 242 z=arguments[6], 243 w=arguments[7] 244 ) 245 )
Bone transform event.
204 @classmethod 205 def from_message_data( 206 cls, 207 channel: str, 208 address: str, 209 arguments: tuple[Any, ...] 210 ) -> 'BoneTransformEvent': 211 """Abstract event constructor. 212 213 Args: 214 channel (str): 215 Channel name. 216 address (str): 217 OSC address. 218 arguments (tuple[Any, ...]): 219 OSC arguments. 220 221 Returns: 222 BoneTransformEvent: 223 Instance. 224 225 Raises: 226 ValueError: 227 If invalid arguments are given. 228 229 """ 230 return cls( 231 str(channel), 232 str(address), 233 joint=Bone(arguments[0]), 234 position=CoordinateVector( 235 x=arguments[1], 236 y=arguments[2], 237 z=arguments[3] 238 ), 239 rotation=Quaternion( 240 x=arguments[4], 241 y=arguments[5], 242 z=arguments[6], 243 w=arguments[7] 244 ) 245 )
Abstract event constructor.
Args: channel (str): Channel name. address (str): OSC address. arguments (tuple[Any, ...]): OSC arguments.
Returns: BoneTransformEvent: Instance.
Raises: ValueError: If invalid arguments are given.
248@dataclass(frozen=True, slots=True) 249class DeviceTransformEvent(TransformEvent): 250 """Device transform receiving event.""" 251 252 ADDRESS_PATTERN: ClassVar[str] = ( 253 f"/VMC/Ext/{{{','.join([t.value for t in DeviceType])}}}//" 254 ) 255 """str: OSC address pattern matching.""" 256 257 joint: str 258 """str: OpenVR device label or serial.""" 259 260 device_type: DeviceType 261 """DeviceType: Device type.""" 262 263 is_local: bool 264 """bool: If transform is relative to avatar, word space otherwise.""" 265 266 @classmethod 267 def from_message_data( 268 cls, 269 channel: str, 270 address: str, 271 arguments: tuple[Any, ...] 272 ) -> 'DeviceTransformEvent': 273 """Abstract event constructor. 274 275 Args: 276 channel (str): 277 Channel name. 278 address (str): 279 OSC address. 280 arguments (tuple[Any, ...]): 281 OSC arguments. 282 283 Returns: 284 DeviceTransformEvent: 285 Instance. 286 287 Raises: 288 ValueError: 289 If invalid arguments are given. 290 291 """ 292 return cls( 293 str(channel), 294 str(address), 295 joint=str(arguments[0]), 296 position=CoordinateVector( 297 x=arguments[1], 298 y=arguments[2], 299 z=arguments[3] 300 ), 301 rotation=Quaternion( 302 x=arguments[4], 303 y=arguments[5], 304 z=arguments[6], 305 w=arguments[7] 306 ), 307 device_type=DeviceType(address.split('/')[3]), 308 is_local=bool(address.count('/') > 4) 309 )
Device transform receiving event.
266 @classmethod 267 def from_message_data( 268 cls, 269 channel: str, 270 address: str, 271 arguments: tuple[Any, ...] 272 ) -> 'DeviceTransformEvent': 273 """Abstract event constructor. 274 275 Args: 276 channel (str): 277 Channel name. 278 address (str): 279 OSC address. 280 arguments (tuple[Any, ...]): 281 OSC arguments. 282 283 Returns: 284 DeviceTransformEvent: 285 Instance. 286 287 Raises: 288 ValueError: 289 If invalid arguments are given. 290 291 """ 292 return cls( 293 str(channel), 294 str(address), 295 joint=str(arguments[0]), 296 position=CoordinateVector( 297 x=arguments[1], 298 y=arguments[2], 299 z=arguments[3] 300 ), 301 rotation=Quaternion( 302 x=arguments[4], 303 y=arguments[5], 304 z=arguments[6], 305 w=arguments[7] 306 ), 307 device_type=DeviceType(address.split('/')[3]), 308 is_local=bool(address.count('/') > 4) 309 )
Abstract event constructor.
Args: channel (str): Channel name. address (str): OSC address. arguments (tuple[Any, ...]): OSC arguments.
Returns: DeviceTransformEvent: Instance.
Raises: ValueError: If invalid arguments are given.
312@dataclass(frozen=True, slots=True) 313class BlendShapeEvent(Event): 314 """Blend shape event.""" 315 316 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/Blend/Val" 317 """str: OSC address pattern matching.""" 318 319 key: str 320 """str: Blend shape key.""" 321 322 value: float 323 """float: Blend shape value.""" 324 325 @classmethod 326 def from_message_data( 327 cls, 328 channel: str, 329 address: str, 330 arguments: tuple[Any, ...] 331 ) -> 'BlendShapeEvent': 332 """Abstract event constructor. 333 334 Args: 335 channel (str): 336 Channel name. 337 address (str): 338 OSC address. 339 arguments (tuple[Any, ...]): 340 OSC arguments. 341 342 Returns: 343 BlendShapeEvent: 344 Instance. 345 346 Raises: 347 ValueError: 348 If invalid arguments are given. 349 350 """ 351 return cls( 352 str(channel), 353 str(address), 354 key=arguments[0], 355 value=arguments[1] 356 )
Blend shape event.
325 @classmethod 326 def from_message_data( 327 cls, 328 channel: str, 329 address: str, 330 arguments: tuple[Any, ...] 331 ) -> 'BlendShapeEvent': 332 """Abstract event constructor. 333 334 Args: 335 channel (str): 336 Channel name. 337 address (str): 338 OSC address. 339 arguments (tuple[Any, ...]): 340 OSC arguments. 341 342 Returns: 343 BlendShapeEvent: 344 Instance. 345 346 Raises: 347 ValueError: 348 If invalid arguments are given. 349 350 """ 351 return cls( 352 str(channel), 353 str(address), 354 key=arguments[0], 355 value=arguments[1] 356 )
Abstract event constructor.
Args: channel (str): Channel name. address (str): OSC address. arguments (tuple[Any, ...]): OSC arguments.
Returns: BlendShapeEvent: Instance.
Raises: ValueError: If invalid arguments are given.
359@dataclass(frozen=True, slots=True) 360class BlendShapeApplyEvent(Event): 361 """Blend shape apply event.""" 362 363 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/Blend/Apply" 364 """str: OSC address pattern matching.""" 365 366 @classmethod 367 def from_message_data( 368 cls, 369 channel: str, 370 address: str, 371 arguments: tuple[Any, ...] 372 ) -> 'BlendShapeApplyEvent': 373 """Abstract event constructor. 374 375 Args: 376 channel (str): 377 Channel name. 378 address (str): 379 OSC address. 380 arguments (tuple[Any, ...]): 381 OSC arguments. 382 383 Returns: 384 BlendShapeApplyEvent: 385 Instance. 386 387 Raises: 388 ValueError: 389 If invalid arguments are given. 390 391 """ 392 if len(arguments) != 0: 393 raise ValueError(f"Arguments not empty: {arguments}") 394 return cls( 395 channel, 396 address 397 )
Blend shape apply event.
366 @classmethod 367 def from_message_data( 368 cls, 369 channel: str, 370 address: str, 371 arguments: tuple[Any, ...] 372 ) -> 'BlendShapeApplyEvent': 373 """Abstract event constructor. 374 375 Args: 376 channel (str): 377 Channel name. 378 address (str): 379 OSC address. 380 arguments (tuple[Any, ...]): 381 OSC arguments. 382 383 Returns: 384 BlendShapeApplyEvent: 385 Instance. 386 387 Raises: 388 ValueError: 389 If invalid arguments are given. 390 391 """ 392 if len(arguments) != 0: 393 raise ValueError(f"Arguments not empty: {arguments}") 394 return cls( 395 channel, 396 address 397 )
Abstract event constructor.
Args: channel (str): Channel name. address (str): OSC address. arguments (tuple[Any, ...]): OSC arguments.
Returns: BlendShapeApplyEvent: Instance.
Raises: ValueError: If invalid arguments are given.
400@dataclass(frozen=True, slots=True) 401class StateEvent(Event): 402 """Availability state event.""" 403 404 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/OK" 405 """str: OSC address pattern matching.""" 406 407 model_state: ModelState 408 """ModelState: Model state.""" 409 410 calibration_state: CalibrationState | None 411 """CalibrationState | None: Calibration state.""" 412 413 calibration_mode: CalibrationMode | None 414 """CalibrationMode | None: Calibration mode.""" 415 416 tracking_state: TrackingState | None 417 """TrackingState | None: Tracking state.""" 418 419 @classmethod 420 def from_message_data( 421 cls, 422 channel: str, 423 address: str, 424 arguments: tuple[Any, ...] 425 ) -> 'StateEvent': 426 """Abstract event constructor. 427 428 Args: 429 channel (str): 430 Channel name. 431 address (str): 432 OSC address. 433 arguments (tuple[Any, ...]): 434 OSC arguments. 435 436 Returns: 437 StateEvent: 438 Instance. 439 440 Raises: 441 ValueError: 442 If invalid arguments are given. 443 444 """ 445 calibration_state: CalibrationState | None = None 446 calibration_mode: CalibrationMode | None = None 447 tracking_state: TrackingState | None = None 448 match len(arguments): 449 case 4: 450 # Since VMC protocol specification v2.7.0. 451 calibration_state = CalibrationState(arguments[1]) 452 calibration_mode = CalibrationMode(arguments[2]) 453 tracking_state = TrackingState(arguments[3]) 454 case 3: 455 # Since VMC protocol specification v2.5.0. 456 calibration_state = CalibrationState(arguments[1]) 457 calibration_mode = CalibrationMode(arguments[2]) 458 case 1: 459 pass 460 case _: 461 raise ValueError(f"Invalid arguments: {arguments}") 462 return cls( 463 str(channel), 464 str(address), 465 model_state=ModelState(arguments[0]), 466 calibration_state=calibration_state, 467 calibration_mode=calibration_mode, 468 tracking_state=tracking_state 469 )
Availability state event.
419 @classmethod 420 def from_message_data( 421 cls, 422 channel: str, 423 address: str, 424 arguments: tuple[Any, ...] 425 ) -> 'StateEvent': 426 """Abstract event constructor. 427 428 Args: 429 channel (str): 430 Channel name. 431 address (str): 432 OSC address. 433 arguments (tuple[Any, ...]): 434 OSC arguments. 435 436 Returns: 437 StateEvent: 438 Instance. 439 440 Raises: 441 ValueError: 442 If invalid arguments are given. 443 444 """ 445 calibration_state: CalibrationState | None = None 446 calibration_mode: CalibrationMode | None = None 447 tracking_state: TrackingState | None = None 448 match len(arguments): 449 case 4: 450 # Since VMC protocol specification v2.7.0. 451 calibration_state = CalibrationState(arguments[1]) 452 calibration_mode = CalibrationMode(arguments[2]) 453 tracking_state = TrackingState(arguments[3]) 454 case 3: 455 # Since VMC protocol specification v2.5.0. 456 calibration_state = CalibrationState(arguments[1]) 457 calibration_mode = CalibrationMode(arguments[2]) 458 case 1: 459 pass 460 case _: 461 raise ValueError(f"Invalid arguments: {arguments}") 462 return cls( 463 str(channel), 464 str(address), 465 model_state=ModelState(arguments[0]), 466 calibration_state=calibration_state, 467 calibration_mode=calibration_mode, 468 tracking_state=tracking_state 469 )
Abstract event constructor.
Args: channel (str): Channel name. address (str): OSC address. arguments (tuple[Any, ...]): OSC arguments.
Returns: StateEvent: Instance.
Raises: ValueError: If invalid arguments are given.
472@dataclass(frozen=True, slots=True) 473class RelativeTimeEvent(Event): 474 """Relative time event.""" 475 476 ADDRESS_PATTERN: ClassVar[str] = "/VMC/Ext/T" 477 """str: OSC address pattern matching.""" 478 479 delta: float 480 """float: Relative frame time.""" 481 482 @classmethod 483 def from_message_data( 484 cls, 485 channel: str, 486 address: str, 487 arguments: tuple[Any, ...] 488 ) -> 'RelativeTimeEvent': 489 """Abstract event constructor. 490 491 Args: 492 channel (str): 493 Channel name. 494 address (str): 495 OSC address. 496 arguments (tuple[Any, ...]): 497 OSC arguments. 498 499 Returns: 500 RelativeTimeEvent: 501 Instance. 502 503 Raises: 504 ValueError: 505 If invalid arguments are given. 506 507 """ 508 if len(arguments) != 1: 509 raise ValueError(f"Invalid arguments: {arguments}") 510 return cls( 511 str(channel), 512 str(address), 513 delta=float(arguments[0]) 514 )
Relative time event.
482 @classmethod 483 def from_message_data( 484 cls, 485 channel: str, 486 address: str, 487 arguments: tuple[Any, ...] 488 ) -> 'RelativeTimeEvent': 489 """Abstract event constructor. 490 491 Args: 492 channel (str): 493 Channel name. 494 address (str): 495 OSC address. 496 arguments (tuple[Any, ...]): 497 OSC arguments. 498 499 Returns: 500 RelativeTimeEvent: 501 Instance. 502 503 Raises: 504 ValueError: 505 If invalid arguments are given. 506 507 """ 508 if len(arguments) != 1: 509 raise ValueError(f"Invalid arguments: {arguments}") 510 return cls( 511 str(channel), 512 str(address), 513 delta=float(arguments[0]) 514 )
Abstract event constructor.
Args: channel (str): Channel name. address (str): OSC address. arguments (tuple[Any, ...]): OSC arguments.
Returns: RelativeTimeEvent: Instance.
Raises: ValueError: If invalid arguments are given.