1 /*
2 * Copyright (C) 2005-2020 Team Kodi (https://kodi.tv)
3 * Copyright (C) 2012 Marcel Ebmer
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSE.md for more information.
7 */
8
9 #include "fische_internal.h"
10
11 #include <string.h>
12 #include <thread>
13 #include <chrono>
14 #include <thread>
15
16 #ifdef DEBUG
17 #include <stdio.h>
18 #endif
19
create_vectors(fische * F)20 void create_vectors (fische* F)
21 {
22 struct _fische__internal_ * P = static_cast<_fische__internal_*>(F->priv);
23 P->vectorfield = fische__vectorfield_new (F,
24 &P->init_progress,
25 &P->init_cancel);
26 return;
27 }
28
indicate_busy(fische * F)29 void indicate_busy (fische* F)
30 {
31 struct _fische__internal_ * P = static_cast<_fische__internal_*>(F->priv);
32 struct fische__screenbuffer* sbuf = P->screenbuffer;
33
34 fische__point center;
35 center.x = sbuf->priv->width / 2;
36 center.y = sbuf->priv->height / 2;
37 double dim = (center.x > center.y) ? center.y / 2 : center.x / 2;
38
39 double last = -1;
40
41 while ( (P->init_progress < 1) && (!P->init_cancel)) {
42
43 if ( (P->init_progress < 0) || (P->init_progress == last)) {
44 std::this_thread::sleep_for(std::chrono::microseconds(10000));
45 continue;
46 }
47
48 last = P->init_progress;
49 double angle = P->init_progress * -2 * 3.1415 + 3.0415;
50
51 fische__vector c1;
52 c1.x = sin (angle) * dim;
53 c1.y = cos (angle) * dim;
54
55 fische__vector c2;
56 c2.x = sin (angle + 0.1) * dim;
57 c2.y = cos (angle + 0.1) * dim;
58
59 fische__vector e1 = fische__vector_single (&c1);
60 fische__vector_mul (&e1, dim / 2);
61 fische__vector e2 = fische__vector_single (&c2);
62 fische__vector_mul (&e2, dim / 2);
63
64 fische__vector c3 = c2;
65 fische__vector_sub (&c3, &e2);
66 fische__vector c4 = c1;
67 fische__vector_sub (&c4, &e1);
68
69 fische__vector_mul (&c1, F->scale);
70 fische__vector_mul (&c2, F->scale);
71 fische__vector_mul (&c3, F->scale);
72 fische__vector_mul (&c4, F->scale);
73
74 fische__vector_add (&c1, ¢er);
75 fische__vector_add (&c2, ¢er);
76 fische__vector_add (&c3, ¢er);
77 fische__vector_add (&c4, ¢er);
78
79 fische__screenbuffer_lock (sbuf);
80 fische__screenbuffer_line (sbuf, c1.x, c1.y, c2.x, c2.y, 0xffffffff);
81 fische__screenbuffer_line (sbuf, c2.x, c2.y, c3.x, c3.y, 0xffffffff);
82 fische__screenbuffer_line (sbuf, c3.x, c3.y, c4.x, c4.y, 0xffffffff);
83 fische__screenbuffer_line (sbuf, c4.x, c4.y, c1.x, c1.y, 0xffffffff);
84 fische__screenbuffer_unlock (sbuf);
85 }
86
87 return;
88 }
89
90 struct fische *
fische_new()91 fische_new() {
92 struct fische* retval = static_cast<fische*>(malloc (sizeof (struct fische)));
93
94 retval->used_cpus = _fische__cpu_detect_();
95 if (retval->used_cpus > 8)
96 retval->used_cpus = 8;
97
98 retval->frame_counter = 0;
99 retval->audio_format = FISCHE_AUDIOFORMAT_FLOAT;
100 retval->pixel_format = FISCHE_PIXELFORMAT_0xAABBGGRR;
101 retval->width = 512;
102 retval->height = 256;
103 retval->read_vectors = 0;
104 retval->write_vectors = 0;
105 retval->on_beat = 0;
106 retval->nervous_mode = 0;
107 retval->blur_mode = FISCHE_BLUR_SLICK;
108 retval->line_style = FISCHE_LINESTYLE_ALPHA_SIMULATION;
109 retval->scale = 1;
110 retval->amplification = 0;
111 retval->priv = 0;
112 retval->error_text = "no error";
113
114 return retval;
115 }
116
117 int
fische_start(struct fische * handle)118 fische_start (struct fische* handle)
119 {
120 // plausibility checks
121 if ( (handle->used_cpus > 8) || (handle->used_cpus < 1)) {
122 handle->error_text = "CPU count out of range (1 <= used_cpus <= 8)";
123 return 1;
124 }
125
126 if (handle->audio_format >= _FISCHE__AUDIOFORMAT_LAST_) {
127 handle->error_text = "audio format invalid";
128 return 1;
129 }
130
131 if (handle->line_style >= _FISCHE__LINESTYLE_LAST_) {
132 handle->error_text = "line style invalid";
133 return 1;
134 }
135
136 if (handle->frame_counter != 0) {
137 handle->error_text = "frame counter garbled";
138 return 1;
139 }
140
141 if ( (handle->amplification < -10) || (handle->amplification > 10)) {
142 handle->error_text = "amplification value out of range (-10 <= amplification <= 10)";
143 return 1;
144 }
145
146 if ( (handle->height < 16) || (handle->height > 2048)) {
147 handle->error_text = "height value out of range (16 <= height <= 2048)";
148 return 1;
149 }
150
151 if ( (handle->width < 16) || (handle->width > 2048)) {
152 handle->error_text = "width value out of range (16 <= width <= 2048)";
153 return 1;
154 }
155
156 if (handle->width % 4 != 0) {
157 handle->error_text = "width value invalid (must be a multiple of four)";
158 return 1;
159 }
160
161 if (handle->pixel_format >= _FISCHE__PIXELFORMAT_LAST_) {
162 handle->error_text = "pixel format invalid";
163 return 1;
164 }
165
166 if ( (handle->scale < 0.5) || (handle->scale > 2)) {
167 handle->error_text = "scale value out of range (0.5 <= scale <= 2.0)";
168 return 1;
169 }
170
171 if (handle->blur_mode >= _FISCHE__BLUR_LAST_) {
172 handle->error_text = "blur option invalid";
173 return 1;
174 }
175
176 // initialize private struct
177 handle->priv = malloc (sizeof (struct _fische__internal_));
178 memset (handle->priv, '\0', sizeof (struct _fische__internal_));
179 struct _fische__internal_* P = static_cast<_fische__internal_*>(handle->priv);
180
181 P->init_progress = -1;
182
183 P->analyst = fische__analyst_new (handle);
184 P->screenbuffer = fische__screenbuffer_new (handle);
185 P->wavepainter = fische__wavepainter_new (handle);
186 P->blurengine = fische__blurengine_new (handle);
187 P->audiobuffer = fische__audiobuffer_new (handle);
188
189 // start vector creation and busy indicator threads
190 std::thread(create_vectors, handle).detach();
191 std::thread(indicate_busy, handle).detach();
192
193 return 0;
194 }
195
196 uint32_t*
fische_render(struct fische * handle)197 fische_render (struct fische* handle)
198 {
199 struct _fische__internal_* P = static_cast<_fische__internal_*>(handle->priv);
200
201 // only if init completed
202 if (P->init_progress >= 1) {
203
204 // analyse sound data
205 fische__audiobuffer_lock (P->audiobuffer);
206 fische__audiobuffer_get (P->audiobuffer);
207 int_fast8_t analysis = fische__analyst_analyse (P->analyst, P->audiobuffer->back_samples, P->audiobuffer->back_sample_count);
208
209 // act accordingly
210 if (handle->nervous_mode) {
211 if (analysis >= 2)
212 fische__wavepainter_change_shape (P->wavepainter);
213 if (analysis >= 1)
214 fische__vectorfield_change (P->vectorfield);
215 } else {
216 if (analysis >= 1)
217 fische__wavepainter_change_shape (P->wavepainter);
218 if (analysis >= 2)
219 fische__vectorfield_change (P->vectorfield);
220 }
221
222 if (analysis >= 3) {
223 fische__wavepainter_beat (P->wavepainter, P->analyst->frames_per_beat);
224 }
225 if (analysis >= 4) {
226 if (handle->on_beat)
227 handle->on_beat (handle->handler, P->analyst->frames_per_beat);
228 }
229
230 P->audio_valid = analysis >= 0 ? 1 : 0;
231
232 fische__wavepainter_change_color (P->wavepainter, P->analyst->frames_per_beat, P->analyst->relative_energy);
233
234
235 // wait for blurring to be finished
236 // and swap buffers
237 fische__screenbuffer_lock (P->screenbuffer);
238 fische__blurengine_swapbuffers (P->blurengine);
239 fische__screenbuffer_unlock (P->screenbuffer);
240
241 // draw waves
242 if (P->audio_valid)
243 fische__wavepainter_paint (P->wavepainter, P->audiobuffer->front_samples, P->audiobuffer->front_sample_count);
244
245 // start blurring for the next frame
246 fische__blurengine_blur (P->blurengine, P->vectorfield->field);
247
248 fische__audiobuffer_unlock (P->audiobuffer);
249 }
250
251 handle->frame_counter ++;
252
253 return P->screenbuffer->pixels;
254 }
255
256 void
fische_free(struct fische * handle)257 fische_free (struct fische* handle)
258 {
259 if (!handle)
260 return;
261
262 struct _fische__internal_* P = static_cast<_fische__internal_*>(handle->priv);
263
264 if (handle->priv) {
265 // tell init threads to quit
266 P->init_cancel = 1;
267
268 // wait for init threads to quit
269 while (P->init_progress < 1)
270 std::this_thread::sleep_for(std::chrono::microseconds(10));
271
272 fische__audiobuffer_free (P->audiobuffer);
273 fische__blurengine_free (P->blurengine);
274 fische__vectorfield_free (P->vectorfield);
275 fische__wavepainter_free (P->wavepainter);
276 fische__screenbuffer_free (P->screenbuffer);
277 fische__analyst_free (P->analyst);
278
279 free (handle->priv);
280 }
281
282 free (handle);
283 }
284
285 void
fische_audiodata(struct fische * handle,const void * data,size_t data_size)286 fische_audiodata (struct fische* handle, const void* data, size_t data_size)
287 {
288 struct _fische__internal_* P = static_cast<_fische__internal_*>(handle->priv);
289
290 if (NULL == P->audiobuffer)
291 return;
292
293 fische__audiobuffer_lock (P->audiobuffer);
294 fische__audiobuffer_insert (P->audiobuffer, data, data_size);
295 fische__audiobuffer_unlock (P->audiobuffer);
296 }
297