Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Build and Test

on:
push:
branches: [ '**' ]
pull_request:
branches: [ '**' ]

jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install -y libsdl2-dev build-essential

- name: Compile
run: make clean && make

- name: Check binary
run: |
if [ ! -f bin/singularity ]; then
echo "Binary not found!"
exit 1
fi
echo "Linux build successful."

build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4

- name: Set up MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
install: >-
mingw-w64-x86_64-gcc
mingw-w64-x86_64-SDL2
make

- name: Compile
shell: msys2 {0}
run: make clean && make

- name: Check binary
shell: msys2 {0}
run: |
if [ ! -f bin/singularity.exe ]; then
echo "Binary not found!"
exit 1
fi
echo "Windows build successful."
91 changes: 91 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: Release

on:
push:
tags:
- 'v*'

jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install -y libsdl2-dev build-essential

- name: Compile
run: make clean && make

- name: Package
run: |
mkdir -p singularity-linux
cp bin/singularity singularity-linux/
tar -czvf singularity-linux.tar.gz singularity-linux/

- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: linux-artifact
path: singularity-linux.tar.gz

build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4

- name: Set up MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
install: >-
mingw-w64-x86_64-gcc
mingw-w64-x86_64-SDL2
make

- name: Compile & Bundle
shell: msys2 {0}
run: make clean && make bundle-sdl2

- name: Package
shell: bash
run: |
mkdir -p singularity-windows
cp bin/singularity.exe singularity-windows/
cp bin/SDL2.dll singularity-windows/
7z a singularity-windows.zip singularity-windows/

- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: windows-artifact
path: singularity-windows.zip

create-release:
needs: [build-linux, build-windows]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download Linux Artifact
uses: actions/download-artifact@v4
with:
name: linux-artifact

- name: Download Windows Artifact
uses: actions/download-artifact@v4
with:
name: windows-artifact

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: |
singularity-linux.tar.gz
singularity-windows.zip
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
.vscode/
.vscode/
bin/
build/
output.txt
*.txt
*.bmp
*.log
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Singularity

Singularity is a high-performance **S-plane visualizer** and experimental music instrument that translates complex transfer functions, formed by the interaction of **poles and zeros**, into a symphony of color and sound.

## Purpose & Inspiration

This project is a tribute to the logical elegance of **Laplace Transformations** and control theory. It provides a real-time, interactive window into the **S-Domain**, where the stability and behavior of linear systems are dictated by the landscape of singularities.

Influenced by the work and spirit of the late developer **Terry Davis**, Singularity was built with a dedication to first-principles development and the creation of unique, personal digital artifacts.

The goal is to move beyond the textbook definitions of transfer functions. It allows users to **see the colors of math** and explore the infinite intricacy of the complex plane. By mapping mathematical magnitude and phase to vibrant visual gradients and synthetic soundscapes, we turn the screen into an auditory and visual representation of the **Laplace landscape**.

## Features

- **High-Performance Math Engine**: Built in C with a Structure of Arrays (SoA) layout for maximum SIMD efficiency.
- **Dynamic Sonification**: The field magnitude and phase are mapped to a procedurally generated synthesizer, turning the visualizer into a playable instrument.
- **Advanced Visual Overlays**:
- **Phase Trails**: Real-time vector field streamlines tracing the flow of the complex plane.
- **Domain Coloring**: A warped checkerboard pattern illustrating the transformation of space.
- **Cinematic Experience**: Supports auto-orbit, pulsing animations, and high-resolution screenshot export.
- **Cross-Platform**: Compiles natively on Windows (MinGW) and Linux (Ubuntu).

## Usage & Controls

### General Navigation
| Key | Action |
|---|---|
| `Alt + Enter` | Toggle Fullscreen |
| `Escape` | Exit Application |
| `H` | Toggle HUD Overlays |
| `S` / `F1` | Open Settings Panel |
| `P` | Export Screenshot (saved as `.bmp`) |
| `Ctrl + R` | Randomize all singularities |
| `Ctrl + Z / Y` | Undo / Redo changes |

### Interaction & Manipulation
| Input | Action |
|---|---|
| `G` | Toggle Select ↔ Move Mode |
| `Z` / `X` | Add Zero / Pole at cursor (Move Mode) |
| `Delete` | Remove selected singularity |
| `Mouse Wheel` | Zoom in/out at cursor position |
| `Middle Click Drag` | Pan around the complex plane |
| `Right Click Drag` | Drag to select a group of singularities |
| `1` - `9` | Load mathematical presets (Ring, Elliptic, Cross, etc.) |

### Visual & Audio Effects
| Key | Action |
|---|---|
| `Tab` | Cycle through 6 distinct Color Maps |
| `Backspace`| Cycle Normalization (Linear, Log, Steps) |
| `C` | Cycle Entity Rendering (Solid, Transparent, Dashed, etc.) |
| `O` | Toggle Auto-Orbit Animation |
| `U` | Toggle Magnitude Pulsation |
| `F` | Toggle Vector Field / Phase Trails |
| `D` | Toggle Domain Coloring Overlay |
| `A` | **Toggle Audio Sonification** (Theremin Mode) |

## Building

### Windows (MinGW/MSYS2)
Ensure you have `gcc`, `make`, and `SDL2` installed via MSYS2.
```bash
make
./bin/singularity.exe
```

### Linux (Ubuntu)
```bash
sudo apt install libsdl2-dev build-essential
make
./bin/singularity
```

---

*Visualization is not just about seeing; it's about understanding the rhythmic beauty of thought.*
Binary file added images/Screenshot 2025-08-15 200518.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/Screenshot 2025-08-15 200537.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/Screenshot 2025-08-15 200545.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/Screenshot 2025-08-15 200554.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/Screenshot 2025-08-15 200601.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/Screenshot 2025-08-15 200607.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions include/app.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#ifndef APP_H
#define APP_H

#include <SDL.h>
#include "img_utils.h"

typedef struct {
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *H_tex;
SDL_Texture *UI_tex;
img_t H_img;
img_t UI_img;

int screen_w, screen_h; /* current window pixel dimensions */
int grid_w, grid_h; /* low-res math grid (screen / GRID_DIVISOR) */
int is_fullscreen;
int windowed_w, windowed_h; /* saved windowed size for toggle */

double x_range[2]; /* [x_min, x_max] */
double y_range[2]; /* [y_min, y_max] */

/* Camera for zoom/pan */
double cam_cx, cam_cy; /* center in complex space */
double cam_zoom; /* multiplier: >1 = zoomed in */

SDL_Cursor *cursor_arrow;
SDL_Cursor *cursor_hand;
SDL_Cursor *cursor_move;
} App;

/* Returns 0 on success, non-zero on failure */
int app_init(App *a);
void app_toggle_fullscreen(App *a);
void app_handle_resize(App *a, int w, int h);
void app_destroy(App *a);

#endif /* APP_H */
21 changes: 21 additions & 0 deletions include/audio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef AUDIO_H
#define AUDIO_H

#include <SDL.h>

/* Initialize SDL audio and start the callback thread */
void audio_init(void);

/* Shutdown the audio device */
void audio_shutdown(void);

/* Smoothly update the target frequency and amplitude.
freq: in Hz. amp: 0.0 to 1.0. */
void audio_set_params(double freq, double amp);

/* Toggle synthesis on/off */
void audio_set_enabled(int enabled);

void audio_get_params(double *freq, double *amp);

#endif /* AUDIO_H */
17 changes: 17 additions & 0 deletions include/cpu_detect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef _CPU_DETECT_HH
#define _CPU_DETECT_HH

#include <stdint.h>

typedef enum {
CPU_FEATURE_NONE = 0,
CPU_FEATURE_SSE2 = 1 << 0,
CPU_FEATURE_AVX = 1 << 1,
CPU_FEATURE_AVX2 = 1 << 2,
CPU_FEATURE_AVX512F = 1 << 3,
} cpu_features_t;

cpu_features_t detect_cpu_features(void);
const char* get_simd_level_name(cpu_features_t features);

#endif
15 changes: 15 additions & 0 deletions include/font_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef _FONT_UTILS_HH
#define _FONT_UTILS_HH

#include <stdint.h>
#include "img_utils.h"

void draw_char(img_t *img, char c, uint32_t x, uint32_t y);
void draw_char_colored(img_t *img, char c, uint32_t x, uint32_t y, uint32_t color);
void draw_string_colored(img_t *img, const char *str, uint32_t x, uint32_t y, uint32_t color);
void draw_string(img_t *img, const char *str, uint32_t x, uint32_t y);

void draw_char_dynamic(img_t *img, char c, uint32_t x, uint32_t y, int primary_channel);
void draw_string_dynamic(img_t *img, const char *str, uint32_t x, uint32_t y, int primary_channel);

#endif /* _FONT_UTILS_HH */
59 changes: 59 additions & 0 deletions include/img_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#ifndef _IMG_UTILS_HH
#define _IMG_UTILS_HH

#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>

struct img_t;

typedef struct img_t {
uint32_t *data;
size_t height;
size_t width;
struct img_t *bg_ref;
} img_t;

img_t *create_img(size_t width, size_t height, img_t *img);

static inline void channel_color(img_t *img, int32_t x, int32_t y, int ch, uint8_t *tr, uint8_t *tg, uint8_t *tb) {
uint32_t bg_pixel = 0;
if (img->bg_ref) {
/* Sample from background reference (scaled) */
int32_t bx = x * (int32_t)img->bg_ref->width / (int32_t)img->width;
int32_t by = y * (int32_t)img->bg_ref->height / (int32_t)img->height;
if ((uint32_t)bx < img->bg_ref->width && (uint32_t)by < img->bg_ref->height) {
bg_pixel = img->bg_ref->data[by * img->bg_ref->width + bx];
}
} else {
/* Sample from current image */
uint32_t idx = (uint32_t)y * img->width + (uint32_t)x;
bg_pixel = img->data[idx];
}

uint8_t r = (bg_pixel >> 16) & 0xFF, g = (bg_pixel >> 8) & 0xFF, b = bg_pixel & 0xFF;
if (ch == 1) { *tr = 255; *tg = (255-g)/2; *tb = (255-b)/2; }
else if (ch == 3) { *tr = (255-r)/2; *tg = (255-g)/2; *tb = 255; }
else { *tr = (255-r); *tg = 255; *tb = (255-b); }
}

/* Basic shapes */
void draw_circle_aa(img_t *img, int32_t cx, int32_t cy, int32_t radius, uint32_t color);
void draw_circle_aa_dynamic(img_t *img, int32_t cx, int32_t cy, int32_t radius, int primary_channel);
void draw_circle_aa_alpha(img_t *img, int32_t cx, int32_t cy, int32_t radius, int primary_channel, uint8_t alpha_scale);
void draw_circle_dashed_aa_dynamic(img_t *img, int32_t cx, int32_t cy, int32_t radius, int primary_channel);
void draw_circle_glow(img_t *img, int32_t cx, int32_t cy, int32_t radius, int primary_channel);
void draw_circle_glow_color(img_t *img, int32_t cx, int32_t cy, int32_t radius, uint32_t color);

void fill_circle(img_t *img, int32_t cx, int32_t cy, int32_t radius, uint32_t color);
void fill_circle_dynamic(img_t *img, int32_t cx, int32_t cy, int32_t radius, int primary_channel);
void fill_circle_glow(img_t *img, int32_t cx, int32_t cy, int32_t radius, int primary_channel);

void draw_rect_fill(img_t *img, int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color);
void draw_rect_blend(img_t *img, int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color);
void draw_rect_stroke(img_t *img, int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color);

void draw_rounded_rect_blend(img_t *img, int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color);
void draw_rounded_rect_fill(img_t *img, int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color);

#endif /* _IMG_UTILS_HH */
Loading