summaryrefslogtreecommitdiffstats
path: root/osc_ctrl.py
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2022-10-02 17:24:16 -0700
committeryum <yum.food.vr@gmail.com>2022-10-02 17:24:16 -0700
commit704fd9a64fb8a8b1e929700c3e7413f8c3aaa2c2 (patch)
tree0906bf698d1f4a20eff581ec7a7ea465975b0eaa /osc_ctrl.py
parentf09f444a9c5761da6e6e115e1cddc10a79faa53a (diff)
Add parameters to resize board (likely broken)
... and a bunch of bugfixes: * Shader is now transparent * Simplify shader row/column calculation * Add punctuation to texture * Fix generate.sh * Add lorum_ipsum.txt * Fix how long text is scrolled * Simplify encoding logic in osc_ctrl.py
Diffstat (limited to 'osc_ctrl.py')
-rw-r--r--osc_ctrl.py181
1 files changed, 144 insertions, 37 deletions
diff --git a/osc_ctrl.py b/osc_ctrl.py
index 23b63c2..fcb2445 100644
--- a/osc_ctrl.py
+++ b/osc_ctrl.py
@@ -4,6 +4,7 @@ import argparse
import random
import time
import fileinput
+import generate_utils
from pythonosc import udp_client
from math import ceil
@@ -16,8 +17,8 @@ from generate_utils import NUM_LAYERS
from generate_utils import BOARD_ROWS
from generate_utils import BOARD_COLS
-#MSG_DELAY_S=0.3
-MSG_DELAY_S=0.1
+#CELL_TX_TIME_S=1.0
+CELL_TX_TIME_S=0.6
def usage():
print("python3 -m pip install python-osc")
@@ -30,30 +31,57 @@ args = parser.parse_args()
client = udp_client.SimpleUDPClient(args.i, args.p)
+class EvilGlobalState():
+ # Mapping from ascii char to encoded byte.
+ encoding = {}
+state = EvilGlobalState()
+
+def generateEncoding(state):
+ for i in range(0, 26):
+ state.encoding[chr(ord('A') + i)] = i
+ for i in range(26, 52):
+ state.encoding[chr(ord('a') + i - 26)] = i
+ for i in range(52, 62):
+ state.encoding[chr(ord('0') + i - 52)] = i
+ state.encoding[','] = 62
+ state.encoding['.'] = 63
+ state.encoding[' '] = 64
+ state.encoding['?'] = 65
+ state.encoding['!'] = 66
+ state.encoding[';'] = 67
+ state.encoding[':'] = 68
+ state.encoding['-'] = 69
+ state.encoding['_'] = 70
+ state.encoding["'"] = 71
+ state.encoding['"'] = 72
+
def encodeMessage(lines):
result = []
for line in lines:
for char in line:
- char_int = ord(char)
- if char_int >= ord('A') and char_int <= ord('Z'):
- result.append(ord(char) - ord('A'))
- elif char >= 'a' and char <= 'z':
- result.append((ord(char) - ord('a')) + 26)
- elif char >= '0' and char <= '9':
- result.append((ord(char) - ord('0')) + 52)
- elif char == '.':
- result.append(63)
- elif char == ',':
- result.append(62)
- elif char == ' ':
- result.append(64)
- # Pad message with spaces so that it overwrites any leftover text.
- result += [65] * (BOARD_COLS - len(line))
+ result.append(state.encoding[char])
+ result += [state.encoding[' ']] * (BOARD_COLS - len(line))
#print("Encoded message: {}".format(result))
return result
+def updateCell(cell_idx, letter_encoded, s0, s1, s2):
+ addr="/avatar/parameters/" + getLayerParam(cell_idx)
+ client.send_message(addr, letter_encoded)
+
+ addr="/avatar/parameters/" + getSelectParam(cell_idx, 0)
+ client.send_message(addr, s0)
+
+ addr="/avatar/parameters/" + getSelectParam(cell_idx, 1)
+ client.send_message(addr, s1)
+
+ addr="/avatar/parameters/" + getSelectParam(cell_idx, 2)
+ client.send_message(addr, s2)
+
+# Send a cell all at once.
# `which_cell` is an integer in the range [0,8).
-def sendMessageCell(msg_cell, which_cell):
+def sendMessageCellDiscrete(msg_cell, which_cell):
+ # Really long messages just wrap back around.
+ which_cell = (which_cell % 8)
s0 = ((floor(which_cell / 4) % 2) == 1)
s1 = ((floor(which_cell / 2) % 2) == 1)
@@ -62,22 +90,10 @@ def sendMessageCell(msg_cell, which_cell):
print("Cell s0/s1/s2: {}/{}/{}".format(s0,s1,s2))
# Seek each layer to the current cell.
for i in range(0, len(msg_cell)):
- print("Board index: {}".format(getBoardIndex(i, s0, s1, s2)))
-
- addr="/avatar/parameters/" + getLayerParam(i)
- client.send_message(addr, msg_cell[i])
-
- addr="/avatar/parameters/" + getSelectParam(i, 0)
- client.send_message(addr, (floor(which_cell / 4) % 2) == 1)
-
- addr="/avatar/parameters/" + getSelectParam(i, 1)
- client.send_message(addr, (floor(which_cell / 2) % 2) == 1)
-
- addr="/avatar/parameters/" + getSelectParam(i, 2)
- client.send_message(addr, (which_cell % 2) == 1)
+ updateCell(i, msg_cell[i], s0, s1, s2)
# Wait for convergence.
- time.sleep(MSG_DELAY_S)
+ time.sleep(CELL_TX_TIME_S / 3.0)
# Enable each layer.
# TODO(yum_food) for some reason, if we don't active every layer, the
@@ -87,7 +103,7 @@ def sendMessageCell(msg_cell, which_cell):
client.send_message(addr, True)
# Wait for convergence.
- time.sleep(MSG_DELAY_S)
+ time.sleep(CELL_TX_TIME_S / 3.0)
# Disable each layer.
for i in range(0, NUM_LAYERS):
@@ -95,7 +111,50 @@ def sendMessageCell(msg_cell, which_cell):
client.send_message(addr, False)
# Wait for convergence.
- time.sleep(MSG_DELAY_S)
+ time.sleep(CELL_TX_TIME_S / 3.0)
+
+# Send a cell smoothly spread out over the course of CELL_TX_TIME_S.
+# `which_cell` is an integer in the range [0,8).
+# TODO(yum_food) because we can only reliably update entire cells at once,
+# this method does not work :(
+def sendMessageCellContinuous(msg_cell, which_cell):
+ s0 = ((floor(which_cell / 4) % 2) == 1)
+ s1 = ((floor(which_cell / 2) % 2) == 1)
+ s2 = ((floor(which_cell / 1) % 2) == 1)
+
+ time_quanta = 100
+ dt = CELL_TX_TIME_S / (time_quanta * 1.0)
+
+ # key: time quantum \elem [0, 100)
+ # value: idx to handle
+ update_times = {}
+ enable_times = {}
+ disable_times = {}
+
+ for i in range(0, len(msg_cell)):
+ update_time = int(((i / NUM_LAYERS) + 0.000) * time_quanta) % time_quanta
+ enable_time = int(((i / NUM_LAYERS) + 0.333) * time_quanta) % time_quanta
+ disable_time = int(((i / NUM_LAYERS) + 0.666) * time_quanta) % time_quanta
+
+ update_times[update_time] = i
+ enable_times[enable_time] = i
+ disable_times[disable_time] = i
+
+ for t in range(0, time_quanta):
+ if t in update_times:
+ which_cell = update_times[t]
+ print("which cell: {}".format(which_cell))
+ updateCell(which_cell, msg_cell[which_cell], s0, s1, s2)
+ if t in enable_times:
+ which_cell = enable_times[t]
+ addr="/avatar/parameters/" + getEnableParam(which_cell)
+ client.send_message(addr, True)
+ if t in disable_times:
+ which_cell = disable_times[t]
+ addr="/avatar/parameters/" + getEnableParam(which_cell)
+ client.send_message(addr, False)
+
+ time.sleep(dt)
# The board is broken down into contiguous collections of characters called
# cells. Each cell contains `NUM_LAYERS` characters. We can update one cell
@@ -139,19 +198,67 @@ def sendMessage(msg):
print("Encoded message: {}".format(msg))
+ openBoard()
+
n_cells = ceil(msg_len / NUM_LAYERS)
print("n_cells: {}".format(n_cells))
for cell in range(0, n_cells):
- # Really long messages just wrap back around.
- cell = cell % NUM_LAYERS
+ cell_begin = cell * NUM_LAYERS
+ cell_end = (cell + 1) * NUM_LAYERS
+ cell_msg = msg[cell_begin:cell_end]
+ print("Send cell {}".format(cell))
+ sendMessageCellDiscrete(cell_msg, cell)
+
+ closeBoard()
+def sendRawMessage(msg):
+ n_cells = ceil(len(msg) / NUM_LAYERS)
+ for cell in range(0, n_cells):
cell_begin = cell * NUM_LAYERS
cell_end = (cell + 1) * NUM_LAYERS
cell_msg = msg[cell_begin:cell_end]
print("Send cell {}".format(cell))
- sendMessageCell(cell_msg, cell)
+ sendMessageCellDiscrete(cell_msg, cell)
+
+def clear():
+ sendRawMessage([state.encoding[' ']] * BOARD_ROWS * BOARD_COLS)
+
+def openBoard():
+ addr="/avatar/parameters/" + generate_utils.getResize0Param()
+ client.send_message(addr, False)
+ addr="/avatar/parameters/" + generate_utils.getResize1Param()
+ client.send_message(addr, False)
+
+ time.sleep(0.1)
+
+ addr="/avatar/parameters/" + generate_utils.getResizeEnableParam()
+ client.send_message(addr, True)
+
+ time.sleep(0.1)
+
+ addr="/avatar/parameters/" + generate_utils.getResizeEnableParam()
+ client.send_message(addr, False)
+
+def closeBoard():
+ addr="/avatar/parameters/" + generate_utils.getResize0Param()
+ client.send_message(addr, True)
+ addr="/avatar/parameters/" + generate_utils.getResize1Param()
+ client.send_message(addr, True)
+
+ time.sleep(0.1)
+
+ addr="/avatar/parameters/" + generate_utils.getResizeEnableParam()
+ client.send_message(addr, True)
+
+ time.sleep(0.1)
+
+ addr="/avatar/parameters/" + generate_utils.getResizeEnableParam()
+ client.send_message(addr, False)
if __name__ == "__main__":
+ generateEncoding(state)
+ clear()
+
for line in fileinput.input():
sendMessage(line)