DOOM rendered on a hardware oscilloscope via sound card


ScopeDoom renders DOOM's 3D world as wireframe vector graphics on a real oscilloscope. It uses your computer's sound card as a dual-channel DAC - the left channel drives the X-axis, the right channel drives the Y-axis, and the scope displays in X-Y mode.
DOOM Engine (C)
|
| Extract walls & entities as vectors
v
Unix Domain Socket
|
| JSON: {walls: [...], entities: [...]}
v
doom_scope.py (Python)
|
| Convert to X-Y point stream
v
Sound Card (44.1kHz stereo)
|
| Left = X, Right = Y
v
Oscilloscope (X-Y Mode)
MacBook Pro 3.5mm Jack
|
+--- Left (Tip) ----[1k]----+---- CH1 (X)
| |
+--- Right (Ring) --[1k]----+---- CH2 (Y)
| |
+--- Ground (Sleeve) -------+---- GND
# Generate test patterns (no DOOM needed)
python3 scope_wav_test.py
afplay scope_square.wav # Should show a square on scope
# Terminal 1: Start the scope renderer
python3 doom_scope.py
# Terminal 2: Launch DOOM (from doomgeneric build)
./doomgeneric_kicad -w 1 1
ScopeDoom requires a modified DOOM engine that extracts vector data. See doom/source/build.sh for build instructions.
The key modification is extracting wall segments (drawsegs[]) and sprite positions (vissprites[]) and sending them over a Unix socket as JSON.
| Metric | Value |
|---|---|
| Sample Rate | 44,100 Hz |
| Points per Frame | ~5,000-10,000 |
| Effective Refresh | 4-8 Hz |
| Walls Rendered | 30-50 typical |
| Entities Rendered | 0-10 |
The refresh rate depends on scene complexity. More walls/entities = more points = slower refresh. But it's still playable!
pip install sounddevice numpy
Optional (for scope screenshots):
pip install python-vxi11
ScopeDoom/
├── doom_scope.py # Main DOOM-to-scope renderer
├── scope_capture.py # Oscilloscope screenshot capture
├── scope_output.py # Test pattern generator
├── scope_wav_test.py # WAV file test patterns
├── assets/ # Screenshots and demos
└── doom/source/ # Modified DOOM engine source
GPL (inherits from DOOM source code)
7 commits
Hacker News (1)
Python
48.7%
C
44.6%
Shell
6.7%
DOOM rendered on a hardware oscilloscope via sound card


ScopeDoom renders DOOM's 3D world as wireframe vector graphics on a real oscilloscope. It uses your computer's sound card as a dual-channel DAC - the left channel drives the X-axis, the right channel drives the Y-axis, and the scope displays in X-Y mode.
DOOM Engine (C)
|
| Extract walls & entities as vectors
v
Unix Domain Socket
|
| JSON: {walls: [...], entities: [...]}
v
doom_scope.py (Python)
|
| Convert to X-Y point stream
v
Sound Card (44.1kHz stereo)
|
| Left = X, Right = Y
v
Oscilloscope (X-Y Mode)
MacBook Pro 3.5mm Jack
|
+--- Left (Tip) ----[1k]----+---- CH1 (X)
| |
+--- Right (Ring) --[1k]----+---- CH2 (Y)
| |
+--- Ground (Sleeve) -------+---- GND
# Generate test patterns (no DOOM needed)
python3 scope_wav_test.py
afplay scope_square.wav # Should show a square on scope
# Terminal 1: Start the scope renderer
python3 doom_scope.py
# Terminal 2: Launch DOOM (from doomgeneric build)
./doomgeneric_kicad -w 1 1
ScopeDoom requires a modified DOOM engine that extracts vector data. See doom/source/build.sh for build instructions.
The key modification is extracting wall segments (drawsegs[]) and sprite positions (vissprites[]) and sending them over a Unix socket as JSON.
| Metric | Value |
|---|---|
| Sample Rate | 44,100 Hz |
| Points per Frame | ~5,000-10,000 |
| Effective Refresh | 4-8 Hz |
| Walls Rendered | 30-50 typical |
| Entities Rendered | 0-10 |
The refresh rate depends on scene complexity. More walls/entities = more points = slower refresh. But it's still playable!
pip install sounddevice numpy
Optional (for scope screenshots):
pip install python-vxi11
ScopeDoom/
├── doom_scope.py # Main DOOM-to-scope renderer
├── scope_capture.py # Oscilloscope screenshot capture
├── scope_output.py # Test pattern generator
├── scope_wav_test.py # WAV file test patterns
├── assets/ # Screenshots and demos
└── doom/source/ # Modified DOOM engine source
GPL (inherits from DOOM source code)
Hacker News (1)
7 commits
Python
48.7%
C
44.6%
Shell
6.7%