words

Here are published texts relating to my artistic practice and research.

UPIC Ludique: Reimagining Xenakis’s UPIC as a Toy for Drawing Sound.

Blackmore, Simon. “UPIC Ludique: Reimagining Xenakis’s UPIC as a Toy for Drawing Sound.” ECHO, no. 8 (September 7, 2026).
https://doi.org/10.47041/HSDI2354

Drawing Sound: From 20th-Century Experiments to L’UPIC Ludique

Blackmore, Simon. “Drawing Sound: From 20th-Century Experiments to L’UPIC Ludique.” Arts 15, no. 6 (2026): 125.
https://doi.org/10.3390/arts15060125.

L’UPIC Ludique

Blackmore, S. (2025). L’UPIC Ludique. Proceedings of the International Conference on New Interfaces for Musical Expression, 102–103.
https://doi.org/10.5281/zenodo.15028075

Playing Code: Interacting with computers through rhythm

Submitted in partial fulfilment of the requirements for the Degree of Doctor of Philosophy awarded by Oxford Brookes University
Submitted for examination September 2020
PhD Playing Code

Data Transmission as Musical Performance

Simon Blackmore. (2018, July 4). Data Transmission as Musical Performance. 15th Sound and Music Computing Conference (SMC2018), Limassol, Cyprus.
https://doi.org/10.5281/zenodo.1422647

from picamera2 import Picamera2
import cv2
import numpy as np
import random

picam2 = Picamera2()

config = picam2.create_preview_configuration(main={“size”: (640, 480)})
picam2.configure(config)
picam2.start()

def rgb_shift(img, shift=5):
“””Chromatic aberration glitch (safe).”””
b, g, r = cv2.split(img)
b = np.roll(b, shift, axis=1)
r = np.roll(r, -shift, axis=1)
return cv2.merge((b, g, r))

def scanline_glitch(img, intensity=10):
“””Horizontal distortion glitch.”””
out = img.copy()
h, w = img.shape[:2]
for y in range(0, h, 4):
offset = random.randint(-intensity, intensity)
out[y:y+2] = np.roll(out[y:y+2], offset, axis=1)
return out

def block_glitch(img, blocks=4):
“””Scramble blocks without breaking shape.”””
out = img.copy()
h, w = img.shape[:2]

for _ in range(blocks):
x = random.randint(0, w – 40)
y = random.randint(0, h – 40)
bw = random.randint(20, 50)
bh = random.randint(20, 50)

block = out[y:y+bh, x:x+bw].copy()

# shuffle rows only (keeps same shape)
np.random.shuffle(block)

out[y:y+bh, x:x+bw] = block

return out

while True:
frame = picam2.capture_array()

# Ensure 3-channel BGR (some Pi cameras give BGRA)
if frame.shape[2] == 4:
frame = cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR)
print(frame)
print(cv2.mouseY)

# —- Pixelate into 10×10 grid —-
small = cv2.resize(frame, (100, 100), interpolation=cv2.INTER_AREA)
pixelated = cv2.resize(small, (400, 400), interpolation=cv2.INTER_NEAREST)

# —- Apply glitch effects —-
pot1 = random.randint(25,60)
pot2 = random.randint(25,99)
glitch = rgb_shift(pixelated,pot2)
glitch = scanline_glitch(glitch, pot1)
glitch = block_glitch(glitch, 5)

cv2.imshow(“Glitchy Feed”, glitch)

if cv2.waitKey(1) == ord(‘q’):
break

cv2.destroyAllWindows()