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 * $Id$
9 *
10 * Copyright (C) 1999 Chris Allegretta
11 * Copyright (C) 2005 Alastair S - ported to podzilla
12 * Copyright (C) 2005 Jonas Häggqvist - ported to rockbox
13 *
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25/*
26 * TODO:
27 * - The font is a bit large, create smaller one
28 * - For colour/greyscale displays, the font from the xscreensaver xmatrix
29 * should be converted and used
30 * BUGS:
31 * - The animation "dies" after a few seconds, not sure why. Works in sim.
32 * Symtom Fixed Oct 2007 GRaTT (Gerritt Gonzales)
33 */
34
35
36#include "plugin.h"
37#include "lib/pluginlib_actions.h"
38
39/* Images */
40#include "pluginbitmaps/matrix_bold.h"
41#include "pluginbitmaps/matrix_normal.h"
42#define MAXCHARS 27 - 1
43#define COL_W 14
44#define COL_H 15
45
46#define COLS LCD_WIDTH/COL_W
47#define ROWS LCD_HEIGHT/COL_H
48
49#define LEFTMARGIN (LCD_WIDTH-(COLS*COL_W))/2
50#define TOPMARGIN (LCD_HEIGHT-(ROWS*COL_H))/2
51
52/* this set the context to use with PLA */
53static const struct button_mapping *plugin_contexts[] = { pla_main_ctx };
54
55#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
56 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
57 || (CONFIG_KEYPAD == IPOD_4G_PAD)
58#define MATRIX_EXIT2 PLA_UP
59#else
60#define MATRIX_EXIT2 PLA_CANCEL
61#endif
62
63#ifdef HAVE_SCROLLWHEEL
64#define MATRIX_SLEEP_MORE PLA_SCROLL_BACK
65#define MATRIX_SLEEP_MORE_REPEAT PLA_SCROLL_BACK_REPEAT
66#define MATRIX_SLEEP_LESS PLA_SCROLL_FWD
67#define MATRIX_SLEEP_LESS_REPEAT PLA_SCROLL_FWD_REPEAT
68#else
69#define MATRIX_SLEEP_MORE PLA_UP
70#define MATRIX_SLEEP_MORE_REPEAT PLA_UP_REPEAT
71#define MATRIX_SLEEP_LESS PLA_DOWN
72#define MATRIX_SLEEP_LESS_REPEAT PLA_DOWN_REPEAT
73#endif /* HAVE_SCROLLWHEEL */
74#define MATRIX_PAUSE PLA_SELECT
75#define MATRIX_EXIT PLA_EXIT
76
77#define SLEEP HZ/50
78
79/* Each position is of this type */
80typedef struct cmatrix {
81 int val;
82 int bold;
83} cmatrix;
84
85/* The matrix - who'd have guessed it was just a few hundred bytes? */
86static cmatrix matrix[ROWS][COLS];
87static int length[COLS];
88static int spaces[COLS];
89static int updates[COLS];
90
91static void matrix_init(void) {
92 int i,j;
93
94 /* Seed rand */
95 rb->srand(*rb->current_tick);
96
97 /* Make the matrix */
98 for (i = 0; i < ROWS; i++) {
99 for (j = 0; j < COLS; j++) {
100 matrix[i][j].val = -1;
101 matrix[i][j].bold = 0;
102 }
103 }
104
105 for (j = 0; j < COLS; j++) {
106 /* Set up spaces[] array of how many spaces to skip */
107 spaces[j] = rb->rand() % ROWS + 1;
108
109 /* And length of the stream */
110 length[j] = rb->rand() % (ROWS - 3) + 3;
111
112 /* Sentinel value for creation of new objects */
113 matrix[1][j].val = 129;
114
115 /* And set updates[] array for update speed. */
116 updates[j] = rb->rand() % 3 + 1;
117 }
118}
119
120static void matrix_blit_char(const int row, const int col, int cha)
121{
122 if (cha == 129 || cha == 2 || cha > MAXCHARS)
123 cha = 0;
124
125 if (matrix[row][col].bold == 1) {
126 rb->lcd_bitmap_part(matrix_bold, cha*COL_W, 0,
127 STRIDE( SCREEN_MAIN,
128 BMPWIDTH_matrix_bold, BMPHEIGHT_matrix_bold),
129 col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
130 }
131 else {
132 rb->lcd_bitmap_part(matrix_normal, cha*COL_W, 0,
133 STRIDE( SCREEN_MAIN,
134 BMPWIDTH_matrix_normal, BMPHEIGHT_matrix_normal),
135 col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
136 }
137}
138
139static void matrix_loop(void)
140{
141 int i, j = 0, y, z, firstcoldone = 0;
142 static int count = 0;
143 int randomness = 6;
144
145 count++;
146 if (count > 4)
147 count = 1;
148
149 for (j = 0; j < COLS; j++) {
150 if (count > updates[j]) {
151 /* New style scrolling */
152 if (matrix[0][j].val == -1 && matrix[1][j].val == 129
153 && spaces[j] > 0) {
154 matrix[0][j].val = -1;
155 spaces[j]--;
156 } else if (matrix[0][j].val == -1 && matrix[1][j].val == 129){
157 length[j] = rb->rand() % (ROWS - 3) + 3;
158 matrix[0][j].val = rb->rand() % (MAXCHARS-1) + 1;
159 if (rb->rand() % 2 == 1)
160 matrix[0][j].bold = 2;
161 spaces[j] = rb->rand() % ROWS + 1;
162 }
163 i = 0;
164 y = 0;
165 firstcoldone = 0;
166 while (i <= ROWS) {
167 /* Skip over spaces */
168 /* this is whear the characters were disappearing */
169/*
170 while (i <= ROWS && (matrix[i][j].val == 129 ||
171 matrix[i][j].val == -1))
172 i++;
173*/
174 /* A little more random now for spaces */
175 if (rb->rand() % randomness == 1){
176 while (i < ROWS && (matrix[i][j].val == 129 ||
177 matrix[i][j].val == -1)){
178 i++;
179 randomness--;
180 if(randomness <=1)
181 randomness = 6;}
182 }else{
183 randomness++;
184 if(randomness >6)
185 randomness = 6;
186 }
187
188
189 if (i >= ROWS)
190 break;
191
192 /* Go to the head of this collumn */
193 z = i;
194 y = 0;
195 while (i < ROWS && (matrix[i][j].val != 129 &&
196 matrix[i][j].val != -1)) {
197 i++;
198 y++;
199 }
200
201 if (i >= ROWS) {
202 matrix[z][j].val = 129;
203 matrix[ROWS - 1][j].bold = 1;
204 matrix_blit_char(z - 1, j, matrix[z][j].val);
205 continue;
206 }
207
208 matrix[i][j].val = rb->rand() % (MAXCHARS-1) + 1;
209
210 if (i > 0 && matrix[i - 1][j].bold == 2) {
211 matrix[i - 1][j].bold = 1;
212 matrix[i][j].bold = 2;
213 }
214
215 /* If we're at the top of the collumn and it's reached its
216 * full length (about to start moving down), we do this
217 * to get it moving. This is also how we keep segments
218 * not already growing from growing accidentally =>
219 */
220 if (y > length[j] || firstcoldone) {
221 matrix[z][j].val = 129;
222 matrix[0][j].val = -1;
223 }
224 firstcoldone = 1;
225 i++;
226 }
227 for (i = 1; i < ROWS; i++) {
228 if (matrix[i][j].val == 0 || matrix[i][j].bold == 2) {
229 if (matrix[i][j].val == 0)
230 matrix_blit_char(i - 1, j, 20);
231 else
232 matrix_blit_char(i - 1, j, matrix[i][j].val);
233 } else {
234 if (matrix[i][j].val == 1)
235 matrix_blit_char(i - 1, j, 2);
236 else if (matrix[i][j].val == -1)
237 matrix_blit_char(i - 1, j, 129);
238 else
239 matrix_blit_char(i - 1, j, matrix[i][j].val);
240 }
241 }
242 }
243 }
244}
245
246enum plugin_status plugin_start(const void* parameter) {
247 int button;
248 int sleep = SLEEP;
249 bool frozen = false;
250
251 (void)parameter;
252
253 rb->lcd_set_background(LCD_BLACK);
254 rb->lcd_set_backdrop(NULL);
255 rb->lcd_clear_display();
256 matrix_init();
257
258 while (1) {
259 if (!frozen) {
260 matrix_loop();
261 rb->lcd_update();
262 rb->sleep(sleep);
263 }
264
265 button = pluginlib_getaction(frozen ? TIMEOUT_BLOCK : TIMEOUT_NOBLOCK,
266 plugin_contexts, ARRAYLEN(plugin_contexts));
267
268 switch(button) {
269 case MATRIX_PAUSE:
270 frozen = !frozen;
271 break;
272 case MATRIX_EXIT:
273 case MATRIX_EXIT2:
274 return PLUGIN_OK;
275 break;
276 case MATRIX_SLEEP_MORE:
277 case MATRIX_SLEEP_MORE_REPEAT:
278 /* Sleep longer */
279 sleep += SLEEP;
280 break;
281 case MATRIX_SLEEP_LESS:
282 case MATRIX_SLEEP_LESS_REPEAT:
283 /* Sleep less */
284 sleep -= SLEEP;
285 if (sleep < 0) sleep = 0;
286 break;
287 default:
288 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
289 return PLUGIN_USB_CONNECTED;
290 }
291 break;
292 }
293 }
294 return PLUGIN_OK;
295}