grapheqd

grapheqd stands for graphical equalizer daemon. It displays the frequency spectrum of an audio signal via its HTML5 webpage or ASCII based telnet interface. grapheqd runs as a daemon on either Linux with OpenWRT in mind, or FreeBSD. Thus, it uses either ALSA or OSS, choosen at compile time. As FFT computation might require a lot CPU resources on systems without mathematical coprocessor, grapheqd can operate in a client/server mode, where a remote instance on a more powerful system does not use an actual sound device, but connects to a grapheqd instance running on a system with limited CPU power. In such scenarios, you should point your web browser or telnet client only to the remote instance. grapheqd supports PCM signals with one or two channels (read: mono or stereo) and 16 bits per channel. Your audio device must be capable of sampling at 44100 or 48000 Hz. You need a modern web browser with support for JavaScript, CSS3, and websockets in order to access the web interface.

Background

Back in the 80ies and 90ies hifis and stereos came with a graphical equalizer as a separate, physical device, or could be equipped with one. You don't easily find one of these nowadays, at least not for the consumer market. I have never found any use of actually adjusting the audio signal, but always liked the fluorescent dot matrix displays or LCDs. grapheqd tries to reassemble this.

Screenshots

The web interface runs on port 8083 by default:



Point your telnet client to port 8083 as well, and simply enter a c followed by Enter to access the ASCII interface in color mode:



If your terminal does not support colors and/or escape sequences, press m followed by Enter:

Help

grapheqd version 7
PCM driver: OSS

Usage:
grapheqd [-d] [-e <program>] [-l <address[:port]>] [-p <pidfile>]
         [-r <address[:port]>] [-s <soundcard>] [-u <user>]
grapheqd -h

  -d                     run in foreground, and log to stdout/stderr, do not
                         detach from terminal, do not log to syslog
  -e <program>           read PCM data from this program's standard output;
                         the name of the soundcard is passed as first
                         commandline parameter to <program>;
                         if the second commandline parameter is present and
                         has a value of "stderr", i.e. if grapheqd has been
                         started with -d, then <program> can write to
                         standard error safely;
                         otherwise, error logging must be done via syslog,
                         e.g. by calling logger;
                         cannot be used in conjunction with either option -c
                         or -r
  -l <address[:port]>    listen on this address and port; a maximum of 16
                         addresses may be specified; port defaults to 8083;
                         default: 0.0.0.0:8083
  -p <pidfile>           daemonize and save pid to this file; no default, pid
                         gets not written to any file unless <pidfile> is given
  -r <address[:port]>    connect to another grapheqd running at this address and
                         port; <port> defaults to 8083; cannot be used in
                         conjunction with either option -e or -s
  -s <soundcard>         read PCM from this soundcard; default: /dev/dsp0;
                         cannot be used in conjunction with option -r; a
                         program given via parameter -e takes precedence
  -u <user>              switch to this user; no default, run as invoking user
  -h                     show this help ;-)

Installation

Requirements

Build

  1. Either clone this repository:
    $ git clone https://github.com/felixjogris/grapheqd.git
    
    or grab an official release from this site
  2. If you haven't fetched KISS FFT yet, do it now:
    $ git clone https://github.com/mborgerding/kissfft.git ../kissfft
    
  3. Call make. It will use Makefile or GNUmakefile on FreeBSD or Linux, respectively, and fetch KISS FFT automatically if you haven't done it, and will compile everything.
  4. Optionally, if you want systemd integration, call make with USE_SYSTEMD=1
  5. You now have grapheqd in the current directory. Either call it directly, copy it somewhere, or run sudo make install, which will place it to /usr/local/sbin. Then either add it to your RC init or systemd configuration, or use the provided scripts grapheqd.service, grapheqd.openrc, or grapheqd.sh, which make install has copied to /lib/systemd/system, /etc/init.d, or /usr/local/etc/rc.d, respectively.
  6. Starting with version 5, the RC script /usr/local/etc/rc.d/grapheqd on FreeBSD supports multiple profiles, e.g. one might have this in /etc/rc.conf:
    grapheqd_enable="YES"
    grapheqd_profiles="scard remote"
    grapheqd_scard_soundcard="/dev/dsp1"
    grapheqd_scard_username="audiouser"
    grapheqd_remote_address="0.0.0.0:8084"
    grapheqd_remote_raddress="somehost:8083"
    
    You can start each instance via service grapheqd start scard and service grapheqd start remote, respectively. If you omit the profile name, the RC script operates on every configured and enabled instance, e.g. service grapheqd stop.

OpenWRT

Create a directory package/grapheqd inside your copy of the OpenWRT source tree, and download openwrt/Makefile to that directory. Now run make menuconfig, and under Multimedia select grapheqd. Optionally, select kmod-usb-audio under Kernel modules -> Sound Support. Then build OpenWRT as usual, e.g. by calling make.
https://github.com/felixjogris/grapheqd/blob/master/openwrt/Makefile is a copy of that Makefile.

Audio sources

Under the hood

Per channel, grapheqd passes 4096 16 bit audio samples (mono or stereo) at a time to FFT, and pushes calculated linear frequency data to all connected clients, thus resulting in roughly 11 or 12 updates per second if your hardware supports sampling at 44100 or 48000 Hz, respectively. The web interface adjusts the labels under each band (vertical bar) to match its frequency range. If only mono audio is available, then the FFT is called just once per loop, while the output data is duplicated. If no client is connected, then no PCM data is read and FFT does not burn CPU cycles unnecessarily.

The internal web serving routines (to put it nicely) use static and predetermined buffers where possible. printf() and family are not used in the hot code paths and loops.

Releases

Source code