Skip to content

Commit f25c17a

Browse files
bsdcodekarlstav
authored andcommitted
JACK support
- JACK input backend support - JACK priority after sndio (and both after pipewire) - doc: extended documentation in README.md - fix getPulseDefaultSink compilation warning
1 parent db3084b commit f25c17a

File tree

13 files changed

+526
-55
lines changed

13 files changed

+526
-55
lines changed

Makefile.am

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ if OSS
5353
cava_SOURCES += input/oss.c
5454
endif
5555

56+
if JACK
57+
cava_SOURCES += input/jack.c
58+
endif
59+
5660
if NCURSES
5761
cava_SOURCES += output/terminal_ncurses.c
5862
endif

README.md

Lines changed: 102 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ by [Karl Stavestrand](mailto:[email protected])
2222
- [MPD](#mpd)
2323
- [sndio](#sndio)
2424
- [OSS](#oss)
25+
- [JACK](#jack)
2526
- [squeezelite](#squeezelite)
2627
- [macOS](#macos-1)
2728
- [Windows](#windows)
@@ -77,11 +78,12 @@ The development lib of one of these audio frameworks, depending on your distro:
7778
* Pipewire
7879
* Portaudio
7980
* Sndio
81+
* JACK
8082

8183
Optional components:
8284
* SDL2 dev files
8385

84-
Only FFTW and the other build tools are actually required for CAVA to compile, but this will only give you the ability to read from fifo files. To more easly grab audio from your system pulseaudio, alsa, sndio or portaudio dev files are recommended (depending on what audio system you are using). Not sure how to get the pulseaudio dev files for other distros than debian/ubuntu or if they are bundled in pulseaudio.
86+
Only FFTW and the other build tools are actually required for CAVA to compile, but this will only give you the ability to read from fifo files. To more easly grab audio from your system pulseaudio, alsa, sndio, jack or portaudio dev files are recommended (depending on what audio system you are using). Not sure how to get the pulseaudio dev files for other distros than debian/ubuntu or if they are bundled in pulseaudio.
8587

8688

8789
For better a better visual experience ncurses is also recomended.
@@ -90,11 +92,17 @@ All the requirements can be installed easily in all major distros:
9092

9193
FreeBSD
9294

93-
pkg install autoconf-archive autotools fftw3 iniparser pkgconf psftools sdl2 sndio
95+
pkg install autoconf autoconf-archive automake fftw3 iniparser jackit libglvnd libtool pkgconf psftools sdl2 sndio
96+
97+
Additionally, run these commands on FreeBSD before building:
98+
99+
export CFLAGS="-I/usr/local/include"
100+
export LDFLAGS="-L/usr/local/lib"
101+
94102

95103
Debian/Ubuntu:
96104

97-
sudo apt install build-essential libfftw3-dev libasound2-dev libncursesw5-dev libpulse-dev libtool automake autoconf-archive libiniparser-dev libsdl2-2.0-0 libsdl2-dev libpipewire-0.3-dev pkgconf
105+
sudo apt install build-essential libfftw3-dev libasound2-dev libncursesw5-dev libpulse-dev libtool automake autoconf-archive libiniparser-dev libsdl2-2.0-0 libsdl2-dev libpipewire-0.3-dev libjack-jackd2-dev pkgconf
98106

99107

100108
ArchLinux:
@@ -340,9 +348,12 @@ $ AUDIODEVICE=snd/0.monitor cava
340348

341349
### OSS
342350

351+
Set
352+
353+
method = oss
354+
343355
The audio system used on FreeBSD is the Open Sound System (OSS).
344356
The following example demonstrates how to setup CAVA for OSS on FreeBSD:
345-
346357
```sh
347358
$ cat /dev/sndstat
348359
Installed devices:
@@ -351,12 +362,11 @@ pcm1: <Realtek ALC1220 (Front Analog Mic)> (rec)
351362
pcm2: <USB audio> (play/rec)
352363
No devices installed from userspace.
353364
```
354-
355365
The system has three `pcm` sound devices, `pcm0`, `pcm1` and `pcm2`. `pcm0` corresponds to the analog
356366
output jack on the rear, in which external stereo speakers are plugged in, and the analog input jack,
357367
in which one could plug in a microphone. Because it encapsulates both, output and input, it is marked
358368
as `play/rec`. It is also set as the `default` sound device. `pcm1` corresponds to another analog input
359-
jack for a mic on the front side and is marked `rec`. A USB headset which an integrated mic is plugged
369+
jack for a mic on the front side and is marked `rec`. A USB headset with an integrated mic is plugged
360370
in an USB port and the system has created the `pcm2` sound device with `play/rec` capabilities for
361371
it.
362372

@@ -367,20 +377,17 @@ which acts like a symlink to the `default` audio device, in this example to `/de
367377

368378
Now in order to visualize the mic input in CAVA, the `source` value in the configuration file must
369379
be set to the corresponding audio device, i.e.
370-
```sh
371-
[input]
372-
source = /dev/dsp # or /dev/dsp0 for which /dev/dsp is a symlink in this example
373-
```
380+
381+
source = /dev/dsp # or /dev/dsp0 for which /dev/dsp is a symlink in this example
382+
374383
(which is already the default for CAVA) for the `pcm0` mic on the rear, or
375-
```sh
376-
[input]
377-
source = /dev/dsp1
378-
```
384+
385+
source = /dev/dsp1
386+
379387
for the `pcm1` mic on the front, or
380-
```sh
381-
[input]
382-
source = /dev/dsp2
383-
```
388+
389+
source = /dev/dsp2
390+
384391
for the `pcm2` mic on the USB headset.
385392

386393
OSS can't record the outgoing audio on its own, i.e. the sounds from a music player or a browser which
@@ -403,6 +410,83 @@ It created a virtual device `dsp` from `/dev/dsp0`. Now the audio is visualized
403410
`source = /dev/dsp` in the configuration file. Virtual OSS can be configured and started as a service
404411
on FreeBSD.
405412

413+
### JACK
414+
415+
Set
416+
417+
method = jack
418+
419+
The JACK Audio Connection Kit (JACK) is a professional sound server API which is available on several
420+
operating systems, e.g. FreeBSD and Linux.
421+
422+
CAVA is a JACK client with the base client name `cava` and adheres to the standard server start and
423+
stop behaviour, i.e. CAVA starts a JACK server if none is already running and the environment variable
424+
`JACK_START_SERVER` is defined, in which case the server also stops when all clients have exited. The
425+
`source` in the CAVA configuration file specifies the name of the JACK server to which CAVA tries to
426+
connect to. The default value is `default`, which is also the default JACK server name. The value can
427+
be empty, in which case it implies `default`. Therefore the following three entries are equivalent:
428+
429+
; source = default
430+
source = default
431+
source =
432+
433+
One exception is the combination of an empty `source` entry and the environment variable `JACK_DEFAULT_SERVER`.
434+
If the environment variable is defined, e.g. `export JACK_DEFAULT_SERVER=foo`, then the following entries
435+
are equivalent:
436+
437+
source = foo
438+
source =
439+
440+
Consult the manpage `jackd(1)` for further information regarding configuration and startup of a JACK
441+
server.
442+
443+
CAVA creates terminal audio-typed (so no MIDI support) input ports. These ports can connect to output
444+
ports of other JACK clients, e.g. connect to the output ports of a music player and CAVA will visualize
445+
the music. Currently CAVA supports up to two input ports, i.e. it supports mono and stereo. The number
446+
of input ports can be controlled via the `channels` option in the input section of the configuration
447+
file:
448+
449+
channels = 1 # one input port, mono
450+
451+
or
452+
453+
channels = 2 # two input ports, stereo
454+
455+
The port's short name is simply `M` for mono, and `L` and `R` for stereo. The full name of the input
456+
port according to the base client name is `cava:M` for mono, and `cava:L` and `cava:R` for stereo.
457+
458+
Currently CAVA doesn't connect its ports to other client's ports automatically, i.e. on program start
459+
CAVA isn't connected to any other program and won't connect during execution on its own. There are
460+
connection management programs in order to control and manage the connection between ports of the different
461+
client programs. Some well known connection managers with a graphical user interface include QjackCtl
462+
and Cadence. The JACK package itself often comes with CLI tools. Depending on the operating system
463+
they might need to get installed separately, e.g. on FreeBSD
464+
```sh
465+
$ doas pkg install jack-example-tools
466+
```
467+
Among the tools are the programs `jack_lsp` and `jack_connect`. These two tools are enough to list
468+
and connect ports on the commandline. The following example demonstrates how to setup connections with
469+
these tools:
470+
```sh
471+
$ jack_lsp
472+
system:capture_1
473+
system:capture_2
474+
system:playback_1
475+
system:playback_2
476+
cava:L
477+
moc:output0
478+
moc:output1
479+
cava:R
480+
```
481+
This listing shows all full port names that are currently available. These correspond to two external
482+
JACK clients (cava and moc) and one internal JACK client (system). There are also `-p` and `-c` switches
483+
for `jack_lsp`, with which the types and current connections between the ports are listed. Connect
484+
the ports of cava and moc:
485+
```sh
486+
$ jack_connect cava:L moc:output0
487+
$ jack_connect cava:R moc:output1
488+
```
489+
Now CAVA visualizes the outgoing audio from MOC.
406490

407491
### squeezelite
408492
[squeezelite](https://en.wikipedia.org/wiki/Squeezelite) is one of several software clients available for the Logitech Media Server. Squeezelite can export its audio data as shared memory, which is what this input module uses.

cava.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070

7171
#include "input/alsa.h"
7272
#include "input/fifo.h"
73+
#include "input/jack.h"
7374
#include "input/oss.h"
7475
#include "input/pipewire.h"
7576
#include "input/portaudio.h"
@@ -422,9 +423,17 @@ as of 0.4.0 all options are specified in config file, see in '/home/username/.co
422423
case INPUT_OSS:
423424
audio.format = p.samplebits;
424425
audio.rate = p.samplerate;
426+
audio.channels = p.channels;
425427
audio.threadparams = 1; // OSS can adjust parameters
426428
thr_id = pthread_create(&p_thread, NULL, input_oss, (void *)&audio);
427429
break;
430+
#endif
431+
#ifdef JACK
432+
case INPUT_JACK:
433+
audio.channels = p.channels;
434+
audio.threadparams = 1; // JACK server provides parameters
435+
thr_id = pthread_create(&p_thread, NULL, input_jack, (void *)&audio);
436+
break;
428437
#endif
429438
case INPUT_SHMEM:
430439
audio.format = 16;

config.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,21 @@ const char *default_shader_name[NUMBER_OF_SHADERS] = {"northern_lights.frag", "p
4545
double smoothDef[5] = {1, 1, 1, 1, 1};
4646

4747
enum input_method default_methods[] = {
48-
INPUT_FIFO, INPUT_PORTAUDIO, INPUT_ALSA, INPUT_PULSE,
49-
INPUT_PIPEWIRE, INPUT_WINSCAP, INPUT_SNDIO, INPUT_OSS,
48+
INPUT_FIFO, INPUT_PORTAUDIO, INPUT_ALSA, INPUT_PULSE, INPUT_JACK,
49+
INPUT_SNDIO, INPUT_PIPEWIRE, INPUT_WINSCAP, INPUT_OSS,
5050
};
5151

5252
char *outputMethod, *orientation, *channels, *xaxisScale, *monoOption, *fragmentShader,
5353
*vertexShader;
5454

5555
const char *input_method_names[] = {
56-
"fifo", "portaudio", "pipewire", "alsa", "pulse", "sndio", "oss", "shmem", "winscap",
56+
"fifo", "portaudio", "pipewire", "alsa", "pulse", "sndio", "oss", "jack", "shmem", "winscap",
5757
};
5858

5959
const bool has_input_method[] = {
6060
HAS_FIFO, /** Always have at least FIFO and shmem input. */
61-
HAS_PORTAUDIO, HAS_PIPEWIRE, HAS_ALSA, HAS_PULSE, HAS_SNDIO, HAS_OSS, HAS_SHMEM, HAS_WINSCAP,
61+
HAS_PORTAUDIO, HAS_PIPEWIRE, HAS_ALSA, HAS_PULSE, HAS_SNDIO,
62+
HAS_OSS, HAS_JACK, HAS_SHMEM, HAS_WINSCAP,
6263
};
6364

6465
enum input_method input_method_by_name(const char *str) {
@@ -328,7 +329,7 @@ bool validate_config(struct config_params *p, struct error_s *error) {
328329
if (p->stereo == -1) {
329330
write_errorf(
330331
error,
331-
"output channels %s is not supported, supported channelss are: 'mono' and 'stereo'\n",
332+
"output channels %s is not supported, supported channels are: 'mono' and 'stereo'\n",
332333
channels);
333334
return false;
334335
}
@@ -389,6 +390,12 @@ bool validate_config(struct config_params *p, struct error_s *error) {
389390
}
390391
p->sens = p->sens / 100;
391392

393+
// validate: channels
394+
if (p->channels <= 1)
395+
p->channels = 1;
396+
else
397+
p->channels = 2;
398+
392399
return validate_colors(p, error);
393400
}
394401

@@ -546,7 +553,6 @@ bool load_config(char configPath[PATH_MAX], struct config_params *p, bool colors
546553
monoOption = malloc(sizeof(char) * 32);
547554
p->raw_target = malloc(sizeof(char) * 129);
548555
p->data_format = malloc(sizeof(char) * 32);
549-
channels = malloc(sizeof(char) * 32);
550556
orientation = malloc(sizeof(char) * 32);
551557
vertexShader = malloc(sizeof(char) * PATH_MAX / 2);
552558
fragmentShader = malloc(sizeof(char) * PATH_MAX / 2);
@@ -677,6 +683,7 @@ bool load_config(char configPath[PATH_MAX], struct config_params *p, bool colors
677683

678684
p->samplerate = iniparser_getint(ini, "input:sample_rate", 44100);
679685
p->samplebits = iniparser_getint(ini, "input:sample_bits", 16);
686+
p->channels = iniparser_getint(ini, "input:channels", 2);
680687

681688
enum input_method default_input = INPUT_FIFO;
682689
for (size_t i = 0; i < ARRAY_SIZE(default_methods); i++) {
@@ -716,6 +723,11 @@ bool load_config(char configPath[PATH_MAX], struct config_params *p, bool colors
716723
case INPUT_OSS:
717724
p->audio_source = strdup(iniparser_getstring(ini, "input:source", "/dev/dsp"));
718725
break;
726+
#endif
727+
#ifdef JACK
728+
case INPUT_JACK:
729+
p->audio_source = strdup(iniparser_getstring(ini, "input:source", "default"));
730+
break;
719731
#endif
720732
case INPUT_SHMEM:
721733
p->audio_source =

config.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@
4343
#define HAS_OSS false
4444
#endif
4545

46+
#ifdef JACK
47+
#define HAS_JACK true
48+
#else
49+
#define HAS_JACK false
50+
#endif
51+
4652
#ifdef _MSC_VER
4753
#define HAS_WINSCAP true
4854
#define SDL true
@@ -66,6 +72,7 @@ enum input_method {
6672
INPUT_PULSE,
6773
INPUT_SNDIO,
6874
INPUT_OSS,
75+
INPUT_JACK,
6976
INPUT_SHMEM,
7077
INPUT_WINSCAP,
7178
INPUT_MAX,
@@ -104,9 +111,9 @@ struct config_params {
104111
enum orientation orientation;
105112
int userEQ_keys, userEQ_enabled, col, bgcol, autobars, stereo, raw_format, ascii_range,
106113
bit_format, gradient, gradient_count, fixedbars, framerate, bar_width, bar_spacing,
107-
bar_height, autosens, overshoot, waves, samplerate, samplebits, sleep_timer, sdl_width,
108-
sdl_height, sdl_x, sdl_y, sdl_full_screen, draw_and_quit, zero_test, non_zero_test, reverse,
109-
sync_updates, continuous_rendering, disable_blanking;
114+
bar_height, autosens, overshoot, waves, samplerate, samplebits, channels, sleep_timer,
115+
sdl_width, sdl_height, sdl_x, sdl_y, sdl_full_screen, draw_and_quit, zero_test,
116+
non_zero_test, reverse, sync_updates, continuous_rendering, disable_blanking;
110117
};
111118

112119
struct error_s {

configure.ac

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,29 @@ AS_IF([test "x$enable_input_oss" != "xno"], [
248248

249249
AM_CONDITIONAL([OSS], [test "x$have_oss" = "xyes"])
250250

251+
dnl ######################
252+
dnl checking for jack dev
253+
dnl ######################
254+
AC_ARG_ENABLE([input_jack],
255+
AS_HELP_STRING([--disable-input-jack],
256+
[do not include support for input from jack])
257+
)
258+
259+
AS_IF([test "x$enable_input_jack" != "xno"], [
260+
PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no)
261+
if [[ $have_jack = "yes" ]] ; then
262+
LIBS="$LIBS $JACK_LIBS"
263+
CPPFLAGS="$CPPFLAGS -DJACK $JACK_CFLAGS"
264+
fi
265+
266+
if [[ $have_jack = "no" ]] ; then
267+
AC_MSG_NOTICE([WARNING: No jack dev files found building without jack support])
268+
fi],
269+
[have_jack=no]
270+
)
271+
272+
AM_CONDITIONAL([JACK], [test "x$have_jack" = "xyes"])
273+
251274
dnl ######################
252275
dnl checking for math lib
253276
dnl ######################

0 commit comments

Comments
 (0)