#include #include #include #include #include #include #include #include #include #include #define BREATHING_INTERVAL 90 // in milliseconds #define STRESS_THRESHOLD 8.0 // System load threshold for stress mode #define SHM_NAME "/breathing_color_shm" // Shared memory name #define SOUND_FILE_STRESS "/usr/local/share/sounds/AresEnraged.wav" // Sound for stress mode #define SOUND_FILE_NORMAL "/usr/local/share/sounds/ThanatosVent.wav" // Sound for normal mode #define DEFAULT_COLORS 3 #define STRESS_COLORS 4 const double default_colors[DEFAULT_COLORS][3] = { {1.0, 0.91, 0.4}, //Y {0.95, 0.44, 0.28}, //O {0.24, 0.85, 0.38} //G }; const double stress_colors[STRESS_COLORS][3] = { {0.96, 0.0, 0.0}, //Bright {0.55, 0.0, 0.0}, //Dark {0.64, 0.0, 0.0}, //Muted {0.35, 0.0, 0.0}, //Deep }; // Convert Linear RGB to sRGB double linear_to_srgb(double value) { if (value <= 0.0031308) return value * 12.92; else return 1.055 * pow(value, 1.0 / 2.4) - 0.055; } // Function to interpolate between two colors in linear RGB space void interpolate_color(const double *color1, const double *color2, double t, char *output) { unsigned int r1, g1, b1, r2, g2, b2; double lr1, lg1, lb1, lr2, lg2, lb2, lr, lg, lb; lr1 = color1[0]; lg1 = color1[1]; lb1 = color1[2]; lr2 = color2[0]; lg2 = color2[1]; lb2 = color2[2]; // Interpolate in linear RGB space lr = lr1 + t * (lr2 - lr1); lg = lg1 + t * (lg2 - lg1); lb = lb1 + t * (lb2 - lb1); // Convert back to sRGB r1 = round(linear_to_srgb(lr) * 255); g1 = round(linear_to_srgb(lg) * 255); b1 = round(linear_to_srgb(lb) * 255); // Output the interpolated color as hex snprintf(output, 8, "#%02x%02x%02x", r1, g1, b1); } // Function to read system load double get_system_load() { double load; FILE *f = fopen("/proc/loadavg", "r"); if (f) { fscanf(f, "%lf", &load); fclose(f); } else { perror("Failed to read /proc/loadavg"); load = 0.0; } return load; } // Function to play the sound (non-blocking) void play_sound_background(const char *sound_file) { if (fork() == 0) { // Child process // Use paplay or any other sound player to play the sound char command[100]; snprintf(command, sizeof(command), "paplay %s", sound_file); system(command); // If execlp fails, exit the child process perror("execlp failed"); exit(1); } } // Function to update breathing color void update_breathing_color(char *shm_ptr, double *last_load, int *in_stress_mode) { static int color_index = 0; static double t = 0.0; char new_color[8]; double current_load = get_system_load(); int new_stress_mode = current_load > STRESS_THRESHOLD; // Trigger sound on load crossing (up or down) if (new_stress_mode != *in_stress_mode) { if (new_stress_mode) { play_sound_background(SOUND_FILE_STRESS); // Play stress sound } else { play_sound_background(SOUND_FILE_NORMAL); // Play normal sound } *in_stress_mode = new_stress_mode; } // Determine the current color set (default or stress) const double (*current_colors)[3]; int num_colors; if (new_stress_mode) { current_colors = stress_colors; num_colors = STRESS_COLORS; } else { current_colors = default_colors; num_colors = DEFAULT_COLORS; } // Interpolate between the current and next color in the palette interpolate_color( current_colors[color_index], current_colors[(color_index + 1) % num_colors], t, new_color ); // Store the new color to shared memory (for example purposes) snprintf(shm_ptr, 8, "%s", new_color); // Update interpolation factor and color index t += 0.02; // Adjust speed of interpolation here if (t >= 1.0) { t = 0.0; color_index = (color_index + 1) % num_colors; } } int main() { struct timespec last_breathing_update = {0}, now; double last_load = 0.0; int in_stress_mode = 0; char *shm_ptr; // Initialize shared memory for color int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666); ftruncate(shm_fd, 8); // Set size of shared memory shm_ptr = mmap(NULL, 8, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); // Initialize breathing colors clock_gettime(CLOCK_MONOTONIC, &last_breathing_update); while (1) { clock_gettime(CLOCK_MONOTONIC, &now); // Update breathing colors double elapsed_breathing = (now.tv_sec - last_breathing_update.tv_sec) * 1000.0 + (now.tv_nsec - last_breathing_update.tv_nsec) / 1.0e6; if (elapsed_breathing >= BREATHING_INTERVAL) { update_breathing_color(shm_ptr, &last_load, &in_stress_mode); last_breathing_update = now; } usleep(100000); // Sleep for 0.1 seconds to reduce CPU usage } // Clean up shared memory munmap(shm_ptr, 8); shm_unlink(SHM_NAME); return 0; }