Skip to content

Commit 609cc63

Browse files
committed
+ Equalizer
1 parent b887663 commit 609cc63

File tree

23 files changed

+812
-4
lines changed

23 files changed

+812
-4
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ Contents:
3737
* List/search file meta tags; edit file tags, write ReplayGain tags (`.mp3`, `.ogg/.opus`, `.flac`)
3838
* List available audio devices
3939
* Input: file, directory, ICY/HLS/HTTP/HTTPS URL, console (stdin), playlists: `.m3u`, `.pls`, `.cue`
40+
* Audio filters:
41+
* DynamicAudioNormalizer, auto loudness and ReplayGain normalizer
42+
* multi-band equalizer
43+
* noise gate
4044
* Command Line Interface for Desktop OS
4145
* Terminal/Console UI for interaction at runtime
4246
* GUI for Windows, Linux, Android: manage your playlists and audio files
@@ -124,6 +128,9 @@ phiola http://server/stream -tee "@artist - @title.mp3"
124128

125129
# Play MP3 audio via HTTP and convert to a local 64-kbit/sec AAC file
126130
phiola http://server/music.mp3 -dup @stdout.wav | phiola convert @stdin -aac_q 64 -o output.m4a
131+
132+
# Play audio with 2-band Equalizer (at 600Hz, 2.0 Q-factor width, -6 dB gain; at 10KHz, +3 dB gain)
133+
phiola file.mp3 -equalizer "600 2.0q -6.0 10000 2.0q 3.0"
127134
```
128135

129136
While audio is playing, you can control phiola via keyboard. The most commonly used commands are:
@@ -371,6 +378,7 @@ libmpc,
371378
[libopus](https://github.com/xiph/opus),
372379
[libvorbis](https://github.com/xiph/vorbis),
373380
libwavpack,
381+
libsox,
374382
[libsoxr](https://github.com/dofuuz/soxr),
375383
[libzstd](https://github.com/facebook/zstd),
376384
[libDynamicAudioNormalizer](https://github.com/lordmulder/DynamicAudioNormalizer).

alib3/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ LIBS := \
1313
mp3lame \
1414
mpg123 \
1515
opus \
16+
sox \
1617
soxr \
1718
vorbis
1819
ifneq "$(SYS)" "android"
@@ -64,6 +65,10 @@ libopus-phi.$(SO):
6465
$(MAKE) -f $(ALIB3)/opus/Makefile
6566
opus: libopus-phi.$(SO)
6667

68+
libsox-phi.$(SO):
69+
$(MAKE) -f $(ALIB3)/sox/Makefile
70+
sox: libsox-phi.$(SO)
71+
6772
libsoxr-phi.$(SO):
6873
$(MAKE) -f $(ALIB3)/soxr/Makefile
6974
soxr: libsoxr-phi.$(SO)

alib3/sox/0001.patch

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
diff --git a/src/effects.h b/src/effects.h
2+
index 450a5c2..378fcb4 100644
3+
--- a/src/effects.h
4+
+++ b/src/effects.h
5+
@@ -15,76 +15,4 @@
6+
7+
/* FIXME: generate this list automatically */
8+
9+
- EFFECT(allpass)
10+
- EFFECT(band)
11+
- EFFECT(bandpass)
12+
- EFFECT(bandreject)
13+
- EFFECT(bass)
14+
- EFFECT(bend)
15+
- EFFECT(biquad)
16+
- EFFECT(chorus)
17+
- EFFECT(channels)
18+
- EFFECT(compand)
19+
- EFFECT(contrast)
20+
- EFFECT(dcshift)
21+
- EFFECT(deemph)
22+
- EFFECT(delay)
23+
- EFFECT(dft_filter) /* abstract */
24+
- EFFECT(dither)
25+
- EFFECT(divide)
26+
- EFFECT(downsample)
27+
- EFFECT(earwax)
28+
- EFFECT(echo)
29+
- EFFECT(echos)
30+
EFFECT(equalizer)
31+
- EFFECT(fade)
32+
- EFFECT(fir)
33+
- EFFECT(firfit)
34+
- EFFECT(flanger)
35+
- EFFECT(gain)
36+
- EFFECT(highpass)
37+
- EFFECT(hilbert)
38+
- EFFECT(input)
39+
-#ifdef HAVE_LADSPA_H
40+
- EFFECT(ladspa)
41+
-#endif
42+
- EFFECT(loudness)
43+
- EFFECT(lowpass)
44+
- EFFECT(mcompand)
45+
- EFFECT(noiseprof)
46+
- EFFECT(noisered)
47+
- EFFECT(norm)
48+
- EFFECT(oops)
49+
- EFFECT(output)
50+
- EFFECT(overdrive)
51+
- EFFECT(pad)
52+
- EFFECT(phaser)
53+
- EFFECT(pitch)
54+
- EFFECT(rate)
55+
- EFFECT(remix)
56+
- EFFECT(repeat)
57+
- EFFECT(reverb)
58+
- EFFECT(reverse)
59+
- EFFECT(riaa)
60+
- EFFECT(silence)
61+
- EFFECT(sinc)
62+
-#ifdef HAVE_PNG
63+
- EFFECT(spectrogram)
64+
-#endif
65+
- EFFECT(speed)
66+
-#ifdef HAVE_SPEEXDSP
67+
- EFFECT(speexdsp)
68+
-#endif
69+
- EFFECT(splice)
70+
- EFFECT(stat)
71+
- EFFECT(stats)
72+
- EFFECT(stretch)
73+
- EFFECT(swap)
74+
- EFFECT(synth)
75+
- EFFECT(tempo)
76+
- EFFECT(treble)
77+
- EFFECT(tremolo)
78+
- EFFECT(trim)
79+
- EFFECT(upsample)
80+
- EFFECT(vad)
81+
- EFFECT(vol)

alib3/sox/Makefile

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# libsox
2+
3+
include ../config.mk
4+
5+
VER := 14.4.2
6+
URL := /sox-$(VER).tar.bz2
7+
MD5SUM := ba804bb1ce5c71dd484a102a5b27d0dd
8+
PKG := $(ALIB3)/sox/sox-$(VER).tar.bz2
9+
DIR := sox-$(VER)
10+
LIB := libsox-phi.$(SO)
11+
12+
default: $(DIR)/src/soxconfig.h
13+
$(SUBMAKE) $(LIB)
14+
15+
# download
16+
$(PKG):
17+
$(CURL) -o $(PKG) $(URL)
18+
19+
# unpack
20+
$(DIR): $(PKG)
21+
echo "$(MD5SUM) *$(PKG)" | md5sum -c -
22+
$(UNTAR_BZ2) $(PKG)
23+
24+
CONFIGURE_FLAGS := --without-libltdl
25+
ifeq "$(OS)" "windows"
26+
CONFIGURE_FLAGS += --host=x86_64-w64-mingw32
27+
endif
28+
29+
$(DIR)/src/soxconfig.h: | $(DIR)
30+
cd $(DIR) && ./configure $(CONFIGURE_FLAGS)
31+
cat $@
32+
cat $(ALIB3)/sox/*.patch | patch -d $(DIR) -p1
33+
34+
# build
35+
CFLAGS += \
36+
-I$(DIR) -I$(DIR)/src
37+
38+
SRC := \
39+
$(DIR)/src/effects.c \
40+
$(DIR)/src/effects_i.c \
41+
$(DIR)/src/xmalloc.c \
42+
$(DIR)/src/biquad.c \
43+
$(DIR)/src/biquads.c
44+
45+
OBJ := sox-phi.o $(SRC:.c=.o)
46+
47+
%.o: $(ALIB3)/sox/%.c $(wildcard $(DIR)/src/*.h)
48+
$(C) $(CFLAGS) $< -o $@
49+
50+
%.o: %.c $(wildcard $(DIR)/src/*.h)
51+
$(C) $(CFLAGS) $< -o $@
52+
53+
$(LIB): $(OBJ)
54+
$(LINK) -shared $+ $(LINKFLAGS) -o $@
55+
56+
clean:
57+
$(RM) $(OBJ) $(DIR)

alib3/sox/sox-phi.c

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/** libsox wrapper
2+
2026, Simon Zolin */
3+
4+
#include "sox-phi.h"
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <sox.h>
8+
9+
struct sox_ctx {
10+
sox_effects_chain_t *chain;
11+
sox_signalinfo_t signal;
12+
13+
size_t input_len4;
14+
const sox_sample_t *input;
15+
16+
size_t output_len4;
17+
const sox_sample_t *output;
18+
};
19+
20+
void phi_sox_destroy(sox_ctx *c)
21+
{
22+
if (!c) return;
23+
24+
if (c->chain)
25+
sox_delete_effects_chain(c->chain);
26+
free(c);
27+
}
28+
29+
static int input_drain(sox_effect_t *e, sox_sample_t *obuf, size_t *osamp)
30+
{
31+
struct sox_ctx *c = *(void**)e->priv;
32+
if (*osamp > c->input_len4)
33+
*osamp = c->input_len4;
34+
memcpy(obuf, c->input, *osamp * 4);
35+
c->input_len4 -= *osamp;
36+
c->input += *osamp;
37+
return SOX_EOF;
38+
}
39+
40+
static const sox_effect_handler_t input_handler = {
41+
"input", NULL, SOX_EFF_MCHAN, NULL, NULL, NULL, input_drain, NULL, NULL,
42+
.priv_size = sizeof(void*)
43+
};
44+
45+
static int output_flow(sox_effect_t *e, const sox_sample_t *ibuf, sox_sample_t *obuf, size_t *isamp, size_t *osamp)
46+
{
47+
struct sox_ctx *c = *(void**)e->priv;
48+
c->output = ibuf;
49+
c->output_len4 = *isamp;
50+
*osamp = 0;
51+
return (c->output_len4) ? SOX_EOF : 0;
52+
}
53+
54+
static const sox_effect_handler_t output_handler = {
55+
"output", NULL, SOX_EFF_MCHAN, NULL, NULL, output_flow, NULL, NULL, NULL,
56+
.priv_size = sizeof(void*)
57+
};
58+
59+
int phi_sox_create(sox_ctx **pc, struct sox_conf *conf)
60+
{
61+
sox_ctx *c = calloc(1, sizeof(struct sox_ctx));
62+
63+
sox_signalinfo_t signal = {
64+
.rate = conf->rate,
65+
.channels = conf->channels,
66+
};
67+
c->signal = signal;
68+
69+
sox_encodinginfo_t encoding = {};
70+
c->chain = sox_create_effects_chain(&encoding, &encoding);
71+
72+
sox_effect_t *e = sox_create_effect(&input_handler);
73+
*(void**)e->priv = c;
74+
if (sox_add_effect(c->chain, e, &signal, &signal))
75+
goto err;
76+
free(e); e = NULL;
77+
78+
*pc = c;
79+
return 0;
80+
81+
err:
82+
free(e);
83+
phi_sox_destroy(c);
84+
return 1;
85+
}
86+
87+
int phi_sox_filter(sox_ctx *c, const char *name, const char* argv[], unsigned argc)
88+
{
89+
sox_effect_t *e = NULL;
90+
91+
if (!name) {
92+
e = sox_create_effect(&output_handler);
93+
*(void**)e->priv = c;
94+
goto done;
95+
}
96+
97+
const sox_effect_handler_t *eh;
98+
if (!(eh = sox_find_effect(name)))
99+
goto err;
100+
e = sox_create_effect(eh);
101+
102+
if (argc
103+
&& sox_effect_options(e, argc, (char**)argv))
104+
goto err;
105+
106+
done:
107+
if (sox_add_effect(c->chain, e, &c->signal, &c->signal))
108+
goto err;
109+
free(e); e = NULL;
110+
return 0;
111+
112+
err:
113+
free(e);
114+
return 1;
115+
}
116+
117+
int phi_sox_process(sox_ctx *c, const int *input, size_t *len, int **output)
118+
{
119+
c->input = input;
120+
c->input_len4 = *len / 4;
121+
c->output_len4 = 0;
122+
sox_flow_effects(c->chain, NULL, NULL);
123+
*len -= c->input_len4 * 4;
124+
*output = (int*)c->output;
125+
return c->output_len4 * 4;
126+
}
127+
128+
129+
static void output_message(unsigned level, const char *filename, const char *fmt, va_list ap) {}
130+
131+
static sox_globals_t s_sox_globals = {
132+
2, /* unsigned verbosity */
133+
output_message, /* sox_output_message_handler */
134+
sox_false, /* sox_bool repeatable */
135+
8192, /* size_t bufsiz */
136+
0, /* size_t input_bufsiz */
137+
0, /* int32_t ranqd1 */
138+
NULL, /* char const * stdin_in_use_by */
139+
NULL, /* char const * stdout_in_use_by */
140+
NULL, /* char const * subsystem */
141+
NULL, /* char * tmp_path */
142+
sox_false, /* sox_bool use_magic */
143+
sox_false, /* sox_bool use_threads */
144+
10 /* size_t log2_dft_min_size */
145+
};
146+
147+
sox_globals_t* sox_get_globals() { return &s_sox_globals; }
148+
149+
static sox_effects_globals_t s_sox_effects_globals = {sox_plot_off, &s_sox_globals};
150+
151+
sox_effects_globals_t* sox_get_effects_globals()
152+
{
153+
return &s_sox_effects_globals;
154+
}
155+
156+
#define SOX_MESSAGE_FUNCTION(name,level) \
157+
void name(char const * fmt, ...) { \
158+
va_list ap; \
159+
va_start(ap, fmt); \
160+
if (sox_globals.output_message_handler) \
161+
(*sox_globals.output_message_handler)(level,sox_globals.subsystem,fmt,ap); \
162+
va_end(ap); \
163+
}
164+
165+
SOX_MESSAGE_FUNCTION(lsx_fail_impl , 1)
166+
SOX_MESSAGE_FUNCTION(lsx_warn_impl , 2)
167+
SOX_MESSAGE_FUNCTION(lsx_report_impl, 3)
168+
SOX_MESSAGE_FUNCTION(lsx_debug_impl , 4)
169+
SOX_MESSAGE_FUNCTION(lsx_debug_more_impl , 5)
170+
SOX_MESSAGE_FUNCTION(lsx_debug_most_impl , 6)
171+
172+
void init_fft_cache() {}
173+
void clear_fft_cache() {}

0 commit comments

Comments
 (0)