A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* Copyright (C) 2005 Kevin Ferrare
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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16* KIND, either express or implied.
17*
18****************************************************************************/
19
20#include "plugin.h"
21#include "lib/helper.h"
22#include "lib/pluginlib_exit.h"
23#include "lib/pluginlib_actions.h"
24/******************************* Globals ***********************************/
25/* this set the context to use with PLA */
26static const struct button_mapping *plugin_contexts[] = { pla_main_ctx };
27
28/* Key assignement */
29#define STARFIELD_QUIT PLA_EXIT
30#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
31 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
32 || (CONFIG_KEYPAD == IPOD_4G_PAD)
33#define STARFIELD_QUIT2 PLA_UP
34#define STARFIELD_INCREASE_ZMOVE PLA_SCROLL_FWD
35#define STARFIELD_INCREASE_ZMOVE_REPEAT PLA_SCROLL_FWD_REPEAT
36#define STARFIELD_DECREASE_ZMOVE PLA_SCROLL_BACK
37#define STARFIELD_DECREASE_ZMOVE_REPEAT PLA_SCROLL_BACK_REPEAT
38#else
39#define STARFIELD_QUIT2 PLA_CANCEL
40#define STARFIELD_INCREASE_ZMOVE PLA_UP
41#define STARFIELD_INCREASE_ZMOVE_REPEAT PLA_UP_REPEAT
42#define STARFIELD_DECREASE_ZMOVE PLA_DOWN
43#define STARFIELD_DECREASE_ZMOVE_REPEAT PLA_DOWN_REPEAT
44#endif
45#define STARFIELD_INCREASE_NB_STARS PLA_RIGHT
46#define STARFIELD_INCREASE_NB_STARS_REPEAT PLA_RIGHT_REPEAT
47#define STARFIELD_DECREASE_NB_STARS PLA_LEFT
48#define STARFIELD_DECREASE_NB_STARS_REPEAT PLA_LEFT_REPEAT
49#define STARFIELD_TOGGLE_COLOR PLA_SELECT
50
51#define LCD_CENTER_X (LCD_WIDTH/2)
52#define LCD_CENTER_Y (LCD_HEIGHT/2)
53#define Z_MAX_DIST 100
54
55#define MAX_STARS (LCD_WIDTH*LCD_HEIGHT*20)/100
56#define INIT_STARS 200
57#define STARFIELD_INCREASE_STEP 50
58#define INIT_SPACE_SPEED 1
59#define STAR_MAX_VELOCITY 2
60/*
61 * max 3d coord in the 2d screen :
62 * example with x
63 * x2d=x3d/z+LCD_CENTER_X (+LCD_CENTER_X to center ...)
64 * so
65 * max_x2d=max_x3d/max_z+LCD_CENTER_X
66 * max_x3d=(max_x2d-LCD_CENTER_X)*max_z
67 * with
68 * max_x2d = LCD_WIDTH
69 * max_z = Z_MAX_DIST
70 * we have now
71 * max_x3d=(LCD_WIDTH-LCD_CENTER_X)*Z_MAX_DIST
72 * max_x3d=LCD_CENTER_X*Z_MAX_DIST
73 */
74
75#define MAX_INIT_STAR_X LCD_CENTER_X*Z_MAX_DIST
76#define MAX_INIT_STAR_Y LCD_CENTER_Y*Z_MAX_DIST
77
78#define MSG_DISP_TIME 30
79
80/*
81 * Each star's stuffs
82 */
83struct star
84{
85 int x,y,z;
86 int velocity;
87#ifdef HAVE_LCD_COLOR
88 int color;
89#endif
90};
91
92static inline void star_init(struct star * star, int z_move, bool color)
93{
94 star->velocity=rb->rand() % STAR_MAX_VELOCITY+1;
95 /* choose x between -MAX_INIT_STAR_X and MAX_INIT_STAR_X */
96 star->x=rb->rand() % (2*MAX_INIT_STAR_X)-MAX_INIT_STAR_X;
97 star->y=rb->rand() % (2*MAX_INIT_STAR_Y)-MAX_INIT_STAR_Y;
98#ifdef HAVE_LCD_COLOR
99 if(color)
100 star->color=LCD_RGBPACK(rb->rand()%128+128,rb->rand()%128+128,
101 rb->rand()%128+128);
102 else
103 star->color=LCD_WHITE;
104#else
105 (void)color;
106#endif
107 if(z_move>=0)
108 star->z=Z_MAX_DIST;
109 else
110 star->z=rb->rand() %Z_MAX_DIST/2+1;
111}
112
113static inline void star_move(struct star * star, int z_move, bool color)
114{
115 star->z -= z_move*star->velocity;
116 if (star->z <= 0 || star->z > Z_MAX_DIST)
117 star_init(star, z_move, color);
118}
119
120static inline void star_draw(struct star * star, int z_move, bool color)
121{
122 int x_draw, y_draw;
123 /*
124 * 3d -> 2d : projection on the screen : x2d=x3d/z (thales theorem)
125 * we put the star in the center of the screen
126 */
127 x_draw = star->x / star->z + LCD_CENTER_X;
128 if (x_draw < 1 || x_draw >= LCD_WIDTH)
129 {
130 star_init(star, z_move, color);
131 return;
132 }
133 y_draw = star->y / star->z + LCD_CENTER_Y;
134 if (y_draw < 1 || y_draw >= LCD_HEIGHT)
135 {
136 star_init(star, z_move, color);
137 return;
138 }
139
140#ifdef HAVE_LCD_COLOR
141 rb->lcd_set_foreground(star->color);
142#endif
143
144 rb->lcd_drawpixel(x_draw, y_draw);
145 if(star->z<5*Z_MAX_DIST/6)
146 {
147 rb->lcd_drawpixel(x_draw, y_draw - 1);
148 rb->lcd_drawpixel(x_draw - 1, y_draw);
149 if(star->z<Z_MAX_DIST/2)
150 {
151 rb->lcd_drawpixel(x_draw + 1, y_draw);
152 rb->lcd_drawpixel(x_draw, y_draw + 1);
153 }
154 }
155}
156
157/*
158 * Whole starfield operations
159 */
160struct starfield
161{
162 struct star tab[MAX_STARS];
163 int nb_stars;
164 int z_move;
165 bool color;
166};
167
168static inline void starfield_init(struct starfield * starfield)
169{
170 starfield->nb_stars=0;
171 starfield->z_move=INIT_SPACE_SPEED;
172 starfield->color=false;
173}
174
175static inline void starfield_add_stars(struct starfield * starfield,
176 int nb_to_add)
177{
178 int i, old_nb_stars;
179 old_nb_stars=starfield->nb_stars;
180 starfield->nb_stars+=nb_to_add;
181
182 if(starfield->nb_stars > MAX_STARS)
183 starfield->nb_stars=MAX_STARS;
184
185 for( i=old_nb_stars ; i < starfield->nb_stars ; ++i )
186 {
187 star_init( &(starfield->tab[i]), starfield->z_move, starfield->color );
188 }
189}
190
191static inline void starfield_del_stars(struct starfield * starfield,
192 int nb_to_add)
193{
194 starfield->nb_stars-=nb_to_add;
195 if(starfield->nb_stars<0)
196 starfield->nb_stars=0;
197}
198
199static inline void starfield_move_and_draw(struct starfield * starfield)
200{
201 int i;
202 for(i=0;i<starfield->nb_stars;++i)
203 {
204 star_move(&(starfield->tab[i]), starfield->z_move, starfield->color);
205 star_draw(&(starfield->tab[i]), starfield->z_move, starfield->color);
206 }
207}
208
209static struct starfield starfield;
210
211static int plugin_main(void)
212{
213 int button, avg_peak, t_disp=0;
214 int font_h, font_w;
215 bool pulse __attribute__ ((unused)) = true; /* 'unused' resolves warnings */
216 rb->lcd_getstringsize("A", &font_w, &font_h);
217 starfield_init(&starfield);
218 starfield_add_stars(&starfield, INIT_STARS);
219
220#if LCD_DEPTH > 1
221 rb->lcd_set_backdrop(NULL);
222#endif
223#ifdef HAVE_LCD_COLOR
224 rb->lcd_set_background(LCD_BLACK);
225 rb->lcd_set_foreground(LCD_WHITE);
226#endif
227
228 while (true)
229 {
230 rb->sleep(1);
231 rb->lcd_clear_display();
232
233 /* This will make the stars pulse to the music */
234 if(pulse){
235
236 /* Get the peaks. ( Borrowed from vu_meter ) */
237 static struct pcm_peaks peaks;
238 rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
239 &peaks);
240 #define left_peak peaks.left
241 #define right_peak peaks.right
242
243 /* Devide peak data by 4098 to bring the max
244 value down from ~32k to 8 */
245 left_peak = left_peak/0x1000;
246 right_peak = right_peak/0x1000;
247
248 /* Make sure they dont stop */
249 if(left_peak<0x1)
250 left_peak = 0x1;
251 if(right_peak<0x1)
252 right_peak = 0x1;
253
254 /* And make sure they dont go over 8 */
255 if(left_peak>0x8)
256 left_peak = 0x8;
257 if(right_peak>0x8)
258 right_peak = 0x8;
259
260 /* We need the average of both chanels */
261 avg_peak = ( left_peak + right_peak )/2;
262
263 /* Set the speed to the peak meter */
264 starfield.z_move = avg_peak;
265
266 } /* if pulse */
267
268 starfield_move_and_draw(&starfield);
269
270#ifdef HAVE_LCD_COLOR
271 rb->lcd_set_foreground(LCD_WHITE);
272#endif
273
274 /* if a parameter is updated (by the user), we must print it */
275 if (t_disp > 0)
276 {
277 --t_disp;
278#ifdef HAVE_LCD_COLOR
279 rb->lcd_set_foreground(LCD_WHITE);
280#endif
281 rb->lcd_putsxyf(0, LCD_HEIGHT-font_h, "star:%d speed:%d",
282 starfield.nb_stars, starfield.z_move);
283 }
284 rb->lcd_update();
285
286 /*We get button from PLA this way */
287 button = pluginlib_getaction(TIMEOUT_NOBLOCK, plugin_contexts,
288 ARRAYLEN(plugin_contexts));
289
290 switch(button)
291 {
292 case (STARFIELD_INCREASE_ZMOVE):
293 case (STARFIELD_INCREASE_ZMOVE_REPEAT):
294 ++(starfield.z_move);
295 pulse=false;
296 t_disp=MSG_DISP_TIME;
297 break;
298 case (STARFIELD_DECREASE_ZMOVE):
299 case (STARFIELD_DECREASE_ZMOVE_REPEAT):
300 --(starfield.z_move);
301 pulse=false;
302 t_disp=MSG_DISP_TIME;
303 break;
304 case(STARFIELD_INCREASE_NB_STARS):
305 case(STARFIELD_INCREASE_NB_STARS_REPEAT):
306 starfield_add_stars(&starfield, STARFIELD_INCREASE_STEP);
307 t_disp=MSG_DISP_TIME;
308 break;
309 case(STARFIELD_DECREASE_NB_STARS):
310 case(STARFIELD_DECREASE_NB_STARS_REPEAT):
311 starfield_del_stars(&starfield, STARFIELD_INCREASE_STEP);
312 t_disp=MSG_DISP_TIME;
313 break;
314#ifdef HAVE_LCD_COLOR
315 case(STARFIELD_TOGGLE_COLOR):
316 starfield.color=!starfield.color;
317 break;
318#endif
319 case(STARFIELD_QUIT):
320 case(STARFIELD_QUIT2):
321 return PLUGIN_OK;
322 break;
323 default:
324 exit_on_usb(button);
325 break;
326 }
327 }
328}
329
330/*************************** Plugin entry point ****************************/
331
332enum plugin_status plugin_start(const void* parameter)
333{
334 int ret;
335
336 (void)parameter;
337
338 /* Turn off backlight timeout */
339 backlight_ignore_timeout();
340
341 ret = plugin_main();
342
343 /* Turn on backlight timeout (revert to settings) */
344 backlight_use_settings();
345
346 return ret;
347}