Added smooth pass option, improved texture lookup performance, fixes #10 (and fixed issues with config copying)
This commit is contained in:
4
glava.c
4
glava.c
@@ -103,7 +103,7 @@ static void copy_cfg(const char* path, const char* dest, bool verbose) {
|
||||
fprintf(stderr, "failed to open (source) '%s': %s\n", p, strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
if ((dest = open(f, O_WRONLY | O_CREAT, ACCESSPERMS)) < 0) {
|
||||
if ((dest = open(f, O_TRUNC | O_WRONLY | O_CREAT, ACCESSPERMS)) < 0) {
|
||||
fprintf(stderr, "failed to open (destination) '%s': %s\n", f, strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -126,7 +126,7 @@ static void copy_cfg(const char* path, const char* dest, bool verbose) {
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (symlink(p, f))
|
||||
if (symlink(p, f) && errno != EEXIST)
|
||||
fprintf(stderr, "failed to symlink '%s' -> '%s': %s\n", p, f, strerror(errno));
|
||||
else if (verbose)
|
||||
printf("symlink '%s' -> '%s'\n", p, f);
|
||||
|
||||
274
render.c
274
render.c
@@ -36,6 +36,74 @@
|
||||
#define VERTEX_SHADER_SRC \
|
||||
"layout(location = 0) in vec3 pos; void main() { gl_Position = vec4(pos.x, pos.y, 0.0F, 1.0F); }"
|
||||
|
||||
/* GLSL bind source */
|
||||
|
||||
struct gl_bind_src {
|
||||
const char* name;
|
||||
int type;
|
||||
int src_type;
|
||||
};
|
||||
|
||||
/* function that can be applied to uniform binds */
|
||||
|
||||
struct gl_transform {
|
||||
const char* name;
|
||||
int type;
|
||||
void (*apply)(struct gl_data*, void**, void* data);
|
||||
};
|
||||
|
||||
/* data for sampler1D */
|
||||
|
||||
struct gl_sampler_data {
|
||||
float* buf;
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
/* GLSL uniform bind */
|
||||
|
||||
struct gl_bind {
|
||||
const char* name;
|
||||
GLuint uniform;
|
||||
int type;
|
||||
int src_type;
|
||||
void (**transformations)(struct gl_data*, void**, void* data);
|
||||
size_t t_sz;
|
||||
void* udata;
|
||||
};
|
||||
|
||||
/* GL screen framebuffer object */
|
||||
|
||||
struct gl_sfbo {
|
||||
GLuint fbo, tex, shader;
|
||||
bool valid;
|
||||
const char* name;
|
||||
struct gl_bind* binds;
|
||||
size_t binds_sz;
|
||||
};
|
||||
|
||||
/* data for screen-space overlay (quad) */
|
||||
|
||||
struct overlay_data {
|
||||
GLuint vbuf, vao;
|
||||
};
|
||||
|
||||
struct gl_data {
|
||||
struct gl_sfbo* stages;
|
||||
struct overlay_data overlay;
|
||||
GLuint audio_tex_r, audio_tex_l, bg_tex, sm_prog;
|
||||
size_t stages_sz, bufscale, avg_frames;
|
||||
GLFWwindow* w;
|
||||
int lww, lwh, lwx, lwy; /* last window dimensions */
|
||||
int rate; /* framerate */
|
||||
double tcounter;
|
||||
int fcounter, ucounter, kcounter;
|
||||
bool print_fps, avg_window, interpolate, force_geometry, copy_desktop, smooth_pass;
|
||||
void** t_data;
|
||||
float gravity_step, target_spu, fr, ur, smooth_distance, smooth_ratio, smooth_factor, fft_scale, fft_cutoff;
|
||||
float* interpolate_buf[6];
|
||||
int geometry[4];
|
||||
};
|
||||
|
||||
/* load shader file */
|
||||
static GLuint shaderload(const char* rpath,
|
||||
GLenum type,
|
||||
@@ -43,7 +111,8 @@ static GLuint shaderload(const char* rpath,
|
||||
const char* config,
|
||||
struct request_handler* handlers,
|
||||
int shader_version,
|
||||
bool raw) {
|
||||
bool raw,
|
||||
struct gl_data* gl) {
|
||||
|
||||
size_t s_len = strlen(shader);
|
||||
|
||||
@@ -73,7 +142,11 @@ static GLuint shaderload(const char* rpath,
|
||||
|
||||
const GLchar* map = raw ? shader : mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
|
||||
static const GLchar* header_fmt = "#version %d\n#define UNIFORM_LIMIT %d\n";
|
||||
static const GLchar* header_fmt =
|
||||
"#version %d\n"
|
||||
"#define UNIFORM_LIMIT %d\n"
|
||||
"#define PRE_SMOOTHED_AUDIO %d\n"
|
||||
"#define SMOOTH_FACTOR %.6f\n";
|
||||
|
||||
struct glsl_ext ext = {
|
||||
.source = raw ? NULL : map,
|
||||
@@ -88,9 +161,10 @@ static GLuint shaderload(const char* rpath,
|
||||
/* If this is raw input, skip processing */
|
||||
if (!raw) ext_process(&ext, rpath);
|
||||
|
||||
size_t blen = strlen(header_fmt) + 28;
|
||||
size_t blen = strlen(header_fmt) + 42;
|
||||
GLchar* buf = malloc((blen * sizeof(GLchar*)) + ext.p_len);
|
||||
int written = snprintf(buf, blen, header_fmt, (int) shader_version, (int) max_uniforms);
|
||||
int written = snprintf(buf, blen, header_fmt, (int) shader_version, (int) max_uniforms,
|
||||
gl->smooth_pass ? 1 : 0, (double) gl->smooth_factor);
|
||||
if (written < 0) {
|
||||
fprintf(stderr, "snprintf() encoding error while prepending header to shader '%s'\n", path);
|
||||
return 0;
|
||||
@@ -173,9 +247,10 @@ static GLuint shaderlink_f(GLuint* arr) {
|
||||
}
|
||||
|
||||
/* load shaders */
|
||||
#define shaderbuild(shader_path, c, r, v, ...) \
|
||||
shaderbuild_f(shader_path, c, r, v, (const char*[]) {__VA_ARGS__, 0})
|
||||
static GLuint shaderbuild_f(const char* shader_path,
|
||||
#define shaderbuild(gl, shader_path, c, r, v, ...) \
|
||||
shaderbuild_f(gl, shader_path, c, r, v, (const char*[]) {__VA_ARGS__, 0})
|
||||
static GLuint shaderbuild_f(struct gl_data* gl,
|
||||
const char* shader_path,
|
||||
const char* config,
|
||||
struct request_handler* handlers,
|
||||
int shader_version,
|
||||
@@ -193,7 +268,7 @@ static GLuint shaderbuild_f(const char* shader_path,
|
||||
if (!strcmp(path + t + 1, "frag") || !strcmp(path + t + 1, "glsl")) {
|
||||
if (!(shaders[i] = shaderload(path, GL_FRAGMENT_SHADER,
|
||||
shader_path, config, handlers,
|
||||
shader_version, false))) {
|
||||
shader_version, false, gl))) {
|
||||
return 0;
|
||||
}
|
||||
} else if (!strcmp(path + t + 1, "vert")) {
|
||||
@@ -213,7 +288,7 @@ static GLuint shaderbuild_f(const char* shader_path,
|
||||
}
|
||||
}
|
||||
/* load builtin vertex shader */
|
||||
shaders[sz] = shaderload(NULL, GL_VERTEX_SHADER, VERTEX_SHADER_SRC, NULL, handlers, shader_version, true);
|
||||
shaders[sz] = shaderload(NULL, GL_VERTEX_SHADER, VERTEX_SHADER_SRC, NULL, handlers, shader_version, true, gl);
|
||||
fflush(stdout);
|
||||
return shaderlink_f(shaders);
|
||||
}
|
||||
@@ -247,48 +322,8 @@ static void update_1d_tex(GLuint tex, size_t w, float* data) {
|
||||
#define BIND_SAMPLER1D 8
|
||||
#define BIND_SAMPLER2D 9
|
||||
|
||||
/* GLSL bind source */
|
||||
|
||||
struct gl_bind_src {
|
||||
const char* name;
|
||||
int type;
|
||||
int src_type;
|
||||
};
|
||||
|
||||
/* function that can be applied to uniform binds */
|
||||
|
||||
struct gl_transform {
|
||||
const char* name;
|
||||
int type;
|
||||
void (*apply)(struct gl_data*, void**, void* data);
|
||||
};
|
||||
|
||||
struct gl_sampler_data {
|
||||
float* buf;
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
/* GLSL uniform bind */
|
||||
|
||||
struct gl_bind {
|
||||
const char* name;
|
||||
GLuint uniform;
|
||||
int type;
|
||||
int src_type;
|
||||
void (**transformations)(struct gl_data*, void**, void* data);
|
||||
size_t t_sz;
|
||||
};
|
||||
|
||||
/* setup screen framebuffer object and its texture */
|
||||
|
||||
struct gl_sfbo {
|
||||
GLuint fbo, tex, shader;
|
||||
bool valid;
|
||||
const char* name;
|
||||
struct gl_bind* binds;
|
||||
size_t binds_sz;
|
||||
};
|
||||
|
||||
static void setup_sfbo(struct gl_sfbo* s, int w, int h) {
|
||||
GLuint tex = s->valid ? s->tex : ({ glGenTextures(1, &s->tex); s->tex; });
|
||||
GLuint fbo = s->valid ? s->fbo : ({ glGenFramebuffers(1, &s->fbo); s->fbo; });
|
||||
@@ -311,10 +346,6 @@ static void setup_sfbo(struct gl_sfbo* s, int w, int h) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
struct overlay_data {
|
||||
GLuint vbuf, vao;
|
||||
};
|
||||
|
||||
static void overlay(struct overlay_data* d) {
|
||||
GLfloat buf[18];
|
||||
buf[0] = -1.0f; buf[1] = -1.0f; buf[2] = 0.0f;
|
||||
@@ -352,23 +383,6 @@ static void drawoverlay(const struct overlay_data* d) {
|
||||
#define TRANSFORM_FFT 1
|
||||
#define TRANSFORM_WINDOW 2
|
||||
|
||||
struct gl_data {
|
||||
struct gl_sfbo* stages;
|
||||
struct overlay_data overlay;
|
||||
GLuint audio_tex_r, audio_tex_l, bg_tex;
|
||||
size_t stages_sz, bufscale, avg_frames;
|
||||
GLFWwindow* w;
|
||||
int lww, lwh, lwx, lwy; /* last window dimensions */
|
||||
int rate; /* framerate */
|
||||
double tcounter;
|
||||
int fcounter, ucounter, kcounter;
|
||||
bool print_fps, avg_window, interpolate, force_geometry, copy_desktop;
|
||||
void** t_data;
|
||||
float gravity_step, target_spu, fr, ur, smooth_distance, smooth_ratio, fft_scale, fft_cutoff;
|
||||
float* interpolate_buf[6];
|
||||
int geometry[4];
|
||||
};
|
||||
|
||||
#ifdef GLAD_DEBUG
|
||||
|
||||
struct err_msg {
|
||||
@@ -677,10 +691,13 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
.gravity_step = 4.2,
|
||||
.interpolate = true,
|
||||
.force_geometry = false,
|
||||
.smooth_factor = 0.025,
|
||||
.smooth_distance = 0.01,
|
||||
.smooth_ratio = 4,
|
||||
.bg_tex = 0,
|
||||
.sm_prog = 0,
|
||||
.copy_desktop = true,
|
||||
.smooth_pass = true,
|
||||
.fft_scale = 10.2F,
|
||||
.fft_cutoff = 0.3F,
|
||||
.geometry = { 0, 0, 500, 400 }
|
||||
@@ -814,6 +831,10 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
.handler = RHANDLER(name, args, { gl->avg_window = *(bool*) args[0]; }) },
|
||||
{ .name = "setgravitystep", .fmt = "f",
|
||||
.handler = RHANDLER(name, args, { gl->gravity_step = *(float*) args[0]; }) },
|
||||
{ .name = "setsmoothpass", .fmt = "b",
|
||||
.handler = RHANDLER(name, args, { gl->smooth_pass = *(bool*) args[0]; }) },
|
||||
{ .name = "setsmoothfactor", .fmt = "f",
|
||||
.handler = RHANDLER(name, args, { gl->smooth_factor = *(float*) args[0]; }) },
|
||||
{ .name = "setsmooth", .fmt = "f",
|
||||
.handler = RHANDLER(name, args, { gl->smooth_distance = *(float*) args[0]; }) },
|
||||
{ .name = "setsmoothratio", .fmt = "f",
|
||||
@@ -887,7 +908,8 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
.type = src->type,
|
||||
.src_type = src->src_type,
|
||||
.transformations = malloc(1),
|
||||
.t_sz = 0
|
||||
.t_sz = 0,
|
||||
.udata = NULL
|
||||
};
|
||||
})
|
||||
},
|
||||
@@ -1038,7 +1060,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
};
|
||||
|
||||
current = s;
|
||||
GLuint id = shaderbuild(shaders, data, handlers, shader_version, d->d_name);
|
||||
GLuint id = shaderbuild(gl, shaders, data, handlers, shader_version, d->d_name);
|
||||
if (!id) {
|
||||
abort();
|
||||
}
|
||||
@@ -1073,6 +1095,18 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const char* util_folder = "util";
|
||||
size_t u_len = strlen(util_folder);
|
||||
size_t usz = d_len + u_len + 2;
|
||||
char util[usz]; /* module pack path to use */
|
||||
snprintf(util, usz, "%s/%s", data, util_folder);
|
||||
|
||||
if (!(gl->sm_prog = shaderbuild(gl, util, data, handlers, shader_version, "smooth_pass.frag"))) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
gl->stages = stages;
|
||||
gl->stages_sz = count;
|
||||
|
||||
@@ -1243,9 +1277,9 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
"}" "\n";
|
||||
if (!setup) {
|
||||
bg_prog = shaderlink(shaderload(NULL, GL_VERTEX_SHADER, VERTEX_SHADER_SRC,
|
||||
NULL, NULL, 330, true),
|
||||
NULL, NULL, 330, true, gl),
|
||||
shaderload(NULL, GL_FRAGMENT_SHADER, frag_shader,
|
||||
NULL, NULL, 330, true));
|
||||
NULL, NULL, 330, true, gl));
|
||||
bg_utex = glGetUniformLocation(bg_prog, "tex");
|
||||
bg_screen = glGetUniformLocation(bg_prog, "screen");
|
||||
glBindFragDataLocation(bg_prog, 1, "fragment");
|
||||
@@ -1278,7 +1312,7 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
struct gl_bind* bind = ¤t->binds[b];
|
||||
|
||||
/* Handle transformations and bindings for 1D samplers */
|
||||
void handle_1d_tex(GLuint tex, float* buf, float* ubuf, size_t sz, int offset) {
|
||||
void handle_1d_tex(GLuint tex, float* buf, float* ubuf, size_t sz, int offset, bool audio) {
|
||||
|
||||
/* Only apply transformations if the buffers we
|
||||
were given are newly copied from PA */
|
||||
@@ -1294,10 +1328,90 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
transform types are added) */
|
||||
}
|
||||
}
|
||||
|
||||
/* Update texture with our data */
|
||||
update_1d_tex(tex, sz, gl->interpolate ? (ubuf ? ubuf : buf) : buf);
|
||||
|
||||
/* Apply pre-smoothing shader pass if configured */
|
||||
if (audio && gl->smooth_pass) {
|
||||
static bool setup = false;
|
||||
static GLuint sm_utex, sm_usz, sm_uw;
|
||||
|
||||
/* Compile preprocess shader and handle uniform locations */
|
||||
if (!setup) {
|
||||
sm_utex = glGetUniformLocation(gl->sm_prog, "tex");
|
||||
sm_usz = glGetUniformLocation(gl->sm_prog, "sz");
|
||||
sm_uw = glGetUniformLocation(gl->sm_prog, "w");
|
||||
glBindFragDataLocation(gl->sm_prog, 1, "fragment");
|
||||
setup = true;
|
||||
}
|
||||
|
||||
/* Per-bind data containing the framebuffer and 1D texture to render to for
|
||||
this smoothing step. */
|
||||
|
||||
struct sm_fb {
|
||||
GLuint fbo, tex;
|
||||
};
|
||||
|
||||
/* Allocate and setup our per-bind data, if needed */
|
||||
|
||||
struct sm_fb* sm;
|
||||
if (!bind->udata) {
|
||||
sm = malloc(sizeof(struct sm_fb));
|
||||
bind->udata = sm;
|
||||
|
||||
glGenTextures(1, &sm->tex);
|
||||
glGenFramebuffers(1, &sm->fbo);
|
||||
|
||||
/* 1D texture parameters */
|
||||
glBindTexture(GL_TEXTURE_1D, sm->tex);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexImage1D(GL_TEXTURE_1D, 0, GL_R16, sz, 0, GL_RED, GL_FLOAT, NULL);
|
||||
|
||||
/* setup and bind framebuffer to texture */
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sm->fbo);
|
||||
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_1D, sm->tex, 0);
|
||||
|
||||
switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
|
||||
case GL_FRAMEBUFFER_COMPLETE: break;
|
||||
default:
|
||||
fprintf(stderr, "error in frambuffer state\n");
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
/* Just bind our data if it was already allocated and setup */
|
||||
sm = (struct sm_fb*) bind->udata;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sm->fbo);
|
||||
glBindTexture(GL_TEXTURE_1D, sm->tex);
|
||||
}
|
||||
|
||||
glUseProgram(gl->sm_prog);
|
||||
glActiveTexture(GL_TEXTURE0 + offset);
|
||||
glBindTexture(GL_TEXTURE_1D, tex);
|
||||
glUniform1i(sm_uw, sz); /* target texture width */
|
||||
glUniform1i(sm_usz, sz); /* source texture width */
|
||||
glUniform1i(sm_utex, offset);
|
||||
glDisable(GL_BLEND);
|
||||
glViewport(0, 0, sz, 1);
|
||||
drawoverlay(&gl->overlay);
|
||||
glViewport(0, 0, ww, wh);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
/* Return state */
|
||||
glUseProgram(current->shader);
|
||||
if (current->valid)
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
|
||||
else
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
tex = sm->tex; /* replace input texture with our processed one */
|
||||
}
|
||||
|
||||
if (!needed[offset]) {
|
||||
glActiveTexture(GL_TEXTURE0 + offset);
|
||||
update_1d_tex(tex, sz, gl->interpolate ? (ubuf ? ubuf : buf) : buf);
|
||||
glBindTexture(GL_TEXTURE_1D, tex);
|
||||
needed[offset] = true;
|
||||
}
|
||||
@@ -1319,10 +1433,10 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
}
|
||||
glUniform1i(bind->uniform, 0);
|
||||
break;
|
||||
case SRC_AUDIO_L: handle_1d_tex(gl->audio_tex_l, lb, ilb, bsz, 1); break;
|
||||
case SRC_AUDIO_R: handle_1d_tex(gl->audio_tex_r, rb, irb, bsz, 2); break;
|
||||
case SRC_AUDIO_SZ: glUniform1i(bind->uniform, bsz); break;
|
||||
case SRC_SCREEN: glUniform2i(bind->uniform, (GLint) ww, (GLint) wh); break;
|
||||
case SRC_AUDIO_L: handle_1d_tex(gl->audio_tex_l, lb, ilb, bsz, 1, true); break;
|
||||
case SRC_AUDIO_R: handle_1d_tex(gl->audio_tex_r, rb, irb, bsz, 2, true); break;
|
||||
case SRC_AUDIO_SZ: glUniform1i(bind->uniform, bsz); break;
|
||||
case SRC_SCREEN: glUniform2i(bind->uniform, (GLint) ww, (GLint) wh); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,4 @@
|
||||
#define DIRECTION 0
|
||||
/* Whether to switch left/right audio buffers */
|
||||
#define INVERT 0
|
||||
/* Smoothing factor, in normalized width */
|
||||
#define SMOOTH 0.025
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ void main() {
|
||||
float p = int(dx / section) / float(nbars / 2); /* position, (-1.0F, 1.0F)) */
|
||||
p += sign(p) * ((0.5F + center) / screen.x); /* index center of bar position */
|
||||
/* Apply smooth function and index texture */
|
||||
#define smooth_f(tex, p) smooth_audio(tex, audio_sz, p, SMOOTH)
|
||||
#define smooth_f(tex, p) smooth_audio(tex, audio_sz, p)
|
||||
float v;
|
||||
/* ignore out of bounds values */
|
||||
if (p > 1.0F || p < -1.0F) {
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#define VSCALE 450
|
||||
/* Rendering direction, either -1 (outwards) or 1 (inwards). */
|
||||
#define DIRECTION 1
|
||||
/* Smoothing factor, in normalized width */
|
||||
#define SMOOTH 0.008
|
||||
|
||||
/* The `RCOL_OFF`, `LCOL_OFF` AND `LSTEP` definitions are used to calculate
|
||||
the `COLOR` macro definition for output. You can remove all these values
|
||||
|
||||
@@ -84,7 +84,7 @@ float half_w;
|
||||
|
||||
void render_side(in sampler1D tex, float idx) {
|
||||
highp float pixel = 1.0F / float(screen.x);
|
||||
float s = smooth_audio_adj(tex, audio_sz, idx / half_w, SMOOTH, pixel);
|
||||
float s = smooth_audio_adj(tex, audio_sz, idx / half_w, pixel);
|
||||
/* scale the data upwards so we can see it */
|
||||
s *= VSCALE;
|
||||
/* clamp far ends of the screen down to make the ends of the graph smoother */
|
||||
|
||||
@@ -21,5 +21,3 @@
|
||||
#define ROTATE (PI / 2)
|
||||
/* Whether to switch left/right audio buffers */
|
||||
#define INVERT 0
|
||||
/* Smoothing factor, in normalized width */
|
||||
#define SMOOTH 0.025
|
||||
|
||||
@@ -50,7 +50,7 @@ void main() {
|
||||
if (INVERT > 0)
|
||||
idx = -idx; /* Invert if needed */
|
||||
float pos = int(abs(idx) / section) / float(NBARS / 2); /* bar position, [0, 1) */
|
||||
#define smooth_f(tex) smooth_audio(tex, audio_sz, pos, SMOOTH) /* smooth function format */
|
||||
#define smooth_f(tex) smooth_audio(tex, audio_sz, pos) /* smooth function format */
|
||||
float v;
|
||||
if (idx > 0) v = smooth_f(audio_l); /* left buffer */
|
||||
else v = smooth_f(audio_r); /* right buffer */
|
||||
|
||||
@@ -45,3 +45,14 @@
|
||||
|
||||
val -= (gravitystep) * (seconds per update) */
|
||||
#request setgravitystep 4.2
|
||||
|
||||
/* Smoothing factor. Larger values mean more smoothing in the output,
|
||||
however high values can be expensive to compute. Values are in
|
||||
normalized width: [0.0, 1.0) */
|
||||
#request setsmoothfactor 0.025
|
||||
|
||||
/* Whether to use a separate pass for audio data while smoothing. On
|
||||
most hardware, this will improve performance, but involves doing a
|
||||
separate render step for each audio texture and will add some driver
|
||||
(CPU) overhead. */
|
||||
#request setsmoothpass true
|
||||
|
||||
@@ -29,28 +29,34 @@ float iscale_audio(float idx) {
|
||||
return -log((SAMPLE_RANGE) * idx) / (SAMPLE_SCALE);
|
||||
}
|
||||
|
||||
float smooth_audio(in sampler1D tex, int tex_sz, highp float idx, float r) {
|
||||
/* Note: the SMOOTH_FACTOR macro is defined by GLava itself, from `#request setsmoothfactor`*/
|
||||
|
||||
float smooth_audio(in sampler1D tex, int tex_sz, highp float idx) {
|
||||
#if PRE_SMOOTHED_AUDIO < 1
|
||||
float
|
||||
smin = scale_audio(clamp(idx - r, 0, 1)) * tex_sz,
|
||||
smax = scale_audio(clamp(idx + r, 0, 1)) * tex_sz,
|
||||
smin = scale_audio(clamp(idx - SMOOTH_FACTOR, 0, 1)) * tex_sz,
|
||||
smax = scale_audio(clamp(idx + SMOOTH_FACTOR, 0, 1)) * tex_sz,
|
||||
avg = 0, s, weight = 0;
|
||||
float m = ((smax - smin) / 2.0F);
|
||||
float rm = smin + m; /* middle */
|
||||
for (s = smin; s <= smax; s += 1.0F) {
|
||||
float w = ROUND_FORMULA(clamp((m - abs(rm - s)) / m, 0, 1));
|
||||
weight += w;
|
||||
avg += texture(tex, float(s) / float(tex_sz)).r * w;
|
||||
avg += texelFetch(tex, int(round(s)), 0).r * w;
|
||||
}
|
||||
avg /= weight;
|
||||
return avg;
|
||||
#else
|
||||
return texelFetch(tex, int(round(idx * tex_sz)), 0).r;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Applies the audio smooth sampling function three times to the adjacent values */
|
||||
float smooth_audio_adj(in sampler1D tex, int tex_sz, highp float idx, float r, highp float pixel) {
|
||||
float smooth_audio_adj(in sampler1D tex, int tex_sz, highp float idx, highp float pixel) {
|
||||
float
|
||||
al = smooth_audio(tex, tex_sz, max(idx - pixel, 0.0F), r),
|
||||
am = smooth_audio(tex, tex_sz, idx, r),
|
||||
ar = smooth_audio(tex, tex_sz, min(idx + pixel, 1.0F), r);
|
||||
al = smooth_audio(tex, tex_sz, max(idx - pixel, 0.0F)),
|
||||
am = smooth_audio(tex, tex_sz, idx),
|
||||
ar = smooth_audio(tex, tex_sz, min(idx + pixel, 1.0F));
|
||||
return (al + am + ar) / 3.0F;
|
||||
}
|
||||
|
||||
|
||||
16
shaders/util/smooth_pass.frag
Normal file
16
shaders/util/smooth_pass.frag
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
uniform sampler1D tex;
|
||||
uniform int sz;
|
||||
uniform int w;
|
||||
|
||||
out vec4 fragment;
|
||||
in vec4 gl_FragCoord;
|
||||
|
||||
#undef PRE_SMOOTHED_AUDIO
|
||||
#define PRE_SMOOTHED_AUDIO 0
|
||||
|
||||
#include ":util/smooth.glsl"
|
||||
|
||||
void main() {
|
||||
fragment = vec4(smooth_audio(tex, sz, gl_FragCoord.x / w), 0, 0, 0);
|
||||
}
|
||||
Reference in New Issue
Block a user