implement smooth seeking acceleration for audio playback and mpegplayer
[Rockbox.git] / apps / gui / pitchscreen.c
blob6b8fcf23562427e0a0e8a68e7addaa68b59bfb16
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <stdbool.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include "config.h"
24 #include "sprintf.h"
25 #include "settings.h"
26 #include "action.h"
27 #include "system.h"
28 #include "font.h"
29 #include "misc.h"
30 #include "dsp.h"
31 #include "sound.h"
32 #include "pcmbuf.h"
33 #include "lang.h"
34 #include "icons.h"
35 #include "screen_access.h"
36 #include "screens.h"
38 #define PITCH_MAX 2000
39 #define PITCH_MIN 500
40 #define PITCH_SMALL_DELTA 1
41 #define PITCH_BIG_DELTA 10
42 #define PITCH_NUDGE_DELTA 20
44 #define PITCH_MODE_ABSOLUTE 1
45 #define PITCH_MODE_SEMITONE -PITCH_MODE_ABSOLUTE
47 static int pitch_mode = PITCH_MODE_ABSOLUTE; /* 1 - absolute, -1 - semitone */
49 /* returns:
50 0 if no key was pressed
51 1 if USB was connected */
53 static void pitch_screen_draw(struct screen *display, int pitch, int pitch_mode)
55 unsigned char* ptr;
56 unsigned char buf[32];
57 int w, h;
59 display->clear_display();
61 if (display->nb_lines < 4) /* very small screen, just show the pitch value */
63 w = snprintf((char *)buf, sizeof(buf), "%s: %d.%d%%",str(LANG_PITCH),
64 pitch / 10, pitch % 10 );
65 display->putsxy((display->width-(w*display->char_width))/2,
66 display->nb_lines/2,buf);
68 else /* bigger screen, show everything... */
71 /* UP: Pitch Up */
72 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
73 ptr = str(LANG_PITCH_UP);
74 } else {
75 ptr = str(LANG_PITCH_UP_SEMITONE);
77 display->getstringsize(ptr,&w,&h);
78 display->putsxy((display->width-w)/2, 0, ptr);
79 display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow],
80 display->width/2 - 3, h, 7, 8);
82 /* DOWN: Pitch Down */
83 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
84 ptr = str(LANG_PITCH_DOWN);
85 } else {
86 ptr = str(LANG_PITCH_DOWN_SEMITONE);
88 display->getstringsize(ptr,&w,&h);
89 display->putsxy((display->width-w)/2, display->height - h, ptr);
90 display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
91 display->width/2 - 3, display->height - h*2, 7, 8);
93 /* RIGHT: +2% */
94 ptr = "+2%";
95 display->getstringsize(ptr,&w,&h);
96 display->putsxy(display->width-w, (display->height-h)/2, ptr);
97 display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
98 display->width-w-8, (display->height-h)/2, 7, 8);
100 /* LEFT: -2% */
101 ptr = "-2%";
102 display->getstringsize(ptr,&w,&h);
103 display->putsxy(0, (display->height-h)/2, ptr);
104 display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward],
105 w+1, (display->height-h)/2, 7, 8);
107 /* "Pitch" */
108 snprintf((char *)buf, sizeof(buf), str(LANG_PITCH));
109 display->getstringsize(buf,&w,&h);
110 display->putsxy((display->width-w)/2, (display->height/2)-h, buf);
111 /* "XX.X%" */
112 snprintf((char *)buf, sizeof(buf), "%d.%d%%",
113 pitch / 10, pitch % 10 );
114 display->getstringsize(buf,&w,&h);
115 display->putsxy((display->width-w)/2, display->height/2, buf);
118 display->update();
121 static int pitch_increase(int pitch, int delta, bool allow_cutoff)
123 int new_pitch;
125 if (delta < 0) {
126 if (pitch + delta >= PITCH_MIN) {
127 new_pitch = pitch + delta;
128 } else {
129 if (!allow_cutoff) {
130 return pitch;
132 new_pitch = PITCH_MIN;
134 } else if (delta > 0) {
135 if (pitch + delta <= PITCH_MAX) {
136 new_pitch = pitch + delta;
137 } else {
138 if (!allow_cutoff) {
139 return pitch;
141 new_pitch = PITCH_MAX;
143 } else {
144 /* delta == 0 -> no real change */
145 return pitch;
147 sound_set_pitch(new_pitch);
149 return new_pitch;
152 /* Factor for changing the pitch one half tone up.
153 The exact value is 2^(1/12) = 1.05946309436
154 But we use only integer arithmetics, so take
155 rounded factor multiplied by 10^5=100,000. This is
156 enough to get the same promille values as if we
157 had used floating point (checked with a spread
158 sheet).
160 #define PITCH_SEMITONE_FACTOR 105946L
162 /* Some helpful constants. K is the scaling factor for SEMITONE.
163 N is for more accurate rounding
164 KN is K * N
166 #define PITCH_K_FCT 100000UL
167 #define PITCH_N_FCT 10
168 #define PITCH_KN_FCT 1000000UL
170 static int pitch_increase_semitone(int pitch, bool up)
172 uint32_t tmp;
173 uint32_t round_fct; /* How much to scale down at the end */
174 tmp = pitch;
175 if (up) {
176 tmp = tmp * PITCH_SEMITONE_FACTOR;
177 round_fct = PITCH_K_FCT;
178 } else {
179 tmp = (tmp * PITCH_KN_FCT) / PITCH_SEMITONE_FACTOR;
180 round_fct = PITCH_N_FCT;
182 /* Scaling down with rounding */
183 tmp = (tmp + round_fct / 2) / round_fct;
184 return pitch_increase(pitch, tmp - pitch, false);
187 bool pitch_screen(void)
189 int button;
190 int pitch = sound_get_pitch();
191 int new_pitch, delta = 0;
192 bool nudged = false;
193 bool exit = false;
194 int i;
196 #if CONFIG_CODEC == SWCODEC
197 pcmbuf_set_low_latency(true);
198 #endif
200 while (!exit)
202 FOR_NB_SCREENS(i)
203 pitch_screen_draw(&screens[i], pitch, pitch_mode);
205 button = get_action(CONTEXT_PITCHSCREEN,TIMEOUT_BLOCK);
206 switch (button) {
207 case ACTION_PS_INC_SMALL:
208 delta = PITCH_SMALL_DELTA;
209 break;
211 case ACTION_PS_INC_BIG:
212 delta = PITCH_BIG_DELTA;
213 break;
215 case ACTION_PS_DEC_SMALL:
216 delta = -PITCH_SMALL_DELTA;
217 break;
219 case ACTION_PS_DEC_BIG:
220 delta = -PITCH_BIG_DELTA;
221 break;
223 case ACTION_PS_NUDGE_RIGHT:
224 new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false);
225 nudged = (new_pitch != pitch);
226 pitch = new_pitch;
227 break;
229 case ACTION_PS_NUDGE_RIGHTOFF:
230 if (nudged) {
231 pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false);
233 nudged = false;
234 break;
236 case ACTION_PS_NUDGE_LEFT:
237 new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false);
238 nudged = (new_pitch != pitch);
239 pitch = new_pitch;
240 break;
242 case ACTION_PS_NUDGE_LEFTOFF:
243 if (nudged) {
244 pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false);
246 nudged = false;
247 break;
249 case ACTION_PS_RESET:
250 pitch = 1000;
251 sound_set_pitch( pitch );
252 break;
254 case ACTION_PS_TOGGLE_MODE:
255 pitch_mode = -pitch_mode;
256 break;
258 case ACTION_PS_EXIT:
259 exit = true;
260 break;
262 default:
263 if(default_event_handler(button) == SYS_USB_CONNECTED)
264 return 1;
265 break;
268 if(delta)
270 if (pitch_mode == PITCH_MODE_ABSOLUTE) {
271 pitch = pitch_increase(pitch, delta, true);
272 } else {
273 pitch = pitch_increase_semitone(pitch, delta > 0 ? true:false);
276 delta = 0;
280 #if CONFIG_CODEC == SWCODEC
281 pcmbuf_set_low_latency(false);
282 #endif
283 lcd_setfont(FONT_UI);
284 return 0;