Updated our source code header to explicitly mention that we are GPL v2 or
[Rockbox.git] / apps / gui / pitchscreen.c
blobc9d6750242995b230fea3a16d3f81d6ede7de00a
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"
40 #define PITCH_MAX 2000
41 #define PITCH_MIN 500
42 #define PITCH_SMALL_DELTA 1
43 #define PITCH_BIG_DELTA 10
44 #define PITCH_NUDGE_DELTA 20
46 #define PITCH_MODE_ABSOLUTE 1
47 #define PITCH_MODE_SEMITONE -PITCH_MODE_ABSOLUTE
49 static int pitch_mode = PITCH_MODE_ABSOLUTE; /* 1 - absolute, -1 - semitone */
51 /* returns:
52 0 if no key was pressed
53 1 if USB was connected */
55 static void pitch_screen_draw(struct screen *display, int pitch, int pitch_mode)
57 unsigned char* ptr;
58 unsigned char buf[32];
59 int w, h;
61 display->clear_display();
63 if (display->nb_lines < 4) /* very small screen, just show the pitch value */
65 w = snprintf((char *)buf, sizeof(buf), "%s: %d.%d%%",str(LANG_PITCH),
66 pitch / 10, pitch % 10 );
67 display->putsxy((display->width-(w*display->char_width))/2,
68 display->nb_lines/2,buf);
70 else /* bigger screen, show everything... */
73 /* UP: Pitch Up */
74 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
75 ptr = str(LANG_PITCH_UP);
76 } else {
77 ptr = str(LANG_PITCH_UP_SEMITONE);
79 display->getstringsize(ptr,&w,&h);
80 display->putsxy((display->width-w)/2, 0, ptr);
81 display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow],
82 display->width/2 - 3, h, 7, 8);
84 /* DOWN: Pitch Down */
85 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
86 ptr = str(LANG_PITCH_DOWN);
87 } else {
88 ptr = str(LANG_PITCH_DOWN_SEMITONE);
90 display->getstringsize(ptr,&w,&h);
91 display->putsxy((display->width-w)/2, display->height - h, ptr);
92 display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
93 display->width/2 - 3, display->height - h*2, 7, 8);
95 /* RIGHT: +2% */
96 ptr = "+2%";
97 display->getstringsize(ptr,&w,&h);
98 display->putsxy(display->width-w, (display->height-h)/2, ptr);
99 display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
100 display->width-w-8, (display->height-h)/2, 7, 8);
102 /* LEFT: -2% */
103 ptr = "-2%";
104 display->getstringsize(ptr,&w,&h);
105 display->putsxy(0, (display->height-h)/2, ptr);
106 display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward],
107 w+1, (display->height-h)/2, 7, 8);
109 /* "Pitch" */
110 snprintf((char *)buf, sizeof(buf), str(LANG_PITCH));
111 display->getstringsize(buf,&w,&h);
112 display->putsxy((display->width-w)/2, (display->height/2)-h, buf);
113 /* "XX.X%" */
114 snprintf((char *)buf, sizeof(buf), "%d.%d%%",
115 pitch / 10, pitch % 10 );
116 display->getstringsize(buf,&w,&h);
117 display->putsxy((display->width-w)/2, display->height/2, buf);
120 display->update();
123 static int pitch_increase(int pitch, int delta, bool allow_cutoff)
125 int new_pitch;
127 if (delta < 0) {
128 if (pitch + delta >= PITCH_MIN) {
129 new_pitch = pitch + delta;
130 } else {
131 if (!allow_cutoff) {
132 return pitch;
134 new_pitch = PITCH_MIN;
136 } else if (delta > 0) {
137 if (pitch + delta <= PITCH_MAX) {
138 new_pitch = pitch + delta;
139 } else {
140 if (!allow_cutoff) {
141 return pitch;
143 new_pitch = PITCH_MAX;
145 } else {
146 /* delta == 0 -> no real change */
147 return pitch;
149 sound_set_pitch(new_pitch);
151 return new_pitch;
154 /* Factor for changing the pitch one half tone up.
155 The exact value is 2^(1/12) = 1.05946309436
156 But we use only integer arithmetics, so take
157 rounded factor multiplied by 10^5=100,000. This is
158 enough to get the same promille values as if we
159 had used floating point (checked with a spread
160 sheet).
162 #define PITCH_SEMITONE_FACTOR 105946L
164 /* Some helpful constants. K is the scaling factor for SEMITONE.
165 N is for more accurate rounding
166 KN is K * N
168 #define PITCH_K_FCT 100000UL
169 #define PITCH_N_FCT 10
170 #define PITCH_KN_FCT 1000000UL
172 static int pitch_increase_semitone(int pitch, bool up)
174 uint32_t tmp;
175 uint32_t round_fct; /* How much to scale down at the end */
176 tmp = pitch;
177 if (up) {
178 tmp = tmp * PITCH_SEMITONE_FACTOR;
179 round_fct = PITCH_K_FCT;
180 } else {
181 tmp = (tmp * PITCH_KN_FCT) / PITCH_SEMITONE_FACTOR;
182 round_fct = PITCH_N_FCT;
184 /* Scaling down with rounding */
185 tmp = (tmp + round_fct / 2) / round_fct;
186 return pitch_increase(pitch, tmp - pitch, false);
189 bool pitch_screen(void)
191 int button;
192 int pitch = sound_get_pitch();
193 int new_pitch, delta = 0;
194 bool nudged = false;
195 bool exit = false;
196 int i;
198 #if CONFIG_CODEC == SWCODEC
199 pcmbuf_set_low_latency(true);
200 #endif
202 while (!exit)
204 FOR_NB_SCREENS(i)
205 pitch_screen_draw(&screens[i], pitch, pitch_mode);
207 button = get_action(CONTEXT_PITCHSCREEN,TIMEOUT_BLOCK);
208 switch (button) {
209 case ACTION_PS_INC_SMALL:
210 delta = PITCH_SMALL_DELTA;
211 break;
213 case ACTION_PS_INC_BIG:
214 delta = PITCH_BIG_DELTA;
215 break;
217 case ACTION_PS_DEC_SMALL:
218 delta = -PITCH_SMALL_DELTA;
219 break;
221 case ACTION_PS_DEC_BIG:
222 delta = -PITCH_BIG_DELTA;
223 break;
225 case ACTION_PS_NUDGE_RIGHT:
226 new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false);
227 nudged = (new_pitch != pitch);
228 pitch = new_pitch;
229 break;
231 case ACTION_PS_NUDGE_RIGHTOFF:
232 if (nudged) {
233 pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false);
235 nudged = false;
236 break;
238 case ACTION_PS_NUDGE_LEFT:
239 new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false);
240 nudged = (new_pitch != pitch);
241 pitch = new_pitch;
242 break;
244 case ACTION_PS_NUDGE_LEFTOFF:
245 if (nudged) {
246 pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false);
248 nudged = false;
249 break;
251 case ACTION_PS_RESET:
252 pitch = 1000;
253 sound_set_pitch( pitch );
254 break;
256 case ACTION_PS_TOGGLE_MODE:
257 pitch_mode = -pitch_mode;
258 break;
260 case ACTION_PS_EXIT:
261 exit = true;
262 break;
264 default:
265 if(default_event_handler(button) == SYS_USB_CONNECTED)
266 return 1;
267 break;
270 if(delta)
272 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
273 pitch = pitch_increase(pitch, delta, true);
274 } else {
275 pitch = pitch_increase_semitone(pitch, delta > 0 ? true:false);
278 delta = 0;
282 #if CONFIG_CODEC == SWCODEC
283 pcmbuf_set_low_latency(false);
284 #endif
285 lcd_setfont(FONT_UI);
286 return 0;