Rename crt → osc throughout
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
86
src/osc.nim
Normal file
86
src/osc.nim
Normal file
@@ -0,0 +1,86 @@
|
||||
## CRT Oscilloscope — terminal-based oscilloscope with phosphor physics.
|
||||
##
|
||||
## Features:
|
||||
## - CRT boot/shutdown animations (ported from AetherTune)
|
||||
## - Y-T (time-domain) and X-Y (Lissajous) display modes
|
||||
## - Phosphor persistence with bloom and decay
|
||||
## - Half-block rendering for 2× vertical resolution
|
||||
## - Live audio capture via ffmpeg/PulseAudio or demo signal
|
||||
|
||||
import illwill, os
|
||||
import osc/[effects, phosphor, scope, audio]
|
||||
|
||||
proc exitProc() {.noconv.} =
|
||||
illwillDeinit()
|
||||
showCursor()
|
||||
quit(0)
|
||||
|
||||
proc main() =
|
||||
illwillInit(fullscreen = true)
|
||||
setControlCHook(exitProc)
|
||||
hideCursor()
|
||||
|
||||
let w = terminalWidth()
|
||||
let h = terminalHeight()
|
||||
var tb = newTerminalBuffer(w, h)
|
||||
|
||||
crtTurnOn(tb, w, h)
|
||||
|
||||
var scope = initScope(w, h)
|
||||
var audio = startAudio()
|
||||
var running = true
|
||||
|
||||
while running:
|
||||
if not scope.frozen:
|
||||
audio.readSamples(scope)
|
||||
|
||||
scope.phosphor.decay()
|
||||
|
||||
if not scope.frozen:
|
||||
scope.renderTrace()
|
||||
|
||||
tb = newTerminalBuffer(w, h)
|
||||
scope.phosphor.render(tb)
|
||||
drawGraticule(tb, w, h, scope.grid)
|
||||
drawHUD(tb, w, h, scope, audio.sourceLabel)
|
||||
tb.display()
|
||||
|
||||
let key = getKey()
|
||||
case key
|
||||
of Key.Q, Key.Escape:
|
||||
running = false
|
||||
of Key.M:
|
||||
scope.mode = if scope.mode == ModeYT: ModeXY else: ModeYT
|
||||
of Key.Plus, Key.Equals:
|
||||
scope.gain = min(scope.gain * 1.3, 20.0)
|
||||
of Key.Minus:
|
||||
scope.gain = max(scope.gain / 1.3, 0.5)
|
||||
of Key.RightBracket:
|
||||
scope.timeDiv = min(scope.timeDiv * 1.5, 16.0)
|
||||
of Key.LeftBracket:
|
||||
scope.timeDiv = max(scope.timeDiv / 1.5, 0.25)
|
||||
of Key.Space:
|
||||
scope.frozen = not scope.frozen
|
||||
of Key.G:
|
||||
scope.grid = case scope.grid
|
||||
of gsGrid: gsCross
|
||||
of gsCross: gsOff
|
||||
of gsOff: gsGrid
|
||||
of Key.D:
|
||||
audio.cyclePreset()
|
||||
else:
|
||||
discard
|
||||
|
||||
sleep(16)
|
||||
|
||||
audio.stop()
|
||||
crtTurnOff(tb, w, h)
|
||||
|
||||
tb = newTerminalBuffer(w, h)
|
||||
tb.display()
|
||||
sleep(100)
|
||||
illwillDeinit()
|
||||
showCursor()
|
||||
|
||||
when isMainModule:
|
||||
main()
|
||||
Reference in New Issue
Block a user