Repository navigation
Palinopsia v1.2.5 : data and rhythm
Palinopsia v1.2.5 : data and rhythm.
A release about marks, steps and the picture read as data. Lowercase is a new source
of machine-cut marks that land on a step and hold, and Signal is a new Sonify voice
that walks the picture with read heads and fires a micro-grain at every bright cell it
crosses : point the one at the other and the marks play themselves. Every layer gains a
Vary of its own that a modulator can fire, a layer's racks can be re-dealt one at a
time, and everything you fire now blinks so you can see it act.
Underneath, the instrument stopped paying for something it should never have paid for.
It reads its own picture back every frame (for the vision features, Sonify's taps and
the depth input), and on a computer whose graphics chip shares memory with the processor
each of those reads stopped the whole pipeline for about 17 ms. Opening the Performance
tab turned one of them on, and the show then spent up to two thirds of every second
waiting inside the graphics driver, with nothing in the app to show it. The reads are queued now
and collected a frame or two later, and the picture never waits for them. The picture itself is
untouched : the same passes, the same formats, the same resolution. (The light output and the
/opsia/av/mark-signal strip still read synchronously : both are off unless you use them.)
Highlights
- Lowercase, a new source. Eight figures of machine-cut marks : a data matrix whose
cells subdivide into one to three narrow bars, blocks, bars, ticks, a scan rule, a
lattice, sprocket ladders down the edges, and one white slab with bars cut out of it.
Everything lands on a step and holds; nothing sweeps. Every deal is a fresh draw, or,
with scroll, the same one slid a cell along : the field read as a stream of data. It pulses on its own, up to 120
steps a second, or plays any rhythm you bind to its gate (a Euclid, a Spastic, an
audio transient). cells runs to 512 : the grids turn to crisp 1-bit static and the
slab becomes a barcode. A sidechain reads another layer one sample per cell, so a
film arrives as a 1-bit halftone of cells on this clock. One accent color marks a
regular lattice of cells, and the previous step trails behind as a filmed projection
does. - Signal, a new Sonify voice, before Chord. Read heads walk the picture on a clock and
every cell they cross that is brighter than a threshold fires one micro-grain : pip,
ping, damped, noise, click, fm, square, tri or pink, from a 0.2 ms tick to a 500 ms
ring. Nothing here is a stored rhythm; the picture is the pattern. One to four heads
each read their own band, and spread pulls their sweeps out of step into a
polymeter that drifts back. Pitch comes from the place along the bar, with a snap
from free frequency to the scale whose middle is microtonal. Every grain lands on its
exact sample rather than on the audio block, a fixed moment after its step, which is
what keeps a fast grid a grid; synced, it runs on the beat clock the Sonify sequencers
share. - A Vary for each layer, under its Speed : the global Vary aimed at one layer alone,
with its own amount. Its button is a modulation target that fires as the modulator
crosses its middle, so a pattern can re-vary a layer; an auto-fire stays out of undo.
Each fire is a variant around where the layer stood, so a modulator can fire it all
night without the layer wandering off. - Re-deal one rack from a layer's right-click menu : the effects of source A, of
source B, or the layer's own, leaving the sources and the other racks alone. Dealt
racks also reach four effects now (they stopped at two, and a source rack came out
empty about half the time). - You see what fires. Every Vary, the Randomize button and the return-to-default
buttons blink when they act, whether by a click, a modulator, a MIDI pad or a key, each
in the color of its kind of action. - The picture readout is free. Measured on an 8 GB Apple-silicon Mac Mini, a blank
1920x1080 session, a 50 Hz display, the Performance tab open, three runs each : 41.9
to 50.0 fps before, a steady 50.0 after. The app's own meter reads 1.4 ms of
processor time per frame instead of 14.2, and the worst single frame 5.5 ms instead
of 42.8. Blocking readback time fell from 560 ms per second to 0.1. - The frame rate reads against your display :
50 fps / 50 Hzin the Performance
tab and in the corner of the preview. The render is locked to the display's refresh
rate, so that rate is the ceiling, not 60, and 24 fps on a display set to 24 Hz is
every frame drawn. The red warning and the frame budget follow the display too, frames
the GPU backlog guard drops are counted asskips, and the GPU and VRAM meters
work on a Mac. - Esc closes a fullscreen output. A plain fullscreen output on one display could
only be left with the window shortcut (Cmd+W, Ctrl+W); a tap of Esc now closes it. On
a projector the control window is not behind, Esc hands focus back to the controls
instead and the show goes on, and an installation keeps its 1.5 s hold, so a brushed
key never ends a show. And on a Mac, screen capture says how to
grant its permission instead of showing a grid of black thumbnails.
Install
| Platform | File |
|---|---|
| Windows | Palinopsia-1.2.5-win-x64.exe (installer) or Palinopsia-1.2.5-portable.exe |
| macOS (Apple Silicon) | Palinopsia-1.2.5-mac-arm64.dmg |
| Linux | Palinopsia-1.2.5-linux-x86_64.AppImage or Palinopsia-1.2.5-linux-amd64.deb |
Builds are unsigned :
- Windows : SmartScreen may warn, click More info → Run anyway.
- macOS (Apple Silicon) : not notarized. Drag Palinopsia into Applications first
(run from the disk image or Downloads, macOS runs a hidden temporary copy), then run
xattr -cr /Applications/Palinopsia.apponce in Terminal, or open it and click Open
Anyway in System Settings → Privacy & Security. The first launch asks for the local
network, and for the camera and the microphone when you use them : accept, or OSC, NDI
and light output stay silent. Screen capture is the one permission macOS never prompts
for : switch Palinopsia on under Privacy & Security → Screen & System Audio Recording,
then start it again. - Linux :
chmod +xthe AppImage, then run it.
Sessions saved with v1.2.0 open and play unchanged : a layer without a Vary amount reads
the default, and a Sonify patch without Signal reads it as off.
Intel Macs (x64) : this release ships Apple Silicon only. On an Intel Mac, build from
source (npm install, then npm run build:mac).
For developers
- Sonify voices are stored by index. A session saves each voice's mixer channel, DJ
filter and sequencer mask by position, and a MIDI on/off binding is
sonify:voice:i. Signal is therefore APPENDED as voice 9 (NVOICE10, a ten-entry
mixFilter, older nine-entry arrays padded on load), andVOICE_ORDERin
SonifyPage.tsxonly shows it before Chord. A new voice goes at the end, always. - Adding a Sonify voice : the two steps that are easy to miss. Claim its tap in the
tick'sneed[]: a voice missing there runs only while ANOTHER voice reads the same
tap, which a test hides whenever Spectra is on (it is by default, on tap 0). And
nothing insetSonify: it now merges every voice block with its default, so a
session saved before a voice existed loads with that voice off instead of crashing
the Sonify page on a missing block. - Signal's scan runs on the main thread, so it reads
sonifyModValuesitself : the
simple-mod overlay ships modulated values to the worklet only, and a scan reading its
base config would ignore every modulator. Onsets carry a per-grain sample delay into
their render block (wait) instead of firing at the block's start. pushSideTex(Compositor) is the counterpart ofpushAudioTex: any ISF source
that declaressideTexreceives its slot's sidechain, keyed on the declaration, so a
new source that reads a layer needs no registration. No layer picked unfeeds the
input, which then reads the bridge's transparent texel : weigh a sidechain by its
alpha and "none" means none.- A modulatable trigger : the layer
varytarget is an EVENT, not a value. The
modulation path folds every driver of a layer into one value a frame (the highest),
andflushVaryEdgestests it once : one fire per upward crossing of the middle,
re-armed below 0.4, never twice inside 60 ms, and none on the first frame a binding
is seen. It hands the fire out throughsetVaryTrigger, which App runs inside
runSilently;runSilentlycommits a pending user edit first. <Blink>(components/Blink.tsx) shows a fired action : given a count it blinks
when the count changes (actions a modulator, a pad or a key can fire :varyPulse,
randPulse, transient store state outside the composition) and only for a change since
it mounted, and without one it blinks on its own button's click, drawn over the page
so it outlives a button that disables or hides itself.- The three rack-size distributions are one constant each in
randomize.ts
(SOURCE_A_RACK,SOURCE_B_RACK,LAYER_RACK) : they used to be nine copies across
every randomizer. src/renderer/src/engine/gridReadback.tsis the small-grid counterpart to
frameCapture.ts: pixel-pack buffers,fenceSyncplus a zero-timeout
clientWaitSync, the newest finished grid wins, andkick()skips rather than waits
when every slot is in flight. It flushes only when the window is NOT painting : a
painting window submits the work itself, and a submit into a full command queue blocks.
A ring hands each landed grid out ONCE : two consumers of one source share a read
(readSonifyGridkeeps each source's grid for the frame), anddropInFlight()is for a
consumer back from a pause.- The cost of a synchronous readback on a shared-memory GPU is the pipeline drain, not
the bytes : 1x1, 32x32 and 256x256 all measured the same. Size is not the knob. PerfStatscarrieshz, the refresh rate of the window's display, anddisplay:hz
returns just that rate. Rates print throughformatHz()(60, not60.00; real
fractional rates such as 59.94 keep their decimals).kiosk:activereports whether THIS session runs as an installation;kiosk:config
reports the stored setting, which stays on after an exit.
Full details in CHANGELOG.md.