Update Beast installation instructions to use beastpatcher and remove instructions...
[kugel-rb.git] / apps / gui / pitchscreen.c
blobdb50a5d866a90dc77b3170387601d8afc6170cca
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Björn Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdbool.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include "config.h"
26 #include "sprintf.h"
27 #include "action.h"
28 #include "dsp.h"
29 #include "sound.h"
30 #include "pcmbuf.h"
31 #include "lang.h"
32 #include "icons.h"
33 #include "screens.h"
34 #include "statusbar.h"
35 #include "viewport.h"
36 #include "pitchscreen.h"
38 #define PITCH_MODE_ABSOLUTE 1
39 #define PITCH_MODE_SEMITONE -PITCH_MODE_ABSOLUTE
40 #define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */
41 /* on both sides when drawing */
44 #define PITCH_MAX 2000
45 #define PITCH_MIN 500
46 #define PITCH_SMALL_DELTA 1
47 #define PITCH_BIG_DELTA 10
48 #define PITCH_NUDGE_DELTA 20
51 static int pitch_mode = PITCH_MODE_ABSOLUTE; /* 1 - absolute, -1 - semitone */
53 enum
55 PITCH_TOP = 0,
56 PITCH_MID,
57 PITCH_BOTTOM,
58 PITCH_ITEM_COUNT,
61 static void pitchscreen_fix_viewports(struct viewport *parent,
62 struct viewport pitch_viewports[PITCH_ITEM_COUNT])
64 int i, height;
65 height = font_get(parent->font)->height;
66 for (i = 0; i < PITCH_ITEM_COUNT; i++)
68 pitch_viewports[i] = *parent;
69 pitch_viewports[i].height = height;
71 pitch_viewports[PITCH_TOP].y += ICON_BORDER;
73 pitch_viewports[PITCH_MID].x += ICON_BORDER;
74 pitch_viewports[PITCH_MID].width = parent->width - ICON_BORDER*2;
75 pitch_viewports[PITCH_MID].height = height * 2;
76 pitch_viewports[PITCH_MID].y += parent->height / 2 -
77 pitch_viewports[PITCH_MID].height / 2;
79 pitch_viewports[PITCH_BOTTOM].y += parent->height - height - ICON_BORDER;
82 /* must be called before pitchscreen_draw, or within
83 * since it neither clears nor updates the display */
84 static void pitchscreen_draw_icons (struct screen *display,
85 struct viewport *parent)
87 display->set_viewport(parent);
88 display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow],
89 parent->width/2 - 3,
90 2, 7, 8);
91 display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
92 parent->width /2 - 3,
93 parent->height - 10, 7, 8);
94 display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
95 parent->width - 10,
96 parent->height /2 - 4, 7, 8);
97 display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward],
99 parent->height /2 - 4, 7, 8);
100 display->update_viewport();
103 static void pitchscreen_draw (struct screen *display, int max_lines,
104 struct viewport pitch_viewports[PITCH_ITEM_COUNT], int pitch)
106 unsigned char* ptr;
107 unsigned char buf[32];
108 int width_val, w, h;
109 bool show_lang_pitch;
111 /* Hide "Pitch up/Pitch down" for a small screen */
112 if (max_lines >= 5)
114 /* UP: Pitch Up */
115 display->set_viewport(&pitch_viewports[PITCH_TOP]);
116 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
117 ptr = str(LANG_PITCH_UP);
118 } else {
119 ptr = str(LANG_PITCH_UP_SEMITONE);
121 display->getstringsize(ptr,&w,&h);
122 display->clear_viewport();
123 /* draw text */
124 display->putsxy((pitch_viewports[PITCH_TOP].width / 2) -
125 (w / 2), 0, ptr);
126 display->update_viewport();
128 /* DOWN: Pitch Down */
129 display->set_viewport(&pitch_viewports[PITCH_BOTTOM]);
130 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
131 ptr = str(LANG_PITCH_DOWN);
132 } else {
133 ptr = str(LANG_PITCH_DOWN_SEMITONE);
135 display->getstringsize(ptr,&w,&h);
136 display->clear_viewport();
137 /* draw text */
138 display->putsxy((pitch_viewports[PITCH_BOTTOM].width / 2) -
139 (w / 2), 0, ptr);
140 display->update_viewport();
142 display->set_viewport(&pitch_viewports[PITCH_MID]);
144 snprintf((char *)buf, sizeof(buf), "%s", str(LANG_PITCH));
145 display->getstringsize(buf,&w,&h);
146 /* lets hide LANG_PITCH for smaller screens */
147 display->clear_viewport();
148 if ((show_lang_pitch = (max_lines >= 3)))
149 display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
150 0, buf);
152 /* "XXX.X%" */
153 snprintf((char *)buf, sizeof(buf), "%d.%d%%",
154 pitch / 10, pitch % 10 );
155 display->getstringsize(buf,&width_val,&h);
156 display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (width_val / 2),
157 (show_lang_pitch? h : h/2), buf);
159 /* What's wider? LANG_PITCH or the value?
160 * Only interesting if LANG_PITCH is actually drawn */
161 if (show_lang_pitch && width_val > w)
162 w = width_val;
164 /* Let's treat '+' and '-' as equally wide
165 * This saves a getstringsize call
166 * Also, it wouldn't look nice if -2% shows up, but +2% not */
167 display->getstringsize("+2%",&width_val,&h);
168 w += width_val*2;
169 /* hide +2%/-2% for a narrow screens */
170 if (w <= pitch_viewports[PITCH_MID].width)
172 /* RIGHT: +2% */
173 display->putsxy(pitch_viewports[PITCH_MID].width - width_val, h /2, "+2%");
174 /* LEFT: -2% */
175 display->putsxy(0, h / 2, "-2%");
177 display->update_viewport();
178 display->set_viewport(NULL);
181 static int pitch_increase(int pitch, int delta, bool allow_cutoff)
183 int new_pitch;
185 if (delta < 0) {
186 if (pitch + delta >= PITCH_MIN) {
187 new_pitch = pitch + delta;
188 } else {
189 if (!allow_cutoff) {
190 return pitch;
192 new_pitch = PITCH_MIN;
194 } else if (delta > 0) {
195 if (pitch + delta <= PITCH_MAX) {
196 new_pitch = pitch + delta;
197 } else {
198 if (!allow_cutoff) {
199 return pitch;
201 new_pitch = PITCH_MAX;
203 } else {
204 /* delta == 0 -> no real change */
205 return pitch;
207 sound_set_pitch(new_pitch);
209 return new_pitch;
212 /* Factor for changing the pitch one half tone up.
213 The exact value is 2^(1/12) = 1.05946309436
214 But we use only integer arithmetics, so take
215 rounded factor multiplied by 10^5=100,000. This is
216 enough to get the same promille values as if we
217 had used floating point (checked with a spread
218 sheet).
220 #define PITCH_SEMITONE_FACTOR 105946L
222 /* Some helpful constants. K is the scaling factor for SEMITONE.
223 N is for more accurate rounding
224 KN is K * N
226 #define PITCH_K_FCT 100000UL
227 #define PITCH_N_FCT 10
228 #define PITCH_KN_FCT 1000000UL
230 static int pitch_increase_semitone(int pitch, bool up)
232 uint32_t tmp;
233 uint32_t round_fct; /* How much to scale down at the end */
234 tmp = pitch;
235 if (up) {
236 tmp = tmp * PITCH_SEMITONE_FACTOR;
237 round_fct = PITCH_K_FCT;
238 } else {
239 tmp = (tmp * PITCH_KN_FCT) / PITCH_SEMITONE_FACTOR;
240 round_fct = PITCH_N_FCT;
242 /* Scaling down with rounding */
243 tmp = (tmp + round_fct / 2) / round_fct;
244 return pitch_increase(pitch, tmp - pitch, false);
248 returns:
249 0 on exit
250 1 if USB was connected
253 int gui_syncpitchscreen_run(void)
255 int button, i;
256 int pitch = sound_get_pitch();
257 int new_pitch, delta = 0;
258 bool nudged = false;
259 bool exit = false;
260 /* should maybe be passed per parameter later, not needed for now */
261 struct viewport parent[NB_SCREENS];
262 struct viewport pitch_viewports[NB_SCREENS][PITCH_ITEM_COUNT];
263 int max_lines[NB_SCREENS];
265 /* initialize pitchscreen vps */
266 FOR_NB_SCREENS(i)
268 screens[i].clear_display();
269 viewport_set_defaults(&parent[i], i);
270 max_lines[i] = viewport_get_nb_lines(&parent[i]);
271 pitchscreen_fix_viewports(&parent[i], pitch_viewports[i]);
273 /* also, draw the icons now, it's only needed once */
274 pitchscreen_draw_icons(&screens[i], &parent[i]);
276 #if CONFIG_CODEC == SWCODEC
277 pcmbuf_set_low_latency(true);
278 #endif
280 while (!exit)
282 FOR_NB_SCREENS(i)
283 pitchscreen_draw(&screens[i], max_lines[i],
284 pitch_viewports[i], pitch);
285 button = get_action(CONTEXT_PITCHSCREEN,HZ);
286 switch (button) {
287 case ACTION_PS_INC_SMALL:
288 delta = PITCH_SMALL_DELTA;
289 break;
291 case ACTION_PS_INC_BIG:
292 delta = PITCH_BIG_DELTA;
293 break;
295 case ACTION_PS_DEC_SMALL:
296 delta = -PITCH_SMALL_DELTA;
297 break;
299 case ACTION_PS_DEC_BIG:
300 delta = -PITCH_BIG_DELTA;
301 break;
303 case ACTION_PS_NUDGE_RIGHT:
304 new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false);
305 nudged = (new_pitch != pitch);
306 pitch = new_pitch;
307 break;
309 case ACTION_PS_NUDGE_RIGHTOFF:
310 if (nudged) {
311 pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false);
313 nudged = false;
314 break;
316 case ACTION_PS_NUDGE_LEFT:
317 new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false);
318 nudged = (new_pitch != pitch);
319 pitch = new_pitch;
320 break;
322 case ACTION_PS_NUDGE_LEFTOFF:
323 if (nudged) {
324 pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false);
326 nudged = false;
327 break;
329 case ACTION_PS_RESET:
330 pitch = 1000;
331 sound_set_pitch( pitch );
332 break;
334 case ACTION_PS_TOGGLE_MODE:
335 pitch_mode = -pitch_mode;
336 break;
338 case ACTION_PS_EXIT:
339 exit = true;
340 break;
342 default:
343 if(default_event_handler(button) == SYS_USB_CONNECTED)
344 return 1;
345 break;
347 if(delta)
349 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
350 pitch = pitch_increase(pitch, delta, true);
351 } else {
352 pitch = pitch_increase_semitone(pitch, delta > 0 ? true:false);
355 delta = 0;
358 #if CONFIG_CODEC == SWCODEC
359 pcmbuf_set_low_latency(false);
360 #endif
361 return 0;