Codec lib directories renamed, except for demac.
[kugel-rb.git] / apps / gui / pitchscreen.c
blob7a05a5774355ff81388700cf7d068dd8ea99c58c
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 "settings.h"
28 #include "action.h"
29 #include "system.h"
30 #include "font.h"
31 #include "misc.h"
32 #include "dsp.h"
33 #include "sound.h"
34 #include "pcmbuf.h"
35 #include "lang.h"
36 #include "icons.h"
37 #include "screen_access.h"
38 #include "screens.h"
39 #include "statusbar.h"
40 #include "viewport.h"
41 #include "pitchscreen.h"
43 #define PITCH_MODE_ABSOLUTE 1
44 #define PITCH_MODE_SEMITONE -PITCH_MODE_ABSOLUTE
45 #define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */
46 /* on both sides when drawing */
49 #define PITCH_MAX 2000
50 #define PITCH_MIN 500
51 #define PITCH_SMALL_DELTA 1
52 #define PITCH_BIG_DELTA 10
53 #define PITCH_NUDGE_DELTA 20
56 static int pitch_mode = PITCH_MODE_ABSOLUTE; /* 1 - absolute, -1 - semitone */
58 enum
60 PITCH_TOP = 0,
61 PITCH_MID,
62 PITCH_BOTTOM,
63 PITCH_ITEM_COUNT,
66 static void pitchscreen_fix_viewports(struct viewport *parent,
67 struct viewport pitch_viewports[PITCH_ITEM_COUNT])
69 short n, height;
70 height = font_get(parent->font)->height;
71 for (n = 0; n < PITCH_ITEM_COUNT; n++)
73 pitch_viewports[n] = *parent;
74 pitch_viewports[n].height = height;
76 pitch_viewports[PITCH_TOP].y += ICON_BORDER;
78 pitch_viewports[PITCH_MID].x += ICON_BORDER;
79 pitch_viewports[PITCH_MID].width = parent->width - ICON_BORDER*2;
80 pitch_viewports[PITCH_MID].height = height * 2;
81 pitch_viewports[PITCH_MID].y += parent->height / 2 -
82 pitch_viewports[PITCH_MID].height / 2;
83 pitch_viewports[PITCH_BOTTOM].y += parent->height - height - ICON_BORDER;
86 /* must be called before pitchscreen_draw, or within
87 * since it neither clears nor updates the display */
88 static void pitchscreen_draw_icons (struct screen *display,
89 struct viewport *parent)
91 display->set_viewport(parent);
92 display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow],
93 parent->width/2 - 3,
94 2, 7, 8);
95 display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
96 parent->width /2 - 3,
97 parent->height - 10, 7, 8);
98 display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
99 parent->width - 10,
100 parent->height /2 - 4, 7, 8);
101 display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward],
103 parent->height /2 - 4, 7, 8);
106 static void pitchscreen_draw (struct screen *display, int max_lines,
107 struct viewport pitch_viewports[PITCH_ITEM_COUNT], int pitch)
109 unsigned char* ptr;
110 unsigned char buf[32];
111 int w, h;
112 bool show_lang_pitch;
114 /* Hide "Pitch up/Pitch down" for a small screen */
115 if (max_lines >= 5)
117 /* UP: Pitch Up */
118 display->set_viewport(&pitch_viewports[PITCH_TOP]);
119 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
120 ptr = str(LANG_PITCH_UP);
121 } else {
122 ptr = str(LANG_PITCH_UP_SEMITONE);
124 display->getstringsize(ptr,&w,&h);
125 display->clear_viewport();
126 /* draw text */
127 display->putsxy((pitch_viewports[PITCH_TOP].width / 2) -
128 (w / 2), 0, ptr);
130 /* DOWN: Pitch Down */
131 display->set_viewport(&pitch_viewports[PITCH_BOTTOM]);
132 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
133 ptr = str(LANG_PITCH_DOWN);
134 } else {
135 ptr = str(LANG_PITCH_DOWN_SEMITONE);
137 display->getstringsize(ptr,&w,&h);
138 display->clear_viewport();
139 /* draw text */
140 display->putsxy((pitch_viewports[PITCH_BOTTOM].width / 2) -
141 (w / 2), 0, ptr);
143 display->set_viewport(&pitch_viewports[PITCH_MID]);
145 snprintf((char *)buf, sizeof(buf), "%s", str(LANG_PITCH));
146 display->getstringsize(buf,&w,&h);
147 /* lets hide LANG_PITCH for smaller screens */
148 display->clear_viewport();
149 if ((show_lang_pitch = (max_lines >= 3)))
150 display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
151 0, buf);
153 /* we don't need max_lines any more, reuse it*/
154 max_lines = w;
155 /* "XXX.X%" */
156 snprintf((char *)buf, sizeof(buf), "%d.%d%%",
157 pitch / 10, pitch % 10 );
158 display->getstringsize(buf,&w,&h);
159 display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
160 (show_lang_pitch? h : h/2), buf);
162 /* What's wider? LANG_PITCH or the value?
163 * Only interesting if LANG_PITCH is actually drawn */
164 max_lines = (show_lang_pitch ? ((max_lines > w) ? max_lines : w) : w);
166 /* Let's treat '+' and '-' as equally wide
167 * This saves a getstringsize call
168 * Also, it wouldn't look nice if -2% shows up, but +2% not */
169 display->getstringsize("+2%",&w,&h);
170 max_lines += 2*w;
171 /* hide +2%/-2% for a narrow screens */
172 if (max_lines < pitch_viewports[PITCH_MID].width)
174 /* RIGHT: +2% */
175 display->putsxy(pitch_viewports[PITCH_MID].width - w, h /2, "+2%");
176 /* LEFT: -2% */
177 display->putsxy(0, h / 2, "-2%");
179 /* Lastly, a fullscreen update */
180 display->set_viewport(NULL);
181 display->update();
184 static int pitch_increase(int pitch, int delta, bool allow_cutoff)
186 int new_pitch;
188 if (delta < 0) {
189 if (pitch + delta >= PITCH_MIN) {
190 new_pitch = pitch + delta;
191 } else {
192 if (!allow_cutoff) {
193 return pitch;
195 new_pitch = PITCH_MIN;
197 } else if (delta > 0) {
198 if (pitch + delta <= PITCH_MAX) {
199 new_pitch = pitch + delta;
200 } else {
201 if (!allow_cutoff) {
202 return pitch;
204 new_pitch = PITCH_MAX;
206 } else {
207 /* delta == 0 -> no real change */
208 return pitch;
210 sound_set_pitch(new_pitch);
212 return new_pitch;
215 /* Factor for changing the pitch one half tone up.
216 The exact value is 2^(1/12) = 1.05946309436
217 But we use only integer arithmetics, so take
218 rounded factor multiplied by 10^5=100,000. This is
219 enough to get the same promille values as if we
220 had used floating point (checked with a spread
221 sheet).
223 #define PITCH_SEMITONE_FACTOR 105946L
225 /* Some helpful constants. K is the scaling factor for SEMITONE.
226 N is for more accurate rounding
227 KN is K * N
229 #define PITCH_K_FCT 100000UL
230 #define PITCH_N_FCT 10
231 #define PITCH_KN_FCT 1000000UL
233 static int pitch_increase_semitone(int pitch, bool up)
235 uint32_t tmp;
236 uint32_t round_fct; /* How much to scale down at the end */
237 tmp = pitch;
238 if (up) {
239 tmp = tmp * PITCH_SEMITONE_FACTOR;
240 round_fct = PITCH_K_FCT;
241 } else {
242 tmp = (tmp * PITCH_KN_FCT) / PITCH_SEMITONE_FACTOR;
243 round_fct = PITCH_N_FCT;
245 /* Scaling down with rounding */
246 tmp = (tmp + round_fct / 2) / round_fct;
247 return pitch_increase(pitch, tmp - pitch, false);
251 returns:
252 0 on exit
253 1 if USB was connected
256 int gui_syncpitchscreen_run(void)
258 int button;
259 int pitch = sound_get_pitch();
260 int new_pitch, delta = 0;
261 bool nudged = false;
262 bool exit = false;
263 short i;
264 struct viewport parent[NB_SCREENS]; /* should maybe
265 be a parameter of this function */
266 short max_lines[NB_SCREENS];
267 struct viewport pitch_viewports[NB_SCREENS][PITCH_ITEM_COUNT];
269 /* initialize pitchscreen vps */
270 FOR_NB_SCREENS(i)
272 screens[i].clear_display();
273 viewport_set_defaults(&parent[i], i);
274 max_lines[i] = viewport_get_nb_lines(&parent[i]);
275 pitchscreen_fix_viewports(&parent[i], pitch_viewports[i]);
277 /* also, draw the icons now, it's only needed once */
278 pitchscreen_draw_icons(&screens[i], &parent[i]);
280 #if CONFIG_CODEC == SWCODEC
281 pcmbuf_set_low_latency(true);
282 #endif
283 i = 0;
284 while (!exit)
286 FOR_NB_SCREENS(i)
287 pitchscreen_draw(&screens[i], max_lines[i],
288 pitch_viewports[i], pitch);
289 gui_syncstatusbar_draw(&statusbars, true);
290 button = get_action(CONTEXT_PITCHSCREEN,HZ);
291 switch (button) {
292 case ACTION_PS_INC_SMALL:
293 delta = PITCH_SMALL_DELTA;
294 break;
296 case ACTION_PS_INC_BIG:
297 delta = PITCH_BIG_DELTA;
298 break;
300 case ACTION_PS_DEC_SMALL:
301 delta = -PITCH_SMALL_DELTA;
302 break;
304 case ACTION_PS_DEC_BIG:
305 delta = -PITCH_BIG_DELTA;
306 break;
308 case ACTION_PS_NUDGE_RIGHT:
309 new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false);
310 nudged = (new_pitch != pitch);
311 pitch = new_pitch;
312 break;
314 case ACTION_PS_NUDGE_RIGHTOFF:
315 if (nudged) {
316 pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false);
318 nudged = false;
319 break;
321 case ACTION_PS_NUDGE_LEFT:
322 new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false);
323 nudged = (new_pitch != pitch);
324 pitch = new_pitch;
325 break;
327 case ACTION_PS_NUDGE_LEFTOFF:
328 if (nudged) {
329 pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false);
331 nudged = false;
332 break;
334 case ACTION_PS_RESET:
335 pitch = 1000;
336 sound_set_pitch( pitch );
337 break;
339 case ACTION_PS_TOGGLE_MODE:
340 pitch_mode = -pitch_mode;
341 break;
343 case ACTION_PS_EXIT:
344 exit = true;
345 break;
347 default:
348 if(default_event_handler(button) == SYS_USB_CONNECTED)
349 return 1;
350 break;
352 if(delta)
354 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
355 pitch = pitch_increase(pitch, delta, true);
356 } else {
357 pitch = pitch_increase_semitone(pitch, delta > 0 ? true:false);
360 delta = 0;
363 #if CONFIG_CODEC == SWCODEC
364 pcmbuf_set_low_latency(false);
365 #endif
366 return 0;