1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
38 #include "pitchscreen.h"
39 #if CONFIG_CODEC == SWCODEC
44 #define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */
45 /* on both sides when drawing */
47 #define PITCH_MAX 2000
49 #define PITCH_SMALL_DELTA 1
50 #define PITCH_BIG_DELTA 10
51 #define PITCH_NUDGE_DELTA 20
53 static bool pitch_mode_semitone
= false;
54 #if CONFIG_CODEC == SWCODEC
55 static bool pitch_mode_timestretch
= false;
66 static void pitchscreen_fix_viewports(struct viewport
*parent
,
67 struct viewport pitch_viewports
[PITCH_ITEM_COUNT
])
70 height
= font_get(parent
->font
)->height
;
71 for (i
= 0; i
< PITCH_ITEM_COUNT
; i
++)
73 pitch_viewports
[i
] = *parent
;
74 pitch_viewports
[i
].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;
84 pitch_viewports
[PITCH_BOTTOM
].y
+= parent
->height
- height
- ICON_BORDER
;
87 /* must be called before pitchscreen_draw, or within
88 * since it neither clears nor updates the display */
89 static void pitchscreen_draw_icons(struct screen
*display
,
90 struct viewport
*parent
)
92 display
->set_viewport(parent
);
93 display
->mono_bitmap(bitmap_icons_7x8
[Icon_UpArrow
],
96 display
->mono_bitmap(bitmap_icons_7x8
[Icon_DownArrow
],
98 parent
->height
- 10, 7, 8);
99 display
->mono_bitmap(bitmap_icons_7x8
[Icon_FastForward
],
101 parent
->height
/2 - 4, 7, 8);
102 display
->mono_bitmap(bitmap_icons_7x8
[Icon_FastBackward
],
104 parent
->height
/2 - 4, 7, 8);
105 display
->update_viewport();
108 static void pitchscreen_draw(struct screen
*display
, int max_lines
,
109 struct viewport pitch_viewports
[PITCH_ITEM_COUNT
],
111 #if CONFIG_CODEC == SWCODEC
119 bool show_lang_pitch
;
121 /* "Pitch up/Pitch down" - hide for a small screen */
125 display
->set_viewport(&pitch_viewports
[PITCH_TOP
]);
126 if (pitch_mode_semitone
)
127 ptr
= str(LANG_PITCH_UP_SEMITONE
);
129 ptr
= str(LANG_PITCH_UP
);
130 display
->getstringsize(ptr
, &w
, &h
);
131 display
->clear_viewport();
133 display
->putsxy((pitch_viewports
[PITCH_TOP
].width
/ 2) -
135 display
->update_viewport();
137 /* DOWN: Pitch Down */
138 display
->set_viewport(&pitch_viewports
[PITCH_BOTTOM
]);
139 if (pitch_mode_semitone
)
140 ptr
= str(LANG_PITCH_DOWN_SEMITONE
);
142 ptr
= str(LANG_PITCH_DOWN
);
143 display
->getstringsize(ptr
, &w
, &h
);
144 display
->clear_viewport();
146 display
->putsxy((pitch_viewports
[PITCH_BOTTOM
].width
/ 2) -
148 display
->update_viewport();
152 display
->set_viewport(&pitch_viewports
[PITCH_MID
]);
153 display
->clear_viewport();
156 /* Middle section upper line - hide for a small screen */
157 if ((show_lang_pitch
= (max_lines
>= 3)))
159 #if CONFIG_CODEC == SWCODEC
160 if (!pitch_mode_timestretch
)
164 snprintf(buf
, sizeof(buf
), "%s", str(LANG_PITCH
));
165 #if CONFIG_CODEC == SWCODEC
170 snprintf(buf
, sizeof(buf
), "%s:%d.%d%%", str(LANG_PITCH
),
171 pitch
/ 10, pitch
% 10);
174 display
->getstringsize(buf
, &w
, &h
);
175 display
->putsxy((pitch_viewports
[PITCH_MID
].width
/ 2) - (w
/ 2),
181 /* Middle section lower line */
182 #if CONFIG_CODEC == SWCODEC
183 if (!pitch_mode_timestretch
)
187 snprintf(buf
, sizeof(buf
), "%d.%d%%",
188 pitch
/ 10, pitch
% 10);
189 #if CONFIG_CODEC == SWCODEC
194 snprintf(buf
, sizeof(buf
), "%s:%d%%", str(LANG_SPEED
),
198 display
->getstringsize(buf
, &w
, &h
);
199 display
->putsxy((pitch_viewports
[PITCH_MID
].width
/ 2) - (w
/ 2),
200 (show_lang_pitch
? h
: h
/2), buf
);
204 /* Middle section left/right labels */
205 const char *leftlabel
= "-2%";
206 const char *rightlabel
= "+2%";
207 #if CONFIG_CODEC == SWCODEC
208 if (pitch_mode_timestretch
)
215 /* Only display if they fit */
216 display
->getstringsize(leftlabel
, &w
, &h
);
218 display
->getstringsize(rightlabel
, &w
, &h
);
221 if (width_used
<= pitch_viewports
[PITCH_MID
].width
)
223 display
->putsxy(0, h
/ 2, leftlabel
);
224 display
->putsxy(pitch_viewports
[PITCH_MID
].width
- w
, h
/2, rightlabel
);
226 display
->update_viewport();
227 display
->set_viewport(NULL
);
230 static int pitch_increase(int pitch
, int pitch_delta
, bool allow_cutoff
)
236 if (pitch
+ pitch_delta
>= PITCH_MIN
)
237 new_pitch
= pitch
+ pitch_delta
;
242 new_pitch
= PITCH_MIN
;
245 else if (pitch_delta
> 0)
247 if (pitch
+ pitch_delta
<= PITCH_MAX
)
248 new_pitch
= pitch
+ pitch_delta
;
253 new_pitch
= PITCH_MAX
;
258 /* pitch_delta == 0 -> no real change */
261 sound_set_pitch(new_pitch
);
266 /* Factor for changing the pitch one half tone up.
267 The exact value is 2^(1/12) = 1.05946309436
268 But we use only integer arithmetics, so take
269 rounded factor multiplied by 10^5=100,000. This is
270 enough to get the same promille values as if we
271 had used floating point (checked with a spread
274 #define PITCH_SEMITONE_FACTOR 105946L
276 /* Some helpful constants. K is the scaling factor for SEMITONE.
277 N is for more accurate rounding
280 #define PITCH_K_FCT 100000UL
281 #define PITCH_N_FCT 10
282 #define PITCH_KN_FCT 1000000UL
284 static int pitch_increase_semitone(int pitch
, bool up
)
287 uint32_t round_fct
; /* How much to scale down at the end */
291 tmp
= tmp
* PITCH_SEMITONE_FACTOR
;
292 round_fct
= PITCH_K_FCT
;
296 tmp
= (tmp
* PITCH_KN_FCT
) / PITCH_SEMITONE_FACTOR
;
297 round_fct
= PITCH_N_FCT
;
299 /* Scaling down with rounding */
300 tmp
= (tmp
+ round_fct
/ 2) / round_fct
;
301 return pitch_increase(pitch
, tmp
- pitch
, false);
307 1 if USB was connected
310 int gui_syncpitchscreen_run(void)
313 int pitch
= sound_get_pitch();
314 #if CONFIG_CODEC == SWCODEC
315 int stretch
= dsp_get_timestretch();
316 int speed
= stretch
* pitch
; /* speed to maintain */
322 /* should maybe be passed per parameter later, not needed for now */
323 struct viewport parent
[NB_SCREENS
];
324 struct viewport pitch_viewports
[NB_SCREENS
][PITCH_ITEM_COUNT
];
325 int max_lines
[NB_SCREENS
];
327 /* initialize pitchscreen vps */
330 screens
[i
].clear_display();
331 viewport_set_defaults(&parent
[i
], i
);
332 max_lines
[i
] = viewport_get_nb_lines(&parent
[i
]);
333 pitchscreen_fix_viewports(&parent
[i
], pitch_viewports
[i
]);
335 /* also, draw the icons now, it's only needed once */
336 pitchscreen_draw_icons(&screens
[i
], &parent
[i
]);
338 #if CONFIG_CODEC == SWCODEC
339 pcmbuf_set_low_latency(true);
345 pitchscreen_draw(&screens
[i
], max_lines
[i
],
346 pitch_viewports
[i
], pitch
347 #if CONFIG_CODEC == SWCODEC
352 button
= get_action(CONTEXT_PITCHSCREEN
, HZ
);
355 case ACTION_PS_INC_SMALL
:
356 pitch_delta
= PITCH_SMALL_DELTA
;
359 case ACTION_PS_INC_BIG
:
360 pitch_delta
= PITCH_BIG_DELTA
;
363 case ACTION_PS_DEC_SMALL
:
364 pitch_delta
= -PITCH_SMALL_DELTA
;
367 case ACTION_PS_DEC_BIG
:
368 pitch_delta
= -PITCH_BIG_DELTA
;
371 case ACTION_PS_NUDGE_RIGHT
:
372 #if CONFIG_CODEC == SWCODEC
373 if (!pitch_mode_timestretch
)
376 new_pitch
= pitch_increase(pitch
, PITCH_NUDGE_DELTA
, false);
377 nudged
= (new_pitch
!= pitch
);
380 #if CONFIG_CODEC == SWCODEC
383 case ACTION_PS_FASTER
:
384 if (pitch_mode_timestretch
&& stretch
< STRETCH_MAX
)
387 dsp_set_timestretch(stretch
);
388 speed
= stretch
* pitch
;
393 case ACTION_PS_NUDGE_RIGHTOFF
:
396 pitch
= pitch_increase(pitch
, -PITCH_NUDGE_DELTA
, false);
401 case ACTION_PS_NUDGE_LEFT
:
402 #if CONFIG_CODEC == SWCODEC
403 if (!pitch_mode_timestretch
)
406 new_pitch
= pitch_increase(pitch
, -PITCH_NUDGE_DELTA
, false);
407 nudged
= (new_pitch
!= pitch
);
410 #if CONFIG_CODEC == SWCODEC
413 case ACTION_PS_SLOWER
:
414 if (pitch_mode_timestretch
&& stretch
> STRETCH_MIN
)
417 dsp_set_timestretch(stretch
);
418 speed
= stretch
* pitch
;
423 case ACTION_PS_NUDGE_LEFTOFF
:
426 pitch
= pitch_increase(pitch
, PITCH_NUDGE_DELTA
, false);
431 case ACTION_PS_RESET
:
433 sound_set_pitch(pitch
);
434 #if CONFIG_CODEC == SWCODEC
436 dsp_set_timestretch(stretch
);
437 speed
= stretch
* pitch
;
441 case ACTION_PS_TOGGLE_MODE
:
442 #if CONFIG_CODEC == SWCODEC
443 if (dsp_timestretch_available() && pitch_mode_semitone
)
444 pitch_mode_timestretch
= !pitch_mode_timestretch
;
446 pitch_mode_semitone
= !pitch_mode_semitone
;
454 if (default_event_handler(button
) == SYS_USB_CONNECTED
)
460 if (pitch_mode_semitone
)
461 pitch
= pitch_increase_semitone(pitch
, pitch_delta
> 0);
463 pitch
= pitch_increase(pitch
, pitch_delta
, true);
464 #if CONFIG_CODEC == SWCODEC
465 if (pitch_mode_timestretch
)
467 /* Set stretch to maintain speed */
468 /* i.e. increase pitch, reduce stretch */
469 int new_stretch
= speed
/ pitch
;
470 if (new_stretch
>= STRETCH_MIN
&& new_stretch
<= STRETCH_MAX
)
472 stretch
= new_stretch
;
473 dsp_set_timestretch(stretch
);
477 speed
= stretch
* pitch
;
481 #if CONFIG_CODEC == SWCODEC
482 pcmbuf_set_low_latency(false);