Created
August 31, 2026 08:46
-
-
Save itzender5820/58f5bc228918abe5fc50504a82f7a169 to your computer and use it in GitHub Desktop.
Make sure to run `wget https://raw.githubusercontent.com/mackron/miniaudio/master/miniaudio.h` before compiling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define MINIAUDIO_IMPLEMENTATION | |
| #include "miniaudio.h" | |
| #include <iostream> | |
| #include <vector> | |
| #include <cmath> | |
| #include <complex> | |
| #include <string> | |
| #include <thread> | |
| #include <chrono> | |
| #include <filesystem> | |
| #include <random> | |
| #include <algorithm> | |
| #include <atomic> | |
| #include <cstdlib> | |
| #include <unistd.h> | |
| #include <termios.h> | |
| #include <sys/ioctl.h> | |
| #include <signal.h> | |
| #include <fcntl.h> | |
| namespace fs = std::filesystem; | |
| using Complex = std::complex<float>; | |
| constexpr size_t FFT_SIZE = 512; | |
| constexpr size_t NUM_BANDS = 32; | |
| constexpr size_t GRID_X = NUM_BANDS * 2; | |
| constexpr size_t GRID_Z = 36; // Slightly extended for a squarer terrain piece | |
| constexpr float PI = 3.14159265358979323846f; | |
| const uint8_t BRAILLE_MAP[4][2] = { | |
| {0x01, 0x08}, {0x02, 0x10}, {0x04, 0x20}, {0x40, 0x80} | |
| }; | |
| struct Vec3 { float x, y, z; }; | |
| std::atomic<bool> g_running{true}; | |
| // POSIX Terminal Controller with Non-Blocking Input | |
| class POSIXTerminal { | |
| private: | |
| struct termios orig_termios; | |
| int orig_flags; | |
| static POSIXTerminal* instance; | |
| void restore() { | |
| std::cout << "\x1b[?1049l\x1b[?25h" << std::flush; | |
| tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); | |
| fcntl(STDIN_FILENO, F_SETFL, orig_flags); | |
| } | |
| static void signalHandler(int signum) { | |
| if (instance) instance->restore(); | |
| exit(signum); | |
| } | |
| public: | |
| int width = 80, height = 24; | |
| POSIXTerminal() { | |
| instance = this; | |
| // Save and set terminal attributes | |
| tcgetattr(STDIN_FILENO, &orig_termios); | |
| struct termios raw = orig_termios; | |
| raw.c_lflag &= ~(ECHO | ICANON); | |
| tcsetattr(STDIN_FILENO, TCSANOW, &raw); | |
| // Enable non-blocking read for standard input | |
| orig_flags = fcntl(STDIN_FILENO, F_GETFL, 0); | |
| fcntl(STDIN_FILENO, F_SETFL, orig_flags | O_NONBLOCK); | |
| struct winsize ws; | |
| if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0) { | |
| width = ws.ws_col; | |
| height = ws.ws_row; | |
| } | |
| struct sigaction sa; | |
| sa.sa_handler = signalHandler; | |
| sigemptyset(&sa.sa_mask); | |
| sa.sa_flags = 0; | |
| sigaction(SIGINT, &sa, NULL); | |
| sigaction(SIGTERM, &sa, NULL); | |
| std::cout << "\x1b[?1049h\x1b[?25l" << std::flush; | |
| } | |
| ~POSIXTerminal() { restore(); } | |
| }; | |
| POSIXTerminal* POSIXTerminal::instance = nullptr; | |
| // ... [Keep AudioRingBuffer, data_callback, and fft implementations exactly as they were] ... | |
| class AudioRingBuffer { | |
| private: | |
| std::vector<float> buffer; | |
| std::atomic<size_t> write_head{0}; | |
| public: | |
| AudioRingBuffer(size_t size) : buffer(size, 0.0f) {} | |
| void push(float sample) { | |
| size_t head = write_head.load(std::memory_order_relaxed); | |
| buffer[head % buffer.size()] = sample; | |
| write_head.store(head + 1, std::memory_order_release); | |
| } | |
| void getLatest(std::vector<float>& out, size_t count) { | |
| size_t head = write_head.load(std::memory_order_acquire); | |
| for (size_t i = 0; i < count; i++) { | |
| size_t idx = (head + buffer.size() - count + i) % buffer.size(); | |
| out[i] = buffer[idx]; | |
| } | |
| } | |
| }; | |
| static AudioRingBuffer g_audio_buffer(4096); | |
| void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { | |
| ma_decoder* pDecoder = (ma_decoder*)pDevice->pUserData; | |
| if (!pDecoder) return; | |
| ma_uint64 framesRead; | |
| ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount, &framesRead); | |
| if (framesRead == 0) g_running = false; | |
| float* samples = (float*)pOutput; | |
| for (ma_uint32 i = 0; i < framesRead; i++) { | |
| float mono = 0.5f * (samples[i * 2] + samples[i * 2 + 1]); | |
| g_audio_buffer.push(mono); | |
| } | |
| (void)pInput; | |
| } | |
| void fft(std::vector<Complex>& a) { | |
| size_t n = a.size(); | |
| if (n <= 1) return; | |
| for (size_t i = 1, j = 0; i < n; i++) { | |
| size_t bit = n >> 1; | |
| for (; j & bit; bit >>= 1) j ^= bit; | |
| j ^= bit; | |
| if (i < j) std::swap(a[i], a[j]); | |
| } | |
| for (size_t len = 2; len <= n; len <<= 1) { | |
| float angle = -2.0f * PI / len; | |
| Complex wlen(cos(angle), sin(angle)); | |
| for (size_t i = 0; i < n; i += len) { | |
| Complex w(1.0f, 0.0f); | |
| for (size_t j = 0; j < len / 2; j++) { | |
| Complex u = a[i + j], v = a[i + j + len / 2] * w; | |
| a[i + j] = u + v; | |
| a[i + j + len / 2] = u - v; | |
| w *= wlen; | |
| } | |
| } | |
| } | |
| } | |
| class TerminalRasterizer { | |
| private: | |
| std::vector<bool> buffer; | |
| int term_w, term_h, pix_w, pix_h; | |
| public: | |
| TerminalRasterizer(int w, int h) : term_w(w), term_h(h), pix_w(w * 2), pix_h(h * 4) { | |
| buffer.resize(pix_w * pix_h, false); | |
| } | |
| void clear() { std::fill(buffer.begin(), buffer.end(), false); } | |
| inline void setPixel(int x, int y) { | |
| if (x >= 0 && x < pix_w && y >= 0 && y < pix_h) buffer[y * pix_w + x] = true; | |
| } | |
| void drawLine(int x0, int y0, int x1, int y1) { | |
| int dx = std::abs(x1 - x0), sx = x0 < x1 ? 1 : -1; | |
| int dy = -std::abs(y1 - y0), sy = y0 < y1 ? 1 : -1; | |
| int err = dx + dy, e2; | |
| while (true) { | |
| setPixel(x0, y0); | |
| if (x0 == x1 && y0 == y1) break; | |
| e2 = 2 * err; | |
| if (e2 >= dy) { err += dy; x0 += sx; } | |
| if (e2 <= dx) { err += dx; y0 += sy; } | |
| } | |
| } | |
| void render(const std::string& title) { | |
| std::string frame; | |
| // Pre-allocate memory to prevent continuous heap reallocations | |
| frame.reserve((term_w * term_h * 4) + 128); | |
| frame += "\x1b[H>> " + title + " | Controls: WASD/Arrows | Q to Quit\n"; | |
| for (int ty = 0; ty < term_h - 2; ty++) { | |
| for (int tx = 0; tx < term_w; tx++) { | |
| uint8_t pattern = 0; | |
| for (int py = 0; py < 4; py++) { | |
| for (int px = 0; px < 2; px++) { | |
| if (buffer[(ty * 4 + py) * pix_w + (tx * 2 + px)]) pattern |= BRAILLE_MAP[py][px]; | |
| } | |
| } | |
| if (pattern == 0) frame += ' '; // Use char instead of string literal | |
| else { | |
| int cp = 0x2800 + pattern; | |
| frame += (char)0xE2; | |
| frame += (char)(0xA0 | ((cp >> 6) & 0x3F)); | |
| frame += (char)(0x80 | (cp & 0x3F)); | |
| } | |
| } | |
| frame += '\n'; | |
| } | |
| std::cout << frame << std::flush; | |
| } | |
| }; | |
| Vec3 rotate3D(Vec3 p, float pitch, float yaw, float roll) { | |
| float y1 = p.y * std::cos(pitch) - p.z * std::sin(pitch); | |
| float z1 = p.y * std::sin(pitch) + p.z * std::cos(pitch); | |
| float x2 = p.x * std::cos(yaw) + z1 * std::sin(yaw); | |
| float z2 = -p.x * std::sin(yaw) + z1 * std::cos(yaw); | |
| float x3 = x2 * std::cos(roll) - y1 * std::sin(roll); | |
| float y3 = x2 * std::sin(roll) + y1 * std::cos(roll); | |
| return {x3, y3, z2}; | |
| } | |
| Vec3 project(Vec3 v, float scale, float distance, int pw, int ph) { | |
| float z = 1.0f / (distance - v.z); | |
| return { v.x * z * scale + (pw / 2.0f), v.y * z * scale + (ph / 2.0f), z }; | |
| } | |
| std::string getSong() { | |
| const char* home = std::getenv("HOME"); | |
| std::string music_dir = home ? std::string(home) + "/disk/Music" : "./"; | |
| std::vector<std::string> files; | |
| const std::vector<std::string> ext = {".mp3", ".wav", ".flac"}; | |
| if (fs::exists(music_dir) && fs::is_directory(music_dir)) { | |
| for (const auto& entry : fs::recursive_directory_iterator(music_dir)) { | |
| if (entry.is_regular_file()) { | |
| std::string e = entry.path().extension().string(); | |
| std::transform(e.begin(), e.end(), e.begin(), ::tolower); | |
| if (std::find(ext.begin(), ext.end(), e) != ext.end()) files.push_back(entry.path().string()); | |
| } | |
| } | |
| } | |
| if (files.empty()) { std::cerr << "[-] No valid tracks found.\n"; exit(1); } | |
| std::mt19937 gen(std::random_device{}()); | |
| std::uniform_int_distribution<> dis(0, files.size() - 1); | |
| return files[dis(gen)]; | |
| } | |
| int main() { | |
| POSIXTerminal term; | |
| TerminalRasterizer rasterizer(term.width, term.height); | |
| int pix_w = term.width * 2, pix_h = term.height * 4; | |
| std::string track_path = getSong(); | |
| std::string track_name = fs::path(track_path).filename().string(); | |
| ma_decoder decoder; | |
| if (ma_decoder_init_file(track_path.c_str(), NULL, &decoder) != MA_SUCCESS) return -1; | |
| ma_device_config config = ma_device_config_init(ma_device_type_playback); | |
| config.playback.format = decoder.outputFormat; | |
| config.playback.channels = decoder.outputChannels; | |
| config.sampleRate = decoder.outputSampleRate; | |
| config.dataCallback = data_callback; | |
| config.pUserData = &decoder; | |
| ma_device device; | |
| if (ma_device_init(NULL, &config, &device) != MA_SUCCESS || ma_device_start(&device) != MA_SUCCESS) return -1; | |
| std::vector<float> raw_pcm(FFT_SIZE); | |
| std::vector<Complex> fft_buffer(FFT_SIZE); | |
| std::vector<float> smoothed_bands(NUM_BANDS, 0.0f); | |
| std::vector<std::vector<float>> height_map(GRID_Z, std::vector<float>(GRID_X, 0.0f)); | |
| const float camera_dist = 18.0f; | |
| const float visual_scale = std::min(pix_w, pix_h) * 1.8f; | |
| // Extracting rotational state for user manipulation | |
| float pitch = 0.8f; | |
| float yaw = 0.0f; | |
| float roll = 0.0f; | |
| const float rot_speed = 0.1f; | |
| while (g_running) { | |
| // --- Non-Blocking Input Polling --- | |
| char c; | |
| while (read(STDIN_FILENO, &c, 1) > 0) { | |
| if (c == '\x1b') { | |
| char seq[2]; | |
| if (read(STDIN_FILENO, &seq[0], 1) > 0 && read(STDIN_FILENO, &seq[1], 1) > 0) { | |
| if (seq[0] == '[') { | |
| switch (seq[1]) { | |
| case 'A': pitch -= rot_speed; break; // Up | |
| case 'B': pitch += rot_speed; break; // Down | |
| case 'C': yaw -= rot_speed; break; // Right | |
| case 'D': yaw += rot_speed; break; // Left | |
| } | |
| } | |
| } | |
| } else { | |
| switch(c) { | |
| case 'w': pitch -= rot_speed; break; | |
| case 's': pitch += rot_speed; break; | |
| case 'a': yaw += rot_speed; break; | |
| case 'd': yaw -= rot_speed; break; | |
| case 'q': g_running = false; break; | |
| } | |
| } | |
| } | |
| rasterizer.clear(); | |
| g_audio_buffer.getLatest(raw_pcm, FFT_SIZE); | |
| for (size_t i = 0; i < FFT_SIZE; i++) { | |
| float w = 0.5f * (1.0f - std::cos(2.0f * PI * i / (FFT_SIZE - 1))); | |
| fft_buffer[i] = Complex(raw_pcm[i] * w, 0.0f); | |
| } | |
| fft(fft_buffer); | |
| for (size_t i = 0; i < NUM_BANDS; i++) { | |
| size_t bin = static_cast<size_t>(std::pow(i / (float)NUM_BANDS, 1.8f) * (FFT_SIZE / 4)) + 1; | |
| bin = std::min(bin, FFT_SIZE / 2 - 1); | |
| float raw_mag = (std::abs(fft_buffer[bin]) / FFT_SIZE) * 12.0f; | |
| float mag = std::clamp(raw_mag, 0.0f, 2.5f); | |
| smoothed_bands[i] = mag > smoothed_bands[i] | |
| ? smoothed_bands[i] * 0.5f + mag * 0.5f | |
| : smoothed_bands[i] * 0.85f + mag * 0.15f; | |
| } | |
| for (size_t z = GRID_Z - 1; z > 0; --z) height_map[z] = height_map[z - 1]; | |
| for (size_t i = 0; i < NUM_BANDS; i++) { | |
| height_map[0][NUM_BANDS - 1 - i] = smoothed_bands[i]; | |
| height_map[0][NUM_BANDS + i] = smoothed_bands[i]; | |
| } | |
| std::vector<std::vector<Vec3>> projected_pts(GRID_Z, std::vector<Vec3>(GRID_X)); | |
| for (size_t z = 0; z < GRID_Z; z++) { | |
| for (size_t x = 0; x < GRID_X; x++) { | |
| float world_x = (x - (float)GRID_X / 2.0f) * 0.4f; | |
| float world_z = (z - (float)GRID_Z / 2.0f) * 0.5f; | |
| // --- Procedural Terrain Bounding (Radial Falloff) --- | |
| // Calculate normalized distance from the center of the grid [-1.0 to 1.0] | |
| float norm_x = (x - (float)GRID_X / 2.0f) / ((float)GRID_X / 2.0f); | |
| float norm_z = (z - (float)GRID_Z / 2.0f) / ((float)GRID_Z / 2.0f); | |
| float radius_sq = norm_x * norm_x + norm_z * norm_z; | |
| // Inverse parabolic attenuation. Clamped to 0 at the boundaries. | |
| float terrain_mask = std::max(0.0f, 1.0f - radius_sq); | |
| // Apply mask to force the geometry flat at the edges | |
| float world_y = -height_map[z][x] * terrain_mask * 1.5f; | |
| Vec3 p = { world_x, world_y, world_z }; | |
| projected_pts[z][x] = project(rotate3D(p, pitch, yaw, roll), visual_scale, camera_dist, pix_w, pix_h); | |
| } | |
| } | |
| // Pass 2: Draw the continuous wireframe using Bresenham lines | |
| for (size_t z = 0; z < GRID_Z; z++) { | |
| for (size_t x = 0; x < GRID_X; x++) { | |
| int px = static_cast<int>(projected_pts[z][x].x); | |
| int py = static_cast<int>(projected_pts[z][x].y); | |
| if (x < GRID_X - 1) { | |
| int p_right_x = static_cast<int>(projected_pts[z][x + 1].x); | |
| int p_right_y = static_cast<int>(projected_pts[z][x + 1].y); | |
| rasterizer.drawLine(px, py, p_right_x, p_right_y); | |
| } | |
| if (z < GRID_Z - 1) { | |
| int p_down_x = static_cast<int>(projected_pts[z + 1][x].x); | |
| int p_down_y = static_cast<int>(projected_pts[z + 1][x].y); | |
| rasterizer.drawLine(px, py, p_down_x, p_down_y); | |
| } | |
| } | |
| } | |
| rasterizer.render(track_name); | |
| std::this_thread::sleep_for(std::chrono::milliseconds(16)); | |
| } | |
| ma_device_uninit(&device); | |
| ma_decoder_uninit(&decoder); | |
| return 0; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
'ln -s /( your internal storage ) disk'
It scans $HOME/disk/Music