summaryrefslogtreecommitdiffstats
path: root/Scripts
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2023-08-29 23:27:54 -0700
committeryum <yum.food.vr@gmail.com>2023-08-29 23:29:04 -0700
commit444914a701628ca2d1937f8d5cc9a714b478917c (patch)
treed55580cbaebf6bdd8de1a98ebe50a80de70fb1cd /Scripts
parent2daa2c8057cf036357a64e09925487e6f5c0025e (diff)
Fix in-game audio indicator
Also fix prefab default size (no longer colossal). TODO * Add runtime & unity-time toggles
Diffstat (limited to 'Scripts')
-rw-r--r--Scripts/generate_params.py4
-rw-r--r--Scripts/generate_utils.py3
-rw-r--r--Scripts/libtastt.py137
-rw-r--r--Scripts/libunity.py4
-rw-r--r--Scripts/osc_ctrl.py28
5 files changed, 174 insertions, 2 deletions
diff --git a/Scripts/generate_params.py b/Scripts/generate_params.py
index 8daf2dc..1f635e6 100644
--- a/Scripts/generate_params.py
+++ b/Scripts/generate_params.py
@@ -61,6 +61,10 @@ def generate():
params["PARAM_NAME"] = generate_utils.getEllipsisParam()
result += generate_utils.replaceMacros(BOOL_PARAM, params)
+ for i in range(5):
+ params["PARAM_NAME"] = generate_utils.getSoundParam(i+1)
+ result += generate_utils.replaceMacros(BOOL_PARAM, params)
+
params["PARAM_NAME"] = generate_utils.getScaleParam()
params["DEFAULT_FLOAT"] = "0.05"
result += generate_utils.replaceMacros(FLOAT_PARAM, params)
diff --git a/Scripts/generate_utils.py b/Scripts/generate_utils.py
index aaae3dc..395eaf7 100644
--- a/Scripts/generate_utils.py
+++ b/Scripts/generate_utils.py
@@ -81,6 +81,9 @@ def getSelectParam() -> str:
def getEnableParam():
return "TaSTT_Enable"
+def getSoundParam(i: int):
+ return f"TaSTT_Sound{str(i)}"
+
def getEllipsisParam():
return "TaSTT_Ellipsis"
diff --git a/Scripts/libtastt.py b/Scripts/libtastt.py
index f941cee..12f9056 100644
--- a/Scripts/libtastt.py
+++ b/Scripts/libtastt.py
@@ -155,6 +155,88 @@ AnimationClip:
m_Events: []
"""
+SOUND_ANIMATION_TEMPLATE = """
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!74 &7400000
+AnimationClip:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: Sound1_On
+ serializedVersion: 6
+ m_Legacy: 0
+ m_Compressed: 0
+ m_UseHighQualityCurve: 1
+ m_RotationCurves: []
+ m_CompressedRotationCurves: []
+ m_EulerCurves: []
+ m_PositionCurves: []
+ m_ScaleCurves: []
+ m_FloatCurves:
+ - curve:
+ serializedVersion: 2
+ m_Curve:
+ - serializedVersion: 3
+ time: 0
+ value: 1
+ inSlope: Infinity
+ outSlope: Infinity
+ tangentMode: 103
+ weightedMode: 0
+ inWeight: 0
+ outWeight: 0
+ m_PreInfinity: 2
+ m_PostInfinity: 2
+ m_RotationOrder: 4
+ attribute: m_IsActive
+ path: World Constraint/Container/TaSTT/Audio 1
+ classID: 1
+ script: {fileID: 0}
+ m_PPtrCurves: []
+ m_SampleRate: 60
+ m_WrapMode: 0
+ m_Bounds:
+ m_Center: {x: 0, y: 0, z: 0}
+ m_Extent: {x: 0, y: 0, z: 0}
+ m_ClipBindingConstant:
+ genericBindings:
+ - serializedVersion: 2
+ path: 2267216663
+ attribute: 2086281974
+ script: {fileID: 0}
+ typeID: 1
+ customType: 0
+ isPPtrCurve: 0
+ pptrCurveMapping: []
+ m_AnimationClipSettings:
+ serializedVersion: 2
+ m_AdditiveReferencePoseClip: {fileID: 0}
+ m_AdditiveReferencePoseTime: 0
+ m_StartTime: 0
+ m_StopTime: 0
+ m_OrientationOffsetY: 0
+ m_Level: 0
+ m_CycleOffset: 0
+ m_HasAdditiveReferencePose: 0
+ m_LoopTime: 1
+ m_LoopBlend: 0
+ m_LoopBlendOrientation: 0
+ m_LoopBlendPositionY: 0
+ m_LoopBlendPositionXZ: 0
+ m_KeepOriginalOrientation: 0
+ m_KeepOriginalPositionY: 1
+ m_KeepOriginalPositionXZ: 0
+ m_HeightFromFeet: 0
+ m_Mirror: 0
+ m_EditorCurves: []
+ m_EulerEditorCurves: []
+ m_HasGenericRootTransform: 0
+ m_HasMotionFloatCurves: 0
+ m_Events: []
+"""
+
LETTER_ANIMATION_TEMPLATE = """
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
@@ -390,6 +472,40 @@ def generateClearAnimation(anim_dir, guid_map):
guid_map[anim_path] = meta.guid
guid_map[meta.guid] = anim_path
+# value: 0 or 1
+def generateSoundAnimation(nth_sound: int, value: int, anim_name: str, anim_dir: str, guid_map: typing.Dict[str, str]):
+ print(f"Generating sound {nth_sound} animation", file=sys.stderr)
+
+ parser = libunity.UnityParser()
+ parser.parse(SOUND_ANIMATION_TEMPLATE)
+
+ anim_node = parser.nodes[0]
+ anim_clip = anim_node.mapping['AnimationClip']
+ curve_template = anim_clip.mapping['m_FloatCurves'].sequence[0]
+ anim_clip.mapping['m_FloatCurves'].sequence = []
+ anim_clip.mapping['m_EditorCurves'].sequence = []
+
+ curve = curve_template.copy()
+ for keyframe in curve.mapping['curve'].mapping['m_Curve'].sequence:
+ keyframe.mapping['value'] = str(value)
+ curve.mapping['path'] = f"World Constraint/Container/TaSTT/Audio {nth_sound}"
+ # Add curve to animation
+ anim_clip.mapping['m_FloatCurves'].sequence.append(curve)
+ anim_clip.mapping['m_EditorCurves'].sequence.append(curve)
+
+ # Serialize animation to file
+ anim_path = os.path.join(anim_dir, anim_name + ".anim")
+ print("Generating sound animation at {}".format(anim_path), file=sys.stderr)
+ with open(anim_path, "w", encoding="utf-8") as f:
+ f.write(libunity.unityYamlToString([anim_node]))
+ # Generate metadata
+ meta = libunity.Metadata()
+ with open(anim_path + ".meta", "w", encoding="utf-8") as f:
+ f.write(str(meta))
+ # Add metadata to guid map
+ guid_map[anim_path] = meta.guid
+ guid_map[meta.guid] = anim_path
+
# Generate a toggle animation for a shader parameter.
def generateToggleAnimations(anim_dir, shader_param, guid_map):
print("Generating shader toggle animation", file=sys.stderr)
@@ -482,6 +598,12 @@ def generateScaleAnimation(anim_name: str, anim_dir: str,
def generateAnimations(anim_dir, guid_map):
generateClearAnimation(anim_dir, guid_map)
+ for i in range(5):
+ anim_name = generate_utils.getSoundParam(i+1) + "_Off"
+ generateSoundAnimation(i+1, 0, anim_name, anim_dir, guid_map)
+ anim_name = generate_utils.getSoundParam(i+1) + "_On"
+ generateSoundAnimation(i+1, 1, anim_name, anim_dir, guid_map)
+
print("Generating letter animations", file=sys.stderr)
parser = libunity.UnityParser()
@@ -544,6 +666,11 @@ def generateFXController(anim: libunity.UnityAnimator) -> typing.Dict[int, libun
anim.addParameter(generate_utils.getClearBoardParam(), bool)
anim.addParameter(generate_utils.getScaleParam(), float)
+ for i in range(5):
+ anim.addParameter(generate_utils.getSoundParam(i+1), bool)
+
+ anim.addLayer("=== TaSTT ===", weight=0.0)
+
layers = {}
for byte in range(0, generate_utils.config.BYTES_PER_CHAR):
layers[byte] = {}
@@ -724,6 +851,16 @@ def generateFX(guid_map, gen_anim_dir):
"TaSTT_Emerge_000.anim",
"TaSTT_Emerge_100.anim",
anim, guid_map, 0.5)
+
+ for i in range(5):
+ param_name = generate_utils.getSoundParam(i+1)
+ generateToggle(f"TaSTT_Audio{i+1}",
+ param_name,
+ gen_anim_dir,
+ param_name + "_Off.anim",
+ param_name + "_On.anim",
+ anim, guid_map)
+
generateScaleLayer(anim, gen_anim_dir, guid_map)
return anim
diff --git a/Scripts/libunity.py b/Scripts/libunity.py
index 9168057..cd8174d 100644
--- a/Scripts/libunity.py
+++ b/Scripts/libunity.py
@@ -598,7 +598,7 @@ class UnityAnimator():
ctrl = param.addChildMapping('m_Controller')
ctrl.mapping['fileID'] = anim.anchor
- def addLayer(self, layer_name, add_to_head = False) -> UnityDocument:
+ def addLayer(self, layer_name, add_to_head = False, weight: float = 1.0) -> UnityDocument:
# Add layer to controller
anim = self.peekNodeOfClass('91')
layers = anim.mapping['AnimatorController'].mapping['m_AnimatorLayers']
@@ -612,7 +612,7 @@ class UnityAnimator():
layer.addChildSequence('m_Behaviours')
layer.mapping['m_BlendingMode'] = '0'
layer.mapping['m_SyncedLayerIndex'] = '-1'
- layer.mapping['m_DefaultWeight'] = '1'
+ layer.mapping['m_DefaultWeight'] = str(weight)
layer.mapping['m_IKPass'] = '0'
layer.mapping['m_SyncedLayerAffectsTiming'] = '0'
layer.addChildMapping('m_Controller').mapping['fileID'] = anim.anchor
diff --git a/Scripts/osc_ctrl.py b/Scripts/osc_ctrl.py
index b1ec765..ad5667f 100644
--- a/Scripts/osc_ctrl.py
+++ b/Scripts/osc_ctrl.py
@@ -8,6 +8,7 @@ from pythonosc import udp_client
import argparse
import generate_utils
+import random
import time
# Based on a couple experiments, this seems like about as fast as we can go
@@ -76,6 +77,11 @@ def clear(osc_state: OscState):
osc_state.reset()
+# Note: `nth_audio` is 1-indexed
+def playAudio(osc_state: OscState, nth_audio: int, value: bool):
+ addr="/avatar/parameters/" + generate_utils.getSoundParam(nth_audio)
+ osc_state.client.send_message(addr, value)
+
def updateRegion(client, region_idx, letter_encoded):
for byte in range(0, generate_utils.config.BYTES_PER_CHAR):
addr="/avatar/parameters/" + generate_utils.getBlendParam(region_idx, byte)
@@ -90,7 +96,29 @@ def pageMessage(osc_state: OscState, msg: str, estate: EmotesState) -> bool:
msg_slice, slice_idx = osc_state.pager.getNextSlice(msg)
if slice_idx == -1:
+ for i in range(5):
+ playAudio(osc_state, i+1, False)
return True
+
+ sounds_to_make = set()
+ letter_i = 1
+ for letter in ["a", "e", "i", "o", "u"]:
+ if letter in msg_slice:
+ sounds_to_make.add(letter_i)
+ letter_i += 1
+ if len(sounds_to_make) == 0:
+ for i in range(5):
+ playAudio(osc_state, i+1, False)
+ else:
+ sound_to_make = random.sample(sounds_to_make, 1)[0]
+ for i in range(5):
+ if i+1 == sound_to_make:
+ # TODO(yum) think about making this probabilistic
+ print(f"Playing sound {i+1}")
+ playAudio(osc_state, i+1, True)
+ else:
+ playAudio(osc_state, i+1, False)
+
#print("sending page {}: {} ({})".format(slice_idx, msg_slice,
# len(msg_slice)))