1 /*
2 Musical Spectrum plugin for the DeaDBeeF audio player
3
4 Copyright (C) 2015 Christian Boxdörfer <christian.boxdoerfer@posteo.de>
5
6 Based on DeaDBeeFs stock spectrum.
7 Copyright (c) 2009-2015 Alexey Yakovenko <waker@users.sourceforge.net>
8 Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24
25 #include <sys/types.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdint.h>
29 #include <assert.h>
30 #include <math.h>
31 #include <fcntl.h>
32 #include <gtk/gtk.h>
33
34 #include "fastftoi.h"
35 #include "config.h"
36 #include "spectrum.h"
37 #include "utils.h"
38
39 int CALCULATED_NUM_BARS = 136;
40
41 int
get_num_bars()42 get_num_bars ()
43 {
44 int bar_num = CALCULATED_NUM_BARS;
45 if (CONFIG_DRAW_STYLE == 1) {
46 bar_num = CALCULATED_NUM_BARS;
47 }
48 else if (CONFIG_BAR_W > 0) {
49 bar_num = CALCULATED_NUM_BARS;
50 }
51 else {
52 bar_num = CONFIG_NUM_BARS;
53 }
54 return bar_num;
55 }
56
57 void
_memset_pattern(char * data,const void * pattern,size_t data_len,size_t pattern_len)58 _memset_pattern (char *data, const void* pattern, size_t data_len, size_t pattern_len)
59 {
60 memmove ((char *)data, pattern, pattern_len);
61 char *start = (char *)data;
62 char *current = (char *)data + pattern_len;
63 char *end = start + data_len;
64 while(current + pattern_len < end) {
65 memmove (current, start, pattern_len);
66 current += pattern_len;
67 pattern_len *= 2;
68 }
69 memmove (current, start, end-current);
70 }
71
72 void
create_gradient_table(uint32_t * dest,GdkColor * colors,int num_colors)73 create_gradient_table (uint32_t *dest, GdkColor *colors, int num_colors)
74 {
75 if (!dest) {
76 return;
77 }
78 num_colors -= 1;
79
80 for (int i = 0; i < GRADIENT_TABLE_SIZE; i++) {
81 double position = (double)i/GRADIENT_TABLE_SIZE;
82 /* if position > 1 then we have repetition of colors it maybe useful */
83 if (position > 1.0) {
84 if (position - ftoi (position) == 0.0) {
85 position = 1.0;
86 }
87 else {
88 position = position - ftoi (position);
89 }
90 }
91
92 double m= num_colors * position;
93 int n=(int)m; // integer of m
94 double f=m-n; // fraction of m
95
96 dest[i] = 0xFF000000;
97 float scale = 255/65535.f;
98 if (num_colors == 0) {
99 dest[i] = (uint32_t)(colors[0].red*scale) << 16 |
100 (uint32_t)(colors[0].green*scale) << 8 |
101 (uint32_t)(colors[0].blue*scale) << 0;
102 }
103 else if (n < num_colors) {
104 dest[i] = (uint32_t)((colors[n].red*scale) + f * ((colors[n+1].red*scale)-(colors[n].red*scale))) << 16 |
105 (uint32_t)((colors[n].green*scale) + f * ((colors[n+1].green*scale)-(colors[n].green*scale))) << 8 |
106 (uint32_t)((colors[n].blue*scale) + f * ((colors[n+1].blue*scale)-(colors[n].blue*scale))) << 0;
107 }
108 else if (n == num_colors) {
109 dest[i] = (uint32_t)(colors[n].red*scale) << 16 |
110 (uint32_t)(colors[n].green*scale) << 8 |
111 (uint32_t)(colors[n].blue*scale) << 0;
112 }
113 else {
114 dest[i] = 0xFFFFFFFF;
115 }
116 }
117 }
118
119 void
create_window_table(gpointer user_data)120 create_window_table (gpointer user_data)
121 {
122 w_spectrum_t *w = user_data;
123
124 switch (CONFIG_WINDOW) {
125 case BLACKMAN_HARRIS:
126 for (int i = 0; i < CONFIG_FFT_SIZE; i++) {
127 // Blackman-Harris
128 w->window[i] = 0.35875 - 0.48829 * cos(2 * M_PI * i / CONFIG_FFT_SIZE) + 0.14128 * cos(4 * M_PI * i / CONFIG_FFT_SIZE) - 0.01168 * cos(6 * M_PI * i / CONFIG_FFT_SIZE);
129 }
130 break;
131 case HANNING:
132 for (int i = 0; i < CONFIG_FFT_SIZE; i++) {
133 // Hanning
134 w->window[i] = (0.5 * (1 - cos (2 * M_PI * i / CONFIG_FFT_SIZE)));
135 }
136 break;
137 default:
138 break;
139 }
140 }
141
142 void
update_num_bars(gpointer user_data)143 update_num_bars (gpointer user_data)
144 {
145 w_spectrum_t *w = user_data;
146
147 GtkAllocation a;
148 gtk_widget_get_allocation (w->drawarea, &a);
149
150 CALCULATED_NUM_BARS = 136;
151 if (CONFIG_DRAW_STYLE == 1) {
152 CALCULATED_NUM_BARS = CLAMP (a.width, 1, MAX_BARS);
153 }
154 else if (CONFIG_BAR_W > 0) {
155 int added_bar_w = CONFIG_BAR_W;
156 if (CONFIG_GAPS)
157 added_bar_w += 1;
158 CALCULATED_NUM_BARS = CLAMP (a.width/added_bar_w, 1, MAX_BARS);
159 }
160 }
161
162 void
create_frequency_table(gpointer user_data)163 create_frequency_table (gpointer user_data)
164 {
165 w_spectrum_t *w = user_data;
166 w->low_res_end = 0;
167
168 update_num_bars (w);
169 const int num_bars = get_num_bars ();
170 const double ratio = num_bars / 132.0;
171 const double a4pos = 57.0 * ratio;
172 const double octave = 12.0 * ratio;
173
174 for (int i = 0; i < num_bars; i++) {
175 w->freq[i] = 440.0 * pow (2.0, (double)(i-a4pos)/octave);
176 w->keys[i] = ftoi (w->freq[i] * CONFIG_FFT_SIZE/(float)w->samplerate);
177 if (i > 0 && w->keys[i-1] == w->keys[i])
178 w->low_res_end = i;
179 }
180 }
181
182 float
linear_interpolate(float y1,float y2,float mu)183 linear_interpolate (float y1, float y2, float mu)
184 {
185 return (y1 * (1 - mu) + y2 * mu);
186 }
187
188 float
lagrange_interpolate(float y0,float y1,float y2,float y3,float x)189 lagrange_interpolate (float y0, float y1, float y2, float y3, float x)
190 {
191 const float a0 = ((x - 1) * (x - 2) * (x - 3)) / -6 * y0;
192 const float a1 = ((x - 0) * (x - 2) * (x - 3)) / 2 * y1;
193 const float a2 = ((x - 0) * (x - 1) * (x - 3)) / -2 * y2;
194 const float a3 = ((x - 0) * (x - 1) * (x - 2)) / 6 * y3;
195 return (a0 + a1 + a2 + a3);
196 }
197