1 /*
2     SuperEQ DSP plugin for DeaDBeeF Player
3     Copyright (C) 2009-2014 Alexey Yakovenko <waker@users.sourceforge.net>
4 
5     This program is free software; you can redistribute it and/or
6     modify it under the terms of the GNU General Public License
7     as published by the Free Software Foundation; either version 2
8     of the License, or (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 */
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <math.h>
23 #include "../../deadbeef.h"
24 #include "Equ.h"
25 
26 static DB_functions_t *deadbeef;
27 static DB_dsp_t plugin;
28 
29 typedef struct {
30     ddb_dsp_context_t ctx;
31     float last_srate;
32     int last_nch;
33     float bands[18];
34     float preamp;
35     void *paramsroot;
36     int params_changed;
37     uintptr_t mutex;
38     SuperEqState state;
39     int enabled;
40 } ddb_supereq_ctx_t;
41 
42 void supereq_reset (ddb_dsp_context_t *ctx);
43 
44 void
recalc_table(ddb_supereq_ctx_t * eq)45 recalc_table (ddb_supereq_ctx_t *eq) {
46     void *params = paramlist_alloc ();
47 
48     deadbeef->mutex_lock (eq->mutex);
49     float bands_copy[18];
50     float srate = eq->last_srate;
51     memcpy (bands_copy, eq->bands, sizeof (eq->bands));
52     for (int i = 0; i < 18; i++) {
53         bands_copy[i] *= eq->preamp;
54     }
55     deadbeef->mutex_unlock (eq->mutex);
56 
57     equ_makeTable (&eq->state, bands_copy, params, srate);
58 
59     deadbeef->mutex_lock (eq->mutex);
60     paramlist_free (eq->paramsroot);
61     eq->paramsroot = params;
62     deadbeef->mutex_unlock (eq->mutex);
63 }
64 
65 int
supereq_plugin_start(void)66 supereq_plugin_start (void) {
67     return 0;
68 }
69 
70 int
supereq_plugin_stop(void)71 supereq_plugin_stop (void) {
72     return 0;
73 }
74 
75 int
supereq_process(ddb_dsp_context_t * ctx,float * samples,int frames,int maxframes,ddb_waveformat_t * fmt,float * r)76 supereq_process (ddb_dsp_context_t *ctx, float *samples, int frames, int maxframes, ddb_waveformat_t *fmt, float *r) {
77     ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
78     if (supereq->enabled != ctx->enabled) {
79         if (ctx->enabled && !supereq->enabled) {
80             supereq_reset (ctx);
81         }
82         supereq->enabled = ctx->enabled;
83 
84 // this causes a glitch on 1st track
85 //        DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
86 //        if (it) {
87 //            float playpos = deadbeef->streamer_get_playpos ();
88 //            deadbeef->streamer_seek (playpos);
89 //            deadbeef->pl_item_unref (it);
90 //        }
91     }
92     if (supereq->params_changed) {
93         recalc_table (supereq);
94         supereq->params_changed = 0;
95     }
96 	if (supereq->last_srate != fmt->samplerate || supereq->last_nch != fmt->channels) {
97         deadbeef->mutex_lock (supereq->mutex);
98 		supereq->last_srate = fmt->samplerate;
99 		supereq->last_nch = fmt->channels;
100         equ_init (&supereq->state, 10, fmt->channels);
101         recalc_table (supereq);
102 		equ_clearbuf(&supereq->state);
103         deadbeef->mutex_unlock (supereq->mutex);
104     }
105 	equ_modifySamples_float(&supereq->state, (char *)samples,frames,fmt->channels);
106 	return frames;
107 }
108 
109 float
supereq_get_band(ddb_dsp_context_t * ctx,int band)110 supereq_get_band (ddb_dsp_context_t *ctx, int band) {
111     ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
112     return supereq->bands[band];
113 }
114 
115 void
supereq_set_band(ddb_dsp_context_t * ctx,int band,float value)116 supereq_set_band (ddb_dsp_context_t *ctx, int band, float value) {
117     ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
118     deadbeef->mutex_lock (supereq->mutex);
119     supereq->bands[band] = value;
120     deadbeef->mutex_unlock (supereq->mutex);
121     supereq->params_changed = 1;
122 }
123 
124 float
supereq_get_preamp(ddb_dsp_context_t * ctx)125 supereq_get_preamp (ddb_dsp_context_t *ctx) {
126     ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
127     return supereq->preamp;
128 }
129 
130 void
supereq_set_preamp(ddb_dsp_context_t * ctx,float value)131 supereq_set_preamp (ddb_dsp_context_t *ctx, float value) {
132     ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
133     deadbeef->mutex_lock (supereq->mutex);
134     supereq->preamp = value;
135     deadbeef->mutex_unlock (supereq->mutex);
136     supereq->params_changed = 1;
137 }
138 
139 void
supereq_reset(ddb_dsp_context_t * ctx)140 supereq_reset (ddb_dsp_context_t *ctx) {
141     ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
142     deadbeef->mutex_lock (supereq->mutex);
143     equ_clearbuf(&supereq->state);
144     deadbeef->mutex_unlock (supereq->mutex);
145 }
146 
147 int
supereq_num_params(void)148 supereq_num_params (void) {
149     return 19;
150 }
151 
152 static const char *bandnames[] = {
153     "Preamp",
154     "55 Hz",
155     "77 Hz",
156     "110 Hz",
157     "156 Hz",
158     "220 Hz",
159     "311 Hz",
160     "440 Hz",
161     "622 Hz",
162     "880 Hz",
163     "1.2 kHz",
164     "1.8 kHz",
165     "2.5 kHz",
166     "3.5 kHz",
167     "5 kHz",
168     "7 kHz",
169     "10 kHz",
170     "14 kHz",
171     "20 kHz"
172 };
173 
174 const char *
supereq_get_param_name(int p)175 supereq_get_param_name (int p) {
176     return bandnames[p];
177 }
178 
179 
180 static inline float
db_to_amp(float dB)181 db_to_amp (float dB) {
182     const float ln10=2.3025850929940002f;
183     return exp(ln10*dB/20.f);
184 }
185 
186 static inline float
amp_to_db(float amp)187 amp_to_db (float amp) {
188     return 20*log10 (amp);
189 }
190 
191 void
supereq_set_param(ddb_dsp_context_t * ctx,int p,const char * val)192 supereq_set_param (ddb_dsp_context_t *ctx, int p, const char *val) {
193     switch (p) {
194     case 0:
195         supereq_set_preamp (ctx, db_to_amp (atof (val)));
196         break;
197     case 1 ... 18:
198         supereq_set_band (ctx, p-1, db_to_amp (atof (val)));
199         break;
200     default:
201         fprintf (stderr, "supereq_set_param: invalid param index (%d)\n", p);
202     }
203 }
204 
205 void
supereq_get_param(ddb_dsp_context_t * ctx,int p,char * v,int sz)206 supereq_get_param (ddb_dsp_context_t *ctx, int p, char *v, int sz) {
207     switch (p) {
208     case 0:
209         snprintf (v, sz, "%f", amp_to_db (supereq_get_preamp (ctx)));
210         break;
211     case 1 ... 18:
212         snprintf (v, sz, "%f", amp_to_db (supereq_get_band (ctx, p-1)));
213         break;
214     default:
215         fprintf (stderr, "supereq_get_param: invalid param index (%d)\n", p);
216     }
217 }
218 
219 
220 ddb_dsp_context_t*
supereq_open(void)221 supereq_open (void) {
222     ddb_supereq_ctx_t *supereq = malloc (sizeof (ddb_supereq_ctx_t));
223     DDB_INIT_DSP_CONTEXT (supereq,ddb_supereq_ctx_t,&plugin);
224 
225     equ_init (&supereq->state, 10, 2);
226     supereq->paramsroot = paramlist_alloc ();
227     supereq->last_srate = 44100;
228     supereq->last_nch = 2;
229     supereq->mutex = deadbeef->mutex_create ();
230     supereq->preamp = 1;
231     for (int i = 0; i < 18; i++) {
232         supereq->bands[i] = 1;
233     }
234     recalc_table (supereq);
235     equ_clearbuf (&supereq->state);
236 
237     return (ddb_dsp_context_t*)supereq;
238 }
239 
240 void
supereq_close(ddb_dsp_context_t * ctx)241 supereq_close (ddb_dsp_context_t *ctx) {
242     ddb_supereq_ctx_t *supereq = (ddb_supereq_ctx_t *)ctx;
243     if (supereq->mutex) {
244         deadbeef->mutex_free (supereq->mutex);
245         supereq->mutex = 0;
246     }
247     equ_quit (&supereq->state);
248     paramlist_free (supereq->paramsroot);
249     free (ctx);
250 }
251 
252 static const char settings_dlg[] =
253     "property \"\" hbox[19] hmg fill expand border=0 spacing=8 height=200;\n"
254         "property \"Preamp\" vscale[20,-20,1] vert 0 0;\n"
255         "property \"55 Hz\" vscale[20,-20,1] vert 1 0;\n"
256         "property \"77 Hz\" vscale[20,-20,1] vert 2 0;\n"
257         "property \"110 Hz\" vscale[20,-20,1] vert 3 0;\n"
258         "property \"156 Hz\" vscale[20,-20,1] vert 4 0;\n"
259         "property \"220 Hz\" vscale[20,-20,1] vert 5 0;\n"
260         "property \"311 Hz\" vscale[20,-20,1] vert 6 0;\n"
261         "property \"440 Hz\" vscale[20,-20,1] vert 7 0;\n"
262         "property \"622 Hz\" vscale[20,-20,1] vert 8 0;\n"
263         "property \"880 Hz\" vscale[20,-20,1] vert 9 0;\n"
264         "property \"1.2 kHz\" vscale[20,-20,1] vert 10 0;\n"
265         "property \"1.8 kHz\" vscale[20,-20,1] vert 11 0;\n"
266         "property \"2.5 kHz\" vscale[20,-20,1] vert 12 0;\n"
267         "property \"3.5 kHz\" vscale[20,-20,1] vert 13 0;\n"
268         "property \"5 kHz\" vscale[20,-20,1] vert 14 0;\n"
269         "property \"7 kHz\" vscale[20,-20,1] vert 15 0;\n"
270         "property \"10 kHz\" vscale[20,-20,1] vert 16 0;\n"
271         "property \"14 kHz\" vscale[20,-20,1] vert 17 0;\n"
272         "property \"20 kHz\" vscale[20,-20,1] vert 18 0;\n"
273 ;
274 
275 static DB_dsp_t plugin = {
276     .plugin.api_vmajor = 1,
277     .plugin.api_vminor = 0,
278     .plugin.version_major = 1,
279     .plugin.version_minor = 0,
280     .plugin.type = DB_PLUGIN_DSP,
281     .plugin.id = "supereq",
282     .plugin.name = "SuperEQ",
283     .plugin.descr = "equalizer plugin using SuperEQ library",
284     .plugin.copyright =
285         "SuperEQ DSP plugin for DeaDBeeF Player\n"
286         "Copyright (C) 2009-2014 Alexey Yakovenko <waker@users.sourceforge.net>\n"
287         "\n"
288         "Uses supereq library by Naoki Shibata, http://shibatch.sourceforge.net\n"
289         "Uses FFT library by Takuya Ooura, http://www.kurims.kyoto-u.ac.jp/~ooura/\n"
290         "\n"
291         "This program is free software; you can redistribute it and/or\n"
292         "modify it under the terms of the GNU General Public License\n"
293         "as published by the Free Software Foundation; either version 2\n"
294         "of the License, or (at your option) any later version.\n"
295         "\n"
296         "This program is distributed in the hope that it will be useful,\n"
297         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
298         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
299         "GNU General Public License for more details.\n"
300         "\n"
301         "You should have received a copy of the GNU General Public License\n"
302         "along with this program; if not, write to the Free Software\n"
303         "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\n"
304         "\n"
305         "\n"
306         "\n"
307         "Based on:\n"
308         "Shibatch Super Equalizer ver 0.03 for winamp\n"
309         "written by Naoki Shibata  shibatch@users.sourceforge.net\n"
310         "\n"
311         "Shibatch Super Equalizer is a graphic and parametric equalizer plugin\n"
312         "for winamp. This plugin uses 16383th order FIR filter with FFT algorithm.\n"
313         "It's equalization is very precise. Equalization setting can be done\n"
314         "for each channel separately.\n"
315         "\n"
316         "Processes of internal equalizer in winamp are actually done by each\n"
317         "input plugin, so the results may differ for each input plugin.\n"
318         "With this plugin, this problem can be avoided.\n"
319         "\n"
320         "This plugin is optimized for processors which have cache equal to or\n"
321         "greater than 128k bytes(16383*2*sizeof(float) = 128k). This plugin\n"
322         "won't work efficiently with K6 series processors(buy Athlon!!!).\n"
323         "\n"
324         "Do not forget pressing \"preview\" button after changing setting.\n"
325         "\n"
326         "http://shibatch.sourceforge.net/\n"
327         "\n"
328         "***\n"
329         "\n"
330         "  This program(except FFT part) is distributed under LGPL. See LGPL.txt for\n"
331         "details.\n"
332         "\n"
333         "  FFT part is a routine made by Mr.Ooura. This routine is a freeware. Contact\n"
334         "Mr.Ooura for details of distributing licenses.\n"
335         "\n"
336         "http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html\n"
337     ,
338     .plugin.website = "http://deadbeef.sf.net",
339     .plugin.start = supereq_plugin_start,
340     .plugin.stop = supereq_plugin_stop,
341     .open = supereq_open,
342     .close = supereq_close,
343     .process = supereq_process,
344     .reset = supereq_reset,
345     .num_params = supereq_num_params,
346     .get_param_name = supereq_get_param_name,
347     .set_param = supereq_set_param,
348     .get_param = supereq_get_param,
349     .configdialog = settings_dlg,
350 };
351 
352 DB_plugin_t *
supereq_load(DB_functions_t * api)353 supereq_load (DB_functions_t *api) {
354     deadbeef = api;
355     return DB_PLUGIN (&plugin);
356 }
357