Hello community,

here is the log from the commit of package glava for openSUSE:Factory checked 
in at 2019-03-12 09:54:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/glava (Old)
 and      /work/SRC/openSUSE:Factory/.glava.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "glava"

Tue Mar 12 09:54:39 2019 rev:3 rq:683773 version:1.6.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/glava/glava.changes      2019-02-25 
17:55:49.978413153 +0100
+++ /work/SRC/openSUSE:Factory/.glava.new.28833/glava.changes   2019-03-12 
09:54:39.907523105 +0100
@@ -1,0 +2,13 @@
+Mon Mar 11 11:47:52 UTC 2019 - [email protected]
+
+- Update to 1.6.0:
+  * FIFO support has been added. See README.md for details, also see #78
+  * Added sampling modes for the GLSL smoothing pass to allow for more 
accurate output
+  * Added support for disabling shader passes through GLSL, see #97
+  * Enhanced rendering and options for graph, courtesy of @arch1t3cht30[3], 
see #97
+  * Fixed clickthrough on Openbox (and potentially other window managers), see 
#80
+  * Fixed the two lowest-frequency bars having the same value while running 
the bars module
+  * Fixed some build issues on Ubuntu, musl, see #94, #91
+  * Fixed a bug with circle that only manifested on some integrated graphics 
chips, see #70
+
+-------------------------------------------------------------------

Old:
----
  v1.5.8.tar.gz

New:
----
  v1.6.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ glava.spec ++++++
--- /var/tmp/diff_new_pack.XJeXcd/_old  2019-03-12 09:54:40.391523009 +0100
+++ /var/tmp/diff_new_pack.XJeXcd/_new  2019-03-12 09:54:40.395523008 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           glava
-Version:        1.5.8
+Version:        1.6.0
 Release:        0
 Summary:        OpenGL audio spectrum visualizer
 License:        GPL-3.0-only

++++++ v1.5.8.tar.gz -> v1.6.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/.gitignore new/glava-1.6.0/.gitignore
--- old/glava-1.5.8/.gitignore  1970-01-01 01:00:00.000000000 +0100
+++ new/glava-1.6.0/.gitignore  2019-03-10 01:55:03.000000000 +0100
@@ -0,0 +1,3 @@
+*.o
+build_state
+glava
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/Makefile new/glava-1.6.0/Makefile
--- old/glava-1.5.8/Makefile    2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/Makefile    2019-03-10 01:55:03.000000000 +0100
@@ -1,3 +1,5 @@
+SHELL := /bin/bash
+
 src = $(wildcard *.c)
 obj = $(src:.c=.o)
 
@@ -39,6 +41,9 @@
     ifndef SHADERDIR
         ifdef XDG_CONFIG_DIRS
             SHADERDIR = /$(firstword $(subst :, ,$(XDG_CONFIG_DIRS)))/glava/
+           ifeq ($(wildcard $(SHADERDIR)/..),)
+                SHADERDIR = /etc/xdg/glava/
+            endif
         else
             SHADERDIR = /etc/xdg/glava/
         endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/README.md new/glava-1.6.0/README.md
--- old/glava-1.5.8/README.md   2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/README.md   2019-03-10 01:55:03.000000000 +0100
@@ -3,7 +3,7 @@
 
 **GLava** is an OpenGL audio spectrum visualizer. Its primary use case is for 
desktop windows or backgrounds. Displayed to the left is the `radial` shader 
module, and [here is a demonstration video](https://streamable.com/dgpj8). 
Development is active, and reporting issues is encouranged.
 
-**Compiling** (Or use the Arch Linux [`glava` 
package](https://www.archlinux.org/packages/community/x86_64/glava/), or the 
[`glava-git` AUR package](https://aur.archlinux.org/packages/glava-git/))**:**
+**Compiling:**
 
 ```bash
 $ git clone https://github.com/wacossusca34/glava
@@ -31,9 +31,16 @@
 
 **Ubuntu/Debian users:** the following command ensures you have all the needed 
packages and headers to compile GLava:
 ```bash
-sudo apt-get install libpulse0 libpulse-dev libglfw3 libglfw3-dev libxext6 
libxext-dev libxcomposite-dev python make gcc 
+sudo apt-get install libpulse0 libpulse-dev libxext6 libxext-dev 
libxrender-dev libxcomposite-dev make gcc 
 ```
 
+## Installation
+Some distributions have a package for `glava`. If your distribution is not 
listed please use the compilation instructions above.
+
+- Arch Linux [`glava` 
package](https://www.archlinux.org/packages/community/x86_64/glava/), or 
[`glava-git` AUR package](https://aur.archlinux.org/packages/glava-git/)
+- NixOS 
[package](https://github.com/NixOS/nixpkgs/blob/release-18.09/pkgs/applications/misc/glava/default.nix)
+- openSUSE 
[package](https://build.opensuse.org/package/show/X11:Utilities/glava)
+
 ## [Configuration](https://github.com/wacossusca34/glava/wiki)
 
 GLava will start by looking for an entry point in the user configuration 
folder (`~/.config/glava/rc.glsl`\*), and will fall back to loading from the 
shader installation folder (`/etc/xdg/glava`\*). The entry point will specify a 
module to load and should set global configuration variables. Configuration for 
specific modules can be done in their respective `.glsl` files, which the 
module itself will include.
@@ -68,6 +75,21 @@
 
 Note that some WMs listed without issues have specific overrides when using 
the `--desktop` flag. See `shaders/env_*.glsl` files for details.
 
+## Reading from MPD's FIFO output
+
+Add the following to your `~/.config/mpd.conf`:
+
+```
+audio_output {
+    type                    "fifo"
+    name                    "glava_fifo"
+    path                    "/tmp/mpd.fifo"
+    format                  "22050:16:2"
+}
+```
+
+Note the `22050` sample rate -- this is the reccommended setting for GLava. 
Restart MPD (if nessecary) and start GLava with `glava --audio=fifo`.
+
 ## Licensing
 
 GLava is licensed under the terms of the GPLv3, with the exemption of 
`khrplatform.h`, which is licensed under the terms in its header. GLava 
includes some (heavily modified) source code that originated from 
[cava](https://github.com/karlstav/cava), which was initially provided under 
the MIT license. The source files that originated from cava are the following:
@@ -86,7 +108,3 @@
 The below copyright applies for the modifications to the files listed above, 
and the remaining sources in the repository:
 
 `Copyright (c) 2017 Levi Webb`
-
-## Porting
-
-GLava was built with GLFW, making the graphics frontend mostly compatible if 
it were to be ported to Windows, and I have taken most of the Xlib-specific 
code and placed it into `xwin.c` if anyone decides they wish to attempt at a 
port.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/fifo.c new/glava-1.6.0/fifo.c
--- old/glava-1.5.8/fifo.c      2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/fifo.c      2019-03-10 01:55:03.000000000 +0100
@@ -7,74 +7,123 @@
 #include <fcntl.h>
 #include <math.h>
 #include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <poll.h>
 
 #include "fifo.h"
 
-void* input_fifo(void* data) {
-       struct audio_data* audio = (struct audio_data *) data;
-       int fd;
-       int n = 0;
-       signed char buf[1024];
-       int tempr, templ, lo;
-       int q, i;
-       int t = 0;
-       int size = 1024;
-       int bytes = 0;
-       int flags;
-       struct timespec req = { .tv_sec = 0, .tv_nsec = 10000000 };
-    
-       fd = open(audio->source, O_RDONLY);
-       flags = fcntl(fd, F_GETFL, 0);
-       fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+/* Implementation struct storage */
+
+typeof(*audio_impls) audio_impls[sizeof(audio_impls) / sizeof(struct 
audio_impl*)] = {};
+size_t audio_impls_idx = 0;
+
+/* FIFO backend */
+
+static void init(struct audio_data* audio) {
+    if (!audio->source) {
+        audio->source = strdup("/tmp/mpd.fifo");
+    }
+}
+
+static void* entry(void* data) {
+    struct audio_data* audio = (struct audio_data *) data;
     
-       while (1) {
-               bytes = read(fd, buf, sizeof(buf));
+    float* bl = (float*) audio->audio_out_l;
+    float* br = (float*) audio->audio_out_r;
+    size_t fsz = audio->audio_buf_sz;
+    size_t ssz = audio->sample_sz;
+    
+    int fd;
+    int16_t buf[ssz / 2];
+    size_t q;
+    int timeout = 50;
+    
+    struct timespec tv_last = {}, tv;
+    bool measured = false;
+    
+    if ((fd = open(audio->source, O_RDONLY)) == -1) {
+        fprintf(stderr, "failed to open FIFO audio source \"%s\": %s\n", 
audio->source, strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+
+    struct pollfd pfd = {
+        .fd     = fd,
+        .events = POLLIN
+    };
+
+    size_t buffer_offset = (fsz - (ssz / 4));
+    
+    while (true) {
+
+        /* The poll timeout is set to accommodate an approximate UPS, but has 
little purpose except
+           for effectively setting the rate of empty samples in the event of 
the FIFO descriptor
+           blocking for long periods of time. */
         
-               if (bytes == -1) { /* if no bytes read, sleep 10ms and zero 
shared buffer */
-                       nanosleep (&req, NULL);
-                       t++;
-                       if (t > 10) {
-                               for (i = 0; i < 2048; i++)audio->audio_out_l[i] 
= 0;
-                               for (i = 0; i < 2048; i++)audio->audio_out_r[i] 
= 0;
-                               t = 0;
-                       }
-               } else { /* if bytes read, go ahead */
-                       t = 0;
-                       for (q = 0; q < (size / 4); q++) {
-                
-                               tempr = (buf[4 * q + 3] << 2);
-                
-                               lo =  (buf[4 * q + 2] >> 6);
-                               if (lo < 0) lo = abs(lo) + 1;
-                               if (tempr >= 0) tempr = tempr + lo;
-                               else tempr = tempr - lo;
-                
-                               templ = (buf[4 * q + 1] << 2);
-                
-                               lo =  (buf[4 * q] >> 6);
-                               if (lo < 0) lo = abs(lo) + 1;
-                               if (templ >= 0) templ = templ + lo;
-                               else templ = templ - lo;
-                
-                               if (audio->channels == 1) audio->audio_out_l[n] 
= (tempr + templ) / 2;
-                
-                               /* stereo storing channels in buffer */
-                               if (audio->channels == 2) {
-                                       audio->audio_out_l[n] = templ;
-                                       audio->audio_out_r[n] = tempr;
-                }
+        switch (poll(&pfd, 1, timeout)) {
+            case -1:
+                fprintf(stderr, "FIFO backend: poll() failed (%s)\n", 
strerror(errno));
+                exit(EXIT_FAILURE);
+            case 0:
+                pthread_mutex_lock(&audio->mutex);
+                
+                memmove(bl, &bl[ssz / 4], buffer_offset * sizeof(float));
+                memmove(br, &br[ssz / 4], buffer_offset * sizeof(float));
+                
+                for (q = 0; q < (ssz / 4); ++q) bl[buffer_offset + q] = 0;
+                for (q = 0; q < (ssz / 4); ++q) br[buffer_offset + q] = 0;
+            
+                audio->modified = true;
+                
+                pthread_mutex_unlock(&audio->mutex);
+                break;
+            default: {
+                read(fd, buf, sizeof(buf));
+                clock_gettime(CLOCK_REALTIME, measured ? &tv : &tv_last);
+                if (measured) {
+                    /* Set the timeout slightly higher than the delay between 
samples to prevent empty writes */
+                    timeout = (((tv.tv_sec - tv_last.tv_sec) * 1000) + 
((tv.tv_nsec - tv_last.tv_nsec) / 1000000)) + 1;
+                    tv_last = tv;
+                } else measured = true;
+            
+                pthread_mutex_lock(&audio->mutex);
+                
+                memmove(bl, &bl[ssz / 4], buffer_offset * sizeof(float));
+                memmove(br, &br[ssz / 4], buffer_offset * sizeof(float));
+            
+                for (size_t n = 0, q = 0; q < (ssz / 2); q += 2) {
+
+                    size_t idx = (fsz - (ssz / 4)) + n;
+                
+                    if (audio->channels == 1) {
+                        float sample = ((buf[q] + buf[q + 1]) / 2) / (float) 
65535;
+                        bl[idx] = sample;
+                        br[idx] = sample;
+                    }
+                
+                    if (audio->channels == 2) {
+                        bl[idx] = buf[q] / (float) 65535;
+                        br[idx] = buf[q + 1] / (float) 65535;
+                    }
                 
-                               n++;
-                               if (n == 2048 - 1)n = 0;
-                       }
-               }
+                    n++;
+                }
+            
+                audio->modified = true;
+            
+                pthread_mutex_unlock(&audio->mutex);
+                break;
+            }
+        }
         
-               if (audio->terminate == 1) {
-                       close(fd);
-                       break;
-               }
+        if (audio->terminate == 1) {
+            close(fd);
+            break;
+        }
         
-       }
+    }
     
-       return 0;
+    return 0;
 }
+
+AUDIO_ATTACH(fifo);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/fifo.h new/glava-1.6.0/fifo.h
--- old/glava-1.5.8/fifo.h      2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/fifo.h      2019-03-10 01:55:03.000000000 +0100
@@ -14,4 +14,26 @@
     pthread_mutex_t mutex;
 };
 
-void* input_fifo(void* data);
+struct audio_impl {
+    const char* name;
+    void  (*init)(struct audio_data* data);
+    void* (*entry)(void* data);
+};
+
+#define AUDIO_FUNC(F)                                   \
+    .F = (typeof(((struct audio_impl*) NULL)->F)) &F
+
+extern struct audio_impl* audio_impls[4];
+extern size_t audio_impls_idx;
+
+static inline void register_audio_impl(struct audio_impl* impl) { 
audio_impls[audio_impls_idx++] = impl; }
+
+#define AUDIO_ATTACH(N)                                         \
+    static struct audio_impl N##_var = {                        \
+        .name = #N,                                             \
+        AUDIO_FUNC(init),                                       \
+        AUDIO_FUNC(entry),                                      \
+    };                                                          \
+    void __attribute__((constructor)) _##N##_construct(void) { \
+        register_audio_impl(&N##_var);                          \
+    }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/glava.c new/glava-1.6.0/glava.c
--- old/glava-1.5.8/glava.c     2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/glava.c     2019-03-10 01:55:03.000000000 +0100
@@ -69,6 +69,10 @@
 #error "Unsupported target system"
 #endif
 
+#ifndef ACCESSPERMS
+#define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) /* 0777 */
+#endif
+
 /* Copy installed shaders/configuration from the installed location
    (usually /etc/xdg). Modules (folders) will be linked instead of
    copied. */
@@ -177,6 +181,7 @@
     "-b, --backend           specifies a window creation backend to use. By 
default, the most\n"
     "                          appropriate backend will be used for the 
underlying windowing\n"
     "                          system.\n"
+    "-a, --audio=BACKEND     specifies an audio input backend to use.\n"
     "-V, --version           print application version and exit\n"
     "\n"
     "The REQUEST argument is evaluated identically to the \'#request\' 
preprocessor directive\n"
@@ -188,13 +193,17 @@
     "The FILE argument may be any file path. All specified file paths are 
relative to the\n"
     "active configuration root (usually ~/.config/glava if present).\n"
     "\n"
+    "The BACKEND argument may be any of the following strings (for this 
particular build):\n"
+    "%s"
+    "\n"
     GLAVA_VERSION_STRING "\n";
 
-static const char* opt_str = "dhvVe:Cm:b:r:";
+static const char* opt_str = "dhvVe:Cm:b:r:a:";
 static struct option p_opts[] = {
     {"help",        no_argument,       0, 'h'},
     {"verbose",     no_argument,       0, 'v'},
     {"desktop",     no_argument,       0, 'd'},
+    {"audio",       required_argument, 0, 'a'},
     {"request",     required_argument, 0, 'r'},
     {"entry",       required_argument, 0, 'e'},
     {"force-mod",   required_argument, 0, 'm'},
@@ -222,11 +231,12 @@
 
     /* Evaluate these macros only once, since they allocate */
     const char
-        * install_path = SHADER_INSTALL_PATH,
-        * user_path    = SHADER_USER_PATH,
-        * entry        = "rc.glsl",
-        * force        = NULL,
-        * backend      = NULL;
+        * install_path  = SHADER_INSTALL_PATH,
+        * user_path     = SHADER_USER_PATH,
+        * entry         = "rc.glsl",
+        * force         = NULL,
+        * backend       = NULL,
+        * audio_impl_name = "pulseaudio";
     const char* system_shader_paths[] = { user_path, install_path, NULL };
     
     char** requests    = malloc(1);
@@ -241,19 +251,26 @@
             case 'C': copy_mode = true;   break;
             case 'd': desktop   = true;   break;
             case 'r': append_buf(requests, &requests_sz, optarg); break;
-            case 'e': entry     = optarg; break;
-            case 'm': force     = optarg; break;
-            case 'b': backend   = optarg; break;
+            case 'e': entry           = optarg; break;
+            case 'm': force           = optarg; break;
+            case 'b': backend         = optarg; break;
+            case 'a': audio_impl_name = optarg; break;
             case '?': exit(EXIT_FAILURE); break;
             case 'V':
                 puts(GLAVA_VERSION_STRING);
                 exit(EXIT_SUCCESS);
                 break;
             default:
-            case 'h':
-                printf(help_str, argc > 0 ? argv[0] : "glava");
+            case 'h': {
+                char buf[2048];
+                size_t bsz = 0;
+                for (size_t t = 0; t < audio_impls_idx; ++t)
+                    bsz += snprintf(buf + bsz, sizeof(buf) - bsz, 
"\t\"%s\"%s\n", audio_impls[t]->name,
+                                    !strcmp(audio_impls[t]->name, 
audio_impl_name) ? " (default)" : "");
+                printf(help_str, argc > 0 ? argv[0] : "glava", buf);
                 exit(EXIT_SUCCESS);
                 break;
+            }
         }
     }
 
@@ -306,13 +323,27 @@
         .sample_sz    = rd->samplesize_request,
         .modified     = false
     };
-    if (!audio.source) {
-        get_pulse_default_sink(&audio);
-        if (verbose) printf("Using default PulseAudio sink: %s\n", 
audio.source);
+
+    struct audio_impl* impl = NULL;
+    
+    for (size_t t = 0; t < audio_impls_idx; ++t) {
+        if (!strcmp(audio_impls[t]->name, audio_impl_name)) {
+            impl = audio_impls[t];
+            break;
+        }
+    }
+
+    if (!impl) {
+        fprintf(stderr, "The specified audio backend (\"%s\") is not 
available.\n", audio_impl_name);
+        exit(EXIT_FAILURE);
     }
     
+    impl->init(&audio);
+    
+    if (verbose) printf("Using audio source: %s\n", audio.source);
+    
     pthread_t thread;
-    pthread_create(&thread, NULL, input_pulse, (void*) &audio);
+    pthread_create(&thread, NULL, impl->entry, (void*) &audio);
     
     float lb[rd->bufsize_request], rb[rd->bufsize_request];
     while (rd->alive) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/glx_wcb.c new/glava-1.6.0/glx_wcb.c
--- old/glava-1.5.8/glx_wcb.c   2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/glx_wcb.c   2019-03-10 01:55:03.000000000 +0100
@@ -193,8 +193,8 @@
     maximized   = false;
     transparent = false;
 
-    void* hgl  = dlopen("libGL.so", RTLD_LAZY);
-    void* hglx = dlopen("libGLX.so", RTLD_LAZY);
+    void* hgl  = dlopen("libGL.so.1", RTLD_LAZY);
+    void* hglx = dlopen("libGLX.so.0", RTLD_LAZY);
 
     if (!hgl && !hglx) {
         fprintf(stderr, "Failed to load GLX functions (libGL and libGLX do not 
exist!)\n");
@@ -254,15 +254,37 @@
     }
 }
 
+static bool find_parent(Window w, Window* parent) {
+    Window root, *children = NULL;
+    unsigned int num_children;
+
+    if(!XQueryTree(display, w, &root, parent, &children, &num_children))
+        return false;
+
+    if (children)
+        XFree(children);
+    
+    return *parent != None;
+}
+
 static void apply_clickthrough(struct glxwin* w) {
     if (w->clickthrough) {
         int ignored;
         if (XShapeQueryExtension(display, &ignored, &ignored)) {
-            Region region;
-            if ((region = XCreateRegion())) {
-                XShapeCombineRegion(display, w->w, ShapeInput, 0, 0, region, 
ShapeSet);
-                XDestroyRegion(region);
+            Window root = DefaultRootWindow(display);
+            Window win = w->w;
+            while (win != None) {
+                Region region;
+                if ((region = XCreateRegion())) {
+                    XShapeCombineRegion(display, w->w, ShapeInput, 0, 0, 
region, ShapeSet);
+                    XDestroyRegion(region);
+                }
+                Window parent;
+                find_parent(win, &parent);
+                win = (parent == root ? None : parent);
             }
+        } else {
+            fprintf(stderr, "Warning: XShape extension not available\n");
         }
     }
 }
@@ -278,6 +300,10 @@
                     w->should_close = true;
                 }
                 break;
+            case MapNotify:
+                apply_clickthrough(w);
+                XFlush(display);
+                break;
             case VisibilityNotify:
                 switch (ev.xvisibility.state) {
                     case VisibilityFullyObscured:
@@ -514,7 +540,6 @@
 static void set_visible(struct glxwin* w, bool visible) {
     if (visible) {
         XMapWindow(display, w->w);
-        apply_clickthrough(w);
         switch (w->override_state) {
             case '+': XRaiseWindow(display, w->w); break;
             case '-': XLowerWindow(display, w->w); break;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/pulse_input.c 
new/glava-1.6.0/pulse_input.c
--- old/glava-1.5.8/pulse_input.c       2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/pulse_input.c       2019-03-10 01:55:03.000000000 +0100
@@ -54,7 +54,9 @@
 }
 
 
-void get_pulse_default_sink(struct audio_data* audio) {
+static void init(struct audio_data* audio) {
+
+    if (audio->source) return;
     
        pa_mainloop_api* mainloop_api;
        pa_context* pulseaudio_context;
@@ -106,7 +108,7 @@
 #error "Unsupported float format (requires 32 bit IEEE (little or big endian) 
floating point support)"
 #endif
 
-void* input_pulse(void* data) {
+static void* entry(void* data) {
     struct audio_data* audio = (struct audio_data*) data;
     int i, n;
     size_t ssz = audio->sample_sz;
@@ -188,3 +190,5 @@
     
        return 0;
 }
+
+AUDIO_ATTACH(pulseaudio);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/render.c new/glava-1.6.0/render.c
--- old/glava-1.5.8/render.c    2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/render.c    2019-03-10 01:55:03.000000000 +0100
@@ -91,7 +91,7 @@
 
 struct gl_sfbo {
     GLuint fbo, tex, shader;
-    bool valid, nativeonly;
+    bool indirect, nativeonly;
     const char* name;
     struct gl_bind* binds;
     size_t binds_sz;
@@ -139,6 +139,7 @@
                          struct request_handler* handlers,
                          int                     shader_version,
                          bool                    raw,
+                         bool*                   skipped,
                          struct gl_data*         gl) {
 
     size_t s_len = strlen(shader);
@@ -218,14 +219,33 @@
     if (ret == GL_FALSE) {
         glGetShaderiv(s, GL_INFO_LOG_LENGTH, &ilen);
         if (ilen) {
-            GLchar ebuf[ilen];
+            GLchar* ebuf = malloc(sizeof(GLchar) * ilen);
             glGetShaderInfoLog(s, ilen, NULL, ebuf);
+            
+            /* check for `#error __disablestage` and flag `*skipped` 
accordingly */
+            if (skipped != NULL) {
+                bool last = false;
+                static const char* skip_keyword = "__disablestage";
+                size_t sksz = sizeof(skip_keyword);
+                for(size_t t = 0; t < (size_t) ilen; ++t) {
+                    if (ebuf[t] == '_') {
+                        if (last && !strncmp(ebuf + t - 1, skip_keyword, 
sksz)) {
+                            *skipped = true;
+                            goto free_ebuf;
+                        } else last = true;
+                    } else last = false;
+                }
+            }
+            
             fprintf(stderr, "Shader compilation failed for '%s':\n", path);
             fwrite(ebuf, sizeof(GLchar), ilen - 1, stderr);
             #ifdef GLAVA_DEBUG
             fprintf(stderr, "Processed shader source for '%s':\n", path);
             fwrite(buf, sizeof(GLchar), sl, stderr);
             #endif
+            
+        free_ebuf:
+            free(ebuf);
             return 0;
         } else {
             fprintf(stderr, "Shader compilation failed for '%s', but no info 
was available\n", path);
@@ -282,14 +302,16 @@
 }
 
 /* load shaders */
-#define shaderbuild(gl, shader_path, c, d, r, v, ...)                    \
-    shaderbuild_f(gl, shader_path, c, d, r, v, (const char*[]) {__VA_ARGS__, 
0})
+#define shaderbuild(gl, shader_path, c, d, r, v, s, ...)                 \
+    shaderbuild_f(gl, shader_path, c, d, r, v, s, (const char*[]) 
{__VA_ARGS__, 0})
 static GLuint shaderbuild_f(struct gl_data* gl,
                             const char* shader_path,
                             const char* config, const char* defaults,
                             struct request_handler* handlers,
                             int shader_version,
+                            bool* skipped,
                             const char** arr) {
+    if (skipped) *skipped = false;
     const char* str;
     int i = 0, sz = 0, t;
     while ((str = arr[i++]) != NULL) ++sz;
@@ -303,7 +325,7 @@
                 if (!strcmp(path + t + 1, "frag") || !strcmp(path + t + 1, 
"glsl")) {
                     if (!(shaders[i] = shaderload(path, GL_FRAGMENT_SHADER,
                                                   shader_path, config, 
defaults, handlers,
-                                                  shader_version, false, gl))) 
{
+                                                  shader_version, false, 
skipped, gl))) {
                         return 0;
                     }
                 } else if (!strcmp(path + t + 1, "vert")) {
@@ -323,7 +345,7 @@
         }
     }
     /* load builtin vertex shader */
-    shaders[sz] = shaderload(NULL, GL_VERTEX_SHADER, VERTEX_SHADER_SRC, NULL, 
NULL, handlers, shader_version, true, gl);
+    shaders[sz] = shaderload(NULL, GL_VERTEX_SHADER, VERTEX_SHADER_SRC, NULL, 
NULL, handlers, shader_version, true, NULL, gl);
     fflush(stdout);
     return shaderlink_f(shaders);
 }
@@ -358,9 +380,9 @@
 /* setup screen framebuffer object and its texture */
 
 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; 
});
-    s->valid = true;
+    GLuint tex = s->indirect ? s->tex : ({ glGenTextures(1, &s->tex); s->tex; 
});
+    GLuint fbo = s->indirect ? s->fbo : ({ glGenFramebuffers(1, &s->fbo); 
s->fbo; });
+    s->indirect = true;
     /* bind texture and setup space */
     glBindTexture(GL_TEXTURE_2D, tex);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -617,48 +639,48 @@
     float wtemp, wr, wpr, wpi, wi, theta;
     float tempr, tempi;
  
-    // reverse-binary reindexing
-    n = nn<<1;
-    j=1;
-    for (i=1; i<n; i+=2) {
-        if (j>i) {
+    /* reverse-binary reindexing */
+    n = nn << 1;
+    j = 1;
+    for (i = 1; i < n; i += 2) {
+        if (j > i) {
             swap(data[j-1], data[i-1]);
             swap(data[j], data[i]);
         }
         m = nn;
-        while (m>=2 && j>m) {
+        while (m >= 2 && j > m) {
             j -= m;
             m >>= 1;
         }
         j += m;
     };
  
-    // here begins the Danielson-Lanczos section
-    mmax=2;
-    while (n>mmax) {
-        istep = mmax<<1;
-        theta = -(2*M_PI/mmax);
-        wtemp = sin(0.5*theta);
-        wpr = -2.0*wtemp*wtemp;
+    /* here begins the Danielson-Lanczos section */
+    mmax = 2;
+    while (n > mmax) {
+        istep = mmax << 1;
+        theta = -(2 * M_PI / mmax);
+        wtemp = sin(0.5 * theta);
+        wpr = -2.0 * wtemp * wtemp;
         wpi = sin(theta);
         wr = 1.0;
         wi = 0.0;
-        for (m=1; m < mmax; m += 2) {
-            for (i=m; i <= n; i += istep) {
-                j=i+mmax;
-                tempr = wr*data[j-1] - wi*data[j];
-                tempi = wr * data[j] + wi*data[j-1];
+        for (m = 1; m < mmax; m += 2) {
+            for (i = m; i <= n; i += istep) {
+                j= i + mmax;
+                tempr = wr * data[j-1] - wi * data[j];
+                tempi = wr * data[j]   + wi * data[j-1];
  
                 data[j-1] = data[i-1] - tempr;
-                data[j] = data[i] - tempi;
+                data[j]   = data[i]   - tempi;
                 data[i-1] += tempr;
-                data[i] += tempi;
+                data[i]   += tempi;
             }
-            wtemp=wr;
-            wr += wr*wpr - wi*wpi;
-            wi += wi*wpr + wtemp*wpi;
+            wtemp = wr;
+            wr += wr * wpr - wi * wpi;
+            wi += wi * wpr + wtemp * wpi;
         }
-        mmax=istep;
+        mmax = istep;
     }
     
     /* abs and log scale */
@@ -1264,37 +1286,40 @@
                             *s = (struct gl_sfbo) {
                                 .name       = strdup(d->d_name),
                                 .shader     = 0,
-                                .valid      = false,
+                                .indirect   = false,
                                 .nativeonly = false,
                                 .binds      = malloc(1),
                                 .binds_sz   = 0
                             };
 
                             current = s;
-                            GLuint id = shaderbuild(gl, shaders, data, dd, 
handlers, shader_version, d->d_name);
-                            if (!id) {
+                            bool skip;
+                            GLuint id = shaderbuild(gl, shaders, data, dd, 
handlers, shader_version, &skip, d->d_name);
+                            if (skip && verbose) printf("disabled: '%s'\n", 
d->d_name);
+                            if (!id && !skip)
                                 abort();
-                            }
 
                             s->shader = id;
 
-                            /* Only setup a framebuffer and texture if this 
isn't the final step,
-                               as it can rendered directly */
-                            if (idx != count) {
-                                int w, h;
-                                gl->wcb->get_fbsize(gl->w, &w, &h);
-                                setup_sfbo(&stages[idx - 1], w, h);
-                            }
+                            if (id) {
+                                /* Only setup a framebuffer and texture if 
this isn't the final step,
+                                   as it can rendered directly */
+                                if (idx != count) {
+                                    int w, h;
+                                    gl->wcb->get_fbsize(gl->w, &w, &h);
+                                    setup_sfbo(&stages[idx - 1], w, h);
+                                }
 
-                            glUseProgram(id);
+                                glUseProgram(id);
                         
-                            /* Setup uniform bindings */
-                            size_t b;
-                            for (b = 0; b < s->binds_sz; ++b) {
-                                s->binds[b].uniform = glGetUniformLocation(id, 
s->binds[b].name);
+                                /* Setup uniform bindings */
+                                size_t b;
+                                for (b = 0; b < s->binds_sz; ++b) {
+                                    s->binds[b].uniform = 
glGetUniformLocation(id, s->binds[b].name);
+                                }
+                                glBindFragDataLocation(id, 1, "fragment");
+                                glUseProgram(0);
                             }
-                            glBindFragDataLocation(id, 1, "fragment");
-                            glUseProgram(0);
                         
                             found = true;
                         }
@@ -1311,16 +1336,13 @@
     
     {
         struct gl_sfbo* final = NULL;
-        if (!gl->premultiply_alpha) {
-            for (size_t t = 0; t < gl->stages_sz; ++t) {
-                if (!gl->stages[t].nativeonly) {
-                    final = &gl->stages[t];
-                }
+        for (size_t t = 0; t < gl->stages_sz; ++t) {
+            if (gl->stages[t].shader && (gl->premultiply_alpha || 
!gl->stages[t].nativeonly)) {
+                final = &gl->stages[t];
             }
         }
-        /* Invalidate framebuffer and use direct rendering if it was 
instantiated 
-           due to a following `nativeonly` shader pass. */
-        if (final) final->valid = false;
+        /* Use dirct rendering on final pass */
+        if (final) final->indirect = false;
     }
 
     /* Compile smooth pass shader */
@@ -1332,7 +1354,7 @@
         char util[usz]; /* module pack path to use */
         snprintf(util, usz, "%s/%s", data, util_folder);
         loading_smooth_pass = true;
-        if (!(gl->sm_prog = shaderbuild(gl, util, data, dd, handlers, 
shader_version, "smooth_pass.frag")))
+        if (!(gl->sm_prog = shaderbuild(gl, util, data, dd, handlers, 
shader_version, NULL, "smooth_pass.frag")))
             abort();
         loading_smooth_pass = false;
     }
@@ -1454,7 +1476,7 @@
     /* Resize screen textures if needed */
     if (ww != gl->lww || wh != gl->lwh) {
         for (t = 0; t < gl->stages_sz; ++t) {
-            if (gl->stages[t].valid) {
+            if (gl->stages[t].indirect) {
                 setup_sfbo(&gl->stages[t], ww, wh);
             }
         }
@@ -1483,16 +1505,16 @@
         /* Current shader program */
         struct gl_sfbo* current = &gl->stages[t];
 
-        if (current->nativeonly && !gl->premultiply_alpha)
+        if (!current->shader || (current->nativeonly && 
!gl->premultiply_alpha))
             continue;
         
         /* Bind framebuffer if this is not the final pass */
-        if (current->valid)
+        if (current->indirect)
             glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
         
         glClear(GL_COLOR_BUFFER_BIT);
         
-        if (!current->valid && gl->copy_desktop) {
+        if (!current->indirect && gl->copy_desktop) {
             /* Self-contained code for drawing background image */
             static GLuint bg_prog, bg_utex, bg_screen;
             static bool setup = false;
@@ -1509,9 +1531,9 @@
                 "}"                                                            
                      "\n";
             if (!setup) {
                 bg_prog = shaderlink(shaderload(NULL, GL_VERTEX_SHADER, 
VERTEX_SHADER_SRC,
-                                                NULL, NULL, NULL, 330, true, 
gl),
+                                                NULL, NULL, NULL, 330, true, 
NULL, gl),
                                      shaderload(NULL, GL_FRAGMENT_SHADER, 
frag_shader,
-                                                NULL, NULL, NULL, 330, true, 
gl));
+                                                NULL, NULL, NULL, 330, true, 
NULL, gl));
                 bg_utex   = glGetUniformLocation(bg_prog, "tex");
                 bg_screen = glGetUniformLocation(bg_prog, "screen");
                 glBindFragDataLocation(bg_prog, 1, "fragment");
@@ -1629,7 +1651,7 @@
 
                     /* Return state */
                     glUseProgram(current->shader);
-                    if (current->valid)
+                    if (current->indirect)
                         glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
                     else
                         glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -1668,7 +1690,7 @@
         drawoverlay(&gl->overlay); /* Fullscreen quad (actually just two 
triangles) */
 
         /* Reset some state */
-        if (current->valid)
+        if (current->indirect)
             glBindFramebuffer(GL_FRAMEBUFFER, 0);
         glUseProgram(0);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/shaders/bars/1.frag 
new/glava-1.6.0/shaders/bars/1.frag
--- old/glava-1.5.8/shaders/bars/1.frag 2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/shaders/bars/1.frag 2019-03-10 01:55:03.000000000 +0100
@@ -49,13 +49,15 @@
     #else
     float d = AREA_HEIGHT - AREA_Y;
     #endif
-    float nbars = floor((AREA_WIDTH * 0.5F) / float(BAR_WIDTH + BAR_GAP)) * 2;
     float section = BAR_WIDTH + BAR_GAP;    /* size of section for each bar 
(including gap) */
     float center =  section / 2.0F;         /* half section, distance to 
center             */
     float m = abs(mod(dx, section));        /* position in section             
             */
     float md = m - center;                  /* position in section from center 
line         */
+    float nbars = floor((AREA_WIDTH * 0.5F) / section) * 2;
+    float p, s;
     if (md < ceil(float(BAR_WIDTH) / 2) && md >= -floor(float(BAR_WIDTH) / 2)) 
{  /* if not in gap */
-        float p = int(dx / section) / float(nbars / 2); /* position, (-1.0F, 
1.0F))     */
+        s = dx / section;
+        p = (sign(s) == 1.0 ? ceil(s) : floor(s)) / float(nbars / 2); /* 
position, (-1.0F, 1.0F))     */
         p += sign(p) * ((0.5F + center) / AREA_WIDTH);    /* index center of 
bar position */
         /* Apply smooth function and index texture */
         #define smooth_f(tex, p) smooth_audio(tex, audio_sz, p)
@@ -66,7 +68,7 @@
             return;
         }
         /* handle user options and store result of indexing in 'v' */
-        if (p >= 0.0F) {
+        if (p > 0.0F) {
             #if DIRECTION == 1
             p = 1.0F - p;
             #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/shaders/circle/1.frag 
new/glava-1.6.0/shaders/circle/1.frag
--- old/glava-1.5.8/shaders/circle/1.frag       2018-11-03 00:27:54.000000000 
+0100
+++ new/glava-1.6.0/shaders/circle/1.frag       2019-03-10 01:55:03.000000000 
+0100
@@ -32,6 +32,8 @@
 /* This shader is based on radial.glsl, refer to it for more commentary */
 
 float apply_smooth(float theta) {
+
+    fragment = vec4(0, 0, 0, 0);
     
     float idx = theta + ROTATE;
     float dir = mod(abs(idx), TWOPI);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/shaders/graph/1.frag 
new/glava-1.6.0/shaders/graph/1.frag
--- old/glava-1.5.8/shaders/graph/1.frag        2018-11-03 00:27:54.000000000 
+0100
+++ new/glava-1.6.0/shaders/graph/1.frag        2019-03-10 01:55:03.000000000 
+0100
@@ -81,16 +81,31 @@
 #define TWOPI 6.28318530718
 
 float half_w;
+float middle;
+highp float pixel = 1.0F / float(screen.x);
 
-void render_side(in sampler1D tex, float idx) {
-    highp float pixel = 1.0F / float(screen.x);
+float get_line_height(in sampler1D tex, float idx) {
     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 */
-    s *= clamp((abs((screen.x / 2) - gl_FragCoord.x) / screen.x) * 48, 0.0F, 
1.0F);
+
+    float fact = clamp((abs((screen.x / 2) - gl_FragCoord.x) / screen.x) * 48, 
0.0F, 1.0F);
+    #if JOIN_CHANNELS > 0
+    fact = -2 * pow(fact, 3) + 3 * pow(fact, 2);    /* To avoid spikes */
+    s = fact * s + (1 - fact) * middle;
+    #else
+    s *= fact;
+    #endif
+
     s *= clamp((min(gl_FragCoord.x, screen.x - gl_FragCoord.x) / screen.x) * 
48, 0.0F, 1.0F);
 
+    return s;
+}
+
+void render_side(in sampler1D tex, float idx) {
+    float s = get_line_height(tex, idx);
+
     /* and finally set fragment color if we are in range */
     #if INVERT > 0
     float pos = float(screen.y) - gl_FragCoord.y;
@@ -106,6 +121,9 @@
 
 void main() {
     half_w = (screen.x / 2);
+
+    middle = VSCALE * (smooth_audio_adj(audio_l, audio_sz, 1, pixel) + 
smooth_audio_adj(audio_r, audio_sz, 0, pixel)) / 2;
+
     if (gl_FragCoord.x < half_w) {
         render_side(audio_l, LEFT_IDX);
     } else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/shaders/graph/2.frag 
new/glava-1.6.0/shaders/graph/2.frag
--- old/glava-1.5.8/shaders/graph/2.frag        2018-11-03 00:27:54.000000000 
+0100
+++ new/glava-1.6.0/shaders/graph/2.frag        2019-03-10 01:55:03.000000000 
+0100
@@ -9,6 +9,10 @@
 #include "@graph.glsl"
 #include ":graph.glsl"
 
+#if DRAW_OUTLINE == 0 && DRAW_HIGHLIGHT == 0
+#error __disablestage
+#endif
+
 void main() {
     fragment = texelFetch(tex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);
     
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/shaders/graph/3.frag 
new/glava-1.6.0/shaders/graph/3.frag
--- old/glava-1.5.8/shaders/graph/3.frag        1970-01-01 01:00:00.000000000 
+0100
+++ new/glava-1.6.0/shaders/graph/3.frag        2019-03-10 01:55:03.000000000 
+0100
@@ -0,0 +1,104 @@
+
+in vec4 gl_FragCoord;
+
+#request uniform "screen" screen
+uniform ivec2 screen; /* screen dimensions */
+
+#request uniform "prev" tex
+uniform sampler2D tex;    /* screen texture    */
+
+out vec4 fragment; /* output */
+
+#include "@graph.glsl"
+#include ":graph.glsl"
+
+#if ANTI_ALIAS == 0
+#error __disablestage
+#endif
+
+/* Moves toward the border of the graph, gives the
+   y coordinate of the last colored pixel */
+float get_col_height_up(float x, float oy) {
+    float y = oy;
+    #if INVERT > 0
+    while (y >= 0) {
+    #else
+    while (y < screen.y) {
+    #endif
+        vec4 f = texelFetch(tex, ivec2(x, y), 0);
+        if (f.a <= 0) {
+            #if INVERT > 0
+            y += 1;
+            #else
+            y -= 1;
+            #endif
+            break;
+        }
+        #if INVERT > 0
+        y -= 1;
+        #else
+        y += 1;
+        #endif
+    }
+
+    return y;
+}
+
+/* Moves toward the base of the graph, gives the
+   y coordinate of the first colored pixel */
+float get_col_height_down(float x, float oy) {
+    float y = oy;
+    #if INVERT > 0
+    while (y < screen.y) {
+    #else
+    while (y >= 0) {
+    #endif
+        vec4 f = texelFetch(tex, ivec2(x, y), 0);
+        if (f.a > 0) {
+            break;
+        }
+        #if INVERT > 0
+        y += 1;
+        #else
+        y -= 1;
+        #endif
+    }
+
+    return y;
+}
+
+void main() {
+    fragment = texelFetch(tex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);
+
+    #if ANTI_ALIAS > 0
+
+    if (fragment.a <= 0) {
+        bool left_done = false;
+        float h2;
+        float a_fact = 0;
+
+        if (texelFetch(tex, ivec2(gl_FragCoord.x - 1, gl_FragCoord.y), 0).a > 
0) {
+            float h1 = get_col_height_up(gl_FragCoord.x - 1, gl_FragCoord.y);
+            h2 = get_col_height_down(gl_FragCoord.x, gl_FragCoord.y);
+            fragment = texelFetch(tex, ivec2(gl_FragCoord.x, h2), 0);
+
+            a_fact = clamp(abs((h1 - gl_FragCoord.y) / (h2 - h1)), 0.0, 1.0);
+
+            left_done = true;
+        }
+        if (texelFetch(tex, ivec2(gl_FragCoord.x + 1, gl_FragCoord.y), 0).a > 
0) {
+            if (!left_done) {
+                h2 = get_col_height_down(gl_FragCoord.x, gl_FragCoord.y);
+                fragment = texelFetch(tex, ivec2(gl_FragCoord.x, h2), 0);
+            }
+            float h3 = get_col_height_up(gl_FragCoord.x + 1, gl_FragCoord.y);
+
+            a_fact = max(a_fact, clamp(abs((h3 - gl_FragCoord.y) / (h2 - h3)), 
0.0, 1.0));
+        }
+        
+        fragment.a *= a_fact;
+
+    }
+
+    #endif
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/shaders/graph.glsl 
new/glava-1.6.0/shaders/graph.glsl
--- old/glava-1.5.8/shaders/graph.glsl  2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/shaders/graph.glsl  2019-03-10 01:55:03.000000000 +0100
@@ -13,8 +13,14 @@
 #define DRAW_OUTLINE 0
 /* 1 to draw edge highlight, 0 to disable */
 #define DRAW_HIGHLIGHT 1
+/* Whether to anti-alias the border of the graph, creating a smoother curve.
+   This may have a small impact on performance.
+   Note: requires `xroot` or `none` opacity to be set */
+#define ANTI_ALIAS 0
 /* outline color */
 #define OUTLINE #262626
+/* 1 to join the two channels together in the middle, 0 to clamp both down to 
zero */
+#define JOIN_CHANNELS 0
 /* 1 to invert (vertically), 0 otherwise */
 #define INVERT 0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/shaders/rc.glsl 
new/glava-1.6.0/shaders/rc.glsl
--- old/glava-1.5.8/shaders/rc.glsl     2018-11-03 00:27:54.000000000 +0100
+++ new/glava-1.6.0/shaders/rc.glsl     2019-03-10 01:55:03.000000000 +0100
@@ -98,9 +98,14 @@
    default when GLava itself is a desktop window. */
 #request setclickthrough false
 
-/* PulseAudio source. Can be a number or a name of an audio
-   sink or device to record from. Set to "auto" to use the
-   default output device. */
+/* Audio source
+
+   When the "pulseaudio" backend is set, this can be a number or
+   a name of an audio sink or device to record from. Set to "auto"
+   to use the default output device.
+   
+   When the "fifo" backend is set, "auto" is interpreted as
+   "/tmp/mpd.fifo". Otherwise, a valid path should be provided. */
 #request setsource "auto"
 
 /* Buffer swap interval (vsync), set to '0' to prevent
@@ -189,7 +194,11 @@
    
    Lower sample rates also can make output more choppy, when
    not using interpolation. It's generally OK to leave this
-   value unless you have a strange PulseAudio configuration. */
+   value unless you have a strange PulseAudio configuration.
+
+   This option does nothing when using the "fifo" audio
+   backend. Instead, an ideal rate should be be configured
+   in the application generating the output. */
 #request setsamplerate 22050
 
 /*                    ** DEPRECATED **
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/shaders/smooth_parameters.glsl 
new/glava-1.6.0/shaders/smooth_parameters.glsl
--- old/glava-1.5.8/shaders/smooth_parameters.glsl      2018-11-03 
00:27:54.000000000 +0100
+++ new/glava-1.6.0/shaders/smooth_parameters.glsl      2019-03-10 
01:55:03.000000000 +0100
@@ -13,10 +13,25 @@
    - circular     heavily rounded points
    - sinusoidal   rounded at both low and high weighted values
                     like a sine wave
-   - linear       not rounded at all, just use linear distance
+   - linear       not rounded at all; linear distance
    */
 #define ROUND_FORMULA sinusoidal
 
+/* The sampling mode for processing raw FFT input:
+   
+   - average     averages all the inputs in the sample range for
+                   a given point. Produces smooth output, but peaks
+                   are not well represented
+   - maximum     obtains the best value from the closest peak in
+                   the sample range. Very accurate peaks, but
+                   output is jagged and sporadic.
+   - hybrid      uses the results from both `average` and `maximum`
+                   with the weight provided in `SAMPLE_HYBRID_WEIGHT` */
+#define SAMPLE_MODE average
+/* Weight should be provided in the range (0, 1). Higher values favour
+   averaged results. `hybrid` mode only. */
+#define SAMPLE_HYBRID_WEIGHT 0.65
+
 /* Factor used to scale frequencies. Lower values allows lower
    frequencies to occupy more space. */
 #define SAMPLE_SCALE 8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/glava-1.5.8/shaders/util/smooth.glsl 
new/glava-1.6.0/shaders/util/smooth.glsl
--- old/glava-1.5.8/shaders/util/smooth.glsl    2018-11-03 00:27:54.000000000 
+0100
+++ new/glava-1.6.0/shaders/util/smooth.glsl    2019-03-10 01:55:03.000000000 
+0100
@@ -21,6 +21,10 @@
 /* take value x that scales linearly between [0, 1) and return its circlar 
curve */
 #define circular(x) sqrt(1 - (((x) - 1) * ((x) - 1)))
 
+#define average 0
+#define maximum 1
+#define hybrid 2
+
 float scale_audio(float idx) {
     return -log((-(SAMPLE_RANGE) * idx) + 1) / (SAMPLE_SCALE);
 }
@@ -32,20 +36,42 @@
 /* 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 - 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);
+        smin = scale_audio(clamp(idx - SMOOTH_FACTOR, 0, 1)) * tex_sz,
+        smax = scale_audio(clamp(idx + SMOOTH_FACTOR, 0, 1)) * tex_sz;
+    float m = ((smax - smin) / 2.0F), s, w;
     float rm = smin + m; /* middle */
+    #if SAMPLE_MODE == average
+    float avg = 0, weight = 0;
     for (s = smin; s <= smax; s += 1.0F) {
-        float w = ROUND_FORMULA(clamp((m - abs(rm - s)) / m, 0, 1));
+        w = ROUND_FORMULA(clamp((m - abs(rm - s)) / m, 0, 1));
         weight += w;
         avg += texelFetch(tex, int(round(s)), 0).r * w;
     }
     avg /= weight;
     return avg;
+    #elif SAMPLE_MODE == hybrid
+    float vmax = 0, avg = 0, weight = 0, v;
+    for (s = smin; s < smax; s += 1.0F) {
+        w = ROUND_FORMULA(clamp((m - abs(rm - s)) / m, 0, 1));
+        weight += w;
+        v = texelFetch(tex, int(round(s)), 0).r * w;
+        avg += v;
+        if (vmax < v)
+            vmax = v;
+    }
+    return (vmax * (1 - SAMPLE_HYBRID_WEIGHT)) + ((avg / weight) * 
SAMPLE_HYBRID_WEIGHT);
+    #elif SAMPLE_MODE == maximum
+    float vmax = 0, v;
+    for (s = smin; s < smax; s += 1.0F) {
+        w = texelFetch(tex, int(round(s)), 0).r * ROUND_FORMULA(clamp((m - 
abs(rm - s)) / m, 0, 1));
+        if (vmax < w)
+            vmax = w;
+    }
+    return vmax;
+    #endif
     #else
     return texelFetch(tex, int(round(idx * tex_sz)), 0).r;
     #endif


Reply via email to