Oscillator sensor visualization and data export scripts #46

Closed
opened 2026-03-19 10:49:45 +00:00 by david · 5 comments
Owner

Summary

Created demo scripts for visualizing and exporting oscillator sensor data:

Scripts Created

  1. scripts/demo_oscillator_simple.py - Visual waveform display

    • Renders oscillator waveforms in real-time in the terminal
    • Shows waveform shape with ASCII characters
    • Displays current value, frame number, and phase
    • Supports all waveforms: sine, square, sawtooth, triangle, noise
    • Runs indefinitely until Ctrl+C or specified frame count
  2. scripts/oscillator_data_export.py - JSON data export

    • Exports oscillator readings as JSON
    • Includes timestamps, values, and phase information
    • Configurable sample rate and duration
    • Can output to file or stdout

Usage Examples

Visual demo:

uv run python scripts/demo_oscillator_simple.py --waveform sine --frequency 1.0

Export data:

uv run python scripts/oscillator_data_export.py --waveform square --frequency 2.0 --duration 10.0 -o data.json

Features

  • Real-time waveform visualization with phase tracking
  • Support for all oscillator waveforms (sine, square, sawtooth, triangle, noise)
  • Configurable frequency, sample rate, and duration
  • Clean ASCII output suitable for terminal display
  • JSON export format for external processing
  • Oscillator sensor: engine/sensors/oscillator.py
## Summary Created demo scripts for visualizing and exporting oscillator sensor data: ### Scripts Created 1. **`scripts/demo_oscillator_simple.py`** - Visual waveform display - Renders oscillator waveforms in real-time in the terminal - Shows waveform shape with ASCII characters - Displays current value, frame number, and phase - Supports all waveforms: sine, square, sawtooth, triangle, noise - Runs indefinitely until Ctrl+C or specified frame count 2. **`scripts/oscillator_data_export.py`** - JSON data export - Exports oscillator readings as JSON - Includes timestamps, values, and phase information - Configurable sample rate and duration - Can output to file or stdout ### Usage Examples Visual demo: ```bash uv run python scripts/demo_oscillator_simple.py --waveform sine --frequency 1.0 ``` Export data: ```bash uv run python scripts/oscillator_data_export.py --waveform square --frequency 2.0 --duration 10.0 -o data.json ``` ### Features - Real-time waveform visualization with phase tracking - Support for all oscillator waveforms (sine, square, sawtooth, triangle, noise) - Configurable frequency, sample rate, and duration - Clean ASCII output suitable for terminal display - JSON export format for external processing ## Related - Oscillator sensor: `engine/sensors/oscillator.py`
Author
Owner

Implementation Details

demo_oscillator_simple.py

  • Uses ANSI escape codes (\033[H\033[J) to clear screen and update display
  • Samples waveform function directly to show the complete waveform shape
  • Displays current oscillator reading value and phase
  • Supports frame limiting or infinite loop until Ctrl+C

oscillator_data_export.py

  • Records oscillator readings at configurable sample rate
  • Outputs structured JSON with metadata (waveform, frequency, duration, timestamp)
  • Each sample includes: index, timestamp, value, and phase
  • Can save to file or print to stdout

Visual Output Example

Oscillator: demo_osc | Waveform: sine | Freq: 1.0Hz
────────────────────────────────────────────────────────
                                                      █████████████             
                                                   ███             ███          
                                                 ██                   ██        
                                               ██                       ██      
...
Value: 0.500 | Frame: 0 | Phase: 0.00

JSON Output Example

{
  "waveform": "sine",
  "frequency": 1.0,
  "duration": 5.0,
  "sample_rate": 60.0,
  "timestamp": "2026-03-19T03:47:41.395743",
  "samples": [
    {
      "index": 0,
      "timestamp": 1773917261.3957593,
      "value": 0.5000561760541257,
      "phase": 1.7881393432617188e-05
    },
    ...
  ]
}

Commits

  • f2b4226: feat: Add oscillator sensor visualization and data export scripts
  • aeac4e6: fix: Remove duplicate argument definitions in demo_oscillator_simple.py
## Implementation Details ### `demo_oscillator_simple.py` - Uses ANSI escape codes (`\033[H\033[J`) to clear screen and update display - Samples waveform function directly to show the complete waveform shape - Displays current oscillator reading value and phase - Supports frame limiting or infinite loop until Ctrl+C ### `oscillator_data_export.py` - Records oscillator readings at configurable sample rate - Outputs structured JSON with metadata (waveform, frequency, duration, timestamp) - Each sample includes: index, timestamp, value, and phase - Can save to file or print to stdout ### Visual Output Example ``` Oscillator: demo_osc | Waveform: sine | Freq: 1.0Hz ──────────────────────────────────────────────────────── █████████████ ███ ███ ██ ██ ██ ██ ... Value: 0.500 | Frame: 0 | Phase: 0.00 ``` ### JSON Output Example ```json { "waveform": "sine", "frequency": 1.0, "duration": 5.0, "sample_rate": 60.0, "timestamp": "2026-03-19T03:47:41.395743", "samples": [ { "index": 0, "timestamp": 1773917261.3957593, "value": 0.5000561760541257, "phase": 1.7881393432617188e-05 }, ... ] } ``` ## Commits - `f2b4226`: feat: Add oscillator sensor visualization and data export scripts - `aeac4e6`: fix: Remove duplicate argument definitions in demo_oscillator_simple.py
david closed this issue 2026-03-19 10:50:12 +00:00
Author
Owner

New Oscilloscope Demo

Added scripts/demo_oscilloscope.py - A proper oscilloscope-style waveform visualization.

How it works:

  1. Time Axis: Each column on the screen represents a different point in time
  2. Trace Drawing: The waveform is sampled at each time point and drawn as a continuous trace
  3. Scrolling: The trace scrolls left-to-right based on the oscillator's phase/frequency
  4. Frequency Response: Higher frequencies scroll faster (proportional to frequency)

Key Features:

  • Single continuous trace instead of multiple copies of the waveform
  • Real oscilloscope behavior - time axis moves, trace follows the signal
  • Frequency-based scrolling - syncs with oscillator frequency
  • All waveforms supported - sine, square, sawtooth, triangle, noise

Visual Output Example:

Oscilloscope: oscilloscope_osc | Wave: sine | Freq: 1.0Hz | Phase: 0.00
────────────────────────────────────────────────────────────────────────────────
       ███████                                 ███████                          
      █████████                               █████████                         
     ██       ██                             ██       ██                        
    ... (single continuous trace scrolling) ...
                                       ◎                                        
Value: 0.500 | Frame: 0 | Phase: 0.00

Usage:

uv run python scripts/demo_oscilloscope.py --waveform sine --frequency 1.0

This completes the oscillator visualization tools with a proper oscilloscope display that shows the waveform as it would appear on a real oscilloscope.

## New Oscilloscope Demo Added `scripts/demo_oscilloscope.py` - A proper oscilloscope-style waveform visualization. ### How it works: 1. **Time Axis**: Each column on the screen represents a different point in time 2. **Trace Drawing**: The waveform is sampled at each time point and drawn as a continuous trace 3. **Scrolling**: The trace scrolls left-to-right based on the oscillator's phase/frequency 4. **Frequency Response**: Higher frequencies scroll faster (proportional to frequency) ### Key Features: - **Single continuous trace** instead of multiple copies of the waveform - **Real oscilloscope behavior** - time axis moves, trace follows the signal - **Frequency-based scrolling** - syncs with oscillator frequency - **All waveforms supported** - sine, square, sawtooth, triangle, noise ### Visual Output Example: ``` Oscilloscope: oscilloscope_osc | Wave: sine | Freq: 1.0Hz | Phase: 0.00 ──────────────────────────────────────────────────────────────────────────────── ███████ ███████ █████████ █████████ ██ ██ ██ ██ ... (single continuous trace scrolling) ... ◎ Value: 0.500 | Frame: 0 | Phase: 0.00 ``` ### Usage: ```bash uv run python scripts/demo_oscilloscope.py --waveform sine --frequency 1.0 ``` This completes the oscillator visualization tools with a proper oscilloscope display that shows the waveform as it would appear on a real oscilloscope.
Author
Owner

Enhanced Oscilloscope with LFO Modulation Chain

Added scripts/demo_oscilloscope_mod.py with these improvements:

Key Changes

  1. 15 FPS frame rate - Slower, smoother viewing for human appreciation
  2. Reduced flicker - Uses cursor positioning (\033[H) instead of full screen clear
  3. LFO modulation chain - One LFO can modulate another's frequency
  4. Dual waveform display - Shows both source and modulated waveforms

Modulation Chain Features

The ModulatedOscillator class implements frequency modulation:

effective_frequency = base_frequency + (modulator_value * modulation_depth)

Usage Examples

# Simple LFO (slow, smooth viewing)
uv run python scripts/demo_oscilloscope_mod.py --lfo

# LFO modulation chain: modulator modulates main oscillator
uv run python scripts/demo_oscilloscope_mod.py --modulate --lfo

# Custom modulation depth (0.0-1.0)
uv run python scripts/demo_oscilloscope_mod.py --modulate --lfo --mod-depth 0.3

# Square wave modulation for rhythmic effects
uv run python scripts/demo_oscilloscope_mod.py --modulate --lfo --mod-waveform square --mod-freq 0.25

# Sawtooth modulation for sweep effects
uv run python scripts/demo_oscilloscope_mod.py --modulate --lfo --mod-waveform sawtooth --mod-depth 0.5

Visual Output

The display shows:

  • Top: Modulator waveform (e.g., sine @ 0.5Hz)
  • Middle: Modulation info (depth, current mod value)
  • Bottom: Modulated waveform (base frequency affected by modulation)

This creates the classic "LFO modulating LFO" patch commonly used in synthesis.

## Enhanced Oscilloscope with LFO Modulation Chain Added `scripts/demo_oscilloscope_mod.py` with these improvements: ### Key Changes 1. **15 FPS frame rate** - Slower, smoother viewing for human appreciation 2. **Reduced flicker** - Uses cursor positioning (`\033[H`) instead of full screen clear 3. **LFO modulation chain** - One LFO can modulate another's frequency 4. **Dual waveform display** - Shows both source and modulated waveforms ### Modulation Chain Features The `ModulatedOscillator` class implements frequency modulation: ``` effective_frequency = base_frequency + (modulator_value * modulation_depth) ``` ### Usage Examples ```bash # Simple LFO (slow, smooth viewing) uv run python scripts/demo_oscilloscope_mod.py --lfo # LFO modulation chain: modulator modulates main oscillator uv run python scripts/demo_oscilloscope_mod.py --modulate --lfo # Custom modulation depth (0.0-1.0) uv run python scripts/demo_oscilloscope_mod.py --modulate --lfo --mod-depth 0.3 # Square wave modulation for rhythmic effects uv run python scripts/demo_oscilloscope_mod.py --modulate --lfo --mod-waveform square --mod-freq 0.25 # Sawtooth modulation for sweep effects uv run python scripts/demo_oscilloscope_mod.py --modulate --lfo --mod-waveform sawtooth --mod-depth 0.5 ``` ### Visual Output The display shows: - **Top**: Modulator waveform (e.g., sine @ 0.5Hz) - **Middle**: Modulation info (depth, current mod value) - **Bottom**: Modulated waveform (base frequency affected by modulation) This creates the classic "LFO modulating LFO" patch commonly used in synthesis.
Author
Owner

Pipeline Switching Demo

Added scripts/demo_oscilloscope_pipeline.py with automatic pipeline switching every 15 seconds:

Pipeline Stages

  1. Text Mode (15 seconds)

    • Pure text-based oscilloscope rendering
    • Smooth 15 FPS viewing for human perception
    • No flicker using cursor positioning
  2. Pygame + PIL to ANSI (15 seconds)

    • Pygame renders waveforms to RGB surface
    • PIL converts to grayscale ANSI character art
    • Uses fonts/Pixel_Sparta.otf for typography
    • Automatic switching back to text mode after 15 seconds

Key Features

  • Automatic Mode Switching: No manual intervention needed
  • Reduced Flicker: Uses \033[H cursor positioning
  • Smooth 15 FPS: Optimal for human appreciation
  • LFO Modulation Chain: One LFO modulates another's frequency

Usage

# Basic pipeline demo
uv run python scripts/demo_oscilloscope_pipeline.py --lfo --modulate

# Custom modulation
uv run python scripts/demo_oscilloscope_pipeline.py --lfo --modulate --mod-depth 0.3 --mod-waveform square

Visualization Modes

Mode Duration Description
Text 15s Direct terminal rendering using ASCII characters
Pygame+PIL 15s Pygame graphics → PIL → ANSI conversion
Loop - Repeats indefinitely

The pipeline demonstrates the concept of switching between rendering backends, which could be expanded into a full scripting language for patching oscillators and effects.

## Pipeline Switching Demo Added `scripts/demo_oscilloscope_pipeline.py` with automatic pipeline switching every 15 seconds: ### Pipeline Stages 1. **Text Mode** (15 seconds) - Pure text-based oscilloscope rendering - Smooth 15 FPS viewing for human perception - No flicker using cursor positioning 2. **Pygame + PIL to ANSI** (15 seconds) - Pygame renders waveforms to RGB surface - PIL converts to grayscale ANSI character art - Uses fonts/Pixel_Sparta.otf for typography - Automatic switching back to text mode after 15 seconds ### Key Features - **Automatic Mode Switching**: No manual intervention needed - **Reduced Flicker**: Uses `\033[H` cursor positioning - **Smooth 15 FPS**: Optimal for human appreciation - **LFO Modulation Chain**: One LFO modulates another's frequency ### Usage ```bash # Basic pipeline demo uv run python scripts/demo_oscilloscope_pipeline.py --lfo --modulate # Custom modulation uv run python scripts/demo_oscilloscope_pipeline.py --lfo --modulate --mod-depth 0.3 --mod-waveform square ``` ### Visualization Modes | Mode | Duration | Description | |------|----------|-------------| | Text | 15s | Direct terminal rendering using ASCII characters | | Pygame+PIL | 15s | Pygame graphics → PIL → ANSI conversion | | Loop | - | Repeats indefinitely | The pipeline demonstrates the concept of switching between rendering backends, which could be expanded into a full scripting language for patching oscillators and effects.
Author
Owner

Image Data Source Integration

Added scripts/demo_image_oscilloscope.py that uses the ImageDataSource pattern:

Implementation

  1. OscilloscopeDataSource class

    • Implements DataSource interface
    • Generates dynamic oscilloscope images from oscillators
    • Uses Pygame to render waveforms
    • Converts to PIL Image (8-bit grayscale with RGBA transparency)
  2. Rendering Pipeline

    Oscillator sensors → Pygame surface → PIL Image → ANSI character art
    
  3. 8-bit Grayscale with Transparency

    • Pygame surface rendered in RGB
    • Converted to PIL L mode (8-bit grayscale)
    • Alpha channel preserved for transparency
    • Character ramp: .:-=+*#%@ (dark to light)

Usage

# Basic image oscilloscope
uv run python scripts/demo_image_oscilloscope.py --lfo --modulate

# Custom settings
uv run python scripts/demo_image_oscilloscope.py --modulate --lfo --mod-depth 0.3 --mod-waveform square

Pattern

This demonstrates how to:

  1. Create a dynamic DataSource that generates images
  2. Use Pygame for graphics rendering
  3. Convert to PIL Image with 8-bit grayscale
  4. Render to ANSI using character ramp
  5. Integrate with the existing oscillator modulation chain

Future Improvements

The image data source pattern could be extended to:

  • Load static images from files/URLs
  • Composite multiple layers (oscilloscope + UI elements)
  • Support different color modes (RGB, palette)
  • Add animation frames for GIF output
## Image Data Source Integration Added `scripts/demo_image_oscilloscope.py` that uses the ImageDataSource pattern: ### Implementation 1. **OscilloscopeDataSource class** - Implements `DataSource` interface - Generates dynamic oscilloscope images from oscillators - Uses Pygame to render waveforms - Converts to PIL Image (8-bit grayscale with RGBA transparency) 2. **Rendering Pipeline** ``` Oscillator sensors → Pygame surface → PIL Image → ANSI character art ``` 3. **8-bit Grayscale with Transparency** - Pygame surface rendered in RGB - Converted to PIL `L` mode (8-bit grayscale) - Alpha channel preserved for transparency - Character ramp: ` .:-=+*#%@` (dark to light) ### Usage ```bash # Basic image oscilloscope uv run python scripts/demo_image_oscilloscope.py --lfo --modulate # Custom settings uv run python scripts/demo_image_oscilloscope.py --modulate --lfo --mod-depth 0.3 --mod-waveform square ``` ### Pattern This demonstrates how to: 1. Create a dynamic `DataSource` that generates images 2. Use Pygame for graphics rendering 3. Convert to PIL Image with 8-bit grayscale 4. Render to ANSI using character ramp 5. Integrate with the existing oscillator modulation chain ### Future Improvements The image data source pattern could be extended to: - Load static images from files/URLs - Composite multiple layers (oscilloscope + UI elements) - Support different color modes (RGB, palette) - Add animation frames for GIF output
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: klubhaus/sideline#46